Skip to content

Commit

Permalink
Merge pull request #31 from genecommerce/re-encrypt-env-deployment-co…
Browse files Browse the repository at this point in the history
…nfig

Added re-encryption functionality for env.php  (#30 plus test)
  • Loading branch information
convenient authored Jul 24, 2024
2 parents e09b664 + f94e3ca commit 5c0e6b6
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 1 deletion.
7 changes: 6 additions & 1 deletion Console/GenerateEncryptionKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Gene\EncryptionKeyManager\Console;

use Gene\EncryptionKeyManager\Service\ChangeEncryptionKey as ChangeEncryptionKeyService;
use Gene\EncryptionKeyManager\Service\ReencryptEnvSystemConfigurationValues;
use Magento\Framework\App\Config\Storage\WriterInterface;
use Magento\Framework\Encryption\Encryptor;
use Magento\Framework\App\Config\ScopeConfigInterface;
Expand Down Expand Up @@ -38,7 +39,8 @@ public function __construct(
private readonly WriterInterface $configWriter,
private readonly Emulation $emulation,
private readonly State $state,
private readonly Encryptor $encryptor
private readonly Encryptor $encryptor,
private readonly ReencryptEnvSystemConfigurationValues $reencryptEnvSystemConfigurationValues
) {
parent::__construct();
}
Expand Down Expand Up @@ -117,6 +119,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
(bool)$input->getOption(self::INPUT_SKIP_SAVED_CREDIT_CARDS)
);
$this->changeEncryptionKey->changeEncryptionKey($newKey);
$output->writeln('reEncryptEnvConfigurationValues - start');
$this->reencryptEnvSystemConfigurationValues->execute();
$output->writeln('reEncryptEnvConfigurationValues - end');
$this->emulation->stopEnvironmentEmulation();
$output->writeln('Cleaning cache');

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ Done

- Use the `--key` option to manually define the new key to use during re-encryption. If no custom key is provided, a new key will be generated.
- Use the `--skip-saved-credit-cards` flag to skip re-encrypting the `sales_order_payment` `cc_number_enc` data. This table can be very large, and many stores will have no data saved in this column.
- This will automatically re-encrypt any `system` values in `app/etc/env.php`

## bin/magento gene:encryption-key-manager:invalidate

Expand Down
83 changes: 83 additions & 0 deletions Service/ReencryptEnvSystemConfigurationValues.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

declare(strict_types=1);

namespace Gene\EncryptionKeyManager\Service;

use Magento\Deploy\Model\DeploymentConfig\Hash;
use Magento\Framework\App\DeploymentConfig;
use Magento\Framework\App\DeploymentConfig\Writer;
use Magento\Framework\Config\Data\ConfigData;
use Magento\Framework\Config\File\ConfigFilePool;
use Magento\Framework\Encryption\EncryptorInterfaceFactory;
use Magento\Framework\Encryption\EncryptorInterface;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Exception\RuntimeException;

class ReencryptEnvSystemConfigurationValues
{
/** @var EncryptorInterface|null */
private $encryptor = null;

/**
* @param DeploymentConfig $deploymentConfig
* @param Writer $writer
* @param EncryptorInterfaceFactory $encryptorFactory
* @param Hash $hash
*/
public function __construct(
private readonly DeploymentConfig $deploymentConfig,
private readonly Writer $writer,
private readonly EncryptorInterfaceFactory $encryptorFactory,
private readonly Hash $hash
) {
}

/**
* Gather all encrypted system config values from env.php and re-encrypt them
*
* @return void
* @throws FileSystemException
* @throws RuntimeException
* @throws \Exception
*/
public function execute(): void
{
$this->deploymentConfig->resetData();
$this->encryptor = $this->encryptorFactory->create();
$systemConfig = $this->deploymentConfig->get('system');
$systemConfig = $this->iterateSystemConfig($systemConfig);

$encryptSegment = new ConfigData(ConfigFilePool::APP_ENV);
$encryptSegment->set('system', $systemConfig);
$this->writer->saveConfig([$encryptSegment->getFileKey() => $encryptSegment->getData()]);

/**
* @see \Magento\Deploy\Console\Command\App\ConfigImport\Processor::execute()
*/
$this->hash->regenerate('system');
}

/**
* Recursively iterate through the system configuration and re-encrypt any encrypted values
*
* @param array $systemConfig
* @return array
* @throws \Exception
*/
private function iterateSystemConfig(array $systemConfig): array
{
foreach ($systemConfig as $key => &$value) {
if (is_array($value)) {
$value = $this->iterateSystemConfig($value);
} elseif (is_string($value) && preg_match('/^\d+:\d+:.*$/', $value)) {
$decryptedValue = $this->encryptor->decrypt($value);
if ($decryptedValue) {
$value = $this->encryptor->encrypt($decryptedValue);
}
}
}

return $systemConfig;
}
}
14 changes: 14 additions & 0 deletions dev/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ err_report() {
echo "Error on line $1"
echo "last test.txt was"
cat test.txt
echo "last app/etc/env.php was"
cat app/etc/env.php
}
trap 'err_report $LINENO' ERR

