Чтение django_settings из менеджера секретов Google Cloud Platform не работает
При выполнении команды python manage.py makemigrations
локально на моем ноутбуке, я получаю следующую ошибку на моей консоли:
(mywebsite) C:\Users\Sander\PycharmProjects\mywebsite>python manage.py makemigrations
Invalid line: echo DATABASE_URL=postgres://myuser:mypassword@//cloudsql/mywebsite:europe-west6:mywebsite-db/mydb > .env
Invalid line: echo GS_BUCKET_NAME=mybucket >> .env
Invalid line: echo SECRET_KEY=$(cat /dev/urandom | LC_ALL=C tr -dc '[:alpha:]'| fold -w 50 | head -n
Обратите внимание, что инструкции echo [... etc. ...] > .env
на самом деле являются содержанием секрета, который я настроил в менеджере секретов Google Cloud Platform, следуя инструкциям Google Cloud Platform по развертыванию моего сайта Django на Google Cloud Run.
Теперь я знаю, что эти инструкции echo [... etc. ...] > .env
должны создать файл .env с переменными DATABASE_URL, GS_BUCKET_NAME и SECRET_KEY в нем, но это, конечно, не так, поскольку он сообщает об ошибке "Invalid line: ..." вместо этого.
Я нашел этот ответ на StackOverflow , в котором говорится, что эти инструкции bash (echo [... etc. ...] > .env
) просто не могут быть выполнены python и что я могу просто выполнить их локально, запустив их из сценария оболочки вместо этого, так что выполнение этого create-env-file.sh
работает:
DATABASE_URL=postgres://myuser:mypassword@//cloudsql/mywebsite:europe-we
st6:mywebsite-db/mydb > .env
GS_BUCKET_NAME=mybucket >> .env
echo SECRET_KEY=$(cat /dev/urandom | LC_ALL=C tr -dc '[:alpha:]'| fold -w 50 | head -n
Однако, при этом создается локальный .env файл и, очевидно, я хотел бы убедиться, что поток с Secret Manager работает вместо него, прежде чем переносить сайт на производство, поскольку если я сохраню .env файл и загружу его на производство, нет смысла продолжать использовать Secret Manager, он просто больше не нужен.
Это также становится очень ясно при просмотре кода, который фактически выполняется в бэке:
import io
import os
from pathlib import Path
import environ
import google.auth
from google.cloud import secretmanager
if os.path.isfile(env_file):
# Use a local secret file, if provided
env.read_env(env_file)
elif os.environ.get("GOOGLE_CLOUD_PROJECT", None):
# Pull secrets from Secret Manager
project_id = os.environ.get("GOOGLE_CLOUD_PROJECT")
client = secretmanager.SecretManagerServiceClient()
settings_name = os.environ.get("SETTINGS_NAME", "django_settings")
name = f"projects/{project_id}/secrets/{settings_name}/versions/latest"
payload = client.access_secret_version(name=name).payload.data.decode("UTF-8")
env.read_env(io.StringIO(payload))
else:
raise Exception("No local .env or GOOGLE_CLOUD_PROJECT detected. No secrets found.")
Я отладил этот код, и проблема заключается в выполнении env.read_env(io.StringIO(payload))
, поскольку полезная нагрузка содержит ожидаемое содержимое (строки echo [... etc. ...] > .env
).
Я вижу преимущество использования менеджера секретов Google, но я начинаю думать, что либо что-то не так с содержанием секрета, который предоставил учебник Django Cloud Run, либо с разбором кода и сохранением его в переменных среды.
Я работаю локально на Windows, со следующими библиотеками (содержимое моего requirements.txt
):
django
# For integrating with Google Cloud Platform:
django-storages[google]>=1.12
django-environ>=0.8.1
psycopg2-binary>=2.9.1
gunicorn>=20.1.0
google-cloud-secret-manager>=2.7.2
Это, очевидно, вызвано двумя причинами:
В settings.py секретное содержимое загружается в переменные окружения с помощью
env.read_env(io.StringIO(payload))
, как указано в вопросе. Эта функция read_env(), очевидно, делает следующее:# ... for line in content.splitlines(): m1 = re.match(r'\A(?:export )?([A-Za-z_0-9]+)=(.*)\Z', line) if m1: # ... elif not line or line.startswith('#'): # ignore warnings for empty line-breaks or comments pass else: logger.warning('Invalid line: %s', line) # ...
Поскольку строки секретного содержимого начинаются с "echo ", строки помечаются как недопустимые (вы можете проверить это на https://regex101.com) и команда
python manage.py makemigrations
поэтому завершается с этой ошибкой.При редактировании
payload
перед входом вenv.read_env(io.StringIO(payload))
так, чтобы он больше не начинался сecho
(для решения проблемы, описанной в пуле выше) и, также из-за регексового соответствия, также удаляя> .env
или>> .env
в конце, 3-я строка также вызывает проблемы:SECRET_KEY=$(cat /dev/urandom | LC_ALL=C tr -dc '[:alpha:]'| fold -w 50 | head -n
. Чтение/dev/urandom
для генерации псевдослучайного SECRET_KEY является проблемой в Windows,/dev/urandom
существует только в операционных системах на базе Linux.
Похоже, что секрет должен работать на производственных Linux-серверах Google Cloud Run, но не на локальном компьютере под управлением Windows, если его выполнить, как в инструкции по развертыванию сайта Django.
Вместо этого, для локальных запусков, do создайте .env файл, либо действительно запустив скрипт create-env-file.sh
, упомянутый в вопросе (*), либо создав .env файл вручную в той же папке, что и settings.py:
DATABASE_URL=postgres://myuser:mypassword@//cloudsql/mywebsite:europe-west6:mywebsite-db/mydb
GS_BUCKET_NAME=mybucket
SECRET_KEY=some1279Long30String5You7Create2Yourself8136
(*) /dev/urandom сработал для меня, потому что когда я выполняю create-env_file.sh
на терминальном окне в PyCharm, на моем компьютере открывается новый терминал Git Bash, возможно потому, что на моем компьютере это зарегистрированная программа для выполнения файлов оболочки.