Как сделать чувствительную информацию секретной

Дата обновления перевода 2023-01-19

Как сделать чувствительную информацию секретной

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

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

Note

Система Секретов требует PHP-расширения sodium.

Генерирование заширофванных ключей

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

1
$ php bin/console secrets:generate-keys

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

config/secrets/dev/dev.encrypt.public.php
Используется для шифрования/добавления секретов в сейф. Может быть отправлено безопасно.
config/secrets/dev/dev.decrypt.private.php
Используется для расшифровки/чтения ключей из сейфа. Ключ расшифровки dev может быть отправлен (предполагая, что в сейфе dev не хранится высокочувствительных секретов), но ключ расшифровки prod не нужно отправлять никогда.

Вы можете сгенерировать пару криптографических ключей для окружения prod, выполнив следующее:

1
$ php bin/console secrets:generate-keys --env=prod

Это сгенерирует config/secrets/prod/prod.encrypt.public.php и config/secrets/prod/prod.decrypt.private.php.

Caution

Файл prod.decrypt.private.php высокочувствителен. Ваша команда разработчиков и даже сервисы Непрерывной интеграции не нуждаются в этом ключе. Если ключ расшифровки был выявлен (например, от вас ушел бывший сотрудник), вам нужно подумать о создании нового, путем выполнения secrets:generate-keys --rotate.

Создание или обновление секретов

Предположим, что вы хотите хранить свой пароль базы данных как секрет. Используя команду secrets:set, вы должны добавить этот секрет в сейфы dev и prod:

1
2
3
4
5
6
7
# ввод скрыт во время того, как вы печатаете, из соображений безопасности

# установите ваше значение разработки по умолчанию (может быть переопределено локально)
$ php bin/console secrets:set DATABASE_PASSWORD

# установите ваше значение производства
$ php bin/console secrets:set DATABASE_PASSWORD --env=prod

Это создаст новый файл для секрета в config/secrets/dev и еще один в config/secrets/prod. Вы также можете установить секрет несколькими другими способами:

1
2
3
4
5
6
7
8
# предоставьте файл для считывания секрета
$ php bin/console secrets:set DATABASE_PASSWORD ~/Download/password.json

# или содержание, переданное STDIN
$ echo -n "$DB_PASS" | php bin/console secrets:set DATABASE_PASSWORD -

# или позвольте Symfony сгенерировать рандомное зачение за вас
$ php bin/console secrets:set REMEMBER_ME --random

Note

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

Ссылание на секреты в файлах конфигурации

На секретные значения можно ссылаться так же как и на переменные окружения. Будьте осторожны, чтобы случайно не определить и секретное значение, и переменную окружения с одинаковым именем: переменные окружения имеют преимущество над секретами.

Если вы сохранили секрет в DATABASE_PASSWORD, вы можете сослаться на него так:

  • YAML
  • XML
  • PHP
1
2
3
4
5
6
# config/packages/doctrine.yaml
doctrine:
    dbal:
        password: '%env(DATABASE_PASSWORD)%'
        # ...
    # ...

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

Список существующих секретов

Все имеют право получить список имент секретов с помощью команды secrets:list. Если у вас есть ключ расшифровки, вы также можете увидеть значения секретов, передав опцию --reveal:

1
2
3
4
5
6
7
$ php bin/console secrets:list --reveal

 ------------------- ------------ --------------------
  Имя                 Значение     Локальное значение
 ------------------- ------------ --------------------
  DATABASE_PASSWORD   "my secret"
 ------------------- ------------ --------------------

Удаление секретов

Symfony предоставляет удобную команду для удаления Секрета:

1
$ php bin/console secrets:remove DATABASE_PASSWORD

Локальные секреты: локальное переопределение секретов

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

Большинство команд secrets - включая secrets:set - имеют опцию --local, которая хранит "секрет" в файле .env.{env}.local в качестве стандартной переменной окружения. Чтобы переопределить секрет DATABASE_PASSWORD локально, выполните:

1
$ php bin/console secrets:set DATABASE_PASSWORD --local

Если вы введете root, то теперь вы увидите в вашем файле .env.dev.local следующее:

1
DATABASE_PASSWORD=root

Это переопределит секрет DATABASE_PASSWORD, так как переменные окружения всегда главенствуют над секретами.

Список секретов теперь тоже будет содержать локальную переменную:

1
2
3
4
5
6
$ php bin/console secrets:list --reveal
 ------------------- ------------ --------------------
  Имя                 Значение     Локальное значение
 ------------------- ------------ --------------------
  DATABASE_PASSWORD   "dev value"   "root"
 ------------------- ------------ --------------------

Symfony также предоставляет команду secrets:decrypt-to-local, которая расшифровывает все секреты и сохраняет их в локальном сейфе, и команду secrets:encrypt-from-local для шифрования всех локальных секретов в сейф.

Секреты в окружении тестирования

Если вы добавите секрет в окружения dev и prod, его не будет в окружении test. Вы можете создать "сейф" для окружения test и определить секреты в нем. Но легче будет установить тестовые значения через файл .env.test:

1
2
# .env.test
DATABASE_PASSWORD="testing"

Запуск секретов в производство

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

  1. Загрузка файла

Первая опция - скопировать ключ расшифровки производства - config/secrets/prod/prod.decrypt.private.php на ваш сервер.

  1. Использование переменной окружения

Второй способ - установить переменную окружения SYMFONY_DECRYPTION_SECRET в зашифрованное значение base64 ключа расшифровки производства. Модным способом получения значения ключа является:

1
2
3
# эта команда только получает значение ключа; вы должны также установить переменную окружения
# в вашей системе с этим значением (например, `export SYMFONY_DECRYPTION_SECRET=...`)
$ php -r 'echo base64_encode(require "config/secrets/prod/prod.decrypt.private.php");'

Чтобы улучшить производительность (т.е. избежать расшифровки секретов во время прогона), вы можете расшифровать ваши секреты во время запуска в "локальном" сейфе:

1
$ php bin/console secrets:decrypt-to-local --force --env=prod

Это запишет все расшифрованные секреты в файл .env.prod.local. После того, как это будет сделано, ключ расшифровки не должен оставаться на сервере(ах).

Ротация секретов

Команда secrets:generate-keys предоставляет опцию --rotate для регенерирования криптографических ключей. Symfony расшифрует существующие секреты с помощью старого ключа, сгенерирует новые криптографические ключи и повторно зашифрует секреты с новым ключом. Для того, чтобы расшифровать предыдущие секреты, разработчику нужен будет ключ расшифровки.

Конфигурация

Система секретов включена по умолчанию и некоторые аспекты ее поведения можно сконфигурировать:

  • YAML
  • XML
  • PHP
1
2
3
4
5
6
# config/packages/framework.yaml
framework:
    secrets:
        #vault_directory: '%kernel.project_dir%/config/secrets/%kernel.environment%'
        #local_dotenv_file: '%kernel.project_dir%/.env.%kernel.environment%.local'
        #decryption_env_var: 'base64:default::SYMFONY_DECRYPTION_SECRET'