Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • SensioLabs Professional services to help you with Symfony
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by SensioLabs
  1. Home
  2. Documentation
  3. Configuration
  4. How to Keep Sensitive Information Secret
  • Documentation
  • Book
  • Reference
  • Bundles
  • Cloud

Table of Contents

  • Generate Cryptographic Keys
  • Create or Update Secrets
  • Referencing Secrets in Configuration Files
  • List Existing Secrets
  • Remove Secrets
  • Local secrets: Overriding Secrets Locally
  • Secrets in the test Environment
  • Deploy Secrets to Production
  • Rotating Secrets
  • Configuration

How to Keep Sensitive Information Secret

Edit this page

How to Keep Sensitive Information Secret

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.

Generate Cryptographic Keys

In order to encrypt and decrypt secrets, Symfony needs cryptographic keys. A pair of keys can be generated by running:

1
$ php bin/console secrets:generate-keys

This will generate a pair of asymmetric cryptographic keys. Each 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:

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

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.

Create or Update Secrets

Suppose you want to store your database password as a secret. By using the secrets:set command, you should add this secret to both the dev and prod vaults:

1
2
3
4
5
6
7
# the input is hidden as you type for security reasons

# set your default development value (can be overridden locally)
$ php bin/console secrets:set DATABASE_PASSWORD

# set your production value
$ APP_RUNTIME_ENV=prod php bin/console secrets:set DATABASE_PASSWORD

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:

1
2
3
4
5
6
7
8
# 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

Note

There's no command to rename secrets, so you'll need to create a new secret and remove the old one.

Referencing Secrets in Configuration Files

Secret values can be referenced in the same way as 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 it by:

1
2
3
4
5
6
# config/packages/doctrine.yaml
doctrine:
    dbal:
        password: '%env(DATABASE_PASSWORD)%'
        # ...
    # ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- config/packages/doctrine.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:doctrine="http://symfony.com/schema/dic/doctrine"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        https://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/doctrine
        https://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">

    <doctrine:config>
        <doctrine:dbal
            password="%env(DATABASE_PASSWORD)%"
        />
    </doctrine:config>

</container>
1
2
3
4
5
6
7
8
9
// config/packages/doctrine.php
use Symfony\Config\DoctrineConfig;

return static function (DoctrineConfig $doctrine) {
    $doctrine->dbal()
        ->connection('default')
            ->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:

1
2
3
4
5
6
7
$ 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:

1
$ 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:

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

If you entered root, you will now see this in your .env.dev.local file:

1
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:

1
2
3
4
5
6
$ php bin/console secrets:list --reveal
 ------------------- ------------- -------------
  Name                Value         Local Value
 ------------------- ------------- -------------
  DATABASE_PASSWORD   "dev value"   "root"
 ------------------- ------------- -------------

Symfony also provides the secrets:decrypt-to-local command which decrypts all secrets and stores them in the local vault and the secrets:encrypt-from-local command 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:

1
2
# .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 production decryption key - config/secrets/prod/prod.decrypt.private.php to your server.

  2. Using an Environment Variable

    The second way is to set the SYMFONY_DECRYPTION_SECRET environment variable to the base64 encoded value of the production decryption key. A fancy way to fetch the value of the key is:

    1
    2
    3
    # this command only gets the value of the key; you must also set an env var
    # in your system with this value (e.g. `export SYMFONY_DECRYPTION_SECRET=...`)
    $ 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:

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

    This will write all the decrypted secrets into the .env.prod.local file. After doing this, the decryption key does not need to remain on the server(s).

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:

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'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- config/packages/framework.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:framework="http://symfony.com/schema/dic/framework"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/framework https://symfony.com/schema/dic/framework/framework-1.0.xsd"
>
    <framework:config secret="%env(APP_SECRET)%">
        <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"
        />
    </framework:config>
</container>
1
2
3
4
5
6
7
8
9
10
// config/packages/framework.php
use Symfony\Config\FrameworkConfig;

return static function (FrameworkConfig $framework) {
    $framework->secrets()
        // ->vaultDirectory('%kernel.project_dir%/config/secrets/%kernel.environment%')
        // ->localDotenvFile('%kernel.project_dir%/.env.%kernel.environment%.local')
        // ->decryptionEnvVar('base64:default::SYMFONY_DECRYPTION_SECRET')
    ;
};
This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version
    We stand with Ukraine.
    Version:

    Symfony 6.2 is backed by

    Symfony 6.2 is backed by

    Code consumes server resources. Blackfire tells you how

    Code consumes server resources. Blackfire tells you how

    Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).

    Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).

    Symfony footer

    ↓ Our footer now uses the colors of the Ukrainian flag because Symfony stands with the people of Ukraine.

    Avatar of Rachid Hammaoui, a Symfony contributor

    Thanks Rachid Hammaoui for being a Symfony contributor

    4 commits • 14 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • Symfony at a Glance
      • Symfony Components
      • Case Studies
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • SymfonyConnect
      • Support
      • How to be Involved
      • Code of Conduct
      • Events & Meetups
      • Projects using Symfony
      • Downloads Stats
      • Contributors
      • Backers
    • Blog

      • Events & Meetups
      • A week of symfony
      • Case studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Documentation
      • Living on the edge
      • Releases
      • Security Advisories
      • SymfonyInsight
      • Twig
      • SensioLabs
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Deployed on

    Follow Symfony