Облачные функции Google - как безопасно хранить закрытый ключ сервисной учетной записи при использовании Google Source Repository?

Я использую Google Source Repository для хранения своих облачных функций Google. (Репозиторий Git, в основном, размещен в Google)

Одной из моих функций требуется доступ к частному файлу Google Sheet, поэтому я создал учетную запись службы. (Слишком много прав, так как трудно понять, какие именно права мы должны предоставить учетной записи службы, и их так сложно обновить позже, но я отвлекся)

Сейчас явно не рекомендуется хранить JSON-файл сервисной учетной записи в самом репозитории git по очевидным причинам. Вот как это выглядит (без значений)

{
  "type": "service_account",
  "project_id": "",
  "private_key_id": "",
  "private_key": "",
  "client_email": "",
  "client_id": "",
  "auth_uri": "",
  "token_uri": "",
  "auth_provider_x509_cert_url": "",
  "client_x509_cert_url": ""
}

Я искал переменные среды для настройки функций или чего-то подобного, но ничего не нашел. Отслеживание ключа (и, следовательно, возможное дублирование этого файла в нескольких репозиториях) действительно не кажется такой хорошей идеей. Но я еще не нашел «правильного» способа сделать это. И из-за того, как работают функции Google, я не могу думать ни о чем другом, кроме переменных env.


person Vadorequest    schedule 03.02.2018    source источник


Ответы (6)


Мое решение при использовании облачной функции с учетной записью службы:

  1. Зашифруйте json-файл учетных данных своей служебной учетной записи с помощью Cloud KMS / vault и загрузите его в облачное хранилище.
  2. Получите json-файл учетных данных служебной учетной записи из облачного хранилища и расшифруйте его с помощью служебной учетной записи Cloud KMS, которая имеет разрешение на шифрование / дешифрование.

  3. Разберите json-файл учетных данных учетной записи службы во время выполнения и получите private_key, client_email и projectId.

  4. Передайте эти три секретные переменные клиентской библиотеке

Мы храним переменные конфигурации как переменные среды для облачной функции, они представляют собой обычный текст, но это нормально. Потому что это не секрет.

Мы не должны хранить секретные вещи, такие как простой текст, например, переменные среды облачных функций.

person slideshowp2    schedule 17.08.2019
comment
На данный момент это кажется наиболее исчерпывающим и надежным ответом, поэтому я помечаю его как ответ. Я не тестировал и не буду, так как давно перешел на AWS. Будущие читатели: Если этот ответ не отвечает на вопрос, дайте мне знать (пинг) в комментариях, и я его рассмотрю. :) - person Vadorequest; 23.08.2019
comment
Это необходимо только в том случае, если вам нужно создать клиента с конкретным файлом JSON учетной записи службы. например, клиент FCM. Если ваша функция Google использует API, которые получают учетные данные из текущего контекста, то этот ответ для вас. stackoverflow.com/questions/55671256/ - person ozOli; 30.09.2019

