Passwordless Flexible Server via Azure Workload Identity
Demonstrates fully passwordless authentication to Azure Database for PostgreSQL Flexible Server using Azure Workload Identity and Microsoft Entra access tokens. No static passwords anywhere.
| Actor | Token mechanism |
|---|---|
| Temporal server pods | azure-token-refresher sidecar writes /azure/pgpass; Temporal reads it via passwordCommand on every connection |
| Schema Job | one-shot initContainer writes /azure/pgpass; schema container reads it via passwordCommand |
| Operator (probe + schema inspection) | obtains an Entra token natively in-process via the Go Azure Workload Identity SDK — no sidecar, no shell required on the distroless image |
This resolved #47.
How it works
The operator generates all the Azure Workload Identity wiring (ServiceAccount,
sidecars, initContainers, passwordCommand, inspector Jobs) from a single
cluster-level persistence.azureWorkloadIdentity.clientId field. You provide the
managed identity’s client ID; the operator synthesizes the rest.
Prerequisites
- AKS with the OIDC issuer and Workload Identity enabled
(
az aks update --enable-oidc-issuer --enable-workload-identity). - A managed identity (or app registration) with a federated credential bound to
the operator-generated ServiceAccount
<cluster-name>-azurein the cluster’s namespace (e.g.,azure-wi-azurein namespacedefault). - The identity mapped to a Postgres role on the Flexible Server:
SELECT pgaadauth_create_principal('temporal-identity', false, false); - Microsoft Entra authentication enabled on the Flexible Server.
- The
azure.extensionsallow-list set tobtree_gin,pg_trgm(required by Temporal’s SQL visibility schema).
Apply
kubectl apply -f temporalcluster.yamlThe operator creates the ServiceAccount (<cluster-name>-azure) and wires the
server pods, schema Jobs, and its own probe/schema-inspection Jobs. Ensure your
managed identity’s federated credential is bound to this generated ServiceAccount
before applying.
Manifests
temporalcluster.yaml
# Passwordless Flexible Server auth via Azure Workload Identity.
# The operator generates ALL the wiring (ServiceAccount, sidecars,
# initContainers, passwordCommand, inspector Jobs) from a single
# `persistence.azureWorkloadIdentity.clientId` field.
apiVersion: temporal.bmor10.com/v1alpha1
kind: TemporalCluster
metadata:
name: azure-wi
spec:
version: "1.31.1"
numHistoryShards: 512
ui:
enabled: true
persistence:
azureWorkloadIdentity:
clientId: REPLACE_WITH_MANAGED_IDENTITY_CLIENT_ID
defaultStore:
sql:
pluginName: postgres12
host: REPLACE_ME.postgres.database.azure.com
port: 5432
database: temporal
# The Postgres role created for the managed identity via
# pgaadauth_create_principal (usually the identity's display name).
user: temporal-identity
tls: { enabled: true }
visibilityStore:
sql:
pluginName: postgres12
host: REPLACE_ME.postgres.database.azure.com
port: 5432
database: temporal_visibility
user: temporal-identity
tls: { enabled: true }