Expand All @@ -20,6 +22,10 @@ vendor/bin/n98-magerun2 --version
vendor/bin/n98-magerun2 admin:user:create --no-interaction --admin-user "$ADMIN" --admin-email "example$CURRENT_TIMESTAMP@example.com" --admin-password $PASSWORD --admin-firstname adminuser --admin-lastname adminuser
vendor/bin/n98-magerun2 config:store:set zzzzz/zzzzz/zzzz xyz123 --encrypt

echo "Spoofing an encrypted config value into env.php"
ENCRYPTED_ENV_VALUE=$(vendor/bin/n98-magerun2 dev:encrypt 'Some Base Name')
bin/magento config:set --lock-env general/store_information/name "$ENCRYPTED_ENV_VALUE"

ADMIN_ID=$(vendor/bin/n98-magerun2 db:query "SELECT user_id FROM admin_user LIMIT 1")
ADMIN_ID="${ADMIN_ID: -1}"
FAKE_GOOGLE_TOKEN=$(vendor/bin/n98-magerun2 dev:encrypt 'googletokenabc123')
Expand All @@ -29,6 +35,7 @@ echo "Generating 2FA data for admin user $ADMIN in tfa_user_config"
vendor/bin/n98-magerun2 db:query "delete from tfa_user_config where user_id=$ADMIN_ID";
vendor/bin/n98-magerun2 db:query "insert into tfa_user_config(user_id, encoded_config) values ($ADMIN_ID, '$TWOFA_JSON_ENCRYPTED');"
vendor/bin/n98-magerun2 db:query "select user_id, encoded_config from tfa_user_config where user_id=$ADMIN_ID";

FAKE_RP_TOKEN=$(vendor/bin/n98-magerun2 dev:encrypt 'abc123')
vendor/bin/n98-magerun2 db:query "update admin_user set rp_token='$FAKE_RP_TOKEN' where username='$ADMIN'"
echo "Generated FAKE_RP_TOKEN=$FAKE_RP_TOKEN and assigned to $ADMIN"
Expand Down Expand Up @@ -90,7 +97,12 @@ fi
echo "";echo "";

echo "Generating a new encryption key"
grep -q "$ENCRYPTED_ENV_VALUE" app/etc/env.php
php bin/magento gene:encryption-key-manager:generate --force > test.txt
if grep -q "$ENCRYPTED_ENV_VALUE" app/etc/env.php; then
echo "FAIL: The old encrypted value in env.php was not updated" && false
fi
grep "'name'" app/etc/env.php | grep -q "1:3:"
grep -q '_reEncryptSystemConfigurationValues - start' test.txt
grep -q '_reEncryptSystemConfigurationValues - end' test.txt
grep -q '_reEncryptCreditCardNumbers - start' test.txt
Expand All @@ -100,6 +112,7 @@ echo "";echo "";

echo "Generating a new encryption key - skipping _reEncryptCreditCardNumbers"
php bin/magento gene:encryption-key-manager:generate --force --skip-saved-credit-cards > test.txt
grep "'name'" app/etc/env.php | grep -q "2:3:"
grep -q '_reEncryptSystemConfigurationValues - start' test.txt
grep -q '_reEncryptSystemConfigurationValues - end' test.txt
grep -q '_reEncryptCreditCardNumbers - skipping' test.txt
Expand Down Expand Up @@ -234,6 +247,7 @@ echo "A peek at an example log"
grep 'gene encryption manager' var/log/system.log | tail -1

echo "A peek at the env.php"
grep "'name'" app/etc/env.php
grep -A10 "'crypt' =>" app/etc/env.php
echo "";echo "";
echo "DONE"

0 comments on commit 5c0e6b6

Please sign in to comment.