Мне нужно хранить ключи API и другую конфиденциальную информацию в app.yaml
качестве переменных среды для развертывания в GAE. Проблема в том, что если я нажимаю app.yaml
на GitHub, эта информация становится общедоступной (не очень хорошо). Я не хочу хранить информацию в хранилище данных, поскольку это не подходит для проекта. Скорее я хотел бы заменить значения из файла, который указан в .gitignore
каждом развертывании приложения.
Вот мой файл app.yaml:
application: myapp
version: 3
runtime: python27
api_version: 1
threadsafe: true
libraries:
- name: webapp2
version: latest
- name: jinja2
version: latest
handlers:
- url: /static
static_dir: static
- url: /.*
script: main.application
login: required
secure: always
# auth_fail_action: unauthorized
env_variables:
CLIENT_ID: ${CLIENT_ID}
CLIENT_SECRET: ${CLIENT_SECRET}
ORG: ${ORG}
ACCESS_TOKEN: ${ACCESS_TOKEN}
SESSION_SECRET: ${SESSION_SECRET}
Любые идеи?
Ответы:
Если это конфиденциальные данные, вы не должны хранить их в исходном коде, поскольку они будут проверены в системе управления версиями. Не те люди (внутри или вне вашей организации) могут найти его там. Кроме того, ваша среда разработки, вероятно, использует другие значения конфигурации из вашей производственной среды. Если эти значения хранятся в коде, вам придется запускать другой код при разработке и производстве, что является беспорядочной и плохой практикой.
В своих проектах я помещаю данные конфигурации в хранилище данных с помощью этого класса:
from google.appengine.ext import ndb class Settings(ndb.Model): name = ndb.StringProperty() value = ndb.StringProperty() @staticmethod def get(name): NOT_SET_VALUE = "NOT SET" retval = Settings.query(Settings.name == name).get() if not retval: retval = Settings() retval.name = name retval.value = NOT_SET_VALUE retval.put() if retval.value == NOT_SET_VALUE: raise Exception(('Setting %s not found in the database. A placeholder ' + 'record has been created. Go to the Developers Console for your app ' + 'in App Engine, look up the Settings record with name=%s and enter ' + 'its value in that record\'s value field.') % (name, name)) return retval.value
Ваше приложение сделает это, чтобы получить значение:
API_KEY = Settings.get('API_KEY')
Если в хранилище данных есть значение для этого ключа, вы его получите. Если нет, будет создана запись-заполнитель и будет выброшено исключение. Исключение будет напоминать вам перейти в консоль разработчика и обновить запись заполнителя.
Я считаю, что это позволяет не догадываться при установке значений конфигурации. Если вы не уверены, какие значения конфигурации нужно установить, просто запустите код, и он сообщит вам!
В приведенном выше коде используется библиотека ndb, которая использует memcache и хранилище данных под капотом, так что это быстро.
Обновить:
Джелдер спросил, как найти значения хранилища данных в консоли App Engine и установить их. Вот как:
Перейдите на https://console.cloud.google.com/datastore/.
Выберите свой проект вверху страницы, если он еще не выбран.
В раскрывающемся списке Тип выберите Настройки .
Если вы запустили приведенный выше код, ваши ключи появятся. Все они будут иметь значение NOT SET . Щелкните каждый из них и установите его значение.
Надеюсь это поможет!
источник
Это простое решение, которое может подойти не всем командам.
Сначала поместите переменные среды в env_variables.yaml , например,
env_variables: SECRET: 'my_secret'
Затем включите это
env_variables.yaml
вapp.yaml
Наконец, добавьте
env_variables.yaml
к.gitignore
, так что секретные переменные не будут существовать в хранилище.В этом случае
env_variables.yaml
необходимо разделить между менеджерами развертывания.источник
process.env.MY_SECRET_KEY
и если вам нужны эти переменные среды в вашей локальной среде разработки, вы можете использоватьdotenv
пакет nodeenv_variables.yaml
добраться до всех экземпляров - это недостающий кусок головоломки.gcloud app deploy
как обычно, для развертывания в Google Cloud. 2. Как установить секретные переменные окружения локально? Есть много способов. Вы можете просто использоватьexport
в командной строке или использовать любые инструменты, такие как @DaveKiss.os.environ.get('SECRET')
.Мой подход заключается в хранении секретов клиента только в самом приложении App Engine. Секреты клиента не находятся ни в системе управления версиями, ни на каких-либо локальных компьютерах. Это дает то преимущество, что любой сотрудник App Engine может развертывать изменения кода, не беспокоясь о секретах клиента.
Я храню секреты клиентов непосредственно в Datastore и использую Memcache для уменьшения задержки доступа к секретам. Сущности хранилища данных необходимо создать только один раз, и они сохранятся при последующих развертываниях. конечно, консоль App Engine можно использовать для обновления этих объектов в любое время.
Есть два варианта выполнения одноразового создания сущности:
источник
На момент публикации этого не существовало, но для всех, кто здесь наткнется, Google предлагает услугу под названием Secret Manager .
Это простая служба REST (конечно, с пакетами SDK) для хранения ваших секретов в безопасном месте на облачной платформе Google. Это лучший подход, чем хранилище данных, требующий дополнительных действий для просмотра хранимых секретов и наличия более детальной модели разрешений - вы можете защитить отдельные секреты по-разному для разных аспектов вашего проекта, если вам нужно.
Он предлагает управление версиями, так что вы можете относительно легко обрабатывать изменения пароля, а также надежный уровень запросов и управления, позволяющий при необходимости обнаруживать и создавать секреты во время выполнения.
SDK Python
Пример использования:
from google.cloud import secretmanager_v1beta1 as secretmanager secret_id = 'my_secret_key' project_id = 'my_project' version = 1 # use the management tools to determine version at runtime client = secretmanager.SecretManagerServiceClient() secret_path = client.secret_verion_path(project_id, secret_id, version) response = client.access_secret_version(secret_path) password_string = response.payload.data.decode('UTF-8') # use password_string -- set up database connection, call third party service, whatever
источник
os.getenv('ENV_VAR')
s?SECRET_KEY = env('SECRET_KEY', default=access_secret_version(GOOGLE_CLOUD_PROJECT_ID, 'SECRET_KEY', 1))
. Установка по умолчанию для использованияaccess_secret_version
secret_id = 'my_secret_key'
, отсутствует в вашем контроле версий?Лучший способ сделать это - сохранить ключи в файле client_secrets.json и исключить их из загрузки в git, указав их в вашем файле .gitignore. Если у вас разные ключи для разных сред, вы можете использовать app_identity api, чтобы определить идентификатор приложения и загрузить его соответствующим образом.
Здесь есть довольно подробный пример -> https://developers.google.com/api-client-library/python/guide/aaa_client_secrets .
Вот пример кода:
# declare your app ids as globals ... APPID_LIVE = 'awesomeapp' APPID_DEV = 'awesomeapp-dev' APPID_PILOT = 'awesomeapp-pilot' # create a dictionary mapping the app_ids to the filepaths ... client_secrets_map = {APPID_LIVE:'client_secrets_live.json', APPID_DEV:'client_secrets_dev.json', APPID_PILOT:'client_secrets_pilot.json'} # get the filename based on the current app_id ... client_secrets_filename = client_secrets_map.get( app_identity.get_application_id(), APPID_DEV # fall back to dev ) # use the filename to construct the flow ... flow = flow_from_clientsecrets(filename=client_secrets_filename, scope=scope, redirect_uri=redirect_uri) # or, you could load up the json file manually if you need more control ... f = open(client_secrets_filename, 'r') client_secrets = json.loads(f.read()) f.close()
источник
app.yaml
развертывании приложения. Есть какие-нибудь идеи?app.yaml
) с секретными ключами и конфиденциальной информацией, и что мне действительно нравится, так это то, что вы используете рабочий процесс Google для выполнения этой задачи. Спасибо @GwynHowell. =)Это решение полагается на устаревший appcfg.py
Вы можете использовать параметр командной строки -E в appcfg.py для настройки переменных среды при развертывании приложения в GAE (обновление appcfg.py)
$ appcfg.py ... -E NAME:VALUE, --env_variable=NAME:VALUE Set an environment variable, potentially overriding an env_variable value from app.yaml file (flag may be repeated to set multiple variables). ...
источник
gcloud
утилиты?Большинство ответов устарели. Сейчас использование облачного хранилища данных Google немного отличается. https://cloud.google.com/python/getting-started/using-cloud-datastore
Вот пример:
from google.cloud import datastore client = datastore.Client() datastore_entity = client.get(client.key('settings', 'TWITTER_APP_KEY')) connection_string_prod = datastore_entity.get('value')
Предполагается, что имя объекта - TWITTER_APP_KEY, тип - settings, а значение - это свойство объекта TWITTER_APP_KEY.
источник
Вам следует зашифровать переменные с помощью Google KMS и встроить его в свой исходный код. ( https://cloud.google.com/kms/ )
поместите зашифрованное (зашифрованное и закодированное в base64) значение в переменную среды (в файле yaml).
Немного питонского кода, чтобы вы начали расшифровывать.
kms_client = kms_v1.KeyManagementServiceClient() name = kms_client.crypto_key_path_path("project", "global", "THEKEYRING", "THECRYPTOKEY") twitter_app_key = kms_client.decrypt(name, base64.b64decode(os.environ.get("TWITTER_APP_KEY"))).plaintext
источник
Похоже, вы можете сделать несколько подходов. У нас есть аналогичная проблема, и мы делаем следующее (адаптировано к вашему варианту использования):
Самый простой способ сделать это - использовать сервер непрерывной интеграции, такой как Hudson , Bamboo или Jenkins . Просто добавьте какой-нибудь плагин, шаг скрипта или рабочий процесс, который выполняет все упомянутые выше элементы. Вы можете передать переменные среды, которые, например, настроены в самом Bamboo.
Таким образом, просто введите значения в процессе сборки в среде, к которой у вас есть доступ. Если вы еще не автоматизируете свои сборки, вам следует это сделать.
Другой вариант вариант - то, что вы сказали, положить в базу. Если причина этого не в том, что все идет слишком медленно, просто вставьте значения в кэш памяти как кеш второго уровня и закрепите значения в экземплярах как кеш первого уровня. Если значения могут измениться и вам нужно обновить экземпляры без их перезагрузки, просто сохраните хэш, который вы можете проверить, чтобы знать, когда они меняются, или запускать его каким-либо образом, когда что-то, что вы делаете, изменяет значения. Так и должно быть.
источник
@Jason F в ответ , основанный на использовании Google Datastore близко, но код немного устарел на основе образца использования на библиотеки документации . Вот фрагмент, который у меня сработал:
from google.cloud import datastore client = datastore.Client('<your project id>') key = client.key('<kind e.g settings>', '<entity name>') # note: entity name not property # get by key for this entity result = client.get(key) print(result) # prints all the properties ( a dict). index a specific value like result['MY_SECRET_KEY'])
Частично навеян этой публикацией на Medium
источник
Просто хотел отметить, как я решил эту проблему в javascript / nodejs. Для локальной разработки я использовал пакет npm 'dotenv', который загружает переменные среды из файла .env в process.env. Когда я начал использовать GAE, я узнал, что переменные среды необходимо устанавливать в файле app.yaml. Что ж, я не хотел использовать dotenv для локальной разработки и app.yaml для GAE (и дублировать переменные среды между двумя файлами), поэтому я написал небольшой скрипт, который загружает переменные среды app.yaml в процесс. .env для локальной разработки. Надеюсь, это кому-то поможет:
yaml_env.js:
(function () { const yaml = require('js-yaml'); const fs = require('fs'); const isObject = require('lodash.isobject') var doc = yaml.safeLoad( fs.readFileSync('app.yaml', 'utf8'), { json: true } ); // The .env file will take precedence over the settings the app.yaml file // which allows me to override stuff in app.yaml (the database connection string (DATABASE_URL), for example) // This is optional of course. If you don't use dotenv then remove this line: require('dotenv/config'); if(isObject(doc) && isObject(doc.env_variables)) { Object.keys(doc.env_variables).forEach(function (key) { // Dont set environment with the yaml file value if it's already set process.env[key] = process.env[key] || doc.env_variables[key] }) } })()
Теперь включите этот файл как можно раньше в свой код, и все готово:
require('../yaml_env')
источник
.env
файл с секретными переменными. Я не дублирую их в своемapp.yaml
файле, и мой развернутый код все еще работает. Но меня беспокоит, что происходит с.env
файлом в облаке. Он зашифрован или что-то в этом роде? Как я могу убедиться, что никто не получит доступ к.env
переменным файла gcloud после его развертывания?Расширение ответа Мартина
from google.appengine.ext import ndb class Settings(ndb.Model): """ Get sensitive data setting from DataStore. key:String -> value:String key:String -> Exception Thanks to: Martin Omander @ Stackoverflow https://stackoverflow.com/a/35261091/1463812 """ name = ndb.StringProperty() value = ndb.StringProperty() @staticmethod def get(name): retval = Settings.query(Settings.name == name).get() if not retval: raise Exception(('Setting %s not found in the database. A placeholder ' + 'record has been created. Go to the Developers Console for your app ' + 'in App Engine, look up the Settings record with name=%s and enter ' + 'its value in that record\'s value field.') % (name, name)) return retval.value @staticmethod def set(name, value): exists = Settings.query(Settings.name == name).get() if not exists: s = Settings(name=name, value=value) s.put() else: exists.value = value exists.put() return True
источник
Существует пакет pypi под названием gae_env, который позволяет сохранять переменные среды appengine в Cloud Datastore. Под капотом он также использует Memcache, поэтому он быстро
Применение:
import gae_env API_KEY = gae_env.get('API_KEY')
Если в хранилище данных есть значение для этого ключа, оно будет возвращено. Если нет,
__NOT_SET__
будет создана запись-заполнитель иValueNotSetError
будет выдан. Исключение будет напоминать вам перейти в консоль разработчика и обновить запись заполнителя.Как и в ответе Мартина, вот как обновить значение ключа в Datastore:
Перейдите в раздел Datastore в консоли разработчика.
Выберите свой проект вверху страницы, если он еще не выбран.
В раскрывающемся списке Тип выберите
GaeEnvSettings
.Ключи, для которых возникло исключение, будут иметь значение
__NOT_SET__
.Перейдите на страницу пакета GitHub для получения дополнительной информации об использовании / настройке.
источник