Cloud-CLI temporary credentials
How to use the CloudCliCredentialWizard in the admin Settings page to mint a short-lived AWS / GCP / Azure credential without shipping the parent credential or the cloud CLI binary into the admin BFF container.
Topology
The CLI subprocess only runs inside alphaswarm_controller. The
admin BFF (alphaswarm_admin) is HTTP-only per its boundary contract; it
never spawns processes or holds the parent credential.
Prerequisites
The control plane host needs the CLI binary on $PATH:
| Provider | Binary | Required pre-auth |
|---|---|---|
| AWS | aws | parent IAM identity (instance profile / IRSA / access key) with sts:AssumeRole on the target role |
| GCP | gcloud | ADC (Application Default Credentials) for an identity with iam.serviceAccounts.getAccessToken on the target SA |
| Azure | az | logged-in az session (az login --identity for managed identity, or interactive) on a principal that can issue tokens for the requested resource |
The wizard's preview step renders a binary present on CP host flag
so the operator can spot a missing CLI before they hit Execute mint.
Walkthrough
1. Pick a provider + fill the form
Open Settings → Cloud-CLI temporary credential mint. The wizard
loads handler metadata from
/admin/settings/credentials/cloud-cli/handlers (proxied to the CP)
and renders the appropriate fields:
| Provider | Required |
|---|---|
| AWS | target_credential_key, role_arn |
| GCP | target_credential_key, service_account_email |
| Azure | target_credential_key (resource / tenant / subscription optional) |
target_credential_key is the resolver key the minted credential
persists under (e.g. idp:aws:prod). Downstream code reads it via
CredentialResolver.resolve(CredentialKey(<service>, <purpose>))
once minted; nothing in the platform passes the bytes directly.
2. Preview
Clicking Preview command posts to
/admin/settings/credentials/cloud-cli/preview which returns the
exact argv the CP would spawn, with token-bearing args masked.
This is a dry run — no subprocess executes.
3. Mint
Execute mint posts to /admin/settings/credentials/cloud-cli/sts.
Server-side the CP:
- writes a
WorkloadRunaudit row withaction=mint_cloud_credentialinPENDINGstate before spawning the subprocess; - invokes
aws sts assume-role/gcloud auth print-access-token/az account get-access-tokenwith a 60s wall-clock timeout; - parses the result, persists the credential under
target_credential_keyvia the resolver chain; - updates the audit row to
SUCCEEDED|FAILED.
The wizard renders the response envelope:
| Field | Meaning |
|---|---|
credential_key | resolver key the temp creds live under |
expires_at | TTL boundary (provider-derived) |
source_identity | role ARN / SA email / subscription id |
audit_run_id | links to the WorkloadRun ledger row |
The raw token is never in the response body or audit ledger.
Step-up MFA
/admin/settings/credentials/cloud-cli/{preview,sts} carry
Depends(require_admin_step_up("admin:cluster")). If the operator's
JWT is older than the configured auth_step_up_default_max_age
(default 180s), the BFF returns
401 insufficient_user_authentication with an RFC 9470
WWW-Authenticate challenge; the wizard's apiFetch middleware
silently re-issues an MFA prompt and retries the original call.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
binary_missing in the preview | CLI not on the CP host's $PATH | Install the CLI in the CP container image, or shell into the host and run which aws/gcloud/az |
nonzero_exit with masked stderr | Parent credential lacks the requested permission | Read the redacted stderr in the audit row's error field; provision the missing role / IAM permission |
parse_error | Upstream returned an unexpected JSON shape | Compare against the canonical aws sts assume-role / az account get-access-token shape in the AWS / Azure docs; file a bug if AWS/Azure changed the format |
timeout | Network / IAM trust-policy resolution stuck | The 60s budget is intentional — re-run; if it persists, run the masked argv from the preview locally to inspect |
persist_failed | Resolver write surface not configured | The default CP resolver doesn't ship a write hook in OSS; provide one via the persist= kwarg of alphaswarm_controller.services.cloud_cli.mint, or wire a Vault / SSM secret manager that supports writes |
Related docs
- Cloud credentials — resolver chain + naming conventions.
- Identity overview — overall rule-26 + rule-52 boundaries.
- Account integrations — the per-org PAT-link sibling surface (HF + Docker Hub).