Identity-aware routing

Page last updated:

This topic provides you with an overview of how identity-aware routing works in Cloud Foundry.

Identity-aware routing lets the Gorouter require and validate mutual TLS (mTLS) on a per-domain basis and route requests based on the caller’s verified identity. It enables app-to-app traffic to flow through the Gorouter — load-balanced and platform-enforced — while the platform authorizes each request from the caller’s certificate rather than relying on the app to authenticate callers itself.

Identity-aware routing has two tiers:

  • Identity-aware domain (the headline use case). An operator creates an mTLS domain with route-policy enforcement enabled. The Gorouter validates the caller’s Diego instance identity certificate, extracts the caller’s app, space, and org, and enforces route policies with a default-deny model. This is the recommended way to do authenticated Cloud Foundry app-to-app communication over the Gorouter.
  • mTLS domain (a variant). An operator creates an mTLS domain that requires and validates any client certificate signed by a configured certificate authority (CA), then forwards it to the app. Route policies are not enforced, so the backend app does its own authorization. This tier suits external, non-Cloud Foundry clients.

The *.apps.identity domain is to identity-aware routing what *.apps.internal is to container-to-container (C2C) networking: a conventional wildcard domain for app-to-app traffic. The key difference is the data path. Identity-aware traffic goes through the Gorouter, where it is load-balanced and centrally authorized, whereas C2C traffic flows directly between containers over an overlay network.

For direct, low-latency app-to-app traffic over an overlay network instead of through the Gorouter, see Container-to-container networking.

Architecture

Identity-aware routing combines four pieces: per-domain mTLS in the Gorouter, route policies stored by the Cloud Controller, the Diego instance identity that gives each app instance a verifiable certificate, and BOSH DNS for the *.apps.identity wildcard alias.

To understand the components and how they work together, see the following diagram and table.

Identity-aware routing request flow: App A presents its instance identity certificate to the Gorouter, which validates it and enforces route policy before forwarding to App B

Part Function
Gorouter (per-domain mTLS) Terminates mTLS for domains configured under router.domains. For each such domain it:
  • Requires a client certificate and validates it against the domain’s configured CA (ca_certs), independent of the platform-wide client-certificate validation setting.
  • Extracts the caller’s Cloud Foundry identity from the certificate Subject.
  • Enforces the route’s policies, denying the request if no policy allows the caller.
  • Forwards the request to the backend with the X-Forwarded-Client-Cert (XFCC) header.
Cloud Controller Stores route policies and the per-domain enforcement setting. It flattens policies into route options that are synced to Diego so the Gorouter can enforce them.
Diego instance identity Issues every app instance a short-lived identity certificate. The Subject carries the caller’s identity as organizational units, for example CN=<instance-id>, OU=app:<app-guid>, OU=space:<space-guid>, OU=organization:<org-guid>. The certificate and key are available to the app as CF_INSTANCE_CERT and CF_INSTANCE_KEY.
BOSH DNS Resolves the *.apps.identity wildcard alias to the Gorouter so that callers reach the platform’s mTLS listener.

How app-to-app identity-aware routing works

When one app calls another over an identity-aware domain, the request flows through the following steps. The numbers correspond to the architecture diagram above.

  1. The calling app (for example, frontend-app) makes an HTTPS request to the destination route, such as https://backend.apps.identity, presenting its Diego instance identity certificate as the client certificate. The certificate and key are mounted in the container as CF_INSTANCE_CERT and CF_INSTANCE_KEY.
  2. The Gorouter terminates mTLS for the domain and validates the presented certificate against the domain’s configured CA (the instance identity CA).
  3. The Gorouter extracts the caller’s Cloud Foundry identity from the certificate Subject organizational units: OU=app:<app-guid>, OU=space:<space-guid>, and OU=organization:<org-guid>.
  4. The Gorouter checks the destination route’s policies. If no policy allows this caller, the Gorouter denies the request with an HTTP 403 Forbidden response. This is the default-deny model.
  5. If a policy allows the caller, the Gorouter forwards the request to the backend app and sets the X-Forwarded-Client-Cert (XFCC) header so the backend can also see the verified caller identity. For more information, see The client certificate header and identity.

This model is destination-controlled: the policies that decide who may reach a route live on the destination route, not on the caller.

Route policies and the default-deny model

Route policies determine which callers are allowed to reach a route on an identity-aware domain. They are destination-controlled: only a Space Developer in the route’s own space manages them.

Default-deny route policies on *.apps.identity: App A is allowed to reach App B and App C by explicit policy, while App B to App C is denied by default

Enabling enforcement

Route-policy enforcement is turned on when the domain is created, and it is immutable for the life of the domain. An operator or org manager creates the domain with --enforce-route-policies:

$ cf create-shared-domain apps.identity --enforce-route-policies
$ cf create-private-domain my-org apps.identity --enforce-route-policies

You can optionally bound the scope that policy sources might target with --scope, which accepts any, org, or space. The --scope flag is only valid together with --enforce-route-policies:

$ cf create-shared-domain apps.identity --enforce-route-policies --scope org

When enforcement is on, every route on the domain denies all callers until a policy explicitly allows them.

Policy sources

A policy allows one source to reach a route. A source identifies the caller by its verified Cloud Foundry identity and takes one of the following forms:

Source Friendly flag Raw value
A specific app --source-app APP cf:app:<app-guid>
All apps in a space --source-space SPACE cf:space:<space-guid>
All apps in an org --source-org ORG cf:org:<org-guid>
Any authenticated Cloud Foundry caller --source-any cf:any

Managing policies

Use the cf CLI to add, list, and remove route policies. For example, to allow frontend-app to reach the backend route, list the policies on the domain, and then remove the policy:

$ cf add-route-policy apps.identity --hostname backend --source-app frontend-app
$ cf route-policies --domain apps.identity
$ cf remove-route-policy apps.identity --hostname backend --source-app frontend-app

You can express the same source with the raw --source form, for example --source cf:app:<app-guid>. To match a specific path, add --path.

The client certificate header and identity

After the Gorouter validates the caller’s certificate, it passes the certificate — or a digest of it — to the backend app in the X-Forwarded-Client-Cert (XFCC) header. This is the same mechanism Cloud Foundry uses for forwarding client certificates in general. For more information, see Forwarding client certificate to apps.

A router.domains entry sets how the certificate is forwarded with xfcc_format:

Format Header contents Approximate size
raw (default) The full client certificate, base64-encoded PEM. ~1.5 KB
envoy A compact representation, Hash=<sha256>;Subject="<DN>". ~300 B

The backend app reads the certificate Subject organizational units (OU=app:<app-guid>, OU=space:<space-guid>, OU=organization:<org-guid>) to learn the caller’s app, space, and org. On an identity-aware domain, the platform has already validated the certificate and authorized the request, so the XFCC header conveys an identity the app can trust for auditing or finer-grained, app-level decisions.

Consuming the envoy (hashed) XFCC value in Java apps relies on the java-buildpack-client-certificate-mapper (cloudfoundry/java-buildpack-client-certificate-mapper#11). If that support is not yet released in your buildpack, prefer the raw format for Java backends.

Identity-aware routing, C2C networking, and ASGs

Identity-aware routing, container-to-container (C2C) networking, and application security groups (ASGs) all control app connectivity, but they operate at different points and with different identity models.

Identity-aware routing C2C networking ASGs
Data path Through the Gorouter (load-balanced) Direct, over the overlay network Egress firewall (no app-to-app path of its own)
Identity source Verified client certificate (Diego instance identity; app, space, org OUs) Source app GUID, tagged in the VXLAN GBP header Source space
Granularity Caller app, space, or org → a route Source app → destination app Space → destination IP range and ports
Enforcement point Gorouter (per-domain mTLS) VXLAN policy agent on the Diego Cell Diego Cell egress
Default model Deny until a policy allows Deny until a policy allows Deny until an ASG allows
Load balancing and access logs Yes (Gorouter access logs) No (direct connection) Not applicable

In short: use identity-aware routing for north-south app-to-app traffic over the Gorouter with a verified caller identity; use C2C networking for direct, low-latency east-west traffic; and use ASGs for coarse-grained egress control.

External client certificates

Not every caller is a Cloud Foundry app. Partner systems, IoT devices, and other external clients present their own certificates, which do not carry a Diego instance identity. For these callers an operator configures a plain mTLS domain.

In this configuration the operator adds a router.domains entry whose CA (ca_certs) is the external CA that issues the client certificates. The Gorouter requires and validates the client certificate against that CA and forwards it to the backend in the XFCC header. Because there is no Cloud Foundry identity to evaluate, route policies are not used, and the backend app authorizes the request from the certificate it receives.

Do not pass --enforce-route-policies for a domain that serves non-Cloud Foundry certificates. Route policies key off the Cloud Foundry identity organizational units (app, space, org) in a Diego instance identity certificate, which external certificates do not have. Enforcement on such a domain would deny every caller.

Observability

The Gorouter records the outcome of mTLS validation and route-policy enforcement in its access logs. When the following fields are enabled as extra fields in the access-log configuration, each router (RTR) log line can include the verified caller identity and the policy decision:

Field Meaning
caller_cf_app The caller’s app GUID, from the validated client certificate.
caller_cf_space The caller’s space GUID.
caller_cf_org The caller’s org GUID.
route_policy The route-policy rule that matched the request, for example cf:app:<app-guid>. It is - when no rule matched or enforcement is disabled.
tls_sni The TLS Server Name Indication (SNI) value the caller requested.

Each field is - when the request carried no verified identity or the field does not apply. For example, an allowed request to backend.apps.identity records the caller and the matching rule:

... 200 ... tls_sni:"backend.apps.identity" caller_cf_app:"app-guid-123" caller_cf_space:"space-guid-456" caller_cf_org:"org-guid-789" route_policy:"cf:app:app-guid-123"

A request that is denied by the default-deny model records the verified caller but no matching rule, with an HTTP 403 status:

... 403 ... tls_sni:"backend.apps.identity" caller_cf_app:"app-guid-123" caller_cf_space:"space-guid-456" caller_cf_org:"org-guid-789" route_policy:"-"

These fields let operators audit who reached a route and which policy decisions allowed or denied traffic.

Create a pull request or raise an issue on the source for this page in GitHub