Вы можете загрузить файл учетной записи службы вместе со своими функциями и использовать его в своем коде. Там он останется в безопасности. Большинство разработчиков будут использовать .gitignore или аналогичный механизм, чтобы этот файл не был добавлен в систему управления версиями. Ниже приведен пример загрузки учетных данных учетной записи службы из образцов Firebase. . (Если вы не используете Firebase SDK, вам нужно не забыть преобразовать определение функции в облачный стиль.

Вы также можете использовать env var, но вам придется проявлять особую осторожность при цитировании и экранировании значений, чтобы убедиться, что они правильно попадают в вашу функцию. Это вроде хлопот, но выполнимо.

person Doug Stevenson    schedule 03.02.2018
comment
Итак, если я правильно понимаю, ваше решение - каким-то образом развернуть service-account-credentials.json файл в функции Google, не добавляя его в репозиторий исходного кода Google, полагаясь на firebase/gcloud CLI? (Я действительно не использую Firebase. Как бы вы использовали переменную env? Можете ли вы добавить пример или документ? Спасибо. - person Vadorequest; 04.02.2018
comment
Да, вот что я говорю. Документы для интерфейса командной строки Firebase: firebase.google.com/docs/cli - person Doug Stevenson; 04.02.2018
comment
привет @DougStevenson! На самом деле я немного смущен ссылкой на Firebase SDK здесь. Вы по существу предлагаете просто развернуть ключ учетной записи службы как часть облачной функции в GCP? - person jayBana; 07.01.2020

По состоянию на январь 2020 года Google выпустил диспетчер секретов, который описывается как:

Secret Manager - это новый облачный сервис Google, который обеспечивает безопасный и удобный метод хранения ключей API, паролей, сертификатов и других конфиденциальных данных. Secret Manager предоставляет центральное место и единый источник правды для управления, доступа и аудита секретов в Google Cloud.

Для облачных функций есть руководство здесь на как создать секрет, а затем получить его из облачной функции.

person neal    schedule 26.08.2020
comment
Обратите внимание, что даже при использовании диспетчера секретов возникает вопрос: а где мне хранить учетные данные для доступа к диспетчеру секретов? или как определить, кто может получить доступ к секретам ?. Все примеры, которые вы связали, полагаются на механизм ADC Google для доступа к секретам, который использует служебную учетную запись облачной функции для обработки начальной аутентификации. Ваш ответ - хорошая замена решению @ slideshowp2 для общих учетных данных (вне области действия GCP), но я думаю, что для доступа к ресурсам GCP люди должны полагаться исключительно на ADC. - person Diego Queiroz; 26.08.2020

Здесь вы можете узнать, как предоставить учетные данные своему приложению, используя переменную среды. GOOGLE_APPLICATION_CREDENTIALS.

person Katayoon    schedule 07.02.2018
comment
Это решение, но оно не будет работать с облачными функциями, поскольку вы не контролируете систему хостинга. Вы можете использовать это на своем локальном компьютере или на собственном сервере, но не с облачными функциями. Кроме того, мне это не нравится, потому что, если вам нужно использовать несколько разных учетных данных, которые не связаны между собой (например, несколько служб, каждая из которых предоставляет что-то, требующее своих собственных учетных данных), вы не можете их использовать. (если вы не создадите большие учетные данные, содержащие все эти учетные данные, но ... микросервисы, верно?) - person Vadorequest; 10.02.2018
comment
Вы можете использовать переменную среды GOOGLE_APPLICATION_CREDENTIALS по своему усмотрению. Вы также можете сохранить файл учетных данных в сегменте (с соответствующим уровнем доступа) и обратиться к нему. Затем вы можете получить и предоставить учетные данные учетной записи службы вручную в коде, как указано в этой документации: cloud .google.com / docs / authentication / - person Katayoon; 12.02.2018
comment
Все знают о ссылке на облачные документы Google, но это работает только в том случае, если вы запустите приложение локально. Проблема в том, что в документации не объясняется, как установить файл json в производство. - person ttfreeman; 22.04.2019
comment
Как насчет установки переменной среды GOOGLE_APPLICATION_CREDENTIALS облачной функции с помощью локального файла credentials.json при развертывании функции? - person pdoherty926; 13.11.2019

Вот как я решил эту проблему. Сначала создайте логику в файле keys.js, чтобы определить, находитесь ли вы в разработке или в производстве (и создайте соответствующие файлы ./dev.js и ./prod.js, где вы должны включить ./dev.js в файл .ignore, чтобы убедитесь, что он не загружен на ваш пульт github):

if (process.env.NODE_ENV === "production") {
  module.exports = require("./prod");
} else {
  module.exports = require("./dev");
}

Во-вторых, вам потребуется файл keys.js, в котором находится описанная выше логика, и создать объект учетных данных на основе данных, полученных из keys.js:

const credentials = {
  type: keys.googleType,
  project_id: keys.googleProjectId,
  private_key_id: keys.googlePrivateKeyId,
  private_key: keys.googlePrivateKey,
  client_email: keys.googleClientEmail,
  client_id: keys.googleClientId,
  auth_uri: keys.googleAuthUri,
  token_uri: keys.googleTokenUri,
  auth_provider_x509_cert_url: keys.googleAuthProviderX509CertUrl,
  client_x509_cert_url: keys.googleClientX509CertUrl
};

Теперь для каждой облачной службы Google вы можете использовать следующие примеры шаблонов:

  const storage = new Storage({
    project_id: credentials.project_id,
    credentials
  });
  const client = new textToSpeech.TextToSpeechClient({
    project_id: credentials.project_id,
    credentials
  });
...
etc.
person ttfreeman    schedule 28.04.2019

Я думаю, что вам действительно не нужно хранить какие-либо ключевые файлы в вашем коде.

Ваша функция работает с назначенной учетной записью службы (обычно это учетная запись службы по умолчанию App Engine, но ее можно изменить в дополнительных настройках). Если у вас есть особые потребности, вы должны создать учетную запись службы, специфичную для вашей функции, и предоставить ей все необходимые разрешения.

В вашей функции аутентификация будет происходить автоматически с использованием учетных данных приложения по умолчанию, поэтому вы не не нужно ни о чем заботиться (забудьте о переменных окружения, ключевых файлах и т. д.). Просто убедитесь, что вы используете клиентские библиотеки Google Cloud для своего языка, что они неявно сделают все за вас.

В частности, я избегаю креативных решений, подобных предложению one @ slideshowp2. Но я согласен, что у них есть свое применение (например, предположим, мне нужно хранить учетные данные для внешней системы вне области действия GCP. В этом сценарии его решение может быть подходящим вариантом), но использовать только службы Google, давайте оставим его просто.

person Diego Queiroz    schedule 26.08.2020