Skip to content

Commit 1ae8ee6

Browse files
committed
Add the secret documentation
1 parent ebf693b commit 1ae8ee6

File tree

5 files changed

+332
-2
lines changed

5 files changed

+332
-2
lines changed

best_practices/configuration.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ to access to it, as long as the database is correctly configured.
4444
To override these variables with machine-specific or sensitive values, create a
4545
``.env.local`` file. This file should not be added to version control.
4646

47+
.. seealso::
48+
49+
You can also encrypt sensitive informations like passwords, tokens, api key,
50+
secrets, etc... See :doc:`/configuration/secrets`.
51+
4752
.. caution::
4853

4954
Beware that dumping the contents of the ``$_SERVER`` and ``$_ENV`` variables

configuration.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ instance, the framework bundle is configured in ``config/packages/framework.yaml
3636
php_errors:
3737
log: true
3838
39+
# Enables secrets management
40+
# secrets: true
41+
3942
.. code-block:: xml
4043
4144
<!-- config/packages/framework.xml -->
@@ -56,6 +59,8 @@ instance, the framework bundle is configured in ``config/packages/framework.yaml
5659
<framework:session/>
5760
5861
<framework:php-errors log="true"/>
62+
63+
<!--<framework:secrets/>-->
5964
</framework:config>
6065
</container>
6166
@@ -78,6 +83,7 @@ instance, the framework bundle is configured in ``config/packages/framework.yaml
7883
'php_errors' => [
7984
'log' => true,
8085
],
86+
//'secrets' => true,
8187
]);
8288
8389
The top-level key (here ``framework``) references configuration for a specific

configuration/environments.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,4 +361,4 @@ includes the following:
361361
Going further
362362
-------------
363363

364-
Read the article on :doc:`/configuration/environment_variables`.
364+
Read the article on :doc:`/configuration/environment_variables` and :doc:`/configuration/secrets`.

