Search by

symfony / azure-keyvault-key-management

fabpot

Symfony Azure Key Vault Key Management Bridge

Package info

github.com/symfony/azure-keyvault-key-management

Homepage

Type:symfony-key-management-bridge

pkg:composer/symfony/azure-keyvault-key-management

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

8.2.x-dev 2026-10-05 03:23 UTC

This package is auto-updated.

Last update: 2026-10-05 05:59:14 UTC


README

Provides an implementation of Symfony\Component\KeyManagement\EncrypterInterface, Symfony\Component\KeyManagement\DecrypterInterface and Symfony\Component\KeyManagement\DataKeyGeneratorInterface backed by Azure Key Vault (and Managed HSM) over its REST API. Encryption, decryption and data-key wrapping never expose the master key: Azure performs them server-side.

This Bridge is experimental. Experimental features are not covered by Symfony's Backward Compatibility Promise.

use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\KeyManagement\Bridge\AzureKeyVault\AzureKeyVault;
use Symfony\Component\KeyManagement\Bridge\AzureKeyVault\ClientCredentialsTokenProvider;

$client = HttpClient::createForBaseUri('https://my-vault.vault.azure.net/');
$tokens = new ClientCredentialsTokenProvider(
    $client,
    $_SERVER['AZURE_TENANT_ID'],
    $_SERVER['AZURE_CLIENT_ID'],
    $_SERVER['AZURE_CLIENT_SECRET'],
);

$kms = new AzureKeyVault($client, $tokens);

// Use the key name for the latest version on writes, or append `/<version>` to select one.
$ciphertext = $kms->encrypt('app-key', 'hello world');
$plaintext  = $kms->decrypt($ciphertext);

$dataKey = $kms->generateDataKey('app-key', 32);
$result  = $dataKey->use(fn (string $dek): string => /* local AEAD encrypt */);

Each new ciphertext and wrapped data key records the key version it was produced under, and the bridge checks that Azure's response names the requested key. Keep older key versions enabled while their ciphertexts or wrapped data keys must remain readable.

Authentication

Bring your own TokenProviderInterface to plug any Azure AD flow: the bundled ClientCredentialsTokenProvider covers the client_credentials grant (tenant id + client id + client secret) and caches the token in memory until 60 seconds before its advertised expiration. Managed Identity, Workload Identity, federated credentials, on-behalf-of, ... are out of scope for the default provider; implement TokenProviderInterface for your authentication flow.

Custom token providers implement invalidateToken($token) to discard a cached token only when it matches the rejected value. If Key Vault responds with HTTP 401, the bridge obtains a new token and retries the request once if that token differs. HTTP 403 is reported directly without invalidating the token.

Algorithms

The bridge accepts two configurable algorithms:

  • encryptAlgorithm (default RSA-OAEP-256): used by encrypt()/decrypt(). RSA-OAEP, RSA1_5 and the AEAD variants A128GCM/A192GCM/A256GCM are also accepted (the AEAD variants require a symmetric key, available on Managed HSM or Key Vault Premium in preview).
  • wrapAlgorithm (default RSA-OAEP-256): used by generateDataKey() and unwrapDataKey(). Same algorithm set as above; with a symmetric key you can use A128KW / A192KW / A256KW by setting it explicitly.

The DSN factory only accepts the algorithm names Azure Key Vault documents (RSA-OAEP-256, RSA-OAEP, RSA1_5, the A*GCM, A*CBC, A*CBCPAD and A*KW families) so that a typo does not surface later as a decryption failure, which is how the decrypt path reports Azure's HTTP 400.

encrypt() / decrypt() go through the RSA path by default and are therefore suited to small payloads (config secrets, tokens). For arbitrary-size payloads, use Symfony\Component\KeyManagement\EnvelopeEncrypter on top of the bridge: the master key only sees the wrapped DEK.

DSN scheme

azure-keyvault://<clientId>:<clientSecret>@<vault-name>.vault.azure.net?tenant=<tenantId>[&algorithm=...&wrap_algorithm=...&api_version=...&audience=...]

The host is the full vault DNS (<name>.vault.azure.net, or <name>.managedhsm.azure.net for Managed HSM). The factory selects a Key Vault or Managed HSM audience from the host, which audience can override, and it always authenticates against the public Microsoft Entra authority. A sovereign cloud (US government, China) needs another authority, so construct AzureKeyVault there manually with a token provider configured for that cloud. Examples:

azure-keyvault://CLIENT_ID:CLIENT_SECRET@my-vault.vault.azure.net?tenant=TENANT_ID
azure-keyvault://CLIENT_ID:CLIENT_SECRET@my-vault.vault.azure.net?tenant=TENANT_ID&algorithm=RSA-OAEP&api_version=7.4
azure-keyvault://CLIENT_ID:CLIENT_SECRET@my-hsm.managedhsm.azure.net?tenant=TENANT_ID&algorithm=A256GCM&wrap_algorithm=A256KW

AAD support

AEAD algorithms (A128GCM/A192GCM/A256GCM) accept Azure's aad parameter natively and are integrity-protected. RSA algorithms have no AAD concept; passing a non-empty $aad to an RSA-configured bridge raises UnsupportedOperationException.

For AEAD ciphertexts, this bridge concatenates the algorithm, IV, tag and value into a single dot-separated blob (<alg>.<iv>.<tag>.<value>, all base64url) so callers can store one opaque ciphertext and let the bridge recover its parts on decrypt. The pieces themselves are exactly what Azure returns; nothing is added to or stripped from them.

Resources