-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[FrameworkBundle] Add secrets management. #31101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
f365e0b
to
d5ad8cd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just CS comments for now
src/Symfony/Bundle/FrameworkBundle/Command/SecretsAddCommand.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Command/SecretsAddCommand.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Exception/SecretNotFoundException.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Command/SecretsAddCommand.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Command/SecretsGenerateKeyCommand.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
Outdated
Show resolved
Hide resolved
Minor comment, it's |
src/Symfony/Bundle/FrameworkBundle/Secret/FilesSecretStorage.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Secret/FilesSecretStorage.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
Outdated
Show resolved
Hide resolved
f164b9b
to
a17c165
Compare
src/Symfony/Bundle/FrameworkBundle/Secret/MutableSecretStorageInterface.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Secret/SecretStorageInterface.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Command/SecretsAddCommand.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Secret/MutableSecretStorageInterface.php
Outdated
Show resolved
Hide resolved
826fb3c
to
bef764e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
first round (wording only)
src/Symfony/Bundle/FrameworkBundle/Command/SecretsAddCommand.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Command/SecretsAddCommand.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Secret/FilesSecretStorage.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Secret/MutableSecretStorageInterface.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Command/SecretsGenerateKeyCommand.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Tests/Secret/FilesSecretStorageTest.php
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice feature :)
src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Command/SecretsAddCommand.php
Outdated
Show resolved
Hide resolved
private $secretsStorage; | ||
private $encoder; | ||
|
||
public function __construct(EncoderInterface $encoder, MutableSecretStorageInterface $secretsStorage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I'm right, we don't use prefixes like Mutable
and Immutable
in Symfony code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would drop the prefix as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
naming things are hard... :(
Here I wanted to distingquihed "readonly storage" from "writable storage" do you have any idea of naming?
note: we have a Symfony\Component\Security\Acl\Model\MutableAclInterface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SecretStorageInterface {
get(): string;
set(): void;
list(): iterable;
}
would be enough IMHO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👎 don't just name it get, set etc without "secret". It should be obvious from the method name that this is confidential data, not a generic data store.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given:
- At first, users only need to fetch secrets from the storage. That's the purpose of the
SecretStorageInterface
. - Symfony provides a default storage (the
FileSecretStorage
) and a convenient way to add new secrets in it (theSecretsAddCommand
). Maybe I should inject theFileSecretStorage
and remove that interface?
We have 2 interface for reasons:
-
From our point of view, it didn't make sens to use symfony's command to manage 3rd party tools like
vault
. Users could use their favorite tool to add/delete secrets from them. -
I think that a futur implementation of
SecretStorageInterface
could be aChainSecretStorage
that iterate over a list ofSecretStorageInterface
. ImplementingsetSecret
in a chain wouldn't make sens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the ChainSecretStorage which will improve the DX by allowing developper/3rd party to create new SecretStorages
src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Secret/FilesSecretStorage.php
Outdated
Show resolved
Hide resolved
68d5fb9
to
29351bb
Compare
src/Symfony/Bundle/FrameworkBundle/Secret/FilesSecretStorage.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Secret/FilesSecretStorage.php
Outdated
Show resolved
Hide resolved
I haven't see that one before. Thanks for the link. Why did he create the PR on his own fork instead of symfony? |
09709e6
to
072b311
Compare
neither do I. There are a lot of common concept in both PR:
which let me think, we are on the right way. But also many differences.
Using interface in this PR leave the possibility open to add a PR rebased, and ready for review |
072b311
to
7ecd091
Compare
would a JSON based secret storage be useful? to group multiple secrets in a single file ... edit: oh you mentioned |
7ecd091
to
2083c18
Compare
hello @ro0NL even if this PR leaves the possibility to implement a Note: storing all secrets in 1 file will have a performance drawback : reading/deconding the entier file for fetching a single secret |
@jderusse im not sure yet :) i must say Docker makes it pretty easy to ship secret files into I think security is a bigger issue then performance actually, as fetching one value reveals all (using the same key). |
I I understand the one file concept right, when using one file only the json keys are revealed. Each secret (under each key) is encrypted independently. |
From performance and security perspective it doesn't matter if it's a single file or one file per secret.
|
Just a friendly reminder that Symfony 4.4/5.0 will enter its "feature freeze" period in 11 days, on October 1st. It'd be nice to have this feature in. I hope you can do a last-ditch effort to finish this. Thanks! |
2083c18
to
c2d8a52
Compare
PR rebased and RFR. Unless I missed a point all comments are resolved. (or could be resolved in a Future dedicated PR, because the current interfaces in this PR are flexible enougth to allow such evolution (ie. Please tell me if I missed a point. |
What about creating a |
Depend of the point of view on the feature. This PR is about providing a "secured" way to store configuration. The encryption thing is an implementation detail. Moving to a component means focusing on loading/storing secret, probably providing/maintaining several backend (vault, KMS, ...). At the time I opened the PR I wasn't sure it worth it. We talked about it with @nicolas-grekas which convince me that we should provide a single backend implementation in order to offer the simplest and best experience for the user. |
c2d8a52
to
afd2f0f
Compare
Having a component does not necessarily mean having to provide more than one backend. Dotenv only provides one ( |
interface EncoderInterface | ||
{ | ||
/** | ||
* Generate the keys and material necessary for its operation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generates
public function generateKeys(bool $override = false): array; | ||
|
||
/** | ||
* Encrypt a secret. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Encrypts
public function encrypt(string $secret): string; | ||
|
||
/** | ||
* Decrypt a secret. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Decrypts
$this->encryptionKey = null; | ||
|
||
$encryptionKey = sodium_crypto_stream_keygen(); | ||
(new Filesystem())->dumpFile($this->encryptionKeyPath, $encryptionKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure we want to depend on Filesystem
closing in favor of #33997 |
…ecret:...)%` processor to deal with secrets seamlessly (Tobion, jderusse, nicolas-grekas) This PR was merged into the 4.4 branch. Discussion ---------- [FrameworkBundle] Add `secrets:*` commands and `%env(secret:...)%` processor to deal with secrets seamlessly | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #27351 | License | MIT | Doc PR | symfony/symfony-docs/pull/11396 This PR continues #31101, please see there for previous discussions. The attached patch has been fine-tuned on nicolas-grekas#33 with @jderusse. This PR is more opinionated and thus a lot simpler than #31101: only Sodium is supported to encrypt/decrypt (polyfill possible), and only local filesystem is available as a storage, with little to no extension point. That's on purpose: the goal here is to provide an experience, not software building blocks. In 5.1, this might be extended and might lead to a new component, but we'd first need reports from real-world needs. Having this straight-to-the-point in 4.4 will allow gathering these needs (if they exist) and will immediately provide a nice workflow for the need we do want to solve now: forwarding secrets from dev to prod using git in a secure way. The workflow this will allow is the following: - public/private key pairs are generated in the `config/secrets/%kernel.environment%/` folder using `bin/console secrets:generate-keys` - for the prod env, the corresponding private key should be deployed to the server using whatever means the hosting provider allows - this key MUST NOT be committed - the public key is used to encrypt secrets and thus *may* be committed in the git repository to allow anyone *that can commit* to add secrets - this is done using `bin/console secrets:set` DI configuration can reference secrets using `%env(secret:...)%` in e.g `services.yaml`. There is also `bin/console secrets:remove` and `bin/console debug:secrets` to complete the toolbox. In terms of design, vs #31101, this groups the dual "encoder" + "storage" concepts in a single "vault" one. That's part of what makes this PR simpler. That's all folks :) Commits ------- c4653e1 Restrict secrets management to sodium+filesystem 02b5d74 Add secrets management 8c8f623 Proof of concept for encrypted secrets
During the Foss Hackathon, we worked 2 wall days to talk and read RFC comment, other framework implementations (laravel, rails, ...)
We tried to cover every used case, building a simple and flexible solution that could be improved in the future or 3rd party bundles.
Here are the choice we tooks and why:
Have a look to the draft of the documentation. it may help you to understand how it work
In short default usage:
%env()%
syntax even if it's not an Environement Variable.Even if it's not related to "environement variables"
", secrets are related to the the
environement. using
%env()%` make perfect sense and is exactly what we need: executed at runtime + many EnvProcessors already definedThe build-in version in symfony will only store secret in a file.
If users want something else: They could implements their own Storage with
SecretStorageInterface
.Some example of storage that are out of scope for now:
The build-in storage stores secrets and key are stored in a path that vary with the
kernel.environement
variable.Thuse will - BY DESIGN - avoid users from being tempted to share the production key with other developpers/CI/...
Because modern and easy to use (avoid mistake by using wrong combinaison of algorithme)
In oposition with everything I thought before, @tobias conviced me to use a symetric algorithm. (Which mean that everybody who's able to generate a secret would also be able to read the secrets)
When using asymetric keys, the private key should be deployed on production and be accessible by few OPS
When using asymetric keys, the keys are not easily renewable (the private key is required to decrypt with the old key and recrypt with the new key)
Because even with asymetric algorithm, the key could be compromised (if an OPS is fired for instance) and not easily renewable,
We recommand to use symetric key (owned by few people) and renew that key (and secrets of course) everytime an owner leaves the project.
A big thank you to @Tobion, @mpdude and @nicolas-grekas .