Есть несколько вариантов для хранения паролей и других секретов, которые должна использовать программа Python, в частности программа, которая должна работать в фоновом режиме, где она не может просто попросить пользователя ввести пароль.
Проблемы, которых следует избегать:
- Проверка пароля в системе контроля версий, где его могут увидеть другие разработчики или даже публика.
- Другие пользователи на том же сервере читают пароль из файла конфигурации или исходного кода.
- Наличие пароля в исходном файле, где другие могут видеть его через ваше плечо, пока вы его редактируете.
Вариант 1: SSH
Это не всегда вариант, но, вероятно, лучший. Ваш закрытый ключ никогда не передается по сети, SSH просто выполняет математические вычисления, чтобы доказать, что у вас есть правильный ключ.
Для того, чтобы он заработал, вам понадобится следующее:
- База данных или все, к чему вы обращаетесь, должна быть доступна по SSH. Попробуйте поискать "SSH" и любую службу, к которой вы обращаетесь. Например, «ssh postgresql» . Если это не функция в вашей базе данных, перейдите к следующему варианту.
- Создайте учетную запись для запуска службы, которая будет звонить в базу данных и генерировать SSH-ключ .
- Либо добавьте открытый ключ к службе, которую вы собираетесь вызвать, либо создайте локальную учетную запись на этом сервере и установите там открытый ключ.
Вариант 2: переменные среды
Это самый простой вариант, поэтому с него можно начать. Это хорошо описано в приложении « Двенадцать факторов» . Основная идея состоит в том, что ваш исходный код просто извлекает пароль или другие секреты из переменных среды, а затем вы настраиваете эти переменные среды в каждой системе, в которой вы запускаете программу. Также было бы неплохо, если бы вы использовали значения по умолчанию, которые подойдут для большинства разработчиков. Вы должны сбалансировать это с тем, чтобы сделать ваше программное обеспечение «безопасным по умолчанию».
Вот пример, который извлекает сервер, имя пользователя и пароль из переменных среды.
import os
server = os.getenv('MY_APP_DB_SERVER', 'localhost')
user = os.getenv('MY_APP_DB_USER', 'myapp')
password = os.getenv('MY_APP_DB_PASSWORD', '')
db_connect(server, user, password)
Узнайте, как установить переменные среды в вашей операционной системе, и подумайте о запуске службы под собственной учетной записью. Таким образом, у вас не будет конфиденциальных данных в переменных среды, когда вы запускаете программы в своей учетной записи. Когда вы настраиваете эти переменные среды, будьте особенно внимательны, чтобы другие пользователи не могли их прочитать. Например, проверьте права доступа к файлам. Конечно, любые пользователи с правами root смогут читать их, но тут ничего не поделаешь. Если вы используете systemd, посмотрите на служебную единицу и будьте осторожны при использовании EnvironmentFile
вместо Environment
любых секретов. Environment
значения могут быть просмотрены любым пользователем с systemctl show
.
Вариант 3: файлы конфигурации
Это очень похоже на переменные среды, но вы читаете секреты из текстового файла. Я по-прежнему считаю переменные среды более гибкими для таких вещей, как инструменты развертывания и серверы непрерывной интеграции. Если вы решите использовать файл конфигурации, Python поддерживает несколько форматов в стандартной библиотеке, например JSON , INI , netrc и XML . Вы также можете найти внешние пакеты, такие как PyYAML и TOML . Лично я считаю JSON и YAML самыми простыми в использовании, а YAML допускает комментарии.
При работе с файлами конфигурации следует учитывать три момента:
- Где файл? Может быть, местоположение по умолчанию, например
~/.my_app
, и параметр командной строки, чтобы использовать другое местоположение.
- Убедитесь, что другие пользователи не могут прочитать файл.
- Очевидно, не фиксируйте файл конфигурации в исходном коде. Возможно, вы захотите зафиксировать шаблон, который пользователи могут скопировать в свой домашний каталог.
Вариант 4: модуль Python
Некоторые проекты просто кладут свои секреты прямо в модуль Python.
db_server = 'dbhost1'
db_user = 'my_app'
db_password = 'correcthorsebatterystaple'
Затем импортируйте этот модуль, чтобы получить значения.
from settings import db_server, db_user, db_password
db_connect(db_server, db_user, db_password)
Одним из проектов, использующих эту технику, является Django . Очевидно, вы не должны фиксировать систему settings.py
управления версиями, хотя вы можете захотеть зафиксировать файл с именем, settings_template.py
который пользователи могут копировать и изменять.
Я вижу несколько проблем с этой техникой:
- Разработчики могут случайно передать файл в систему контроля версий. Добавление к
.gitignore
снижает этот риск.
- Часть вашего кода не находится под контролем источника. Если вы дисциплинированы и вводите здесь только строки и числа, это не будет проблемой. Если вы начнете писать здесь классы фильтров журналирования, остановитесь!
Если ваш проект уже использует эту технику, легко перейти на переменные среды. Просто переместите все значения параметров в переменные среды и измените модуль Python на чтение из этих переменных среды.