CloudAccount

Which cloud identity Ringleader uses for one organization and one cloud account, and the limits on how that account's workstations can be reached.

A CloudAccount binds one organization to one cloud account. It defines which cloud identity to use: which identity Ringleader signs in as in your cloud, and which setting in your cloud accepts Ringleader’s sign-in token. It can also limit how the workstations in that account are reached: whether they may have public addresses, and which addresses may open SSH to them.

apiVersion: core.ringleader.dev/v1
kind: CloudAccount

It is cluster-scoped (it has no metadata.namespace) because a cloud account belongs to an organization, which spans namespaces. A CloudIdentity points at one by name (spec.cloudAccountRef) to mint its credentials through it.

What it is, and what it is not

Each of these questions is answered on one object:

Lives onExample
Which cloud identity to use, meaning which identity Ringleader signs in as and which setting accepts its tokenCloudAccountthe target service account, the workload identity provider, the Entra app, the tenant
The VM’s size and placement, meaning what a workstation VM actually looks likeCloudIdentity’s defaultProviderConfig / overrideProviderConfigproject, zone, machine type, subnet, labels
Who can reach the workstations, for every workstation in the accountCloudAccountallowPublicAddresses, sshSourceRanges

A CloudAccount is not a placement template. It never decides where a workstation runs or how big it is.

It holds no secret

Every identifier in a CloudAccount spec is public: a service-account email, a workload-identity-provider resource name, an Entra application (client) id, a tenant id. Naming an identity gives Ringleader no access by itself.

The authority is the short-lived, signed assertion Ringleader presents, whose subject is derived server-side from the workstation’s namespace, never from anything written on this object. That is what makes this object a pointer rather than a capability.

Who can write one

A CloudAccount is org-owned infrastructure, not a tenant object:

  • Organization administrators may create, read, update, and delete the CloudAccounts of their own organization. The control plane enforces that on both the incoming object and the stored one, so an account cannot be re-homed to another organization by editing it.
  • Ringleader operators (global admins) may write any organization’s.
  • A namespace member holds no permission on this kind at all, not even read. This choice of cloud identity is therefore outside the surface a normal user can write, which is the entire point.

How a workstation reaches it

The reference must stay inside the identity’s own organization. Pointing a CloudIdentity at another organization’s account is refused when you apply it:

apply cloudidentity/gcp: admission: spec.cloudAccountRef names no CloudAccount
in this namespace's org: CloudIdentity dev/gcp references CloudAccount "other-org-gcp"

An account that belongs to someone else and an account that does not exist give you the same message on purpose, so the error cannot be used to discover which account names other organizations have.

The workstation’s namespace must belong to an organization. If it does not, no assertion can be signed for it and the reference is refused for the same reason.

Examples

Google Cloud

apiVersion: core.ringleader.dev/v1
kind: CloudAccount
metadata:
  name: acme-gcp
spec:
  org: acme
  provider: gcp
  gcp:
    # The service account in YOUR project that Ringleader acts as. It holds the
    # workstation permissions; the federated principal impersonates it directly.
    targetServiceAccount: ringleader-workstations@acme-dev.iam.gserviceaccount.com
    # YOUR workload identity provider's resource name. This is the token-exchange
    # audience, NOT the assertion's `aud` claim (see the note below).
    workloadIdentityProvider: projects/123456789/locations/global/workloadIdentityPools/ringleader/providers/oidc

Apply it before the CloudIdentity that references it (a multi-document apply orders them for you):

rl apply -f acme-gcp-account.yaml
rl cloudaccount get        # alias: rl ca get

Microsoft Azure

apiVersion: core.ringleader.dev/v1
kind: CloudAccount
metadata:
  name: acme-azure
spec:
  org: acme
  provider: azure
  azure:
    # The Entra application (client) id that holds the workstation permissions on
    # your resource group, and whose federated identity credential trusts
    # Ringleader's per-organization issuer.
    targetAppClientId: ec6d0a82-536f-463e-baa5-a10221befa86
    # Your Azure AD tenant.
    tenant: bb90f2d3-842d-41ea-8c0c-0e6671775ef7

AWS

apiVersion: core.ringleader.dev/v1
kind: CloudAccount
metadata:
  name: acme-aws
spec:
  org: acme
  provider: aws
  aws:
    # The IAM role in YOUR account that Ringleader assumes via
    # AssumeRoleWithWebIdentity. Its trust policy admits only your organization's
    # subject and audience. This one value is all AWS needs. AWS finds the
    # OIDC provider and the audience from the signed token itself.
    targetRoleArn: arn:aws:iam::123456789012:role/ringleader-workstations

Spec fields

FieldTypeDescription
orgstringRequired. The organization that owns this cloud account. It must be the organization the referencing CloudIdentity’s namespace belongs to.
providerstringRequired. gcp, azure or aws.
gcp.targetServiceAccountstringRequired for gcp. The service account in your project that Ringleader acts as. A bare email, or a fully qualified projects/…/serviceAccounts/… resource name.
gcp.workloadIdentityProviderstringRequired for gcp. Your workload identity provider’s resource name, projects/<number>/locations/global/workloadIdentityPools/<pool>/providers/<provider>. An //iam.googleapis.com/ prefix is accepted and optional.
gcp.targetScopestringOptional OAuth scope override for the minted token (default: cloud-platform).
azure.targetAppClientIdstringRequired for azure. The Entra application (client) id Ringleader authenticates as.
azure.tenantstringRequired for azure. Your Azure AD tenant id.
aws.targetRoleArnstringRequired for aws. The IAM role Ringleader assumes via AssumeRoleWithWebIdentity. It is the only AWS value. AWS finds the identity provider from the token’s iss and checks aud against that provider’s client-id list, so neither is named here. There is no aws.targetScope.
azure.targetScopestringOptional OAuth scope override (default: the Azure Resource Manager .default scope).
allowPublicAddressesboolfalse keeps every workstation in this account off public addresses. See Limiting who can reach workstations.
sshSourceRanges[]stringIPv4 ranges allowed to open SSH to this account’s workstations. Default: any address. See Limiting who can reach workstations.

A gcp account may not carry an azure block, and vice versa. An incomplete configuration is refused when you apply it, not when a workstation later fails to boot:

apply cloudaccount/acme-gcp: validation failed:
spec.gcp.workloadIdentityProvider: is required

Status fields

The system writes these. They answer one question: can a workstation governed by this account actually mint a credential?

FieldTypeDescription
messagestringThe headline: the account is ready: its org's OIDC issuer documents are published, or the account is not ready, so a workstation governed by it cannot mint a cloud credential.
oidc.readyboolWhether the federation is usable end to end.
oidc.messagestringThe specific reason when it is not. This is the one to read.
rl cloudaccount get acme-gcp -o jsonpath='{.status.oidc.message}{"\n"}'

oidc.ready is derived from the account’s own validity and its org’s publish state, so a healthy account whose org has not published yet reports not-ready and says which of the two is the problem, e.g.:

org acme's OIDC issuer documents are not published yet, so a cloud cannot validate
an assertion for it

The account’s own failures read the same way: the account names no org, so no assertion can be signed for it, org acme does not exist, or the validator’s own text when the spec is invalid.

Why AWS needs a single field

The AWS configuration is one field. Unlike the other two clouds, an sts:AssumeRoleWithWebIdentity request names neither an audience nor an identity provider. AWS finds the provider from the token’s own iss, and checks the aud claim against that provider’s client-id list. Both checks therefore live inside the signed token and in your own IAM configuration, so the account carries only the role to assume.

See onboarding AWS for the runbook.

Limiting who can reach workstations

Ringleader keeps a firewall rule admitting SSH to every cloud workstation, on TCP ports 22 and 2222. Cloud workstations also take a public address by default. Two fields on the CloudAccount narrow both for every workstation in the account:

spec:
  org: acme
  provider: gcp
  gcp:
    targetServiceAccount: ringleader-workstations@acme-dev.iam.gserviceaccount.com
    workloadIdentityProvider: projects/123456789/locations/global/workloadIdentityPools/ringleader/providers/oidc
  allowPublicAddresses: false
  sshSourceRanges:
    - 203.0.113.0/24

sshSourceRanges lists the IPv4 ranges Ringleader’s rule admits SSH from. With no list, it admits any address. It also limits who can reach the management ports of the account’s Edges. An IPv6 range is refused, because the rule is IPv4 only. On GCP and Azure, a change to the list reaches the rules of existing workstations within about 10 minutes. On AWS, it reaches them the next time Ringleader creates or changes a workstation in the same VPC.

A rule your own cloud onboarding created still applies alongside Ringleader’s, with one exception. On Azure, a workstation with no egress policy accepts SSH only from the addresses Ringleader’s rule allows. That is because the network security group Ringleader puts on its network interface allows nothing wider.

allowPublicAddresses: false gives none of the account’s workstations a public address. A workstation that asks for one explicitly, with assignPublicIp: true on GCP or AWS or publicIp: true on Azure, is refused when you apply it. A workstation that does not ask gets no address, even when a CloudIdentity’s overrideProviderConfig would give it one. With the field absent, each workstation’s own setting applies. It does not apply to Edges.

A public address is set when a machine is created. Setting allowPublicAddresses: false on an account with running workstations does not remove their addresses: each one reports the PublicAddressChangeNotApplied condition until it is recreated.

The two audience values (Google Cloud)

The single most common mistake when configuring the Google Cloud trust is conflating two different “audiences”:

  • spec.gcp.workloadIdentityProvider is the token-exchange audience: the resource name of your workload identity provider. It is per-customer, and it belongs on this object.
  • The assertion’s aud claim is a per-organization value Ringleader derives itself and pins in your provider’s allowed_audiences. You never write it here.

They are two independent pins on the same exchange. See how Ringleader signs in to your cloud for the exact values to configure in your cloud.

See also