Как я могу безопасно сохранить свои секретные ключи и пароль в моей системе контроля версий?

134

Я сохраняю важные настройки, такие как имена хостов и порты серверов разработки и производства, в моей системе контроля версий. Но я знаю, что хранить секреты (например, закрытые ключи и пароли базы данных) в репозитории VCS - это плохая практика .

Но пароли - как и любой другой параметр - похоже, они должны быть версионными. Так что это правильный способ хранения паролей версии контролируемых?

Я предполагаю, что это будет включать в себя сохранение секретов в их собственном файле «настроек секретов» и шифрование этого файла и контроль версий. Но какие технологии? И как это сделать правильно? Есть ли лучший способ сделать это?


Я задаю вопрос в целом, но в моем конкретном случае я хотел бы хранить секретные ключи и пароли для сайта Django / Python, используя git и github .

Кроме того, идеальным решением было бы сделать что-то волшебное, когда я использую git для push / pull - например, если файл зашифрованных паролей изменится, запускается скрипт, который запрашивает пароль и расшифровывает его на месте.


EDIT: Для ясности, я имею просить о том, где хранить производственные секреты.

Крис У.
источник
1
На самом деле выделили немного денег, чтобы сохранить весь репо в тайне.
Джон Ми
29
@JohnMee Я фактически уже плачу за частный репозиторий, но суть остается неизменной - вы не должны хранить конфиденциальную информацию в своем репозитории.
Крис У.
1
Я думаю, что большую часть причин, по которым удовлетворительные ответы будет сложно получить, заключается в том, что старомодный открытый текстовый пароль для подключения к базе данных является пережитком менее враждебной эпохи. Правильный ответ - что-то вроде «вашему коду не нужен секрет», но системы, к которым вы обращаетесь, не дают вам большого выбора.
Msw
4
Зачем? В паролях управления версиями для внешних сервисов есть большое значение. Основная ценность контроля версий заключается в том, что вы можете проверять исторические ревизии вашего приложения, которые, как известно, находятся в рабочем состоянии, и запускать их . Однако старые пароли для вас бесполезны. Если они были отозваны, они больше никогда не будут работать.
Полковник Паник
1
Возможный дубликат: programmers.stackexchange.com/questions/205606/…
пользователь

Ответы:

100

Вы совершенно правы, желая зашифровать ваш конфиденциальный файл настроек, сохраняя его при управлении версиями. Как вы упомянули, лучшим решением было бы то, в котором Git будет прозрачно шифровать определенные конфиденциальные файлы, когда вы нажимаете их, чтобы локально (т.е. на любом компьютере, на котором есть ваш сертификат) вы могли использовать файл настроек, но Git или Dropbox или кто-либо еще Хранение ваших файлов в VC не позволяет читать информацию в открытом виде.

Учебник по прозрачному шифрованию / дешифрованию во время Push / Pull

Этот гист https://gist.github.com/873637 показывает учебное пособие о том, как использовать Git-драйвер smudge / clean filter с openssl для прозрачного шифрования отправленных файлов. Вам просто нужно сделать некоторые первоначальные настройки.

Краткое описание того, как это работает

В основном вы будете создавать .gitencryptпапку, содержащую 3 скрипта bash,

clean_filter_openssl 
smudge_filter_openssl 
diff_filter_openssl 

которые используются Git для дешифрования, шифрования и поддержки Git diff. Главная фраза-пароль и соль (исправлено!) Определены в этих сценариях, и вы ДОЛЖНЫ гарантировать, что .gitencrypt никогда не будет передан. Пример clean_filter_opensslскрипта:

#!/bin/bash

SALT_FIXED=<your-salt> # 24 or less hex characters
PASS_FIXED=<your-passphrase>

openssl enc -base64 -aes-256-ecb -S $SALT_FIXED -k $PASS_FIXED

Похоже на smudge_filter_open_sslа diff_filter_oepnssl. Смотри Гист.

