Skip to content

Vault providers — HashiCorp, Azure, AWS, GCP

All four expose the same three abstractions (ITransitEncryptionService, ISecretStore, IDatabaseCredentialProvider). Pick based on where the rest of your infrastructure lives:

| | HashiCorp | Azure Key Vault | AWS | GCP | | - | :-: | :-: | :-: | :-: | | Package | Granit.Vault.HashiCorp | Granit.Vault.Azure | Granit.Vault.Aws | Granit.Vault.GoogleCloud | | Encryption backend | Transit engine | RSA-OAEP-256 | KMS | Cloud KMS (AES-256-GCM) | | Native MAC (ITransitMacService) | Transit HMAC | Managed HSM HS256 (premium) | KMS HMAC_256 | Cloud KMS HMAC_SHA256 | | MAC key versioning | min_decryption_version | enabled-version | Current/Previous alias | enabled-version | | Ciphertext carries version | ✅ vault:v{N}:… | ❌ opaque | ❌ opaque | ❌ opaque | | Server-side rewrap | ✅ /transit/rewrap | ❌ (decrypt+encrypt) | ❌ (decrypt+encrypt) | ❌ (decrypt+encrypt) | | Secrets engine for ISecretStore | KV v2 | Secret | Secrets Manager | Secret Manager | | Native binary payload | via __binary convention | via application/octet-stream | ✅ SecretBinary | ✅ ByteString | | Dynamic DB creds | ✅ lease-aware | via secret polling | via secret polling | via secret polling | | Auth for production | Kubernetes JWT | Managed Identity | IAM role | Workload Identity |

All four modules auto-disable in Development — you don’t need a running vault locally.

[DependsOn(typeof(GranitVaultHashiCorpModule))]
public class AppModule : GranitModule { }
{
"Vault": {
"Address": "https://vault.example.com",
"AuthMethod": "Kubernetes",
"KubernetesRole": "my-backend"
}
}

Uses the Kubernetes service account token mounted at /var/run/secrets/kubernetes.io/serviceaccount/token.

{
"Vault": {
"Address": "https://vault.example.com",
"AuthMethod": "Kubernetes",
"KubernetesRole": "my-backend",
"KubernetesTokenPath": "/var/run/secrets/kubernetes.io/serviceaccount/token",
"DatabaseMountPoint": "database",
"DatabaseRoleName": "readwrite",
"TransitMountPoint": "transit",
"KvMountPoint": "secret",
"LeaseRenewalThreshold": 0.75,
"SecretStore": {
"CacheSeconds": 0,
"HealthCheckSecretName": "healthcheck/probe"
}
}
}

| Property | Default | Description | | -------- | ------- | ----------- | | Address | — | Vault server URL | | AuthMethod | "Kubernetes" | "Kubernetes" or "Token" | | KubernetesRole | "my-backend" | Vault Kubernetes auth role | | DatabaseMountPoint | "database" | Database secrets engine mount | | DatabaseRoleName | "readwrite" | Database role for dynamic credentials | | TransitMountPoint | "transit" | Transit secrets engine mount | | KvMountPoint | "secret" | KV v2 secrets engine mount (used by ISecretStore) | | LeaseRenewalThreshold | 0.75 | Renew lease at this fraction of TTL |

The HashiCorp provider implements ITransitMacService via transit/hmac + transit/verify (SHA-256), with native rolling rotation through min_decryption_version. Provision the key with auto-rotation:

Terminal window
vault write -f transit/keys/granit-privacy-export-fragment-hmac \
type=hmac \
auto_rotate_period=2160h # 90 days, ISO 27001 A.10.1.2

App policy needs update on transit/hmac/<key> and transit/verify/<key>.

builder.Services.AddHealthChecks()
.AddGranitVaultHashiCorpHealthCheck() // Vault sys/health probe
.AddGranitSecretStoreHealthCheck(); // ISecretStore canary

The first check verifies Vault connectivity and authentication. The second (shared across all four providers) reads Vault:SecretStore:HealthCheckSecretName through ISecretStore — see Secret retrieval → Liveness probe.

[DependsOn(typeof(GranitVaultAzureModule))]
public class AppModule : GranitModule { }

Uses DefaultAzureCredential — Managed Identity in AKS, az login locally. No credentials in configuration.

{
"Vault": {
"Azure": {
"VaultUri": "https://my-vault.vault.azure.net/"
}
}
}
{
"Vault": {
"Azure": {
"VaultUri": "https://my-vault.vault.azure.net/",
"EncryptionKeyName": "string-encryption",
"EncryptionAlgorithm": "RSA-OAEP-256",
"DatabaseSecretName": "db-credentials",
"RotationCheckIntervalMinutes": 5,
"TimeoutSeconds": 30
},
"SecretStore": {
"CacheSeconds": 0,
"HealthCheckSecretName": "healthcheck/probe"
}
}
}

| Property | Default | Description | | -------- | ------- | ----------- | | Vault:Azure:VaultUri | — | Azure Key Vault URI (required) | | Vault:Azure:EncryptionKeyName | "string-encryption" | Key name for encrypt/decrypt | | Vault:Azure:EncryptionAlgorithm | "RSA-OAEP-256" | "RSA-OAEP-256" or "RSA-OAEP" | | Vault:Azure:DatabaseSecretName | null | Secret name for DB credentials (omit to disable) | | Vault:Azure:RotationCheckIntervalMinutes | 5 | DB secret rotation polling interval | | Vault:Azure:TimeoutSeconds | 30 | Azure SDK operation timeout |

Azure splits by tier. Managed HSM (premium) exposes a native HS256 primitive on an oct-HSM key:

services.AddGranitVaultAzureManagedHsmMac();
{
"Vault": { "Azure": { "ManagedHsm": { "Mac": {
"HsmUri": "https://my-hsm.managedhsm.azure.net/",
"KeyName": "granit-privacy-export-mac"
}}}}
}

Azure Key Vault Standard tier has no HMAC primitive — register the portable SecretBackedMacService from Granit.Vault instead (the key material is stored in a Key Vault secret and HMAC runs locally — a documented trust-boundary trade-off).

builder.Services.AddHealthChecks()
.AddGranitAzureKeyVaultHealthCheck() // GetKey probe on EncryptionKeyName
.AddGranitSecretStoreHealthCheck(); // ISecretStore canary
[DependsOn(typeof(GranitVaultAwsModule))]
public class AppModule : GranitModule { }

When AccessKeyId / SecretAccessKey are null (recommended), the AWS SDK uses its default credential chain — IAM role on ECS/EKS, environment variables, EC2 instance profile, or shared credentials file (local dev only).

{
"Vault": {
"Aws": {
"Region": "eu-west-1",
"KmsKeyId": "alias/granit-encryption"
}
}
}

Set AccessKeyId / SecretAccessKey explicitly only for local dev against LocalStack or when the credential chain can’t find usable credentials.

{
"Vault": {
"Aws": {
"Region": "eu-west-1",
"KmsKeyId": "alias/granit-encryption",
"DatabaseSecretArn": "arn:aws:secretsmanager:eu-west-1:123…:secret:db-credentials",
"RotationCheckIntervalMinutes": 5,
"AccessKeyId": null,
"SecretAccessKey": null,
"TimeoutSeconds": 30
},
"SecretStore": {
"CacheSeconds": 0,
"HealthCheckSecretName": "healthcheck/probe"
}
}
}

| Property | Default | Description | | -------- | ------- | ----------- | | Vault:Aws:Region | — | AWS region endpoint (required) | | Vault:Aws:KmsKeyId | — | KMS key ARN or alias for transit encryption (required) | | Vault:Aws:DatabaseSecretArn | null | Secrets Manager ARN for DB credentials (omit to disable) | | Vault:Aws:RotationCheckIntervalMinutes | 5 | DB secret rotation polling interval | | Vault:Aws:AccessKeyId | null | Override; defaults to SDK credential chain | | Vault:Aws:SecretAccessKey | null | Override; defaults to SDK credential chain | | Vault:Aws:TimeoutSeconds | 30 | API call timeout |

AWS KMS implements ITransitMacService via GenerateMac / VerifyMac on HMAC_256 keys. KMS does not version an HMAC key in place, so rolling rotation uses a Current + Previous alias pair:

{
"Vault": { "Aws": { "Mac": {
"CurrentAlias": "alias/granit/privacy-export-mac-current",
"PreviousAlias": "alias/granit/privacy-export-mac-previous" // optional but recommended
}}}
}

Rotation runbook: provision a new HMAC_256 key, point PreviousAlias at the outgoing key, then CurrentAlias at the new one. Verify keeps accepting the previous tag throughout the grace window — both VerifyMac calls are always issued (constant-time fallback) to defeat timing oracles.

builder.Services.AddHealthChecks()
.AddGranitKmsHealthCheck() // DescribeKey on KmsKeyId
.AddGranitSecretStoreHealthCheck(); // ISecretStore canary
[DependsOn(typeof(GranitVaultGoogleCloudModule))]
public class AppModule : GranitModule { }

Uses Application Default Credentials — Workload Identity in GKE, gcloud auth application-default login locally. Override only for a service account JSON file.

{
"Vault": {
"GoogleCloud": {
"ProjectId": "my-project",
"Location": "europe-west1",
"KeyRing": "my-keyring",
"CryptoKey": "string-encryption"
}
}
}
{
"Vault": {
"GoogleCloud": {
"ProjectId": "my-project",
"Location": "europe-west1",
"KeyRing": "my-keyring",
"CryptoKey": "string-encryption",
"DatabaseSecretName": "db-credentials",
"RotationCheckIntervalMinutes": 5,
"CredentialFilePath": null,
"TimeoutSeconds": 30
},
"SecretStore": {
"CacheSeconds": 0,
"HealthCheckSecretName": "healthcheck/probe"
}
}
}

| Property | Default | Description | | -------- | ------- | ----------- | | Vault:GoogleCloud:ProjectId | — | GCP project id (required) | | Vault:GoogleCloud:Location | — | Cloud KMS location, e.g. "europe-west1" (required) | | Vault:GoogleCloud:KeyRing | — | Cloud KMS key ring name (required) | | Vault:GoogleCloud:CryptoKey | — | Cloud KMS crypto key for transit encryption (required) | | Vault:GoogleCloud:DatabaseSecretName | null | Secret Manager secret name for DB credentials (omit to disable) | | Vault:GoogleCloud:RotationCheckIntervalMinutes | 5 | DB secret rotation polling interval | | Vault:GoogleCloud:CredentialFilePath | null | Service account key JSON; ADC when null | | Vault:GoogleCloud:TimeoutSeconds | 30 | API call timeout |

Google Cloud implements ITransitMacService via MacSign / MacVerify on a CryptoKey with purpose=MAC, algorithm=HMAC_SHA256. It is version-state aware — verification against DISABLED / DESTROYED versions is refused.

{
"Vault": { "GoogleCloud": {
"Mac": { "CryptoKeyId": "granit-privacy-export-mac" }
}}
}

Provision the CryptoKey via Terraform with purpose = "MAC", algorithm = "HMAC_SHA256", and rotation_period = "7776000s" (90 days, ISO 27001 A.10.1.2).

builder.Services.AddHealthChecks()
.AddGranitCloudKmsHealthCheck() // Verifies KMS key accessibility
.AddGranitSecretStoreHealthCheck(); // ISecretStore canary

| Category | Types | Package | | -------- | ----- | ------- | | Modules | GranitEncryptionModule, GranitVaultHashiCorpModule, GranitVaultAzureModule, GranitVaultAwsModule, GranitVaultGoogleCloudModule | — | | Encryption | IStringEncryptionService, IStringEncryptionProvider, AesStringEncryptionProvider | Granit.Encryption | | Transit | ITransitEncryptionService, ReEncryptionOptions, RetiredKeyVersionException | Granit.Vault | | MAC | ITransitMacService, TransitMacResult, SecretBackedMacService, SecretBackedMacOptions | Granit.Vault | | Secrets | ISecretStore, SecretRequest, SecretVersion, SecretDescriptor, SecretMetadata, SecretStoreOptions, SecretVaultException + subclasses | Granit.Vault | | Credentials | IDatabaseCredentialProvider | Granit.Vault | | Observability | VaultMetrics, SecretStoreActivityTags | Granit.Vault | | Health checks | SecretStoreHealthCheck, VaultHealthCheck, AzureKeyVaultHealthCheck, KmsHealthCheck, CloudKmsHealthCheck | per-provider | | Extensions | AddGranitEncryption(), AddGranitVaultHashiCorp(), AddGranitVaultAzure(), AddGranitVaultAws(), AddGranitVaultGoogleCloud(), AddGranitVaultAzureManagedHsmMac(), AddGranitSecretBackedMacService(), AddGranitSecretStore<T>(), AddGranitSecretStoreHealthCheck() | — |