Symfony Secrets Management

Translation of the article prepared in advance of the start of the course Symfony Framework.


Are you tired of storing the file with the secrets of your application in the password manager and copying it into your CI / CD environment every time you change it to deploy the application in accordance with security requirements?

Launch Symfony

Create docker-compose.yml in the root directory of your project and add the following:

(See an introduction to PHP Docker development with XDEBUG here)

version: '3'
services:
  php:
    image: webdevops/php-nginx-dev:7.4
    working_dir: /app
    environment:
      - WEB_DOCUMENT_ROOT=/app/public
      - PHP_DISPLAY_ERRORS=1
      - PHP_MEMORY_LIMIT=2048M
      - PHP_MAX_EXECUTION_TIME=-1
      - XDEBUG_REMOTE_AUTOSTART=1
      - XDEBUG_REMOTE_PORT=9000
      - XDEBUG_PROFILER_ENABLE=0
      - XDEBUG_REMOTE_CONNECT_BACK=0
      - XDEBUG_REMOTE_HOST=docker.for.mac.localhost
      - php.xdebug.idekey=PHPSTORM
      - php.xdebug.remote_enable=1
      - php.xdebug.max_nesting_level=1000
    ports:
      - "8080:80"
    volumes:
      - ./:/app:rw,cached
    depends_on:
      - mysql

  mysql:
    image: mysql:5.7
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: test
      MYSQL_USER: test
      MYSQL_PASSWORD: test

Launch the service using docker-compose up and install Symfony 5 to launch the application:

docker-compose exec php bash -c 'composer create-project symfony/website-skeleton project && mv project/* . && rm -rf project'

Now you can go to http: // localhost: 8080 and see the following:


Symfony default screen

Keep secrets in storage

Starting with Symfony 4.4, you have access to built-in secrets management, which allows you to store all secrets in the vault in an encrypted form. You also have the option to decrypt your secrets using a private key or passphrase. With this command, we can safely save our database connection string, which is currently in the .env file:

php bin/console secrets:set DATABASE_URL

As we see, the team created the repository, a pair of keys and tells you that you should not decrypt the key. We can check the files that were generated in config / secrets / dev:

We see our key, the private (private) decryption key and the public (public) encryption key that can be committed. There is also a php listing file that contains the following content to list all encrypted keys:

It is used for php bin / console: list secrets and shows the following:

As you may have noticed, Symfony keeps secrets shared across environments. Therefore, in order not to block the work of other developers in your team, just comment out the dev-files and everything is ready. You should not commit a private decryption key for production storage files. Adding developer secrets currently works as follows:

git add config/secrets

When we try to query a database, it should just work because Symfony retrieves the% env% parameters if they are not provided as environment variables from the repository. In the doctrine package configuration file, you see the following:


config / packages / doctrine.yaml

We can check if the connection works:

php bin/console doctrine:query:sql "SHOW VARIABLES LIKE 'max_join_size'"

If you do not receive error messages, then everything is fine and the connection worked.

Production warehouse

To save the DATABASE_URL parameter in the production vault, we run the command:

php bin/console secrets:set --env=prod DATABASE_URL

It creates a production store with all the necessary keys and sets DATABASE_URL with the specified value. It is necessary to ensure that the version control system is not added to the private decryption key. This point has already been taken into account when installing Symfony using composer, so we see the following line in the .gitignore file:

/config/secrets/prod/prod.decrypt.private.php

Symfony is so smart!

Retrieving Secret Values

To list all the values ​​that we added to the repository, we need to use the secrets: list command. To see the meaning of secrets, you can pass an option to the command called – reveal:

For production values, use:

php bin/console secrets:list --env=prod --reveal

Now we have secrets in the version control system for several environments. This is pretty cool!

Application Deployment

We have only one confidential value – a private decryption key. Therefore, during deployment, we need to add a private decryption file to the project or deploy it with an environment variable named SYMFONY_DECRYPTION_SECRET.

When do we want to use a variable SYMFONY_DECRYPTION_SECRET, we need to provide the value of the private decryption key encoded using base64, for example, as here:

php -r "echo base64_encode(require 'config/secrets/prod/prod.decrypt.private.php');"

When you use an assembly system such as Jenkins or Gitlab, you can embed this as an environment variable and transfer it to your pre-resized assembly or add the entire file to the assembly files and deploy them. For this, Jenkins offers the function of working with secret files:


Jenkins Secret File Function

But that’s not all – there is another way that does not even involve adding a private decryption key to the deployed code files. You can use this command in your build system to generate a .env file that you can deploy with application files:

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

This command generates a .env.prod.local file. Thus, your Symfony application will use the env variables from this file, and there will be no performance loss due to decryption of secrets at runtime. This is a great opportunity that does not affect security. If someone has access to your server, he can copy the private decryption key or just the .env.prod.local file.

Local storage for overrides at design time

How to override secrets during development? Here is a local storage that we can use to override DATABASE_URL to check something in another database. Add a local value like here:

php bin/console secrets:set DATABASE_URL --local

But what will happen now? Local credential overrides are stored in .env.dev.local! So you don’t need any additional storage and, of course, Symfony no longer added the line to the .gitignore file to prevent you from committing it. In addition, entries in the .env file are overridden, so you can safely do this. The only important point that needs attention is that Symfony first looks for env variables, and then secrets. So with env variables you can always override secret values.

To summarize

  • Env variables in the first place, and secrets in the second
  • Secret: set command automatically enables dev, local and prod env processing
  • Symfony warns about possible git issues with entries in .gitignore


Learn more about the course Symfony Framework.


Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *