Appearance
Create a Cloud
Before plexsphere can provision anything, the platform needs a catalog to provision against: the Clouds it can reach, the Credentials that pay for them, and the Blueprints that describe what to build. The catalog starts empty on a fresh stack — nothing is pre-seeded. You registered the first Blueprint into your Domain in Register a Blueprint; building the catalog-global half — the Clouds and the Credentials that pay for them — is the platform operator's job.
This lesson is the second of three that build that catalog. Here you create a Cloud: a provider account plexsphere can provision against. The next lesson issues a Credential under it; then Provision a cloud Resource consumes the whole catalog to stand up a real S3 bucket.
The Cloud you create names an AWS account. On the lean dev stack that account is served by floci, an in-cluster AWS emulator: the same plexctl cloud create you run here works unchanged against a real AWS account, but locally there is no real account, no token, and no cost. The account id 000000000000 below is floci's well-known dummy account.
This lesson takes about five minutes.
Before you start
This lesson is standalone: it does not build on the explore, build, or Group lessons. You only need a running, logged-in stack from Set up your local plexsphere, plus jq on your $PATH to read the new Cloud's id out of the JSON response.
You act as the platform operator throughout — operator@example.com, the seeded identity whose platform-login row holds the platform:plexsphere#admin authoring grant, so it is the one allowed to build the platform catalog. The operator signs in without selecting a Domain: platform authority is platform-wide, not tenant-scoped, and the grant seed attaches it to the Domain-less platform sign-in. The dev password is password. See the tutorials overview for the full cast.
Recreate the shell environment:
bash
export PATH="$PWD/bin:$PATH"
export PLEXSPHERE_URL=http://localhost:8080Step 1 — Create the demo Cloud
Sign in as the platform operator and save the session under a named operator profile — they curate the catalog, so they are the identity allowed to build it. The --platform flag runs the Domain-independent platform sign-in (the dev stack opts its device-code surface into it). Run the login below, then complete sign-in in the browser as operator@example.com with the password password:
bash
plexctl login --profile-name operator --platformCheck what that sign-in produced:
bash
plexctl whoami --profile operatortext
PRINCIPAL SCOPE SUBJECT DOMAIN ACR AMR
user platform 019100c0-0d0c-7000-8000-000000000002 - - -Two columns carry the whole difference from every earlier lesson. SCOPE reads platform rather than domain, and DOMAIN is - rather than a UUID: this session belongs to no tenant Domain at all, and everything it may do flows from the platform grant instead of from a relation inside a tenant. Compare it with the whoami from Set up your local plexsphere, where the same command named Acme Corp in that column.
The subject is a different principal, too. operator@example.com also has an Acme Corp row, seen in the identity listing in Explore your first Domain, but that is its tenant hat and it is not the identity signing in here.
A Cloud is a provider account plexsphere can provision against; the Credential issued under it (the next lesson) is the vaulted secret that pays for it. Create the demo Cloud — the platform:plexsphere#admin grant the operator holds folds into the platform manage permission Cloud creation gates on:
bash
CLOUD_ID=$(plexctl cloud create \
--slug demo-cloud \
--display-name "Demo Cloud" \
--provider aws \
--external-id 000000000000 \
--endpoint '{"region":"us-east-1","partition":"aws"}' \
--region-defaults '{"default_region":"us-east-1"}' \
--provider-package xpkg.upbound.io/upbound/provider-aws-s3@v2.6.1@sha256:7e00c910bdbf39b2dcc8d7632153b6be1c31d202ede0f2d12ade053eb77aae96 \
--provider-config-api-version aws.m.upbound.io/v1beta1 \
--profile operator --output json | jq -r '.id')
echo "$CLOUD_ID"--provider-package declares one Crossplane provider package for this Cloud as <source>@<version>: the OCI repository it is pulled from, then the version it is pinned at. The flag is repeatable, so a Cloud that needs several providers names them one occurrence each; at least one is required. --provider-config-api-version is a single Cloud-level value, the apiVersion every declared package serves its ProviderConfig under. The values above name the exact package the local stack runs, so the record matches what is really installed.
Creating a Cloud grants its creator manage on it — the relation issuing a credential authorises against — and manage folds into the observe relation reads gate on, so the creator can read the Cloud straight back, as the next step shows.
Step 2 — Read the Cloud back
List the catalog you have started. cloud list filters each row through the per-Cloud observe relation, and the demo Cloud you just created is the only entry:
bash
plexctl cloud list --all --profile operator --output json \
| jq '.items[] | {id, slug, provider, external_id}'json
{
"id": "019fb9c7-97ba-7d4a-8867-29e77d21c5e6",
"slug": "demo-cloud",
"provider": "aws",
"external_id": "000000000000"
}Then fetch that one Cloud by the id you captured in Step 1 — cloud get runs the same observe check before it reads:
bash
plexctl cloud get "$CLOUD_ID" --profile operator --output jsonjson
{
"created_at": "2026-06-24T17:16:24.417317Z",
"display_name": "Demo Cloud",
"endpoint": {
"partition": "aws",
"region": "us-east-1"
},
"external_id": "000000000000",
"id": "019fb9c7-97ba-7d4a-8867-29e77d21c5e6",
"provider": "aws",
"provider_config_api_version": "aws.m.upbound.io/v1beta1",
"provider_packages": [
{
"source": "xpkg.upbound.io/upbound/provider-aws-s3",
"version": "v2.6.1@sha256:7e00c910bdbf39b2dcc8d7632153b6be1c31d202ede0f2d12ade053eb77aae96"
}
],
"region_defaults": {
"default_region": "us-east-1"
},
"slug": "demo-cloud",
"updated_at": "2026-06-24T17:16:24.417317Z"
}Both reads gate on the per-Cloud observe relation. The grant from creating the Cloud reaches the authorization mirror a moment after creation, so if cloud list comes back empty or cloud get returns Permission Denied, wait a second and re-run it — the same lag applies to the next lesson's credential issue.
Do this in the Console
Every step above has a browser equivalent in the Console. Open the Clouds page under the Cloud group in the sidebar: Create Cloud opens a dialog with the same fields you passed to cloud create — a Display name, a kebab-case Slug, a Provider select over the supported providers, an External ID, and JSON textareas for the Endpoint and Region defaults blobs. On success the Cloud appears in the list; clicking its name opens the Cloud detail page — the browser equivalent of cloud get, showing the same metadata and the read-only endpoint and region-defaults JSON.
What you learned
- A Cloud is a provider account plexsphere provisions against. It names the upstream account and its region defaults; the secret that pays for it is a separate Credential, issued under the Cloud in the next lesson.
- The catalog starts empty. Nothing is pre-seeded on a fresh stack, so the operator builds it — beginning with the Cloud, the residency pivot the credential and assignment gates later authorise against.
- Creating a Cloud grants the creator
manageon it. That relation is what the credential-issue gate checks; it also folds intoobserve, so the creator cancloud listandcloud getthe Cloud it just created. The grant reaches the authorization mirror a moment after creation.
Where to go next
- Keep learning by doing — Issue a Cloud Credential issues the vaulted secret that pays for the Cloud you just created.
Or pick the quadrant that matches what you need now:
- You have a job to do — the Manage Clouds how-to covers the operator runbook for creating, updating, and deleting Clouds.
- You want the exact contract — the
plexctl cloudreference documents every flag and output shape. - You want to understand why the catalog is shaped this way — the Cloud Inventory context explains the Cloud aggregate and its invariants.