Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions Console/GetReEncryptedCloudEnvironmentsKeys.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

declare(strict_types=1);

namespace Gene\EncryptionKeyManager\Console;

use Magento\Framework\Console\Cli;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Gene\EncryptionKeyManager\Model\ReEncryptCloudEnvKeysCommand;

class GetReEncryptedCloudEnvironmentsKeys extends Command
{
private const INPUT_KEY_SHOW_DECRYPTED = 'show-decrypted';

/**
* Constructor
*
* @param ReEncryptCloudEnvKeysCommand $reencryptCloudEnvKeysCommand
* @param LoggerInterface $logger
*/
public function __construct(
private readonly ReEncryptCloudEnvKeysCommand $reencryptCloudEnvKeysCommand,
private readonly LoggerInterface $logger
) {
parent::__construct();
}

/**
* The CLI configuration
*
* @return void
*/
protected function configure(): void
{
$this->setName('gene:encryption-key-manager:get-cloud-keys');
$this->setDescription('Reencrypt cloud encrypted keys based on $_ENV variable. ' .
'The CLI command don\'t save new values. It has to be done manually.');
$this->setDefinition([
new InputOption(
self::INPUT_KEY_SHOW_DECRYPTED,
null,
InputOption::VALUE_NONE,
'Whether to show decrypted values.'
),
]);
parent::configure();
}

/**
* Execute the command
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$showDecrypted = !!$input->getOption(self::INPUT_KEY_SHOW_DECRYPTED);

try {
// get old encrypted, decrypted and new encrypted values
$config = $this->reencryptCloudEnvKeysCommand->execute();

if (!count($config)) {
$output->writeln('<info>There is no old encrypted environment variables found</info>');
return CLI::RETURN_SUCCESS;
}

$output->writeln("<info>The CLI command doesn't rewrite values. " .
"You have to update them manually in cloud console!</info>");
$output->writeln("<comment>Rows count: " . count($config) . "</comment>");

foreach ($config as $name => $arr) {
$output->writeln(str_pad('', 120, '#'));

/** @var $arr array{value:string, newValue:string, decryptedValue:string} */
$output->writeln("Name: {$name}");
if ($showDecrypted) {
$output->writeln("Dectypted value: {$arr['decryptedValue']}");
}
$output->writeln("Old Encrypted Value: {$arr['value']}");
$output->writeln("New Encrypted Value: {$arr['newValue']}");
}

} catch (\Exception|\Throwable $e) {
$this->logger->critical("Something went wrong while trying to reencrypt cloud variables.", [
'msg' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
$output->writeln("<error>" . $e->getMessage() . "</error>");

return CLI::RETURN_FAILURE;
}

return CLI::RETURN_SUCCESS;
}
}
59 changes: 59 additions & 0 deletions Model/EncodingHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace Gene\EncryptionKeyManager\Model;

use Magento\Framework\App\DeploymentConfig;

/**
* Common states / validators for commands
*/
class EncodingHelper
{
/**
* @param DeploymentConfig $deploymentConfig
*/
public function __construct(
private readonly DeploymentConfig $deploymentConfig
) {
}

/**
* Return the latest key number
*
* @return int
*/
public function getLatestKeyNumber(): int
{
try {
$keys = preg_split('/\s+/s', trim((string)$this->deploymentConfig->get('crypt/key')));
} catch (\Exception) {
return 0;
}
return count($keys) -1;
}

/**
* Validate whether the value looks like digit:digit:string
*
* @param string $value
* @return bool
*/
public function isEncryptedValue(string $value): bool
{
preg_match('/^\d:\d:\S+/', $value, $matches);
return !!count($matches);
}

/**
* Returns whether the value is already encrypted
*
* @param string $encryptedValue
* @return bool
*/
public function isAlreadyUpdated(string $encryptedValue): bool
{
return str_starts_with($encryptedValue, $this->getLatestKeyNumber() . ":");
}
}
67 changes: 67 additions & 0 deletions Model/ReEncryptCloudEnvKeysCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

namespace Gene\EncryptionKeyManager\Model;

use Magento\Config\Model\Placeholder\PlaceholderFactory;
use Magento\Config\Model\Placeholder\PlaceholderInterface;
use Magento\Framework\Encryption\EncryptorInterface;
use Magento\Framework\Exception\LocalizedException;

class ReEncryptCloudEnvKeysCommand
{
/**
* @var PlaceholderInterface
*/
private PlaceholderInterface $placeholder;

/**
* Constructor
*
* @param EncryptorInterface $encryptor
* @param EncodingHelper $helper
* @param PlaceholderFactory $placeholderFactory
* @throws LocalizedException
*/
public function __construct(
private readonly EncryptorInterface $encryptor,
private readonly EncodingHelper $helper,
PlaceholderFactory $placeholderFactory,
) {
$this->placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT);
}

/**
* Execute the command
*
* @param array|null $environmentVariables
* @return array
* @throws \Exception
*/
public function execute(array $environmentVariables = null): array
{
if ($environmentVariables === null) {
if (!isset($_ENV)) {
throw new \Exception("No environment variables defined");
}
$environmentVariables = $_ENV;
}

$config = [];

foreach ($environmentVariables as $template => $value) {
if (!$this->placeholder->isApplicable($template)
|| !$this->helper->isEncryptedValue($value)
|| $this->helper->isAlreadyUpdated($value)) {
continue;
}

$decryptedValue = $this->encryptor->decrypt($value);
$newValue = $this->encryptor->encrypt($decryptedValue);
$config[$template] = compact('value', 'newValue', 'decryptedValue');
}

return $config;
}
}
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,31 @@ Dry run mode, no changes have been made
########################################################################################################################
Done
```

## bin/magento gene:encryption-key-manager:get-cloud-keys

This command to get re-encrypted cloud environments variables.
This one DOESN'T update existing values, it just returns new ones in console.
The Dev has to update them manually in cloud console.

```bash
# No keys example
$ bin/magento gene:encryption-key-manager:get-cloud-keys
There is no old encrypted environment variables found

# There is some encoded
$ bin/magento gene:encryption-key-manager:get-cloud-keys --show-decrypted
There is no old encrypted environment variables found
The CLI command doesn\'t rewrite values. You have to update them manually in cloud console!
Rows count: 4
##################################################################
Name: CONFIG__DEFAULT__SOME_KEY
Dectypted value: dectypted_value
Old Encrypted Value: 0:3:AAA1
New Encrypted Value: 1:3:BBB1
##################################################################
Name: CONFIG__DEFAULT__SOME_KEY_2
Dectypted value: dectypted_value_2
Old Encrypted Value: 0:3:AAA2
New Encrypted Value: 1:3:BBB2
```
2 changes: 2 additions & 0 deletions etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
<item name="gene_encryption_key_reencrypt" xsi:type="object">Gene\EncryptionKeyManager\Console\ReencryptUnhandledCoreConfigData</item>
<item name="gene_encryption_key_reencryptcolumn" xsi:type="object">Gene\EncryptionKeyManager\Console\ReencryptColumn</item>
<item name="gene_encryption_key_reencrypt_tfa" xsi:type="object">Gene\EncryptionKeyManager\Console\ReencryptTfaData</item>
<item name="gene_encryption_key_get_reencrypted_cloud_env_keys"
xsi:type="object">Gene\EncryptionKeyManager\Console\GetReEncryptedCloudEnvironmentsKeys</item>
</argument>
</arguments>
</type>
Expand Down