If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeWe have successfully added the SENTRY_DSN
secret value to both the dev
and prod
vaults.
How can I prove that? By running:
php bin/console secrets:list
Because we're in the dev
environment, this reads the dev
vault. There's our one secret. To see its value, add --reveal
:
php bin/console secrets:list --reveal
Behind-the-scenes, that used the dev "decrypt" key to decrypt the value: it's an empty string. Ignore this "local value" thing for a minute.
We can do the same thing for the prod
vault by passing --env=prod
:
php bin/console secrets:list --env=prod
Including adding --reveal
to see the value.
php bin/console secrets:list --env=prod --reveal
Ok: because we're in the dev
environment, the dev
secret - the empty string - is the one that should be used. Refresh the page, check the dump, and expand it a few times. It's still using the production value.
Go back into config/packages/sentry.yaml
:
sentry: | |
dsn: '%env(SENTRY_DSN)%' |
We're still using the syntax for reading environment variables. How can we tell it to read the SENTRY_DSN
secret instead? Surprise! To tell Symfony to read a SENTRY_DSN
secret, we use the exact same syntax.
Let me explain: when Symfony sees the %env()%
syntax, it first looks to see if an environment variable called SENTRY_DSN
exists. If it does, it uses it. If there is not, it then looks for a secret in the vault called SENTRY_DSN
. So reading environment variables and secrets uses the same syntax, but environment variables take priority.
This means one important thing: when you identify an environment variable that you want to convert into a secret, you need to remove it entirely as an environment variable. Set a value as an environment variable or a secret, but not both. Delete the SENTRY_DSN
entry from .env
and .env.local
:
... lines 1 - 22 | |
###> sentry/sentry-symfony ### | |
SENTRY_DSN= | |
### |
SENTRY_DSN=https://7f45741877f3498eab0ae2bee6463d57@o372370.ingest.sentry.io/5186941 |
Now Symfony should be read from our dev
vault. Refresh... expand the object and... yes! All the values are null
! It works!
Let's try out production. Until now, to switch to the prod
environment, I've been updating the .env
file:
... lines 1 - 15 | |
###> symfony/framework-bundle ### | |
APP_ENV=dev | |
... lines 18 - 20 | |
### | |
... lines 22 - 26 |
But now that we understand .env.local
, let's add APP_ENV=prod
there instead:
APP_ENV=prod |
Next, clear your cache:
php bin/console cache:clear
Then spin back to your browser and refresh. This time the dump is on top. If I expand it... yes! It's using the production values. Booya! That works because my project has the prod decrypt key. If that was not there, we would get an error.
Go ahead and take out the APP_ENV=
line in .env.local
to get back to the dev
environment:
APP_ENV=prod |
And in QuestionController
, let's cleanup: remove the dump()
, the new Exception
and the HubInterface
argument:
... lines 1 - 12 | |
class QuestionController extends AbstractController | |
{ | |
... lines 15 - 42 | |
public function show($slug, MarkdownHelper $markdownHelper) | |
{ | |
if ($this->isDebug) { | |
$this->logger->info('We are in debug mode!'); | |
} | |
$answers = [ | |
'Make sure your cat is sitting `purrrfectly` still ?', | |
'Honestly, I like furry shoes better than MY cat', | |
'Maybe... try saying the spell backwards?', | |
]; | |
... lines 54 - 62 | |
} | |
} |
After this... things are working again.
You are now ready to use Symfony's secrets system. But! The fact that environment variables take precedent over secrets is something that we can use to our advantage.
Find your terminal and run:
php bin/console secrets:list --reveal
In the dev
environment, the SENTRY_DSN
value is set to an empty string. Let's pretend that, while developing, I want to temporarily set SENTRY_DSN
to a real value so I can test that integration.
We could use secrets:set
to override the value... but that would update the secrets file... and then we would have to be super careful to avoid committing that change.
There's a better way. In .env.local
, set SENTRY_DSN
to the real value. Well, I'll put "FOO" here so it's obvious when this value is being used.
Now run that command again:
php bin/console secrets:list --reveal
The "Value" is still empty quotes, but now it has a "Local Value" set to the string we just used! The "Local Value" is the one that will be used. Why? Because our new environment variable overrides the secret: environment variables always win over secrets. This "Local Value" is a fancy way of saying that.
I'll take that value out of .env.local
so that my secret is once again used.
Next: let's have some fun! We're going to install MakerBundle and start generating some code!
Hey Ruslan,
If you want to dump SENTRY_DSN, you can do it in whatever PHP file you want, e.g. add this in a controller where you need this value:
dd($_SERVER['SENTRY_DSN']);
// or
dd($_ENV['SENTRY_DSN']);
Both should print you your DSN value for Sentry if you set any in your .env files
I hope this helps!
Cheers!
Hi, I'm getting:
Environment variable not found: "SENTRY_DSN".
But the secret is configured as below:
$ bin/console secrets:list --reveal --env=dev
// Use "%env(<name>)%" to reference a secret in a config file.
------------ ------- -------------
Secret Value Local Value
------------ ------- -------------
SENTRY_DSN ""
------------ ------- -------------
And my sentry.yaml file show:
sentry:
dsn: "%env(SENTRY_DSN)%"
I've delete the SENTRY_DSN lines from .env and .env.local
It started working, I'm not sure why, but the only thing I think changed was that I restarted the Symfony server.
I'm getting the following error when trying to reveal secrets in prod environment:
PHP Fatal error: Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException: Circular reference detected for parameter "env(base64:default::SYMFONY_DECRYPTION_SECRET)" ("env(base64:default::SYMFONY_DECRYPTION_SECRET)" > "env(default::SYMFONY_DECRYPTION_SECRET)" > "env(SYMFONY_DECRYPTION_SECRET)" > "env(base64:default::SYMFONY_DECRYPTION_SECRET)"). in cauldron-overflow\vendor\symfony\dependency-injection\Container.php:389
I used this command: php bin/console secrets:list --env=prod --reveal
, Symfony version: 5.1.2
Any ideas?
Hey @Beam OP!
I know this :). You have found a Symfony bug! https://symfonycasts.com/sc...
It is fixed in Symfony 5.1.3, but that hasn't been released yet - I expect that to happen any day now - it's been 28 days since the last bug release.
Cheers!
I am getting the following error in logs when switching to prod:
[2020-06-19T16:54:53.389249+00:00] request.CRITICAL: Uncaught PHP Exception Symfony\Component\OptionsResolver\Exception\InvalidOptionsException: "The option "dsn" with value "" is invalid." at C:\Users\Michael\code\code-symfony-fundamentals\start\vendor\symfony\options-resolver\OptionsResolver.php line 987 {"exception":"[object] (Symfony\\Component\\OptionsResolver\\Exception\\InvalidOptionsException(code: 0): The option \"dsn\" with value \"\u0016\" is invalid. at C:\\Users\\Michael\\code\\code-symfony-fundamentals\\start\\vendor\\symfony\\options-resolver\\OptionsResolver.php:987)"} []
Hey Michał,
If you use Git - try to commit changes and run:
$ git grep dsn
This command will show you all the spots where you use dsn. Make sure that all dsn options are set properly in your project. Also, keep eyes closer where those values should come from, probably you need to set up an env var in your .env or .env.local files? Or probably specifically in .env.prod in your case?
Cheers!
Hey! Doesn't secrets work for console commands? Something weird is happening with my project. When I ran ./bin/console doctrine:database:drop
it returns <blockquote>Connection does not contain a 'path' or 'dbname' parameter and cannot be dropped.</blockquote> I set a breakpoint at exception line and found out that $params
local variable does <b>not</b> contain data for my PostgreSQL connection: at least $params["driver"] = pdo_mysql . I faced with the issue after deploying my whole Docker Compose stack to remote machine through Docker Machine. I set all the demo env var through secrets intentionally. After deploying I decided to re-create database and started with doctrine:database:drop
and got that error. Trying to execute doctrine:migrations:migrate
shows $dsn == mysql:host=localhost;dbname=;charset=utf8mb4;
Nonsense! To be honest I just lost debugging call stack to find out why the app takes default env values instead of stored in secrets. Any ideas?
The problem is that the secrets are NOT read for some reason. They are successfully displayed with `./bin/console secrets:list --env=demo --reveal` but do not work until decrypting into `.env.demo.local`. `debug:config framework secrets` confirms that secrets are enabled. Some googling showed that there might be a problem with sodium extension but I have one both on dev and demo machine/environments.
OMG! Shame on me! I've just forgot to comment out env vars in .env file. I use an empty env vars in .env just not to forget to set them in .env.<env_name> file. Thus empty values in .env just override secrets. And only decrypting secrets with `secrets:decrypt-to-local` writes .env.<env_name>.local which in its turn override empty values in `.env`.
Dang! what a sneaky error. I'm glad you figured it out. FYI what you put on the .env.<environment_name>
will override any other value you already have
Cheers!
// composer.json
{
"require": {
"php": "^7.3.0 || ^8.0.0",
"ext-ctype": "*",
"ext-iconv": "*",
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"knplabs/knp-markdown-bundle": "^1.8", // 1.9.0
"sensio/framework-extra-bundle": "^6.0", // v6.2.1
"sentry/sentry-symfony": "^4.0", // 4.0.3
"symfony/asset": "5.0.*", // v5.0.11
"symfony/console": "5.0.*", // v5.0.11
"symfony/debug-bundle": "5.0.*", // v5.0.11
"symfony/dotenv": "5.0.*", // v5.0.11
"symfony/flex": "^1.3.1", // v1.17.5
"symfony/framework-bundle": "5.0.*", // v5.0.11
"symfony/monolog-bundle": "^3.0", // v3.6.0
"symfony/profiler-pack": "*", // v1.0.5
"symfony/routing": "5.1.*", // v5.1.11
"symfony/twig-pack": "^1.0", // v1.0.1
"symfony/var-dumper": "5.0.*", // v5.0.11
"symfony/webpack-encore-bundle": "^1.7", // v1.8.0
"symfony/yaml": "5.0.*" // v5.0.11
},
"require-dev": {
"symfony/maker-bundle": "^1.15", // v1.23.0
"symfony/profiler-pack": "^1.0" // v1.0.5
}
}
Now that Knp markdown is abandoned I tried to implement the markdown caching service using the suggested twig filter. However that does not support/expose MarkdownParserInterface. I noticed that the twig filter uses michelf php-markdown though, which does support that interface. Luckily I did this in another branch which is now named 'broken' :( Autowiring does not pick up the michelf classes, do I need to put Michelf\Markdown in autoload.php? How do I stop twig from inlining the classes and making them disappear?