diff --git a/http-routing.html.md.erb b/http-routing.html.md.erb index e42eea93..c87aa7f3 100644 --- a/http-routing.html.md.erb +++ b/http-routing.html.md.erb @@ -228,6 +228,10 @@ data path must trust that the back-end component has not allowed the header to b If you configure the load balancer to terminate TLS and set the XFCC header from the received client certificate, you must also configure the load balancer to strip this header if it is present in client requests. This configuration is required to prevent spoofing of the client certificate. +
+To require and validate client certificates on a per-domain basis and enforce identity-based route policies, see Identity-aware routing. +
+ The following sections describe supported deployment configurations. <% if vars.platform_code == 'CF' %> diff --git a/identity-aware-routing.html.md.erb b/identity-aware-routing.html.md.erb new file mode 100644 index 00000000..a1a13514 --- /dev/null +++ b/identity-aware-routing.html.md.erb @@ -0,0 +1,308 @@ +--- +title: Identity-aware routing +owner: CF for VMs Networking +--- + +This topic provides you with an overview of how identity-aware routing works in <%= vars.app_runtime_first %>. + +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 <%= vars.app_runtime_abbr %> 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-<%= vars.app_runtime_abbr %> 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. + + + +| Part | +Function | +
|---|---|
| Gorouter (per-domain mTLS) | +Terminates mTLS for domains configured under router.domains. For each such domain it:
+
|
+
| 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. |
+
+$ 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 may 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 <%= vars.app_runtime_abbr %> 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 <%= vars.app_runtime_abbr %> caller | +--source-any |
+ cf:any |
+
+$ 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:
| 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 | +
+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 | +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 | +
+Do not pass --enforce-route-policies for a domain that serves non-<%= vars.app_runtime_abbr %> certificates. Route policies key off the <%= vars.app_runtime_abbr %> 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.
+
| 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. | +
+... 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. + + +## Related reading + +* [RFC-0055: Identity-Aware Routing for Gorouter](https://github.com/cloudfoundry/community/blob/main/toc/rfc/rfc-0055-identity-aware-routing-for-gorouter.md) +* Container-to-container networking +* HTTP routing: Forwarding client certificate to apps +* [Configuring identity-aware routing](../devguide/deploy-apps/identity-aware-routing.html) (developer how-to) +* [Enabling identity-aware routing](../deploying/cf-deployment/enable-identity-aware-routing.html) (operator setup) diff --git a/images/identity-aware-routing-arch.mmd b/images/identity-aware-routing-arch.mmd new file mode 100644 index 00000000..95705309 --- /dev/null +++ b/images/identity-aware-routing-arch.mmd @@ -0,0 +1,14 @@ +flowchart LR + A["App A
+To route app-to-app traffic through the Gorouter with platform-enforced, identity-based authorization (rather than a direct overlay network), see Identity-aware routing. +
+ ## Architecture