В вашем репо с конфиденциальной информацией должен быть файл .gitattribute (незашифрованный и включенный в репо), который ссылается на каталог .gitencrypt (который содержит все, что Git должен прозрачно зашифровать / дешифровать проект) и который присутствует на вашем локальном компьютере.

.gitattribute содержание:

* filter=openssl diff=openssl
[merge]
    renormalize = true

Наконец, вам также нужно добавить следующее содержимое в ваш .git/configфайл

[filter "openssl"]
    smudge = ~/.gitencrypt/smudge_filter_openssl
    clean = ~/.gitencrypt/clean_filter_openssl
[diff "openssl"]
    textconv = ~/.gitencrypt/diff_filter_openssl

Теперь, когда вы отправляете репозиторий, содержащий ваши конфиденциальные данные, в удаленный репозиторий, файлы будут прозрачно зашифрованы. Когда вы извлекаете данные с локального компьютера, на котором есть каталог .gitencrypt (содержащий вашу фразу-пароль), файлы будут прозрачно расшифрованы.

Ноты

Я должен отметить, что этот учебник не описывает способ только для шифрования вашего конфиденциального файла настроек. Это прозрачно зашифрует весь репозиторий, который передается на удаленный хост VC, и расшифрует весь репозиторий, чтобы он полностью расшифровывался локально. Чтобы добиться желаемого поведения, вы можете поместить конфиденциальные файлы для одного или нескольких проектов в одно Sens_settings_repo. Вы можете исследовать, как этот метод прозрачного шифрования работает с подмодулями Git http://git-scm.com/book/en/Git-Tools-Submodules, если вам действительно нужно, чтобы чувствительные файлы находились в одном и том же хранилище.

Использование фиксированной парольной фразы теоретически может привести к уязвимостям грубой силы, если злоумышленники получат доступ ко многим зашифрованным репозиториям / файлам. ИМО, вероятность этого очень низкая. Как отмечается в нижней части этого урока, отказ от использования фиксированной парольной фразы приведет к тому, что локальные версии репо на разных машинах всегда будут показывать, что изменения произошли с «git status».

рБоп
источник
1
Ох, очень интересно. Это звучит почти так же, как я хочу (за исключением шифрования всего хранилища).
Крис У.
Вы можете сохранить все файлы конфиденциальных настроек для нескольких приложений в одном зашифрованном репозитории или добавить зашифрованный репозиторий с секретными настройками в свой проект в виде подмодуля Git, как описано здесь git-scm.com/book/en/Git-Tools-Submodules ,
рБоп
Хранение производственных паролей / настроек в (зашифрованных) подмодулях не является редкостью. stackoverflow.com/questions/11207284/… . Это даже облегчит управление настройками в разных проектах.
рБоп
Возможно, стоит проверить на github.com/AGWA/git-crypt обновленное решение. Он имеет преимущество, заключающееся в том, что он позволяет кодировать отдельные файлы, и заявляет, что он «доказуемо семантически защищен». Автор самой идеи предположил, что этот инструмент лучше, по адресу github.com/shadowhand/git-encrypt .
Geekley
52

Heroku поддерживает использование переменных среды для настроек и секретных ключей:

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

Лучшее решение - использовать переменные окружения и не допускать ключей в код. На традиционном хосте или работая локально вы можете установить переменные окружения в вашем bashrc. На Heroku вы используете config vars.

С помощью Foreman и .envфайлов Heroku предоставляет завидный набор инструментов для экспорта, импорта и синхронизации переменных среды.


Лично я считаю, что неправильно хранить секретные ключи вместе с кодом. Это принципиально несовместимо с управлением исходным кодом, потому что ключи предназначены для сервисов, присущих коду . Единственным преимуществом было бы то, что разработчик может клонировать HEAD и запускать приложение без какой-либо настройки. Однако предположим, что разработчик проверяет историческую версию кода. Их копия будет содержать прошлогодний пароль базы данных, поэтому приложение не сможет работать с сегодняшней базой данных.

