Skip to content

Commit 37bc5d7

Browse files
authored
Merge pull request #52 from genecommerce/feature/get-cloud-env-keys
The CLI command for getting the reencrypted cloud keys
2 parents ccc383e + c860078 commit 37bc5d7

File tree

5 files changed

+258
-0
lines changed

5 files changed

+258
-0
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Gene\EncryptionKeyManager\Console;
6+
7+
use Magento\Framework\Console\Cli;
8+
use Psr\Log\LoggerInterface;
9+
use Symfony\Component\Console\Input\InputOption;
10+
use Symfony\Component\Console\Command\Command;
11+
use Symfony\Component\Console\Input\InputInterface;
12+
use Symfony\Component\Console\Output\OutputInterface;
13+
use Gene\EncryptionKeyManager\Model\ReEncryptCloudEnvKeysCommand;
14+
15+
class GetReEncryptedCloudEnvironmentsKeys extends Command
16+
{
17+
private const INPUT_KEY_SHOW_DECRYPTED = 'show-decrypted';
18+
19+
/**
20+
* Constructor
21+
*
22+
* @param ReEncryptCloudEnvKeysCommand $reencryptCloudEnvKeysCommand
23+
* @param LoggerInterface $logger
24+
*/
25+
public function __construct(
26+
private readonly ReEncryptCloudEnvKeysCommand $reencryptCloudEnvKeysCommand,
27+
private readonly LoggerInterface $logger
28+
) {
29+
parent::__construct();
30+
}
31+
32+
/**
33+
* The CLI configuration
34+
*
35+
* @return void
36+
*/
37+
protected function configure(): void
38+
{
39+
$this->setName('gene:encryption-key-manager:get-cloud-keys');
40+
$this->setDescription('Reencrypt cloud encrypted keys based on $_ENV variable. ' .
41+
'The CLI command don\'t save new values. It has to be done manually.');
42+
$this->setDefinition([
43+
new InputOption(
44+
self::INPUT_KEY_SHOW_DECRYPTED,
45+
null,
46+
InputOption::VALUE_NONE,
47+
'Whether to show decrypted values.'
48+
),
49+
]);
50+
parent::configure();
51+
}
52+
53+
/**
54+
* Execute the command
55+
*
56+
* @param InputInterface $input
57+
* @param OutputInterface $output
58+
*
59+
* @return int
60+
*/
61+
protected function execute(InputInterface $input, OutputInterface $output): int
62+
{
63+
$showDecrypted = !!$input->getOption(self::INPUT_KEY_SHOW_DECRYPTED);
64+
65+
try {
66+
// get old encrypted, decrypted and new encrypted values
67+
$config = $this->reencryptCloudEnvKeysCommand->execute();
68+
69+
if (!count($config)) {
70+
$output->writeln('<info>There is no old encrypted environment variables found</info>');
71+
return CLI::RETURN_SUCCESS;
72+
}
73+
74+
$output->writeln("<info>The CLI command doesn't rewrite values. " .
75+
"You have to update them manually in cloud console!</info>");
76+
$output->writeln("<comment>Rows count: " . count($config) . "</comment>");
77+
78+
foreach ($config as $name => $arr) {
79+
$output->writeln(str_pad('', 120, '#'));
80+
81+
/** @var $arr array{value:string, newValue:string, decryptedValue:string} */
82+
$output->writeln("Name: {$name}");
83+
if ($showDecrypted) {
84+
$output->writeln("Dectypted value: {$arr['decryptedValue']}");
85+
}
86+
$output->writeln("Old Encrypted Value: {$arr['value']}");
87+
$output->writeln("New Encrypted Value: {$arr['newValue']}");
88+
}
89+
90+
} catch (\Exception|\Throwable $e) {
91+
$this->logger->critical("Something went wrong while trying to reencrypt cloud variables.", [
92+
'msg' => $e->getMessage(),
93+
'trace' => $e->getTraceAsString(),
94+
]);
95+
$output->writeln("<error>" . $e->getMessage() . "</error>");
96+
97+
return CLI::RETURN_FAILURE;
98+
}
99+
100+
return CLI::RETURN_SUCCESS;
101+
}
102+
}

