Skip to content

Issue a Cloud Credential

A Cloud Credential is a brokered secret owned by a Cloud. Issuing one writes the secret material into OpenBao KV-v2, records a broker row, and returns the credential's lifecycle metadata. The secret payload is accepted inbound only — no read surface ever returns it again, so keep your own copy if you need it elsewhere.

Prerequisites

  • An authenticated session — see Log in with plexctl.
  • A Cloud UUID. Issuing a credential needs the manage relation on that Cloud — the Cloud is the residency pivot the issue gate authorises against. A caller without manage is refused with 403 before the payload is ever read.
  • The secret bytes to store, in a file (or piped on stdin).

Steps

Issue with plexctl

shell
export PLEXSPHERE_URL="${PLEXSPHERE_URL:-https://localhost:8080}"

plexctl cloud credential create \
  --server       "${PLEXSPHERE_URL}" \
  --cloud-id     <cloud-uuid> \
  --display-name "Acme AWS provisioner secret" \
  --payload-file ./aws-provisioner.json \
  --key-value    role_arn=arn:aws:iam::123456789012:role/acme-provisioner

The command prints the metadata-only projection of the new credential (id, owning Cloud, display name, version 1, derived status active, and the lifecycle timestamps). Repeat --key-value for each key=value pair you want stored alongside the payload.

To avoid writing the secret to a file, pipe it on stdin with --payload-file -:

shell
printf '%s' "${SECRET_JSON}" | plexctl cloud credential create \
  --server       "${PLEXSPHERE_URL}" \
  --cloud-id     <cloud-uuid> \
  --display-name "Acme AWS provisioner secret" \
  --payload-file -

Issue with the HTTP API

The payload field is base64-encoded secret bytes; key_values is an optional flat map. Both are accepted inbound only.

shell
curl --silent --show-error --fail-with-body -X POST \
  -H "Authorization: Bearer ${TOKEN}" -H 'content-type: application/json' \
  "${PLEXSPHERE_URL}/v1/clouds/<cloud-uuid>/cloud-credentials" -d '{
  "display_name": "Acme AWS provisioner secret",
  "payload": "'"$(base64 < ./aws-provisioner.json | tr -d '\n')"'",
  "key_values": {"role_arn": "arn:aws:iam::123456789012:role/acme-provisioner"}
}'

A 201 carries the new credential's metadata and a Location header holding its canonical read URL (/v1/cloud-credentials/<credential-uuid>).

Verify

Read the credential back — the projection is metadata-only and never includes the payload:

shell
plexctl cloud credential get <credential-uuid> --server "${PLEXSPHERE_URL}"

Or list every credential the Cloud owns:

shell
plexctl cloud credential list --cloud-id <cloud-uuid> --server "${PLEXSPHERE_URL}"

Troubleshooting

  • 403 — the caller lacks cloud#manage on the parent Cloud, or the Cloud UUID is wrong. Issuing under an unknown Cloud fails the manage check first, so a missing Cloud also surfaces as 403.
  • 400 invalid_display_namedisplay_name was empty or whitespace-only.
  • 400 invalid_payload — the payload decoded to zero bytes (an empty file or empty stdin).
  • 413 request_body_too_large — the request exceeded the 8 KiB body ceiling. Large secrets should be referenced indirectly, not inlined.