Skip to content

Commit

Permalink
Merge pull request #51 from keboola/roman-pst-2407-extra-akv-client
Browse files Browse the repository at this point in the history
PST-2407: Add extra AKV client
  • Loading branch information
romantmb authored Feb 10, 2025
2 parents faf6f55 + d421583 commit 3b6724a
Show file tree
Hide file tree
Showing 14 changed files with 1,071 additions and 12 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"aws/aws-sdk-php": "^3.209",
"defuse/php-encryption": "^2.3",
"google/cloud-kms": "^1.20",
"keboola/azure-key-vault-client": "^3.0",
"keboola/azure-key-vault-client": "^4.0",
"keboola/common-exceptions": "^1.2",
"vkartaviy/retry": "^0.2"
},
Expand Down
14 changes: 14 additions & 0 deletions src/EncryptorOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class EncryptorOptions
private ?string $kmsRole;
private int $backoffMaxTries;

/** @var non-empty-string|null */
private ?string $encryptorId;

/**
* @param non-empty-string $stackId
* @param non-empty-string|null $kmsKeyId
Expand All @@ -32,6 +35,7 @@ class EncryptorOptions
* @param non-empty-string|null $akvUrl
* @param non-empty-string|null $gkmsKeyId
* @param int|null $backoffMaxTries
* @param non-empty-string|null $encryptorId
*/
public function __construct(
string $stackId,
Expand All @@ -41,6 +45,7 @@ public function __construct(
?string $akvUrl = null,
?string $gkmsKeyId = null,
?int $backoffMaxTries = null,
?string $encryptorId = null,
) {
$this->stackId = $stackId;
$this->kmsKeyId = $kmsKeyId;
Expand All @@ -49,6 +54,7 @@ public function __construct(
$this->akvUrl = $akvUrl;
$this->gkmsKeyId = $gkmsKeyId;
$this->backoffMaxTries = $backoffMaxTries ?? self::DEFAULT_BACKOFF_MAX_TRIES;
$this->encryptorId = $encryptorId;
$this->validateState();
}

Expand Down Expand Up @@ -102,6 +108,14 @@ public function getBackoffMaxTries(): int
return $this->backoffMaxTries;
}

/**
* @return non-empty-string|null
*/
public function getEncryptorId(): ?string
{
return $this->encryptorId;
}

/**
* @throws ApplicationException
*/
Expand Down
11 changes: 10 additions & 1 deletion src/ObjectEncryptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
use Keboola\ObjectEncryptor\Wrapper\ProjectWideAKVWrapper;
use Keboola\ObjectEncryptor\Wrapper\ProjectWideGKMSWrapper;
use Keboola\ObjectEncryptor\Wrapper\ProjectWideKMSWrapper;
use Psr\Log\LoggerInterface;
use stdClass;
use Throwable;

Expand All @@ -47,7 +48,7 @@ class ObjectEncryptor
private ?KmsClient $kmsClient = null;
private ?KeyManagementServiceClient $gkmsClient = null;

public function __construct(EncryptorOptions $encryptorOptions)
public function __construct(EncryptorOptions $encryptorOptions, private readonly ?LoggerInterface $logger = null)
{
$this->encryptorOptions = $encryptorOptions;
}
Expand Down Expand Up @@ -622,36 +623,43 @@ private function getAKVWrappers(
): array {
$wrappers = [];
$wrapper = new GenericAKVWrapper($this->encryptorOptions);
$wrapper->logger = $this->logger;
$wrappers[] = $wrapper;
if ($this->encryptorOptions->getStackId()) {
if ($projectId) {
$wrapper = new ProjectWideAKVWrapper($this->encryptorOptions);
$wrapper->logger = $this->logger;
$wrapper->setProjectId($projectId);
$wrappers[] = $wrapper;
if ($branchType) {
$wrapper = new BranchTypeProjectWideAKVWrapper($this->encryptorOptions);
$wrapper->logger = $this->logger;
$wrapper->setProjectId($projectId);
$wrapper->setBranchType($branchType);
$wrappers[] = $wrapper;
}
}
if ($componentId) {
$wrapper = new ComponentAKVWrapper($this->encryptorOptions);
$wrapper->logger = $this->logger;
$wrapper->setComponentId($componentId);
$wrappers[] = $wrapper;
if ($projectId) {
$wrapper = new ProjectAKVWrapper($this->encryptorOptions);
$wrapper->logger = $this->logger;
$wrapper->setComponentId($componentId);
$wrapper->setProjectId($projectId);
$wrappers[] = $wrapper;
if ($configurationId) {
$wrapper = new ConfigurationAKVWrapper($this->encryptorOptions);
$wrapper->logger = $this->logger;
$wrapper->setComponentId($componentId);
$wrapper->setProjectId($projectId);
$wrapper->setConfigurationId($configurationId);
$wrappers[] = $wrapper;
if ($branchType) {
$wrapper = new BranchTypeConfigurationAKVWrapper($this->encryptorOptions);
$wrapper->logger = $this->logger;
$wrapper->setComponentId($componentId);
$wrapper->setProjectId($projectId);
$wrapper->setConfigurationId($configurationId);
Expand All @@ -661,6 +669,7 @@ private function getAKVWrappers(
}
if ($branchType) {
$wrapper = new BranchTypeProjectAKVWrapper($this->encryptorOptions);
$wrapper->logger = $this->logger;
$wrapper->setComponentId($componentId);
$wrapper->setProjectId($projectId);
$wrapper->setBranchType($branchType);
Expand Down
19 changes: 13 additions & 6 deletions src/ObjectEncryptorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace Keboola\ObjectEncryptor;

use Psr\Log\LoggerInterface;

class ObjectEncryptorFactory
{
/**
Expand All @@ -28,10 +30,13 @@ public static function getAwsEncryptor(
* @param non-empty-string $keyVaultUrl
* @return ObjectEncryptor
*/
public static function getAzureEncryptor(string $stackId, string $keyVaultUrl): ObjectEncryptor
{
public static function getAzureEncryptor(
string $stackId,
string $keyVaultUrl,
?LoggerInterface $logger = null,
): ObjectEncryptor {
$encryptOptions = new EncryptorOptions($stackId, null, null, null, $keyVaultUrl);
return self::getEncryptor($encryptOptions);
return self::getEncryptor($encryptOptions, $logger);
}

/**
Expand All @@ -45,8 +50,10 @@ public static function getGcpEncryptor(string $stackId, string $gkmsKeyId): Obje
return self::getEncryptor($encryptOptions);
}

public static function getEncryptor(EncryptorOptions $encryptorOptions): ObjectEncryptor
{
return new ObjectEncryptor($encryptorOptions);
public static function getEncryptor(
EncryptorOptions $encryptorOptions,
?LoggerInterface $logger = null,
): ObjectEncryptor {
return new ObjectEncryptor($encryptorOptions, $logger);
}
}
33 changes: 33 additions & 0 deletions src/Temporary/CallbackRetryPolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Keboola\ObjectEncryptor\Temporary;

use Closure;
use Retry\Policy\SimpleRetryPolicy;
use Retry\RetryContextInterface;

class CallbackRetryPolicy extends SimpleRetryPolicy
{
private Closure $shouldRetryCallback;

public function __construct(
callable $shouldRetryCallback,
int $maxAttempts = 3,
) {
parent::__construct($maxAttempts);
$this->shouldRetryCallback = $shouldRetryCallback(...);
}

public function canRetry(RetryContextInterface $context): bool
{
$e = $context->getLastException();

if (($this->shouldRetryCallback)($e, $context) !== true) {
return false;
}

return parent::canRetry($context);
}
}
24 changes: 24 additions & 0 deletions src/Temporary/TransAuthenticatorFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Keboola\ObjectEncryptor\Temporary;

use Keboola\AzureKeyVaultClient\Authentication\AuthenticatorFactory;
use Keboola\AzureKeyVaultClient\Authentication\AuthenticatorInterface;
use Keboola\AzureKeyVaultClient\Exception\ClientException;
use Keboola\AzureKeyVaultClient\GuzzleClientFactory;

class TransAuthenticatorFactory extends AuthenticatorFactory
{
public function getAuthenticator(GuzzleClientFactory $clientFactory, string $resource): AuthenticatorInterface
{
$authenticator = new TransClientCredentialsEnvironmentAuthenticator($clientFactory, $resource);
try {
$authenticator->checkUsability();
return $authenticator;
} catch (ClientException) {
throw new TransClientNotAvailableException;
}
}
}
39 changes: 39 additions & 0 deletions src/Temporary/TransClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace Keboola\ObjectEncryptor\Temporary;

use Keboola\AzureKeyVaultClient\Client;
use Keboola\AzureKeyVaultClient\GuzzleClientFactory;

class TransClient extends Client
{
public function __construct(GuzzleClientFactory $clientFactory, ?string $encryptorId)
{
$vaultBaseUrl = (string) getenv(self::determinateVaultUrlEnvName($encryptorId));

if ($vaultBaseUrl === '') {
throw new TransClientNotAvailableException;
}

parent::__construct(
$clientFactory,
new TransAuthenticatorFactory(),
$vaultBaseUrl,
);
}

public static function determinateVaultUrlEnvName(?string $encryptorId): string
{
$transEnvName = 'TRANS_AZURE_KEY_VAULT_URL';

if (!empty($encryptorId)) { // not null or empty string
$suffix = (string) preg_replace('/[\s\-_]+/', '_', $encryptorId);
$suffix = trim($suffix, '_');
$transEnvName .= sprintf('_%s', strtoupper($suffix));
}

return $transEnvName;
}
}
14 changes: 14 additions & 0 deletions src/Temporary/TransClientCredentialsEnvironmentAuthenticator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Keboola\ObjectEncryptor\Temporary;

use Keboola\AzureKeyVaultClient\Authentication\ClientCredentialsEnvironmentAuthenticator;

class TransClientCredentialsEnvironmentAuthenticator extends ClientCredentialsEnvironmentAuthenticator
{
protected const ENV_AZURE_TENANT_ID = 'TRANS_AZURE_TENANT_ID';
protected const ENV_AZURE_CLIENT_ID = 'TRANS_AZURE_CLIENT_ID';
protected const ENV_AZURE_CLIENT_SECRET = 'TRANS_AZURE_CLIENT_SECRET';
}
11 changes: 11 additions & 0 deletions src/Temporary/TransClientNotAvailableException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Keboola\ObjectEncryptor\Temporary;

use Exception;

class TransClientNotAvailableException extends Exception
{
}
Loading

0 comments on commit 3b6724a

Please sign in to comment.