Model/EncodingHelper.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Gene\EncryptionKeyManager\Model;
6+
7+
use Magento\Framework\App\DeploymentConfig;
8+
9+
/**
10+
* Common states / validators for commands
11+
*/
12+
class EncodingHelper
13+
{
14+
/**
15+
* @param DeploymentConfig $deploymentConfig
16+
*/
17+
public function __construct(
18+
private readonly DeploymentConfig $deploymentConfig
19+
) {
20+
}
21+
22+
/**
23+
* Return the latest key number
24+
*
25+
* @return int
26+
*/
27+
public function getLatestKeyNumber(): int
28+
{
29+
try {
30+
$keys = preg_split('/\s+/s', trim((string)$this->deploymentConfig->get('crypt/key')));
31+
} catch (\Exception) {
32+
return 0;
33+
}
34+
return count($keys) -1;
35+
}
36+
37+
/**
38+
* Validate whether the value looks like digit:digit:string
39+
*
40+
* @param string $value
41+
* @return bool
42+
*/
43+
public function isEncryptedValue(string $value): bool
44+
{
45+
preg_match('/^\d:\d:\S+/', $value, $matches);
46+
return !!count($matches);
47+
}
48+
49+
/**
50+
* Returns whether the value is already encrypted
51+
*
52+
* @param string $encryptedValue
53+
* @return bool
54+
*/
55+
public function isAlreadyUpdated(string $encryptedValue): bool
56+
{
57+
return str_starts_with($encryptedValue, $this->getLatestKeyNumber() . ":");
58+
}
59+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Gene\EncryptionKeyManager\Model;
6+
7+
use Magento\Config\Model\Placeholder\PlaceholderFactory;
8+
use Magento\Config\Model\Placeholder\PlaceholderInterface;
9+
use Magento\Framework\Encryption\EncryptorInterface;
10+
use Magento\Framework\Exception\LocalizedException;
11+
12+
class ReEncryptCloudEnvKeysCommand
13+
{
14+
/**
15+
* @var PlaceholderInterface
16+
*/
17+
private PlaceholderInterface $placeholder;
18+
19+
/**
20+
* Constructor
21+
*
22+
* @param EncryptorInterface $encryptor
23+
* @param EncodingHelper $helper
24+
* @param PlaceholderFactory $placeholderFactory
25+
* @throws LocalizedException
26+
*/
27+
public function __construct(
28+
private readonly EncryptorInterface $encryptor,
29+
private readonly EncodingHelper $helper,
30+
PlaceholderFactory $placeholderFactory,
31+
) {
32+
$this->placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT);
33+
}
34+
35+
/**
36+
* Execute the command
37+
*
38+
* @param array|null $environmentVariables
39+
* @return array
40+
* @throws \Exception
41+
*/
42+
public function execute(array $environmentVariables = null): array
43+
{
44+
if ($environmentVariables === null) {
45+
if (!isset($_ENV)) {
46+
throw new \Exception("No environment variables defined");
47+
}
48+
$environmentVariables = $_ENV;
49+
}
50+
51+
$config = [];
52+
53+
foreach ($environmentVariables as $template => $value) {
54+
if (!$this->placeholder->isApplicable($template)
55+
|| !$this->helper->isEncryptedValue($value)
56+
|| $this->helper->isAlreadyUpdated($value)) {
57+
continue;
58+
}
59+
60+
$decryptedValue = $this->encryptor->decrypt($value);
61+
$newValue = $this->encryptor->encrypt($decryptedValue);
62+
$config[$template] = compact('value', 'newValue', 'decryptedValue');
63+
}
64+
65+
return $config;
66+
}
67+
}

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,31 @@ Dry run mode, no changes have been made
237237
########################################################################################################################
238238
Done
239239
```
240+
241+
## bin/magento gene:encryption-key-manager:get-cloud-keys
242+
243+
This command to get re-encrypted cloud environments variables.
244+
This one DOESN'T update existing values, it just returns new ones in console.
245+
The Dev has to update them manually in cloud console.
246+
247+
```bash
248+
# No keys example
249+
$ bin/magento gene:encryption-key-manager:get-cloud-keys
250+
There is no old encrypted environment variables found
251+
252+
# There is some encoded
253+
$ bin/magento gene:encryption-key-manager:get-cloud-keys --show-decrypted
254+
There is no old encrypted environment variables found
255+
The CLI command doesn\'t rewrite values. You have to update them manually in cloud console!
256+
Rows count: 4
257+
##################################################################
258+
Name: CONFIG__DEFAULT__SOME_KEY
259+
Dectypted value: dectypted_value
260+
Old Encrypted Value: 0:3:AAA1
261+
New Encrypted Value: 1:3:BBB1
262+
##################################################################
263+
Name: CONFIG__DEFAULT__SOME_KEY_2
264+
Dectypted value: dectypted_value_2
265+
Old Encrypted Value: 0:3:AAA2
266+
New Encrypted Value: 1:3:BBB2
267+
```

etc/di.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
<item name="gene_encryption_key_reencrypt" xsi:type="object">Gene\EncryptionKeyManager\Console\ReencryptUnhandledCoreConfigData</item>
3838
<item name="gene_encryption_key_reencryptcolumn" xsi:type="object">Gene\EncryptionKeyManager\Console\ReencryptColumn</item>
3939
<item name="gene_encryption_key_reencrypt_tfa" xsi:type="object">Gene\EncryptionKeyManager\Console\ReencryptTfaData</item>
40+
<item name="gene_encryption_key_get_reencrypted_cloud_env_keys"
41+
xsi:type="object">Gene\EncryptionKeyManager\Console\GetReEncryptedCloudEnvironmentsKeys</item>
4042
</argument>
4143
</arguments>
4244
</type>

0 commit comments

Comments
 (0)