Cloud credentials
How AlphaSwarm routes secret resolution through CredentialResolver once the
cloud SecretStore siblings are wired. Phase C of the Phase 7
rollout (Terraform IaC + multi-cloud).
Resolver chain
Lower priority numbers resolve first. The cloud store is added to the
default chain only when ALPHASWARM_DEFAULT_CLOUD_PROVIDER matches and the
matching SDK is installed (see
alphaswarm/credentials/resolver.py::_build_default_resolver).
Naming conventions
| Store | Key format | Notes |
|---|---|---|
| Env | <SERVICE>_<PURPOSE> (uppercase, : → _) | Always-on safety net. |
| File | bootstrap_state_dir/<service>-<purpose>.json | Bootstrap workflows write these (Polaris principal, etc). |
| Azure Key Vault | alphaswarm-<service>-<purpose> (alphanumerics + - only) | Vault names disallow : / / / _. |
| AWS Secrets Mgr | {prefix}<service>/<purpose> (default prefix alphaswarm/) | Slashes are first-class path separators. |
| GCP Secret Mgr | projects/{project}/secrets/{prefix}<service>-<purpose> | Names allow [A-Za-z0-9_-] only — joins use -. |
| Vault KV v2 | <mount>/data/<service>/<purpose> | hvac.Client.secrets.kv.v2.read_secret_version adds /data/ automatically. |
The cloud secret values are parsed as JSON first; when parsing fails
they're exposed via the canonical credential field.
Example secret layouts
Azure Key Vault — alphaswarm-msal-clientsecret
{
"client_secret": "rxq8Q..."
}
AWS Secrets Manager — alphaswarm/broker/api_key
sk_live_abcdef1234567890
Plain string payload — exposed via credential.get("credential").
GCP Secret Manager — alphaswarm-postgres-password
{
"password": "...",
"username": "alphaswarm"
}
HashiCorp Vault KV v2 — secret/data/alphaswarm/redis/password
{
"password": "..."
}
Wiring a SecretStore
Pick a cloud + install the matching extra:
pip install 'alphaswarm[cloud-azure]' # AzureKeyVaultStore
pip install 'alphaswarm[cloud-aws]' # AwsSecretsManagerStore
pip install 'alphaswarm[cloud-gcp]' # GcpSecretManagerStore
pip install 'alphaswarm[vault]' # HashicorpVaultStore
Configure (matching cloud picked via ALPHASWARM_DEFAULT_CLOUD_PROVIDER):
# Azure
ALPHASWARM_DEFAULT_CLOUD_PROVIDER=azure
ALPHASWARM_AZURE_TENANT_ID=...
ALPHASWARM_AZURE_SUBSCRIPTION_ID=...
ALPHASWARM_AZURE_KEYVAULT_URL=https://alphaswarm-vault.vault.azure.net/
# AWS
ALPHASWARM_DEFAULT_CLOUD_PROVIDER=aws
ALPHASWARM_AWS_REGION=us-east-1
ALPHASWARM_AWS_ACCOUNT_ID=123456789012
ALPHASWARM_AWS_SECRETSMANAGER_PREFIX=alphaswarm/
# GCP
ALPHASWARM_DEFAULT_CLOUD_PROVIDER=gcp
ALPHASWARM_GCP_PROJECT_ID=alphaswarm-prod
ALPHASWARM_GCP_REGION=us-central1
ALPHASWARM_GCP_SECRET_PREFIX=alphaswarm-
# Vault (any cloud)
ALPHASWARM_VAULT_ADDR=https://vault.example.com
ALPHASWARM_VAULT_NAMESPACE=...
ALPHASWARM_VAULT_MOUNT=secret
ALPHASWARM_VAULT_ROLE_ID=...
ALPHASWARM_VAULT_SECRET_ID=...
The resolver auto-adds the matching cloud store + Vault store when the env vars are present. Code that needs a credential does:
from alphaswarm.credentials import get_resolver
from alphaswarm.credentials.protocol import CredentialKey
resolver = get_resolver()
cred = resolver.resolve(CredentialKey(service="msal", purpose="client_secret"))
secret = cred.require("client_secret")
Authentication backends per cloud store
| Store | Identity source |
|---|---|
| Azure Key Vault | DefaultAzureCredential (az login / SP env / Workload Identity) |
| AWS Secrets Manager | boto3 default chain (env / shared credentials / IRSA / EC2 role) |
| GCP Secret Manager | google.auth.default() (gcloud ADC / SA file / Workload Identity) |
| HashiCorp Vault | AppRole (preferred) or whatever the operator pre-configured |
For cluster-side workloads the Workload Identity variants are the canonical path:
- AKS —
AzureAksAdapter+ Azure Workload Identity (Service Account annotationazure.workload.identity/client-id: <managed-identity>). - EKS —
AwsEksAdapter+ IRSA (eks.amazonaws.com/role-arnannotation). - GKE —
GcpGkeAdapter+ GKE Workload Identity (iam.gke.io/gcp-service-accountannotation).
External Secrets Operator integration
The Terraform secrets module wires an
external-secrets ClusterSecretStore
pointing at whichever backend matches vault_backend. The
secret_mappings locals block emits one ExternalSecret per
(k8s_secret_name, vault_path) pair so AlphaSwarm pods consume secrets via
mounted Secrets — never raw env vars.
See alphaswarm_platform/terraform/modules/secrets/main.tf
for the full mapping table.
Temporary credentials minted via cloud CLI
Operators with an admin:cluster scope can mint short-lived
credentials directly from the admin UI without shipping the cloud
CLI binaries into the BFF container. The control plane wraps
aws sts assume-role / gcloud auth print-access-token /
az account get-access-token in an audit-first subprocess runner;
the resulting credential is persisted under a resolver key supplied
by the operator and surfaces through the standard
CredentialResolver.resolve(...) chain. See the
cloud-CLI temporary credentials
runbook for the wizard walkthrough, audit shape, and step-up MFA
contract.