Skip to content

Commit 23a87c7

Browse files
[FrameworkBundle] Derivate kernel.secret from the decryption secret when its env var is not defined
1 parent 85db734 commit 23a87c7

File tree

5 files changed

+24
-3
lines changed

5 files changed

+24
-3
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Add support for setting `headers` with `Symfony\Bundle\FrameworkBundle\Controller\TemplateController`
8+
* Derivate `kernel.secret` from the decryption secret when its env var is not defined
89

910
7.1
1011
---

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

+5-2
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ public function load(array $configs, ContainerBuilder $container): void
372372
$this->registerDebugConfiguration($config['php_errors'], $container, $loader);
373373
$this->registerRouterConfiguration($config['router'], $container, $loader, $config['enabled_locales']);
374374
$this->registerPropertyAccessConfiguration($config['property_access'], $container, $loader);
375-
$this->registerSecretsConfiguration($config['secrets'], $container, $loader);
375+
$this->registerSecretsConfiguration($config['secrets'], $container, $loader, $config['secret'] ?? null);
376376

377377
$container->getDefinition('exception_listener')->replaceArgument(3, $config['exceptions']);
378378

@@ -1755,7 +1755,7 @@ private function registerPropertyAccessConfiguration(array $config, ContainerBui
17551755
;
17561756
}
17571757

1758-
private function registerSecretsConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void
1758+
private function registerSecretsConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader, ?string $secret): void
17591759
{
17601760
if (!$this->readConfigEnabled('secrets', $container, $config)) {
17611761
$container->removeDefinition('console.command.secrets_set');
@@ -1771,6 +1771,9 @@ private function registerSecretsConfiguration(array $config, ContainerBuilder $c
17711771

17721772
$loader->load('secrets.php');
17731773

1774+
$container->resolveEnvPlaceholders($secret, null, $usedEnvs);
1775+
$secretEnvVar = 1 === \count($usedEnvs ?? []) ? substr(key($usedEnvs), 1 + (strrpos(key($usedEnvs), ':') ?: -1)) : null;
1776+
$container->getDefinition('secrets.vault')->replaceArgument(2, $secretEnvVar);
17741777
$container->getDefinition('secrets.vault')->replaceArgument(0, $config['vault_directory']);
17751778

17761779
if ($config['local_dotenv_file']) {

src/Symfony/Bundle/FrameworkBundle/Resources/config/secrets.php

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
->args([
2222
abstract_arg('Secret dir, set in FrameworkExtension'),
2323
service('secrets.decryption_key')->ignoreOnInvalid(),
24+
abstract_arg('Secret env var, set in FrameworkExtension'),
2425
])
2526

2627
->set('secrets.env_var_loader', StaticEnvVarLoader::class)

src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php

+8-1
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,18 @@ class SodiumVault extends AbstractVault implements EnvVarLoaderInterface
2626
private string|\Stringable|null $decryptionKey = null;
2727
private string $pathPrefix;
2828
private ?string $secretsDir;
29+
private ?string $derivedSecretEnvVar;
2930

3031
/**
3132
* @param $decryptionKey A string or a stringable object that defines the private key to use to decrypt the vault
3233
* or null to store generated keys in the provided $secretsDir
3334
*/
34-
public function __construct(string $secretsDir, #[\SensitiveParameter] string|\Stringable|null $decryptionKey = null)
35+
public function __construct(string $secretsDir, #[\SensitiveParameter] string|\Stringable|null $decryptionKey = null, ?string $derivedSecretEnvVar = null)
3536
{
3637
$this->pathPrefix = rtrim(strtr($secretsDir, '/', \DIRECTORY_SEPARATOR), \DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR.basename($secretsDir).'.';
3738
$this->decryptionKey = $decryptionKey;
3839
$this->secretsDir = $secretsDir;
40+
$this->derivedSecretEnvVar = $derivedSecretEnvVar;
3941
}
4042

4143
public function generateKeys(bool $override = false): bool
@@ -177,6 +179,11 @@ public function loadEnvVars(): array
177179
$envs[$name] = LazyString::fromCallable($reveal, $name);
178180
}
179181

182+
if ($this->derivedSecretEnvVar && !array_key_exists($this->derivedSecretEnvVar, $envs)) {
183+
$decryptionKey = $this->decryptionKey;
184+
$envs[$this->derivedSecretEnvVar] = LazyString::fromCallable(static fn () => base64_encode(hash('sha256', $decryptionKey, true)));
185+
}
186+
180187
return $envs;
181188
}
182189

src/Symfony/Bundle/FrameworkBundle/Tests/Secrets/SodiumVaultTest.php

+9
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,13 @@ public function testEncryptAndDecrypt()
7575

7676
$this->assertSame([], $vault->list());
7777
}
78+
79+
public function testDerivedSecretEnvVar()
80+
{
81+
$vault = new SodiumVault($this->secretsDir, null, 'MY_SECRET');
82+
$vault->generateKeys();
83+
$vault->seal('FOO', 'bar');
84+
85+
$this->assertSame(['FOO', 'MY_SECRET'], array_keys($vault->loadEnvVars()));
86+
}
7887
}

0 commit comments

Comments
 (0)