Deploying to AWS without AWS credentials
Most developers do not have (and should not need) AWS credentials to deploy their
app. wbsp deploy to an AWS destination works with only your platform login and
local Docker — no --backdoor. Images are pushed through the platform's
collaborator-gated container registry gateway (registry.wbsp.ai), the same
mechanism you already use for git push.
One login sets everything up
wbsp login # browser sign-inwbsp login signs you in and registers wbsp as your git and docker
credential helper for the platform's hosts. From then on, git push,
docker push, and wbsp deploy all work off that one login — no AWS keys, no
tokens to paste. Each push asks the helper for a freshly-issued token, so
nothing static is stored in your keychain and short-lived tokens never go stale;
the CLI silently renews your session from its refresh token, so you rarely sign
in again (only when the session itself expires). wbsp logout clears it.
wbsp deploy --destination aws-prodThat's it: build runs locally (your source never leaves your machine), the image is
pushed to registry.wbsp.ai/<owner>/<repo>/app (the same <owner>/<repo> as your git
remote), the gateway checks you collaborate on that variant and forwards it to ECR,
and wbsp-api rolls it out.
Two names, one image. registry.wbsp.ai/<owner>/<repo>/app is the gateway
address you push to, keyed by your git <owner>/<repo>. The gateway resolves it
to the variant's underlying ECR repository — wbsp-v-<short-uuid>-app, the
variant-derived name documented in
wbsp-yaml-reference.md — and rewrites the push there, so
you never see or address the ECR id directly. Both are "the same repository git push uses" because your git remote and your catalog variant are bound together;
the address is git-keyed, the storage is variant-keyed.
For the credential helpers to work,
wbspmust be on yourPATH— git runswbsp git-credentialby name, and docker runs adocker-credential-wbspshim thatwbsp logincreates next to thewbspbinary. If you run a checked-outbin/wbsp, put thatbin/onPATH.
CI / automation — one secret, and what it can and cannot do today
A pipeline needs exactly one secret: WBSP_API_TOKEN, an access token minted
by a service account at the identity provider — an application in the tenant
the pipeline acts on, created by that tenant's administrator with the scopes the
work needs (wbsp-platform:deploy for a pipeline that deploys). Mint it with the
client-credentials grant at the start of each job; it serves one tenant and lives
an hour by default, so mint per job rather than storing one:
export WBSP_API_TOKEN=$(curl -sS -X POST https://hap.wbsp.ai/t/<tenant>/oauth2/token \
-d "grant_type=client_credentials&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET" \
| jq -r .access_token)The platform itself mints nothing (feature 093): wbsp token create and
wbsp token revoke are gone, and so are the platform-signed CI tokens they
produced. Revoke by disabling the service account at the provider — effective
within one token lifetime. wbsp whoami reports the service account's identity
while the variable is set.
What the token authenticates, stated separately, because they differ:
- The deploy API — yes.
WBSP_API_TOKENis accepted everywhere a login session is accepted. - The image push through the registry gateway — not today. The registry
and git gateways belong to the website and admit what the website configures
them for, which is currently people's CLI sessions (
wbsp login). A pipeline that builds locally and pushes with a service-account token authenticates the deploy call and then fails at the push with the registry's401. Admitting a service-account audience at the gateway is a request to the website team, not something a pipeline author can configure. This page will say when that changes.
So the CI pattern that works end to end today is deploy an already-published image: a person publishes from their machine, and the pipeline deploys or re-deploys that image with no build and no push —
export WBSP_API_TOKEN=...
wbsp deploy --image registry.wbsp.ai/<owner>/<repo>/app:<tag> \
--tenant <tenant> --app <name> --destination aws-prod(Override hosts with WBSP_REGISTRY_HOST / WBSP_GIT_HOST if your platform uses
different domains.)
A service-account token carries the account's rights, not a person's. Its tenant is the one in its issuer, and its verbs are the scopes its administrator granted, re-checked on every call. It is not tied to any individual's project membership, so a staffing change never silently breaks a pipeline — but it also means a demo publish, which follows project access, needs the service account (not a person) to hold that access on the project.
Publish a sandbox, then promote it
wbsp deploy --destination sandbox # build locally + gateway push + register
wbsp demo promote --sandbox # or promote from the websiteThe sandbox destination needs no --backdoor. After publishing, the sandbox is
launchable ("Try in sandbox") and promotable to the live demo.
You do not need to declare a sandbox: block: with only a demo: block, a
sandbox publish borrows it (and .env.demo), so an app that publishes a demo
today publishes a sandbox with no config change. Declare sandbox: only when the
sandbox should differ from the demo.
wbsp deploy --destination demo --sandboxis retired.--sandboxremains unchanged onwbsp demo launch/remove/status/promote, which act on an already-published sandbox rather than on a placement.
Why it's safe
- Collaborators only. The registry gateway authorizes every push against your variant membership: you can push to the container repository of a project you own or collaborate on. Platform operators may push to any variant — recorded in the push audit under its own reason code, so an operator push to someone else's repository is always visible as one.
- Both gates, before the build. The push rule is narrower than the gate on the
deploy or publish itself (which also admits holders of the destination tenant), so
wbsp deployasks both before it builds anything: you'll seeAuthorized to publish …andAuthorized to push …. - Demos follow project access, not tenant grants. Publishing a demo needs owner or developer access to the project; launching, inspecting and reaping one is also open to its testers and hosters. You never need an operator to grant you a tenant to work with your own project's demo.
- No AWS credential ever reaches your machine — the gateway injects the platform ECR credential server-side after authorizing you.
- Your source is never uploaded — only the built image is pushed.
- Every push is audited (who pushed which image to which variant).
Want your app to run on home machines? The universal destination
A wbsp deploy to a cloud destination builds the cloud image only
(linux/amd64) — if your application is cloud-only, nothing changes for you and
you can skip this section.
The universal destination builds linux/arm64 as well and publishes the two as
a single multi-architecture index, which is what lets your application run on an
Apple Silicon machine — including the wbsp-vm home appliance. It publishes and
stops: no deploy, no database, no routes, nothing running, and no tenant
involved at any point.
destination:
universal: {}wbsp deploy --destination universal{
"app": "my-app",
"destination": "universal",
"image_ref": "registry.wbsp.ai/<owner>/<variant>/app:latest",
"platforms": ["linux/amd64", "linux/arm64"],
"status": "published",
"deployed": false
}Do this if you intend to enable "can run locally" in the catalog: an amd64-only
image pulls cleanly on an appliance and then fails with exec format error.
It is also the whole flow for an appliance-only application — one with no
cloud destination at all. Publish, then enable "can run locally" in the catalog.
It requires the default credential-less route (wbsp login) and is not available
with --backdoor.
Declare release: where the appliance will see it. The appliance cannot read
your wbsp.yaml; it reads the run manifest stamped on the image, which carries
this destination's effective configuration. An empty universal: {} inherits
your top-level release:; override it under the block when the appliance needs
something different.
Three practical notes:
- The first universal publish may create a
wbsp-multiarchbuilder. A stock Docker Desktop cannot build multi-platform images, so the CLI provisions a dedicated buildx builder on first use and reuses it afterwards. You do not need to create one, and you should not delete it between publishes. - Build time barely moves on an Apple Silicon Mac. The amd64 half was already emulated; the arm64 half added alongside it is the native build. On an amd64 CI runner the reverse holds and arm64 is the emulated half.
WBSP_BUILD_PLATFORMS(comma-separated) narrows the published set for a pipeline that has measured the cost. It applies to theuniversaldestination; a cloud deploy is already cloud-only.
Deploying to the cloud as well — order matters
wbsp deploy --destination aws --universal and
wbsp deploy --destination aws --universal --publish-only are both retired.
Deploying and appliance-publishing are two commands now, and a cloud deploy moves
the image tag to a cloud-only manifest:
wbsp deploy --destination aws # cloud
wbsp deploy --destination universal # then restore appliance runnabilityA cloud deploy of an app that declares universal: prints a reminder to that
effect.
What your image tells a deployment target
Your image carries an ai.wbsp.manifest label holding the effective configuration for the
destination it was built for — release, port, database.extensions, your component
topology, and the names of the secrets you declare. That is how something holding only an
image reference knows to run your migrations before starting you.
Secret values never travel: secrets: is published as names and reference keys only, and
your database user and password are excluded outright. Nor is any destination other than the
one the image was built for.
Your non-secret env: values do travel, in the clear. They are copied into the label
verbatim, and reading that label needs no credential beyond the pull — so anyone who may pull
your image can read them. That makes env: the wrong home for anything merely sensitive
rather than secret: an internal hostname, a bucket or account id, a partner's endpoint. Such
values pass the "no secrets in wbsp.yaml" rule and still end up published. If you would
rather not hand a value to whoever can pull the image, declare it in secrets:, where only
the name is published — see
wbsp-yaml-reference.md.
The practical consequence for you: your release: command runs inside your own image,
so that image must contain whatever the command needs. If your release runs psql, ship
psql.
Troubleshooting
| Message | Meaning |
|---|---|
403 … authenticated but do not have access to this container repository on a first publish | A known gateway bug, not a permissions problem: the repository is created by the very request that is refused. wbsp deploy retries once automatically; a hand-run docker push needs one manual retry. |
Multi-platform build is not supported for the docker driver | Seen only on the universal destination: the wbsp-multiarch builder could not be provisioned. Check docker buildx version, or set WBSP_BUILD_PLATFORMS=linux/amd64 to publish a cloud-only image (which will not run on an appliance). |
--publish-only is retired / --universal is retired / --sandbox is retired | Each is a destination now: --destination universal for the first two, --destination sandbox for the third. The error names the replacement. |
no destination "universal" is declared | Add universal: {} under destination: — declaring the block is how an app opts into appliance publishing. |
must not declare type, tenant … on a reserved block | demo, sandbox and universal have platform-supplied identity; remove those keys. env, secrets and release stay yours. |
not allowed to push … (the registry returned 403) | You are signed in, but you neither own the variant, collaborate on it, nor hold the operator role. Ask the owner to add you as a collaborator, or sign in as the owning account. wbsp whoami --all shows your account against the repository owner. |
the registry rejected your credential (401) | Run wbsp login (interactive). If WBSP_API_TOKEN is set: the gateway does not admit a service-account token today — see CI / automation above; deploy a published image with --image instead of pushing from the pipeline. |
the registry has no container repository for … | The registry path comes from the git remote origin; the catalog knows no variant for that repository. |
docker push … failed | The push itself failed; the sentence after the dash says whether it was the credential (401) or entitlement (403). |
not logged in — run \wbsp login`` | No valid session; sign in. |
WBSP_REGISTRY_TOKEN is no longer supported | Personal access tokens were retired — set WBSP_API_TOKEN (CI) or use wbsp login. |
could not read the git remote 'origin' | The project needs its platform git remote (that's how the registry addresses the repo). |
a local container runtime is required | Install/start Docker — the build runs locally. |
Operators
Nothing to enable — the registry gateway (registry.wbsp.ai, features 043/045) is
live. Its validator accepts the audience the website configures it for: since
feature 093 that is people's login sessions; the platform-signed CI-token family
of feature 075 no longer exists, and a service-account WBSP_API_TOKEN is not
admitted at the gateway until the website adds that audience. Personal access
tokens are no longer accepted. --backdoor remains available for
bootstrap/recovery, and is the path for a self-hosted application that is not a
catalog variant (the gateway has no repository for it).