Last active
August 5, 2022 16:15
-
-
Save carlossosa/43d1d4b1702c5ec0368ca7bbb518ce35 to your computer and use it in GitHub Desktop.
Symfony 5.4/DoctrineMongoDBBundle 4.4: Workaround to pass $driver_options["autoEncryption" ] to MongoDB\Client
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Command\System; | |
use MongoDB\Client; | |
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault; | |
use Symfony\Component\Console\Attribute\AsCommand; | |
use Symfony\Component\Console\Command\Command; | |
use Symfony\Component\Console\Input\InputArgument; | |
use Symfony\Component\Console\Input\InputInterface; | |
use Symfony\Component\Console\Output\OutputInterface; | |
use Symfony\Component\Console\Style\SymfonyStyle; | |
#[AsCommand(name: "app:system:create-mongo-encrypt-key")] | |
class CreateMongoEncryptKeyCommand extends Command | |
{ | |
public function __construct(protected AbstractVault $vault) | |
{ | |
parent::__construct(); | |
} | |
protected function configure() | |
{ | |
$this->addArgument('key-id', InputArgument::REQUIRED, 'Key ID'); | |
$this->addArgument('aws-region', InputArgument::OPTIONAL, 'AWS Region', 'us-east-1'); | |
} | |
protected function execute(InputInterface $input, OutputInterface $output) | |
{ | |
$io = new SymfonyStyle($input, $output); | |
$kms = [ | |
"aws" => [ | |
"accessKeyId" => $_ENV['AWS_KEY'], | |
"secretAccessKey" => $_ENV['AWS_SECRET'], | |
] | |
]; | |
$masterKey = [ | |
"key" => $input->getArgument("key-id"), | |
"region" => $input->getArgument('aws-region'), | |
]; | |
$mongoClient = new Client($_ENV['MONGODB_URL']); | |
$encryptClient = $mongoClient->getManager()->createClientEncryption([ | |
"keyVaultNamespace" => $_ENV['MONGODB_DB'].".keyVault", | |
"kmsProviders" => $kms | |
]); | |
$keyId = $encryptClient->createDataKey('aws', [ | |
"masterKey" => $masterKey | |
]); | |
if ($this->vault->generateKeys()) { | |
$io->success($this->vault->getLastMessage()); | |
} | |
$this->vault->seal("MONGO_KEY_ID", base64_encode($keyId->getData())); | |
$io->success($this->vault->getLastMessage() ?? 'Secret was successfully stored in the vault.'); | |
return self::SUCCESS; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\DependencyInjection\Compiler; | |
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; | |
use Symfony\Component\DependencyInjection\ContainerBuilder; | |
class MongoODMConfigurePass implements CompilerPassInterface | |
{ | |
public function process(ContainerBuilder $container) | |
{ | |
$config = $container->getExtension('app')->getConfig(); | |
$defaultConnection = $container->getDefinition("doctrine_mongodb.odm.default_connection"); | |
$arg = $defaultConnection->getArgument(2); | |
if (array_key_exists('autoEncryption', $config)) { | |
$arg['autoEncryption'] = $config['autoEncryption']; | |
} | |
$defaultConnection->setArgument(2, $arg); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\DependencyInjection; | |
use Symfony\Component\Config\Definition\Builder\TreeBuilder; | |
use Symfony\Component\Config\Definition\ConfigurationInterface; | |
class Configuration implements ConfigurationInterface | |
{ | |
public function getConfigTreeBuilder() | |
{ | |
$bsonTypes = [ | |
'string', | |
'int', | |
'float', | |
'bool', | |
'object', | |
'array', | |
'binary', | |
'date', | |
'timestamp', | |
'regex', | |
'dbPointer', | |
'javascript', | |
'symbol', | |
'javascriptWithScope', | |
'int64', | |
'minKey', | |
'maxKey', | |
'numberLong', | |
]; | |
$algorithms = ['AEAD_AES_256_CBC_HMAC_SHA_512-Random','AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic']; | |
$tree = new TreeBuilder('app'); | |
$tree->getRootNode() | |
->children() | |
->arrayNode('autoEncryption') | |
->children() | |
->scalarNode('keyVaultNamespace')->isRequired()->end() | |
->arrayNode('kmsProviders') | |
->isRequired() | |
->requiresAtLeastOneElement() | |
->useAttributeAsKey('name') | |
->arrayPrototype() | |
->children() | |
->scalarNode('accessKeyId')->isRequired()->end() | |
->scalarNode('secretAccessKey')->isRequired()->end() | |
->end() // children | |
->end() // arrayPrototype | |
->end() // kmsProviders | |
->arrayNode('schemaMap') | |
->isRequired() | |
->useAttributeAsKey('name') | |
->arrayPrototype() | |
->children() | |
->enumNode('bsonType')->defaultValue('object')->values($bsonTypes)->end() | |
->arrayNode('encryptMetadata') | |
->children() | |
->arrayNode('keyId')->scalarPrototype()->end()->isRequired()->end() | |
->enumNode('algorithm')->values($algorithms)->defaultValue('AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic')->end() | |
->end() // children | |
->end() // encryptMetadata | |
->arrayNode('properties') | |
->isRequired() | |
->requiresAtLeastOneElement() | |
->useAttributeAsKey('name') | |
->arrayPrototype() | |
->children() | |
->arrayNode('encrypt') | |
->treatTrueLike(['keyId' => null]) | |
->children() | |
->enumNode('bsonType')->defaultValue('string')->values($bsonTypes)->end() | |
->enumNode('algorithm')->values($algorithms)->defaultValue('AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic')->end() | |
->arrayNode('keyId') | |
->validate() | |
->ifEmpty()->thenUnset() | |
->end() // validate | |
->scalarPrototype()->end() // scalarPrototype | |
->end() // keyId | |
->end() // children | |
->end() // encrypt | |
->end() // children | |
->end() // arrayPrototype | |
->end() // array node | |
->end() // children | |
->end() // arrayPrototype | |
->end() // schemaMap | |
->end() // end of mongoAutoEncryption | |
->end() // mongoAutoEncryption | |
->end() // app | |
; | |
return $tree; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\DependencyInjection; | |
use Symfony\Component\DependencyInjection\ContainerBuilder; | |
use Symfony\Component\HttpKernel\DependencyInjection\Extension; | |
class AppExtension extends Extension | |
{ | |
protected array $config = []; | |
public function load(array $configs, ContainerBuilder $container) | |
{ | |
$configuration = new Configuration(); | |
$this->config = $this->processConfiguration($configuration, $configs); | |
} | |
public function getConfig(): array | |
{ | |
return $this->config; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\DependencyInjection; | |
use MongoDB\BSON\Binary; | |
use Symfony\Component\DependencyInjection\EnvVarProcessorInterface; | |
class MongoBinaryEnvVarProcessor implements EnvVarProcessorInterface | |
{ | |
public function getEnv(string $prefix, string $name, \Closure $getEnv) | |
{ | |
$binary = $getEnv( $name); | |
if ( $binary === null) { | |
return null; | |
} | |
return new Binary($binary, Binary::TYPE_UUID); | |
} | |
public static function getProvidedTypes() | |
{ | |
return [ | |
'mongoBinary' => "string", | |
]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App; | |
use App\DependencyInjection\AppExtension; | |
use App\DependencyInjection\Compiler\MongoODMConfigurePass; | |
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; | |
use Symfony\Component\DependencyInjection\ContainerBuilder; | |
use Symfony\Component\HttpKernel\Kernel as BaseKernel; | |
class Kernel extends BaseKernel | |
{ | |
use MicroKernelTrait; | |
protected function build(ContainerBuilder $container) | |
{ | |
$container->registerExtension(new AppExtension()); | |
$container->addCompilerPass(new MongoODMConfigurePass()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
app: | |
autoEncryption: | |
keyVaultNamespace: "%env(MONGODB_DB)%.keyVault" | |
kmsProviders: | |
aws: | |
accessKeyId: "%env(AWS_KEY)%" | |
secretAccessKey: "%env(AWS_SECRET)%" | |
schemaMap: | |
"%env(MONGODB_DB)%.clients": | |
bsonType: "object" | |
encryptMetadata: | |
keyId: ["%env(mongoBinary:base64:MONGO_KEY_ID)%"] | |
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" | |
properties: | |
ssn: | |
encrypt: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Resolver | |
App\DependencyInjection\MongoBinaryEnvVarProcessor: | |
tags: | |
- { name: container.env_var_processor, priority: -1 } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment