Skip to main content

Azure Key Vault Provider

Summary​

Use Azure Key Vault as a provider behind the Secrets Platform (VaultService). Callers use canonical URIs; the platform enforces policy via PDP, adds tracing/metrics, and publishes audit events. This page is production‑ready guidance for admins and developers.

  • Provider: azure
  • Purpose: Retrieve and manage app secrets stored in Azure Key Vault (KV)
  • Highlights:
    • Canonical URI parsing (fragments, versions)
    • Retries, circuit‑breaker, and timeouts
    • OpenTelemetry traces and Prometheus metrics
    • Kafka audit events on delete
    • Metadata helpers (tags) and version discovery

Architecture​

Canonical URI​

  • Scheme: azure://
  • Mount: vault
  • Path: free‑form name (supports slashes for logical grouping)
  • Fragment: optional key selector for JSON payloads
  • Query: optional version string (Azure version ID)

Examples:

  • Full secret dict: azure://vault/app/db
  • Single field: azure://vault/app/db#username
  • Versioned read: azure://vault/app/db#username?version=v1

Behavior:

  • JSON values return a parsed dict; with a fragment, returns {fragment: value}
  • Scalar values return {value: "<scalar>"}; with a fragment, returns {fragment: None}
  • Versions are strings and map to Azure version IDs

API surface (normalized)​

  • get_credentials(ref: str) -> dict
    • Accepts canonical URIs or raw names; applies retries, circuit‑breaker, and timeouts
  • create_credentials(name: str, data: dict) -> dict
    • Stores JSON‑serialized value; creates a new version
  • update_credentials(name: str, data: dict) -> dict
    • Requires existence; creates a new version
  • delete_credentials(name: str) -> bool
    • Soft‑deletes (per KV settings) and emits Kafka audit event
  • list_credentials() -> list[str]
    • All secret names
  • list_keys(path: str) -> list[str]
    • Prefix filter using slash‑separated names
  • read_secret_metadata(name: str) -> dict
    • Returns current version, versions (timestamps/enabled), and custom_metadata (tags)
  • update_custom_metadata(name: str, custom: dict, merge=True) -> None
    • Maps to KV tags (merge or replace)
  • get_latest_version(name: str) -> Optional[str>

Sequence: get_credentials​

Security & authorization​

  • Enforce PDP checks in front of the provider (ENABLE_AUTHORIZATION=true)
  • Require auth on /api/secrets/* (SECRETS_API_REQUIRE_AUTH=true)
  • Scope enforcement recommended (SECRETS_ENFORCE_SCOPES=true)
  • Tenant guard: TENANT_ID, TENANT_ALLOWED_MOUNTS restrict accessible mounts/paths
  • Sender binding: prefer DPoP or mTLS for grant usage

Observability & audit​

  • Tracing: spans per operation (e.g., azure.get_secret, azure.create_secret, azure.update_secret, azure.delete_secret, azure.list_secrets, azure.read_secret_metadata, azure.update_custom_metadata) with attributes secret.name, secret.version (or latest)
  • Metrics: emitted via OTEL exporters → Prometheus
  • Auditing: on delete, emits EventType.SECRET_VERSION_DELETED via CrudKafkaProducer
    • credential_id: azure://vault/<name>
    • resource_ref: HMAC‑masked when TENANT_SALT or SECRET_TENANT_SALT is set

Configuration​

Required:

  • vault_url: https://<vault-name>.vault.azure.net/

Optional:

  • managed_identity_client_id: prefer Managed Identity when present
  • timeout_s (default 30), max_retries (default 3)
  • cb_failure_threshold (default 5), cb_reset_timeout_s (default 30)

Configuration should be supplied via service env/compose; avoid per‑app .env files.

Error semantics (normalized)​

  • VaultSecretNotFoundError: secret or version not found
  • VaultAuthenticationError: permission/auth failures (future mapping)
  • VaultTimeoutError: circuit breaker open or timeout
  • VaultOperationError: generic provider errors

Quick usage​

Fetch a JSON field:

creds = await strategy.get_credentials("azure://vault/app/db#username")

Update tags/metadata:

await strategy.update_custom_metadata("app/db", {"owner": "payments"}, merge=True)

Delete and emit audit:

await strategy.delete_credentials("app/db")

Notes & limitations​

  • Azure Key Vault does not support response wrapping; helpers in this provider are dev‑only stubs for parity with other providers
  • Hierarchical listing is emulated via prefix matching on slash‑separated names
  • Platform overview: ../index.md
  • Authorization model (PDP): ../11-authorization-model-authzen.md
  • Observability: ../06-observability.md
  • Admin how‑to: ../07-admin-howto.md
  • API reference: ../reference/secrets-api.md I'll embed two Mermaid diagrams: an architecture overview and a get_credentials sequence. Then I'll provide the detailed documentation text. Ran tool Ran tool

Azure Key Vault Strategy​

This document describes how to use the Azure Key Vault strategy in VaultService, including canonical URI syntax, supported operations, error semantics, observability, and audit behavior.

Overview​

  • Provider: azure
  • Purpose: Retrieve and manage application secrets stored in Azure Key Vault
  • Key features:
    • Canonical URI parsing with fragments and version selection
    • Retries, circuit breaker, and request timeouts
    • OpenTelemetry tracing
    • Kafka audit events on delete
    • Metadata helpers (tags) and version discovery

Architecture​

[Mermaid] Architecture overview:

Canonical URI​

  • Scheme: azure://
  • Mount: vault
  • Path: free-form name (supports slashes for logical grouping)
  • Fragment: optional key selector for JSON payloads
  • Query: optional version string

Examples:

  • Full secret dict: azure://vault/app/db
  • Single field: azure://vault/app/db#username
  • Versioned read: azure://vault/app/db#username?version=v1

Behavior:

  • If secret value is JSON, returns parsed dict. With a fragment, returns {fragment: value}.
  • If secret value is a scalar and a fragment is requested, returns {fragment: None}.
  • Versions are treated as strings (Azure version IDs).

API Surface​

  • get_credentials(ref: str) -> dict
    • Accepts canonical URIs or raw secret names
    • Uses retries, circuit breaker, timeouts
  • create_credentials(name: str, data: dict) -> dict
    • Stores JSON-serialized value; creates a new version
  • update_credentials(name: str, data: dict) -> dict
    • Validates existence; creates a new version
  • delete_credentials(name: str) -> bool
    • Soft-deletes the secret (per Key Vault settings) and emits a Kafka audit event
  • list_credentials() -> list[str]
    • Returns all secret names
  • list_keys(path: str) -> list[str]
    • Prefix filter using slash-separated names
  • read_secret_metadata(name: str) -> dict
    • Returns current version, versions list (with timestamps and enablement), and custom_metadata (tags)
  • update_custom_metadata(name: str, custom: dict, merge=True) -> None
    • Maps to Key Vault tags (merge or replace)
  • get_latest_version(name: str) -> Optional[str]
  • get_credentials_wrapped(ref: str, wrap_ttl: str) -> dict
    • Dev-friendly stub returning a wrap token
  • unwrap_token(wrap_token: str) -> dict
    • Dev-friendly stub with a success payload

Error Semantics​

  • VaultSecretNotFoundError: secret or version not found
  • VaultAuthenticationError: permission/auth failures (future mapping)
  • VaultTimeoutError: circuit breaker open or timeout
  • VaultOperationError: generic provider errors

All errors are normalized for consistent handling across providers.

Observability​

  • Tracing: Spans per operation with attributes:
    • azure.get_secret, azure.create_secret, azure.update_secret, azure.delete_secret, azure.list_secrets, azure.read_secret_metadata, azure.update_custom_metadata
    • Attributes: secret.name, secret.version (or “latest”)
  • Metrics: leverage OpenTelemetry exporters configured globally

Auditing​

  • On delete: emits EventType.SECRET_VERSION_DELETED to Kafka via CrudKafkaProducer
    • credential_id: azure://vault/<name>
    • resource_ref: hashed reference when TENANT_SALT or SECRET_TENANT_SALT is set

Sequence for get_credentials​

[Mermaid] Sequence diagram:

Configuration​

  • Required:
    • vault_url: https://<vault-name>.vault.azure.net/
  • Optional:
    • managed_identity_client_id: use Managed Identity when present
    • timeout_s (default 30), max_retries (default 3)
    • cb_failure_threshold (default 5), cb_reset_timeout_s (default 30)

Configuration is provided via service environment/compose. Avoid per-app .env files.

Return Shapes​

  • JSON secrets: returns dict; with fragment → {fragment: value}
  • Scalar secrets: returns {value: "<scalar>"}; with fragment → {fragment: None}

Notes and Limitations​

  • Response wrapping is not natively supported by Azure Key Vault; provided helpers are dev stubs for caller parity.
  • Hierarchical listing is emulated via prefix matching on slash-separated secret names.

Quick Usage​

  • Fetch JSON field:
creds = await strategy.get_credentials("azure://vault/app/db#username")
  • Update metadata/tags:
await strategy.update_custom_metadata("app/db", {"owner": "payments"}, merge=True)
  • Delete and audit:
await strategy.delete_credentials("app/db")