С помощью метода Heroku, описанного выше, разработчик может проверить прошлогоднее приложение, настроить его с использованием сегодняшних ключей и успешно запустить его для сегодняшней базы данных.

Полковник паника
источник
1
Этот ответ не имеет достаточного внимания, но он наиболее совпадает с образом Linux.
Николай Фоминых
11
Итак, если в вашем bashrc установлены переменные среды, и вы развертываете новый сервер, то что создает bashrc? Разве это не просто перемещает пароли из репозитория исходного кода в конфигурацию развертывания? (что, по-видимому, также в репо с исходным кодом или в собственном репо?)
Джонатан Хартли
@JonathanHartley ваш .bashrc не должен быть в репозитории для вашего приложения Django.
Стив
4
Извините, мой комментарий неоднозначен, но это потому, что я искренне запутался. Мне нравится звучание этой точки зрения, но я никогда не понимал ее полностью. Если я выполняю развертывание в нескольких различных средах, каждая из которых содержит несколько хостов и, возможно, несколько типов хостов, то, очевидно, мне нужно автоматизировать создание файлов .bashrc, которые будут существовать на каждом хосте, чтобы установить его переменные среды. Итак, ответ говорит, что у меня должен быть второй репо, отдельный от моего источника, который содержит все параметры, которые станут переменными среды в .bashrc при развертывании?
Джонатан Хартли
1
Они должны быть настроены только один раз на машину, на которой вы развертываете. Если ваш процесс развертывания «раскрутить новую машину и проверить, все ли в порядке, прежде чем перенаправлять трафик на нее, а затем выстрелить старой в голову», что, по моему мнению, является наилучшей практикой, вам действительно нужно автоматизировать создание того, что устанавливает env vars.
Джонатан Хартли
16

На мой взгляд, самый чистый способ - использовать переменные окружения. Например, вам не придется иметь дело с файлами .dist , и состояние проекта в производственной среде будет таким же, как и на вашем локальном компьютере.

Я рекомендую прочитать главу по настройке приложения Twelve-Factor , а также другие, если вам интересно.

Сами Диндан
источник
6
Кажется, что переменные среды - хороший способ запустить приложение с секретными настройками ... но это все еще не отвечает на вопрос, где хранить эти настройки.
Крис У.
2
У вас обычно должен быть файл README для каждого из ваших приложений. Там укажите, какие переменные среды должны быть установлены, и каждый раз, когда вы развертываете проект, просто следуйте инструкциям и установите каждую из них. Вы также можете создать сценарий оболочки со многими export MY_ENV_VAR=, и при развертывании просто заполните его правильными значениями и sourceим. Если под « держать» вы подразумеваете версию настроек, вам не следует делать это в первую очередь.
Сами Диндан
Кроме того, upvote для The Twelve-Factor App - действительно отличный материал.
Крис В.
4
@Samy: А если у вас автоматическое развертывание?
Джонатан Хартли
3
@Samy Я до сих пор не понимаю, как переменные среды будут установлены. Страница с 12-факторным приложением также не проясняет это (если только вы не на Heroku, которым не является мой текущий проект). Мы говорим, что генерирующий скрипт должен спросить центральное хранилище конфигурации: «Я машина X, пожалуйста дай мне мои данные конфигурации ", и это отвечает значениями переменных среды, которые должны быть установлены. В этом случае я не думаю, что вам нужен сгенерированный скрипт больше. Я дико размышляю здесь, я лаю правильное дерево?
Джонатан Хартли
10

Можно было бы поместить учетные данные, связанные с проектом, в зашифрованный контейнер (TrueCrypt или Keepass) и отправить их.

Обновить как ответ из моего комментария ниже:

Интересный вопрос, кстати. Я только что нашел это: github.com/shadowhand/git-encrypt, который выглядит очень многообещающим для автоматического шифрования

Шнек
источник
Было бы неплохо иметь что-то, что я мог бы автоматизировать. Так что если мой зашифрованный файл паролей изменится, он автоматически расшифрует новый файл.
Крис У.
7
Интересный вопрос, кстати. Я только что нашел это: github.com/shadowhand/git-encrypt, который выглядит очень перспективным для автоматического шифрования.
Schneck
1
Вау, отлично. Описание git-encryptзвучит как то, что я ищу: «При работе с удаленным git-репозиторием, который размещен на стороннем сервере хранения, конфиденциальность данных иногда становится проблемой. В этой статье вы познакомитесь с процедурами настройки git-репозиториев. для которых ваши локальные рабочие каталоги являются обычными (незашифрованными), но зафиксированный контент зашифрован ». (Конечно, я хочу, чтобы только часть моего контента была зашифрована ...)
Крис В.
@schneck опубликует ваш комментарий как ответ, чтобы Крис мог принять его - похоже, это то, что он ищет.
Тони Абу-Ассале
9

Я предлагаю использовать конфигурационные файлы для этого, а не версию их.

Вы можете, однако, версии примеров файлов.

Я не вижу проблем с разделением настроек разработки. По определению он не должен содержать никаких ценных данных.

TikTak
источник
1
Но тогда где хранить канонические записи пароля? Это заставит меня нервничать, если эти данные будут храниться только в файле конфигурации на машине, которая может взорваться когда-нибудь.
Крис У.
@ChrisW. Если машина выходит из строя, вам больше не нужен пароль ... Однако, если у вас есть только одна копия данных на вашем рабочем компьютере, это должно поднять красный флаг. Но это не значит, что это должно быть в VCS. Должен быть RAID, полные резервные копии, дополненные инкрементными резервными копиями на магнитных и оптических носителях. Многие корпорации имеют процедуру контроля изменений, которая может определять, как и где хранить пароли и другие конфиденциальные материалы на бумаге.
Стив Бузонас
@ChrisW Я не хочу быть грубым, но, похоже, вы не говорите нам правду, а пароли, которые вы хотите сохранить, используются не в разработке, а в производстве. Разве это не правда? В противном случае, почему вам нужны машины для разработки или тестирования и пароли для разработки? Никто бы не сделал это.
Тиктак
Кстати, в нашей компании все пароли для разработки доступны на бумаге и во внутренней сети. Потому что они не имеют значения. Они там, потому что программное обеспечение, которое мы разрабатываем, требует аутентификации.
Тиктак
@tiktak, вы правы - мой вопрос о том, что делать с производственными паролями. Я не особенно беспокоюсь о хранении паролей разработки в A VCS в открытом виде. Извините, если я не прояснил это достаточно.
Крис В.
7

BlackBox был недавно выпущен StackExchange, и, хотя я еще не использовал его, похоже, он точно решает проблемы и поддерживает функции, запрашиваемые в этом вопросе.

Из описания на https://github.com/StackExchange/blackbox :

Безопасно храните секреты в репозитории VCS (например, Git или Mercurial). Эти команды позволяют GPG шифровать определенные файлы в репозитории, чтобы они были «зашифрованы в покое» в вашем хранилище. Тем не менее, сценарии позволяют легко дешифровать их, когда вам нужно просмотреть или отредактировать их, и расшифровать их для использования в производстве.

Крис У.
источник
7

Задав этот вопрос, я остановился на решении, которое я использую при разработке небольшого приложения с небольшой группой людей.

ГИТ-крипта

git-crypt использует GPG для прозрачного шифрования файлов, когда их имена соответствуют определенным шаблонам. Для примера, если вы добавите в свой .gitattributesфайл ...

*.secret.* filter=git-crypt diff=git-crypt

