Storing sensitive application information (passwords, tokens, certificates, etc.) is a challenging task. You cannot rely on traditional configuration files and you cannot rely either on environment variables. That's why in Symfony 4.4 we've added a new encryption-based feature to manage secrets.
Imagine that you want to keep the entire DATABASE_URL
content secret to
avoid leaking the database connection credentials. This is how you can do that:
Step 1. Generate the keys used to encrypt/decrypt secrets (this feature is based on a traditional public-key cryptography and uses the libsodium library):
1
$ php bin/console secrets:generate-keys
This command generates a pair of keys in config/secrets/dev/
(or
config/secrets/prod/
). The public key is used to encrypt secrets and you
should commit it to your shared repository. The private key should not be
committed to the repository and should not be shared in any way.
Step 2. Upload the private key to your remote server using SSH or any other
safe means and store it in the same config/secrets/<environment>/
directory.
Step 3. Create a new secret to store the contents of DATABASE_URL
:
1 2 3 4 5 6
$ php bin/console secrets:set DATABASE_URL
Please type the secret value:
> **************
[OK] Secret "DATABASE_URL" encrypted in "config/secrets/dev/"; you can commit it.
Each secret is stored in its own file inside the config/secrets/<environment>/
directory. You can commit these files to the repository because their contents
are not accessible unless you also have the private key.
That's all. Use this new secret as any other normal env var in your configuration files and Symfony will decrypt the value transparently when needed:
1 2 3 4 5
# config/packages/doctrine.yaml
doctrine:
dbal:
url: "%env(DATABASE_URL)%"
# ...
Repeat the step 3 for all the configuration values that you want to turn into
secrets. Use the other commands to complete the whole secret management
experience: secrets:remove
to delete secrets, secrets:list
to show all
the secrets managed by the application, generate-keys --rotate
to change the
existing keys by new ones and re-encrypt all secrets automatically, etc.
That's really cool
What is the best way to store the private key, except the server?
Thats awesome
Nice feature!
However, this blog post can be misleading for developer not well versed in security and should explain imho a bit better the context.
For a starter: what does this feature protect against? A: It will not change anything for any attacker who gains access to the source code files on the server, can do remote-code-execution or even snoop on the in-memory executing code. It will otoh be useful to prevent the common case of developers storing passwords in plain within the codebase.
Then: why is this feature any safer than using env variables?
Cool! Now we can just keep one key in the CI/CD tool instead a bunch of keys. The most think I liked is that after the first setup, every time we introduce new ENV variable, we only have one place to keep an eye to, and even better this also be version controlled. We have more time thinking about real business issue.
Why? Is this feature aimed for the cases where using environment variables is not possible? (Shared hosting, I imagine) Or has using environment variables (or locally stored .env files for that matter) for configuration strings is out of vogue now?
Awesome! Great job!
Hi, it looks interesting but I am not sure if I understand purpose of this feature. Is the goal to have separated encrypted sensitive data and key to decrypt this data in different folders but probably accessible from same point? If someone change e.g. password to database then the new password must be committed to repository? Maybe I missing something. I would by glad to clarify the benefits. Thank you for the work you are doing
Everyone: the doc PR might clarify some things, see https://github.com/symfony/symfony-docs/pull/11396 This feature is about making it easier to deal with secrets appropriately by using the same git workflow ppl are used to for the code (ie git).
"This feature is about making it easier to deal with secrets appropriately by using the same git workflow ppl are used to for the code (ie git)." --- unless secrets and any other runtime configuration details don't belong to the code and code's repository.
They are part of deployment and should be managed totally separately.
Mmmmh. I was a bit sceptical about this (now, instead of transferring the "secrets" separately, you need to transfer the decrypting key separately; it doesn't seem like a huge gain)... after thinking it for a bit I can see it being useful... on some scenarios.
Still, I'm not sure I'm fully convinced. Environment variables seem to be easier to override on different environments or installs.
I'll keep using environment variables for the time being, which are more tightly integrated with deployment mechanics and more standard anyway.
Not a huge fan of this being added to "best practices". I think it's a bit like going back to the days of "doing things the Symfony way instead of the industry standard way".
Nice feature. Thks.
Very nice feature !
Is secrets vars overidding the normal env (.env & .env.local & .env.prod) ?
@asurion you have the command
secrets:decrypt-to-local
to make them local.A quick question: I guess all secrets should have its keys in the .env file that is committed? I mean if I encrypt the env FOO='bar', in .env file I should include FOO= just for reference, right?