Skip to content

RFC: Service Accounts for Cloud Foundry Workload Identity - #1645

Open
rkoster wants to merge 24 commits into
cloudfoundry:mainfrom
rkoster:rfc-service-accounts
Open

rkoster wants to merge 24 commits into
cloudfoundry:mainfrom
rkoster:rfc-service-accounts

Conversation

@rkoster

@rkoster rkoster commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Index

Summary

Propose service accounts: named identities owned by an org and entitled to the spaces whose apps may use them. Apps prove their account with the certificate Cloud Foundry already gives every instance and exchange it for short-lived UAA tokens. No secret is ever handed to the app.

The main use is workload identity federation (WIF) with cloud services, whether owned by the application team or provisioned by a service broker. The same identity also lets coding agents running as CF apps call the Cloud Foundry API, and authorizes app-to-app routes.

One account, multiple apps, no shared secrets, explicit permissions.

Why

Platform teams need workload identities that are shared by a chosen set of apps, stable across app replacement, renames and space recreation, human-readable, known before the platform exists (so external roles can be created in advance, including for disaster recovery), secretless, and explicitly authorized. For the most sensitive data, teams often own their cloud accounts and write trust policies themselves, so a readable, predetermined identity matters. Instance, app, org and space identities each fail at least one of these requirements.

Proposal at a glance

  • cf create-service-account payments-worker in a space creates an org-owned account entitled to that space only; cf bind-service-account APP payments-worker assigns it. An app has at most one account; many apps can share one. Changes apply on restart.
  • cf entitle-service-account payments-worker SPACE lets another space of the same org use it, decided by an Org Manager or a Space Developer of both spaces. Deleting a space removes its entitlement and keeps the account.
  • The name appears as token subject cf:service-account:payments-worker, certificate SAN payments-worker.svc.identity, and route-policy source cf:svc:payments-worker. Names are immutable, foundation-unique RFC 1123 labels; deleted names stay reserved.
  • Team-owned resources: teams write cloud trust policies (e.g. an AWS IAM role) for the issuer and subject, in advance.
  • Broker-managed services: cf bind-service is unchanged. Cloud Controller adds the account's issuer and subject to the CF context of the bind request; the broker creates and removes its grant. No new plan capability.
  • Tokens are bearer JWTs (at most five minutes, never past the certificate's expiry), without cnf, since cloud WIF does not verify proof of possession; this can be revisited later. Tokens carry instance/app/space/org GUIDs for audit.
  • Assigning an account grants nothing. Access comes from external grants, explicit Cloud Controller roles or route policies. Disable stops new tokens in every entitled space, e.g. after a leaked key; nothing is instant revocation.
  • No new roles: Space Developers create accounts (like service instances) and can disable or delete accounts entitled to their space; Org Managers manage all accounts in the org. Org quotas gain an account limit; operators can set a creation budget against name hoarding. Org deletion deletes its accounts.

Three Mermaid diagrams cover provisioning, token exchange with AWS STS, and a coding agent calling Cloud Controller. An appendix covers OSBAPI, an example RDS binding, the UAA client registration, platform components and CA rotation.

Existing work

UAA certificate-based client authentication is implemented and agreed with the UAA team, pending final review in UAA #4076, including the opt-in certificate-binding policy and named trust bundles, validated in a CF lab.

Companion drafts: Cloud Controller #5520, capi-release #702, BBS #168, Diego #1216, CLI #3875. These still implement an earlier space-owned model; org ownership and entitlements will follow.

Review requested

The next step is community review and RFC approval of the identity model and developer experience. The RFC status remains Draft; no RFC number or FCP is requested yet.

@cloudfoundry/toc — relevant working groups include App Runtime Interfaces, App Runtime Platform and App Runtime Deployments. Feedback is requested from CAPI, Diego/BBS, UAA, CLI, networking and service-broker maintainers.

@rkoster
rkoster marked this pull request as ready for review October 6, 2026 14:22
Copilot AI balanced review requested due to automatic review settings October 6, 2026 14:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The owning-space deletion contract and safeguards against unbounded global tombstones need definition.

Review effort: Balanced
Findings: 1 High severity · 1 Medium severity

Open (2)
What changed in this PR

Proposes space-owned service accounts for stable, secretless Cloud Foundry workload identities.

Changes:

  • Defines account lifecycle, permissions, quotas, and app assignments.
  • Specifies UAA JWT federation, broker integration, and CAPI access.
  • Extends identity-aware routing for service-account identities.
File Description
toc/​rfc/​rfc-draft-service-accounts.md Adds the service-account RFC and developer workflows.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread toc/rfc/rfc-draft-service-accounts.md Outdated
Comment thread toc/rfc/rfc-draft-service-accounts.md Outdated
@beyhan
beyhan requested a review from a team October 6, 2026 14:47
@beyhan
beyhan requested review from Gerg, beyhan, cweibel, mkocher and stephanme and removed request for a team October 6, 2026 14:47
@beyhan beyhan added toc rfc CFF community RFC labels Oct 6, 2026
@pbusko

pbusko commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

IMO this feels like a lot of new concepts and lifecycle machinery for what the federation case actually needs, and most of it looks like it's there to manage the new resource rather than solve the original problem.

mTLS auth with SAN matching is already in the UAA, the actual gap is just a stable identifier that a selected set of apps can share.

Instead of a new first-class resource, could that association just be an app label? e.g.

cf set-label app payments-api identity.cloudfoundry.org/service-account=payments-worker

That's the SPIFFE/OIDC workload-identity style, and space-scoping also drops the need for the creation budget. Today UAA matches against a pre-registered SAN, so for this to work it'd need to read the subject straight from the cert instead. And the SAN would have to be space-scoped, so one app can't grab another space's identity.

@rkoster

rkoster commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

@pbusko — responding to your suggestion to use app labels and space-scoped identities:

Instead of a new first-class resource, could that association just be an app label?

I explored SPIFFE-based identity earlier, including an end-to-end UAA/Diego POC and research on name-derived identities. The main question is the canonical identity and its lifecycle, rather than how an app expresses its assignment.

At Rabobank, a recurring requirement—raised repeatedly during the route-policy work—is human-readable, stable identifiers that teams can use directly in external authorization policies.

Those identifiers must also be known before the platform exists. For disaster recovery, we want to pre-create external WIF roles and trust policies, then recreate the platform and push apps using predetermined identities. Requiring each team to create CF resources, retrieve a generated GUID-based identity, provision external roles, and only then deploy introduces sequencing and state-management complexity into every application pipeline.

A space GUID plus an account label could form a valid SPIFFE ID, but would not meet that pre-provisioning requirement and would change when the space is recreated. Using org/space names instead introduces other problems: CF permits names up to 255 characters, including printable punctuation and Unicode, and those names are mutable. SPIFFE path segments permit only letters, digits, dots, dashes and underscores, and prohibit percent-encoding. Lossy sanitization/truncation introduces collisions; name-based paths change on rename. Deterministic hashing can address representation, but sacrifices readability.

The proposed account name is therefore human-readable, immutable and chosen in advance, independently of platform-generated GUIDs. External policies can be prepared for cf:service-account:payments-worker before CF resources exist. Trust remains scoped to the planned UAA issuer; a different recovery issuer must also be pre-authorized.

This does not rule out SPIFFE: the predetermined account name could appear in a URI SAN. The distinction is the identity model, not DNS versus URI encoding.

A label could be an assignment UX, but needs platform-controlled authorization and issuance: ordinary metadata must not let an app claim an identity with existing grants. Explicit CAPI roles, broker grants and disable/delete behavior also need lifecycle semantics independent of any one app. That is why the RFC models the shared identity as a resource.

Today UAA matches against a pre-registered SAN, so for this to work it'd need to read the subject straight from the cert instead.

That changes the authentication profile. RFC 8705 tls_client_auth requires an exact expected DN/SAN registered for each client. Deriving an unregistered client/subject from a trusted certificate needs a separately specified issuance profile. This RFC builds on existing exact-SAN registration.

Space-scoping could avoid foundation-wide name contention, but still needs a predetermined, stable namespace and name-reuse semantics. The creation budget is configurable, including unlimited for internal platforms.

@rkoster

rkoster commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Pushed fe94f46: a restructure of the RFC based on feedback that it was hard to read, plus several design simplifications from the discussion here and on the UAA PR.

Readability

  • Reorganized around the developer workflow: problem and requirements first, then what developers do, then identity, lifecycle and permissions. Implementation detail (OSBAPI, UAA client registration, platform components, CA rotation) moved to an appendix.
  • Rules and behavior are now tables instead of dense prose; the revocation caveat appears once.
  • The main body is now under 1,900 words; implementation detail lives in the appendix. The document grew slightly overall because of the new requirements, alternatives and team-owned examples.

Clearer motivation

  • Explicit requirements: shared, stable, human-readable, known before the platform exists, secretless, explicitly authorized. Predetermined, readable identities let teams create external roles in advance, including for disaster recovery.
  • New Alternatives considered section covering app labels, GUID-based (e.g. SPIFFE) identities, org/space-name-derived identities, existing app identity and per-app secrets (following up on the discussion with @pbusko).

Team-owned cloud resources are now the primary path

  • For the most sensitive data, shared brokers are often not allowed: following least privilege, databases live in team-owned cloud accounts and teams write trust policies themselves. The RFC now shows the AWS IAM trust policy a team would write, referencing only values known in advance. Brokers are presented as automating the same setup.

Simpler broker integration

  • Dropped the proposed --authentication service-account flag. An app has at most one account, so Cloud Controller simply passes it to the broker.
  • OSBAPI scope reduced to adding the account's issuer and subject to the CF context of a bind request. No new plan capability or versioned bind_resource object.
  • Federation trust and allowed token audiences are operator configuration set up at deploy time; brokers create and remove their own grants. Cloud Controller no longer approves audiences per binding.

Token and UAA details made concrete

  • Explains why tokens carry no cnf: cloud WIF (AWS, Azure, Google Cloud) does not verify proof of possession. Can be revisited later via UAA's per-client setting or DPoP.
  • Tokens carry instance, app, space and org GUIDs for audit, using UAA's existing claim mappings.
  • Added the full UAA client registration example.
  • Added CA rotation, with named UAA trust bundles as the preferred approach (proposed on UAA #4076) and a Cloud Controller fallback.

The PR description has been updated to match.

@Gerg

Gerg commented Oct 20, 2026

Copy link
Copy Markdown
Member

I tried to squeeze this RFC into a new type of service (similar to route services or volume mounts). The benefits of doing that is we could more easily leverage existing UX around binding, async operations, sharing, etc.

I think it could work by using basically the same mechanism described by this RFC except with a layer of "service" abstraction layered on top. However, I don't think it's worth it, since we'd have to make the resulting "identity" services have a bunch of special logic (even more so than route services). For example: limiting a single identity service binding per app, imposing ordering requirements between identity service bindings and other binding types, fitting in "tombstones" somehow.

I think if we implement this feature as written, we'd immediately need to also add cross-space sharing, much like we did for service instances and routes. That makes me suspicious of the proposed tenancy model, where the service accounts exist in a space. Especially since there are so many global/admin concerns around these (e.g. the global unique constraints, tombstones, general squatting concerns, etc).

I wonder if a different tenancy model would be more appropriate. For example something like the isolation segment model, where the resource is global, but it can be "entitled" to orgs (or spaces). Or maybe domains, where there are global domains, but also org-scoped domains (which can then also be shared 😭).

@rkoster

rkoster commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

@Gerg thanks, this was very useful. I've reworked the tenancy model based on it in ce0af13.

I don't think it's worth it, since we'd have to make the resulting "identity" services have a bunch of special logic

Agreed. One identity per app, ordering against other bindings and reserved names would all be special cases, so the RFC keeps a dedicated resource. I've added this to Alternatives considered.

I think if we implement this feature as written, we'd immediately need to also add cross-space sharing [...] That makes me suspicious of the proposed tenancy model

Fair point. Accounts are now owned by the org and entitled to spaces, close to the isolation segment model you suggested, scoped to a single org:

  • cf create-service-account payments-worker in a space creates an org-owned account entitled to that space only, so the default is as narrow as before.
  • cf entitle-service-account payments-worker payments-batch lets apps in another space of the same org use it. Org Managers can do this, as can Space Developers of an already entitled space who are also Space Developers of the new space. Entitlements never cross orgs.
  • Deleting a space removes its entitlement but keeps the account, so recreating the space, or moving the workload, doesn't change the external identity. Deleting the org deletes its accounts.
  • Space Developers of an entitled space can delete or disable the account, so accounts don't pile up in the org without entitlements. Org Managers can manage all accounts in the org. No new roles.

I kept entitlement explicit per space rather than org-wide, because an identity is a credential: anyone who can modify an app in an entitled space can obtain its tokens, and with them its external access. Each extra space should be a deliberate decision.

Especially since there are so many global/admin concerns around these (e.g. the global unique constraints, tombstones, general squatting concerns, etc).

The names stay foundation-wide on purpose. Teams need identities that are readable and known before the platform exists, so they can write external trust policies in advance, including for disaster recovery. A name that depended on the org or space would change when those are renamed or recreated. Squatting is bounded by tombstones, admin-only name reuse and an optional creation budget. Global, admin-owned accounts entitled to orgs, like isolation segments, would fit on top of this model later if there's demand.

The changes are in ce0af13. The implementation drafts still use the earlier space-owned model and will follow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rfc CFF community RFC toc

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

5 participants