... тогда такой файл config.secret.jsonвсегда будет передаваться в удаленные репозитории с шифрованием, но останется незашифрованным в вашей локальной файловой системе.

Если я хочу добавить новый ключ GPG (человека) в репозиторий, который может расшифровать защищенные файлы, тогда запустите git-crypt add-gpg-user <gpg_user_key>. Это создает новый коммит. Новый пользователь сможет расшифровать последующие коммиты.

Крис У.
источник
5

Я задаю вопрос в целом, но в моем конкретном случае я хотел бы хранить секретные ключи и пароли для сайта Django / Python, используя git и github.

Нет, просто не делайте, даже если это ваш личный репозиторий, и вы никогда не собираетесь делиться им, не делайте этого.

Вы должны создать local_settings.py, поставить его на VCS ignore и в вашем settings.py сделать что-то вроде

from local_settings import DATABASES, SECRET_KEY
DATABASES = DATABASES

SECRET_KEY = SECRET_KEY

Если ваши настройки секретов настолько разнообразны, я хочу сказать, что вы делаете что-то не так

Хедде ван дер Хайде
источник
9
Но мне все равно нужно где-то отслеживать эти секреты . Например, комбинация клавиш или что-то в этом роде, верно?
Крис В.
Регулирование и осуществление хранения личных данных зависит от политики компании, для которой проект. Я очень сомневаюсь, что исходный код проекта является подходящим местом, поскольку любой сторонний тестировщик или программист мог бы видеть это
Хедде ван дер Хайде
4

РЕДАКТИРОВАТЬ: я предполагаю, что вы хотите отслеживать ваши предыдущие версии паролей - скажем, для сценария, который предотвратит повторное использование пароля и т. Д.

Я думаю, что GnuPG - лучший способ - он уже используется в одном проекте, связанном с git (git-annex), для шифрования содержимого репозитория, хранящегося в облачных сервисах. GnuPG (GNU PGP) обеспечивает очень надежное шифрование на основе ключей.

  1. Вы держите ключ на своем локальном компьютере.
  2. Вы добавляете mypassword к игнорируемым файлам.
  3. В режиме предварительного фиксирования вы шифруете файл mypassword в файл mypassword.gpg, отслеживаемый git, и добавляете его в коммит.
  4. На крюке после слияния вы просто расшифруете mypassword.gpg в mypassword.

Теперь, если ваш файл mypassword не изменился, шифрование приведет к тому же зашифрованному тексту и не будет добавлено в индекс (без избыточности). Малейшая модификация mypassword приводит к радикально другому зашифрованному тексту, а mypassword.gpg в области подготовки сильно отличается от того, что в репозитории, поэтому будет добавлен в коммит. Даже если злоумышленник схватит ваш ключ gpg, ему все равно придется взломать пароль. Если злоумышленник получит доступ к удаленному хранилищу с зашифрованным текстом, он сможет сравнить несколько зашифрованных текстов, но их число будет недостаточным, чтобы дать ему какое-либо немаловажное преимущество.

Позже вы можете использовать .gitattributes для оперативного дешифрования для выхода из git diff вашего пароля.

Также вы можете иметь отдельные ключи для разных типов паролей и т. Д.

pielgrzym
источник
3

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

/yourapp
    main.py
    default.cfg.dist

И когда я бегу main.py, вставьте реальный пароль в default.cfgэто скопированное.

пс. когда вы работаете с Git или HG. Вы можете игнорировать *.cfgфайлы, чтобы сделать .gitignoreили.hgignore

восхищаюсь
источник
Файлы .dist - это то, о чем я говорил: примеры реальных файлов конфигурации. Хорошей практикой является возможность запуска программного обеспечения только путем переименования, удалив расширение «.dist» (или лучше: копирование), то есть вы сможете попробовать программное обеспечение за считанные секунды, не настраивая его во время целый день.
Тиктак
3