configuration/secrets.rst

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
.. index::
2+
single: Secrets
3+
4+
How to Keep Sensitive Informations Secret
5+
=========================================
6+
7+
In :doc:`/configuration` and :doc:`/configuration/environment_variables`, you
8+
learned how to manage your application configuration. In this article you'll
9+
learn how to easily anbd saftly configure your application with sensitive
10+
information such as credentials, passwords, tokens, api keys without exposing
11+
them.
12+
13+
.. _secrets-configuration:
14+
15+
Configuration
16+
-------------
17+
18+
In order to use secrets you have to enable the feature in the framework's
19+
20+
configuration:
21+
.. configuration-block::
22+
23+
.. code-block:: yaml
24+
25+
# config/packages/framework.yaml
26+
framework:
27+
secrets:
28+
# encrypted_secrets_dir: '%kernel.project_dir%/config/secrets/%kernel.environment%/'
29+
# encryption_key: '%kernel.project_dir%/config/secrets/encryption_%kernel.environment%.key'
30+
31+
.. code-block:: xml
32+
33+
<!-- config/packages/framework.xml -->
34+
<?xml version="1.0" encoding="UTF-8" ?>
35+
<container xmlns="http://symfony.com/schema/dic/services"
36+
xmlns:framework="http://symfony.com/schema/dic/framework"
37+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
38+
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
39+
http://symfony.com/schema/dic/framework https://symfony.com/schema/dic/framework/framework-1.0.xsd"
40+
>
41+
<framework:config secret="%env(APP_SECRET)%">
42+
<framework:secrets/>
43+
</framework:config>
44+
</container>
45+
46+
.. code-block:: php
47+
48+
// config/packages/framework.php
49+
$container->loadFromExtension('framework', [
50+
'secrets' => true,
51+
]);
52+
53+
.. tip::
54+
55+
the ``encryption_key`` configuration parameter accept both a path to an
56+
encription key or the content of the itself. It allows you, for instance,
57+
to store the content of the key in an environement variable and refer it
58+
with ``%env(PRIVATE_KEY)%``.
59+
60+
.. _secrets-generate-key:
61+
62+
Generate an Encryption Key
63+
--------------------------
64+
65+
Before creating a new ``secret``, you need to create ann ``encryption key``.
66+
This can be done with the provided commande ``secrets:generate-key``.
67+
68+
.. code-block:: terminal
69+
70+
$ APP_ENV=prod php bin/console secrets:generate-key
71+
72+
This command will generate a new ``encryption key`` in.
73+
``%kernel.project_dir%/config/secrets/encryption_%kernel.environment%.key``
74+
75+
.. note::
76+
77+
In order to use Symfony's built-in Secret storage, you will need the
78+
`libsodium`_ PHP extension.
79+
80+
Symfony generates a key with a symetrics algorithm, meaning that this key could
81+
be used to both encrypt **and** decrypt secrets. The number of people who
82+
possess this key should be as small as possible.
83+
84+
.. caution::
85+
86+
This file is sensitive and **must not** be commited nor publicly shared. Every
87+
developpers and CI don't need that key. If the encryption key have been
88+
exposed (ex-employee leaving for instance)you should consider regenerating a
89+
new one.
90+
91+
.. _secrets-add:
92+
93+
Create a Secret
94+
---------------
95+
96+
Once the ``encryption key`` generated, you can add new secret with the command
97+
``secrets:add``. Symfony'll ask you to enter the text to encrypt and generate
98+
a new file contains the ciphered text in a file stored by default in the folder
99+
%kernel.project_dir%/config/secrets/%kernel.environment%/. This file should be
100+
commited allongside the other project's files.
101+
102+
.. code-block:: terminal
103+
104+
$ APP_ENV=prod php bin/console secrets:add DATABASE_PASSWORD
105+
106+
.. tip::
107+
108+
If the ``encryption key`` is compromized, you can regenerate a new key with
109+
the command ``secrets:generate-key``. Symfony will decrypt the previous
110+
secret with the old key, adn re-encrypt theme with the new one.
111+
112+
.. _secrets-reference:
113+
114+
Referencing Secrets in Configuration Files
115+
------------------------------------------
116+
117+
You can reference those secrets in any configuration option enclosing their
118+
names using the ``secret`` :ref:`environment variable processors <env-var-processors>`.
119+
Their actual values will be resolved at runtime (once per request), so that
120+
container compilation and cache warmup don't need the ``encryption key``.
121+
122+
.. configuration-block::
123+
124+
.. code-block:: yaml
125+
126+
# config/packages/doctrine.yaml
127+
doctrine:
128+
dbal:
129+
password: '%env(secret:DATABASE_PASSWORD)%'
130+
# ...
131+
# ...
132+
133+
.. code-block:: xml
134+
135+
<!-- config/packages/doctrine.xml -->
136+
<?xml version="1.0" encoding="UTF-8" ?>
137+
<container xmlns="http://symfony.com/schema/dic/services"
138+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
139+
xmlns:doctrine="http://symfony.com/schema/dic/doctrine"
140+
xsi:schemaLocation="http://symfony.com/schema/dic/services
141+
https://symfony.com/schema/dic/services/services-1.0.xsd
142+
http://symfony.com/schema/dic/doctrine
143+
https://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">
144+
145+
<doctrine:config>
146+
<doctrine:dbal
147+
password="%env(secret:DATABASE_PASSWORD)%"
148+
/>
149+
</doctrine:config>
150+
151+
</container>
152+
153+
.. code-block:: php
154+
155+
// config/packages/doctrine.php
156+
$container->loadFromExtension('doctrine', [
157+
'dbal' => [
158+
'password' => '%env(secret:DATABASE_PASSWORD)%',
159+
]
160+
]);
161+
162+
This bellow configuration requires that every environment use secrets. each
163+
environment would have it own ``encryption key`` and encŷpted secrets.
164+
165+
You can also use parameters to configure diffrent strategy per environnement:
166+
By defining a default plaintext secret:
167+
168+
.. configuration-block::
169+
170+
.. code-block:: yaml
171+
172+
# config/packages/doctrine.yaml
173+
doctrine:
174+
dbal:
175+
password: '%database_password%'
176+
# ...
177+
# ...
178+
179+
parameters:
180+
database_password: 'not a secret'
181+
182+
.. code-block:: xml
183+
184+
<!-- config/packages/doctrine.xml -->
185+
<?xml version="1.0" encoding="UTF-8" ?>
186+
<container xmlns="http://symfony.com/schema/dic/services"
187+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
188+
xmlns:doctrine="http://symfony.com/schema/dic/doctrine"
189+
xsi:schemaLocation="http://symfony.com/schema/dic/services
190+
https://symfony.com/schema/dic/services/services-1.0.xsd
191+
http://symfony.com/schema/dic/doctrine
192+
https://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">
193+
194+
<doctrine:config>
195+
<doctrine:dbal
196+
password="%env(secret:DATABASE_PASSWORD)%"
197+
/>
198+
</doctrine:config>
199+
200+
<parameters>
201+
<parameter key="database_password">not a secret</parameter>
202+
</parameters>
203+
204+
</container>
205+
206+
.. code-block:: php
207+
208+
// config/packages/doctrine.php
209+
$container->loadFromExtension('doctrine', [
210+
'dbal' => [
211+
'password' => '%env(secret:DATABASE_PASSWORD)%',
212+
]
213+
]);
214+
$container->setParameter('database_password', 'not a secret');
215+
216+
Then overriding it in production environement:
217+
218+
.. configuration-block::
219+
220+
.. code-block:: yaml
221+
222+
# config/packages/prod/doctrine.yaml
223+
parameters:
224+
database_password: '%env(secret:DATABASE_PASSWORD)'
225+
226+
.. code-block:: xml
227+
228+
<!-- config/packages/prod/doctrine.xml -->
229+
<?xml version="1.0" encoding="UTF-8" ?>
230+
<container xmlns="http://symfony.com/schema/dic/services"
231+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
232+
xmlns:doctrine="http://symfony.com/schema/dic/doctrine"
233+
xsi:schemaLocation="http://symfony.com/schema/dic/services
234+
https://symfony.com/schema/dic/services/services-1.0.xsd
235+
http://symfony.com/schema/dic/doctrine
236+
https://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">
237+
238+
<parameters>
239+
<parameter key="database_password">%env(secret:DATABASE_PASSWORD)</parameter>
240+
</parameters>
241+
242+
</container>
243+
244+
.. code-block:: php
245+
246+
// config/packages/prod/doctrine.php
247+
$container->setParameter('database_password', '%env(secret:DATABASE_PASSWORD)');
248+
249+
.. _secrets-list:
250+
251+
List existing secrets
252+
---------------------
253+
254+
Every body is allowed to list the secret's name with the command ``secrets:list``.
255+
If you have the ``encryption key`` you can also reveal the plain text value by
256+
passing the optoin ``--reveal`` to the command
257+
258+
.. code-block:: terminal
259+
260+
$ APP_ENV=prod php bin/console secrets:list --reveal
261+
262+
------------------- ------------------
263+
key plaintext secret
264+
------------------- ------------------
265+
DATABASE_PASSWORD my-secret
266+
------------------- ------------------
267+
268+
.. _secrets-deploy
269+
270+
Deploy secret to production
271+
---------------------------
272+
273+
As the ``encryption key`` is not commited, during development, you'll have to
274+
manualy deploy the key (once for a will) at the path referenced in the
275+
``encryption_key`` configuration key. Default is ``%kernel.project_dir%/config/secrets/%kernel.environment%``.
276+
277+
.. _secrets-custom-storage
278+
279+
Custom Secret Storage
280+
~~~~~~~~~~~~~~~~~~~~~
281+
282+
It's also possible to add your own secret storage. First create a class that
283+
implements
284+
:class:`Symfony\\Bundle\\FrameworkBundle\\Secret\\SecretStorageInterface`::
285+
286+
use Symfony\Bundle\FrameworkBundle\Secret\SecretStorageInterface;
287+
288+
class EnvSecretStorage implements SecretStorageInterface
289+
{
290+
private $fallback;
291+
public function __construct(SecretStorageInterface $fallback)
292+
{
293+
$this->fallback = $fallback;
294+
}
295+
296+
public function getSecret(string $name): string;
297+
{
298+
if (!isset($_ENV[$name])) {
299+
return $this->fallback->getSecrets($name);
300+
}
301+
302+
return $_ENV[$name];
303+
}
304+
305+
public static function listSecrets(bool $reveal = false): iterable
306+
{
307+
foreach ($_ENV as $name => $value) {
308+
yield $name => $reveal ? $value : null;
309+
}
310+
yield from $this->fallback->listSecrets($reveal);
311+
}
312+
}
313+
314+
To enable the new processor in the app, decorates the ``Symfony\\Bundle\\FrameworkBundle\\Secret\\SecretStorageInterface``
315+
service.
316+
317+
318+
.. _`libsodium`: https://pecl.php.net/package/libsodium

doctrine/pdo_session_storage.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ To use it, first register a new handler service:
7070

7171
Configure the database credentials
7272
:doc:`using environment variables in the config file </configuration/environment_variables>`
73-
to make your application more secure.
73+
or :doc:`using secrets in the config file </configuration/secrets>`to make
74+
your application more secure.
7475

7576
Next, tell Symfony to use your service as the session handler:
7677

0 commit comments

Comments
 (0)