.. index:: single: Secrets How to Keep Sensitive Information Secret ======================================== :ref:`Environment variables ` are the best way to store configuration that depends on where the application is run - for example, some API key that might be set to one value while developing locally and another value on production. When these values are *sensitive* and need to be kept private, you can safely store them by using Symfony's secrets management system - sometimes called a "vault". .. note:: The Secrets system requires the sodium PHP extension that is bundled with PHP 7.2. If you're using an earlier PHP version, you can install the `libsodium`_ PHP extension or use the `paragonie/sodium_compat`_ package. .. _secrets-generate-keys: Generate Cryptographic Keys --------------------------- In order to encrypt and decrypt **secrets**, Symfony needs **cryptographic keys**. A pair of keys can be generated by running: .. code-block:: terminal $ php bin/console secrets:generate-keys This will generate a pair of asymmetric **cryptographic keys**. Each :ref:`environment ` has its own set of keys. Assuming you're coding locally in the ``dev`` environment, this will create: ``config/secrets/dev/dev.encrypt.public.php`` Used to encrypt/add secrets to the vault. Can be safely committed. ``config/secrets/dev/dev.decrypt.private.php`` Used to decrypt/read secrets from the vault. The ``dev`` decryption key can be committed (assuming no highly-sensitive secrets are stored in the dev vault) but the ``prod`` decryption key should *never* be committed. You can generate a pair of cryptographic keys for the ``prod`` environment by running: .. code-block:: terminal $ php bin/console secrets:generate-keys --env=prod This will generate ``config/secrets/prod/prod.encrypt.public.php`` and ``config/secrets/prod/prod.decrypt.private.php``. .. caution:: The ``prod.decrypt.private.php`` file is highly sensitive. Your team of developers and even Continuous Integration services don't need that key. If the **decryption key** has been exposed (ex-employee leaving for instance), you should consider generating a new one by running: ``secrets:generate-keys --rotate``. .. _secrets-set: Create or Update Secrets ------------------------ Suppose you want to store your database password a secret. By using the ``secrets:set`` command, you should add this secret to both the ``dev`` *and* ``prod`` vaults: .. code-block:: terminal # the input is hidden as you type for security # set your a default development value (can be overridden locally) $ php bin/console secrets:set DATABASE_PASSWORD # set your production value $ php bin/console secrets:set DATABASE_PASSWORD --env=prod This will create a new file for the secret in ``config/secrets/dev`` and another in ``config/secrets/prod``. You can also set the secret in a few other ways: .. code-block:: terminal # provide a file where to read the secret from $ php bin/console secrets:set DATABASE_PASSWORD ~/Download/password.json # or contents passed to STDIN $ echo -n "$DB_PASS" | php bin/console secrets:set DATABASE_PASSWORD - # or let Symfony generate a random value for you $ php bin/console secrets:set REMEMBER_ME --random Referencing Secrets in Configuration Files ------------------------------------------ Secret values can be referenced in the same way as :ref:`environment variables`. Be careful that you don't accidentally define a secret *and* an environment variable with the same name: **environment variables override secrets**. If you stored a ``DATABASE_PASSWORD`` secret, you can reference by: .. configuration-block:: .. code-block:: yaml # config/packages/doctrine.yaml doctrine: dbal: password: '%env(DATABASE_PASSWORD)%' # ... # ... .. code-block:: xml .. code-block:: php // config/packages/doctrine.php $container->loadFromExtension('doctrine', [ 'dbal' => [ 'password' => '%env(DATABASE_PASSWORD)%', ] ]); The actual value will be resolved at runtime: container compilation and cache warmup don't need the **decryption key**. List Existing Secrets --------------------- Everybody is allowed to list the secrets names with the command ``secrets:list``. If you have the **decryption key** you can also reveal the secrets' values by passing the ``--reveal`` option: .. code-block:: terminal $ php bin/console secrets:list --reveal ------------------- ------------ ------------- Name Value Local Value ------------------- ------------ ------------- DATABASE_PASSWORD "my secret" ------------------- ------------ ------------- Remove Secrets -------------- Symfony provides a convenient command to remove a Secret: .. code-block:: terminal $ php bin/console secrets:remove DATABASE_PASSWORD Local secrets: Overriding Secrets Locally ----------------------------------------- The ``dev`` environment secrets should contain nice default values for development. But sometimes a developer *still* needs to override a secret value locally when developing. Most of the ``secrets`` commands - including ``secrets:set`` - have a ``--local`` option that stores the "secret" in the ``.env.{env}.local`` file as a standard environment variable. To override the ``DATABASE_PASSWORD`` secret locally, run: .. code-block:: terminal $ php bin/console secrets:set DATABASE_PASSWORD --local If you entered ``root``, you will now see this in your ``.env.dev.local`` file: .. code-block:: bash DATABASE_PASSWORD=root This will *override* the ``DATABASE_PASSWORD`` secret because environment variables always take precedence over secrets. Listing the secrets will now also display the local variable: .. code-block:: terminal $ php bin/console secrets:list --reveal ------------------- ------------- ------------- Name Value Local Value ------------------- ------------- ------------- DATABASE_PASSWORD "dev value" "root" ------------------- ------------- ------------- Symfony also provides the ``secrets:decrypt-to-local`` command to decrypts all secrets and stores them in the local vault and ``secrets:encrypt-from-local`` to encrypt all local secrets to the vault. Secrets in the test Environment ------------------------------- If you add a secret in the ``dev`` and ``prod`` environments, it will be missing from the ``test`` environment. You *could* create a "vault" for the ``test`` environment and define the secrets there. But an easier way is to set the test values via the ``.env.test`` file: .. code-block:: bash # .env.test DATABASE_PASSWORD="testing" Deploy Secrets to Production ---------------------------- Due to the fact that decryption keys should never be committed, you will need to manually store this file somewhere and deploy it. There are 2 ways to do that: 1) Uploading the file: The first option is to copy the **decryption key** - ``/config/secrets/prod/prod.decrypt.private.php`` to your server(s). 2) Using an Environment Variable The second way is to set the ``SYMFONY_DECRYPTION_SECRET`` environment variable to the base64 encoded value of the **decryption key**. A fancy way to fetch the value of the key is: .. code-block:: terminal $ php -r 'echo base64_encode(require "config/secrets/prod/prod.decrypt.private.php");' To improve performance (i.e. avoid decrypting secrets at runtime), you can decrypt your secrets during deployment to the "local" vault: .. code-block:: terminal $ php bin/console secrets:decrypt-to-local --force --env=prod This will put all the decrypted secrets into ``.env.prod.local``. After doing this, the decryption key does *not* need to remain on the server. Rotating Secrets ---------------- The ``secrets:generate-keys`` command provides a ``--rotate`` option to regenerate the **cryptographic keys**. Symfony will decrypt existing secrets with the old key, generate new **cryptographic keys** and re-encrypt secrets with the new key. In order to decrypt previous secrets, the developer must have the **decryption key**. Configuration ------------- The secrets system is enabled by default and some of its behavior can be configured: .. configuration-block:: .. code-block:: yaml # 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' .. code-block:: xml .. code-block:: php // config/packages/framework.php $container->loadFromExtension('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', ], ]); .. _`libsodium`: https://pecl.php.net/package/libsodium .. _`paragonie/sodium_compat`: https://github.com/paragonie/sodium_compat