Предоставить способ переопределить конфигурацию

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

Переменные среды (как уже упоминалось) являются одним из способов сделать это.

Лучший способ - найти внешний файл конфигурации, который переопределяет значения конфигурации по умолчанию. Это позволяет вам управлять внешними конфигурациями через систему управления конфигурацией, такую ​​как Chef, Puppet или Cfengine. Управление конфигурацией является стандартным ответом для управления конфигурациями отдельно от кодовой базы, поэтому вам не нужно делать выпуск для обновления конфигурации на одном хосте или группе хостов.

К вашему сведению: шифрование кредитов не всегда является наилучшей практикой, особенно в местах с ограниченными ресурсами. Может случиться так, что шифрование кредитов не принесет вам дополнительного снижения риска и просто добавит ненужный уровень сложности. Убедитесь, что вы делаете правильный анализ, прежде чем принимать решение.

dietbuddha
источник
2

Зашифруйте файл паролей, используя, например, GPG. Добавьте ключи на вашем локальном компьютере и на вашем сервере. Расшифруйте файл и поместите его в свои папки репо.

Я использую passwords.conf, расположенный в моей домашней папке. При каждом развертывании этот файл обновляется.

Виллиан
источник
Затем программное обеспечение должно расшифровать файл пароля.
Тиктак
Ну, только при развертывании сайта пароль расшифровывается и записывается в простой текстовый файл паролей
Виллиан
2

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

Начиная с Django 1.4, ваши проекты Django теперь поставляются с project.wsgiмодулем, который определяет applicationобъект, и это идеальное место для начала принудительного использованияproject.local модуля настроек, который содержит конфигурации для конкретного сайта.

Этот модуль настроек игнорируется в управлении версиями, но его присутствие требуется при запуске экземпляра проекта в качестве приложения WSGI, типичного для производственных сред. Вот как это должно выглядеть:

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.local")

# This application object is used by the development server
# as well as any WSGI server configured to use this file.
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

Теперь у вас может быть local.pyмодуль, владельца и группу которого можно настроить так, чтобы только авторизованный персонал и процессы Django могли читать содержимое файла.

Филипп Дупанович
источник
2

Если вам нужны VCS для ваших секретов, вы должны, по крайней мере, хранить их во втором хранилище, отделенном от вашего реального кода. Таким образом, вы можете предоставить членам вашей команды доступ к хранилищу исходного кода, и они не увидят ваши учетные данные. Кроме того, разместите этот репозиторий где-нибудь еще (например, на своем собственном сервере с зашифрованной файловой системой, а не на github), и для проверки его в производственной системе вы можете использовать что-то вроде git-submodule .

Бернхард Валлант
источник
1

Другой подход мог бы заключаться в том, чтобы полностью избежать сохранения секретов в системах контроля версий и вместо этого использовать инструмент, такой как хранилище от hashicorp , секретное хранилище с прокруткой и проверкой ключей, с API и встроенным шифрованием.

Кай Питерс
источник
1

Вот что я делаю:

  • Храните все секреты в виде переменных env в $ HOME / .secrets (go-r perms), которые исходники $ HOME / .bashrc (таким образом, если вы откроете .bashrc перед кем-то, они не увидят секреты)
  • Файлы конфигурации хранятся в VCS в виде шаблонов, таких как config.properties, которые хранятся как config.properties.tmpl.
  • Файлы шаблона содержат заполнитель для секрета, такой как:

    my.password = ## my_password ##

  • При развертывании приложения запускается сценарий, который преобразует файл шаблона в целевой файл, заменяя заполнители значениями переменных среды, такими как изменение ## MY_PASSWORD ## на значение $ MY_PASSWORD.

Павел Черников
источник
0

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

Однако потребуется подключить папки EncFS, что может быть сделано вашим приложением на основе пароля, хранящегося в другом месте за пределами версионных папок (например, переменных среды).

dronus
источник