Создание файла учетных данных на сервере с помощью Dockerfile и менеджера секретов облака Google
Я использую облачную сборку Google для CI/CD для моего приложения django, и одно из моих требований - настроить GOOGLE_APPLICATION_CREDENTIALS
так, чтобы я мог выполнять аутентифицированные действия в моей сборке Docker. Например, мне нужно запустить RUN python manage.py collectstatic --noinput
, который требует доступа к моим ведрам облачного хранилища Google.
Я создал учетные данные, и они хорошо работают, если просто включить их в мое (в настоящее время приватное) репо в виде .json-файла, так что они попадают в мой контейнер Docker с помощью команды COPY . .
и установки переменной env с помощью ENV GOOGLE_APPLICATION_CREDENTIALS=credentials.json
. В конечном итоге я хочу получить значение учетных данных из менеджера secret и создать файл учетных данных на этапе сборки, чтобы полностью удалить учетные данные из репозитория. Я пытался сделать это с помощью редактирования cloudbuild.yaml
(ссылаясь на this doc) с различными реализациями конфига availableSecrets
, синтаксиса $$SECRET
и build-args
в команде сборки docker и попыткой доступа в Dockerfile с помощью
ARG GOOGLE_BUILD_CREDS
RUN echo "$GOOGLE_BUILD_CREDS" >> credentials.json
ENV GOOGLE_APPLICATION_CREDENTIALS=credentials.json
безрезультатно.
Если кто-то может подсказать мне, как реализовать это в моем cloudbuild.yaml и Dockerfile, если это возможно, или если есть другое лучшее решение, буду очень признателен.
Это соответствующая часть моего cloudbuild.yaml
steps:
- name: gcr.io/cloud-builders/docker
args:
- build
- '--no-cache'
- '-t'
- '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
- .
- '-f'
- Dockerfile
id: Build
availableSecrets:
secretManager:
- versionName: projects/PROJECT_ID/secrets/CREDENTIALS/versions/latest
env: 'CREDENTIALS'
Если ваш контейнер будет работать на Cloud Run, это очень просто: Удалите файл ключа учетной записи службы (и, грубо говоря, в большинстве случаев использования он вам никогда не понадобится).
Помните, что файл ключа учетной записи службы - это секрет с закрытым ключом. И если вы поместите его в свой контейнер, вы просто будете хранить его в виде обычного текста. Так плохо для секрета!!! (с помощью dive вы можете исследовать содержимое вашего контейнера и украсть секрет, если у вас есть доступ непосредственно к контейнеру)
Но, я уверен, вы знаете это, потому что хотите хранить секрет в менеджере секретов. Теперь вопрос? Как вы получаете доступ к секретному менеджеру? Нужен ли вам файл ключа учетной записи службы для аутентификации, чтобы получить к нему доступ?
На самом деле нет.
Решением является использование ADC (Application default credentials). В клиентских библиотеках используйте метод get default credential, чтобы библиотека автоматически определила платформу и используемый мандат
В Cloud Run (как и в других сервисах Google Cloud) есть сервер метаданных, который позволяет клиентским библиотекам получать информацию об учетных данных из учетной записи сервиса runtime service.
В вашей локальной среде у вас есть 2 варианта:
- Используйте собственные учетные данные. Для этого выполните команду
gcloud auth application-default login
. Это ваши собственные учетные данные и разрешения, не совсем такие же, как в среде выполнения Cloud Run .
- Персонифицируйте учетную запись службы среды выполнения Cloud Run и действуйте как она сама для локального запуска вашего контейнера/кода. Для этого выполните команду
gcloud auth application-default login --impersonate-service-account=<service account email>
, Убедитесь, что у учетной записи службы есть роль service account token creator.
Затем запустите свое приложение локально, и пусть ADC использует учетные данные
Кажется, я нашел решение. Чтобы решить ошибку, о которой я упоминал в своем ответе @guillaume-blaquiere, я обновил build args в cloudbuild.yaml
, чтобы включить --network=cloudbuild
, что позволило мне получить доступ к правильным учетным данным учетной записи сервиса (заслуга этого ответа ).
Следующая проблема, с которой я столкнулся, связана с библиотекой django-storages, возвращающей следующее исключение
AttributeError: you need a private key to sign credentials.the credentials you are currently using <class 'google.auth.compute_engine.credentials.Credentials'> just contains a token. see https://googleapis.dev/python/google-api-core/latest/auth.html#setting-up-a-service-account for more details.
Затем я наткнулся на это предложение добавить параметр GS_QUERYSTRING_AUTH = False в конфигурацию django, и это, похоже, помогло. Единственное, что меня беспокоит, это то, что документация не слишком подробно описывает последствия или риски отключения этого параметра (ведро является общедоступным - читайте, как он рекомендует). Однако кажется, что все работает, как задумано. Так что я буду использовать эту конфигурацию, если не будет предложено лучшего решения.