Skip to content

RFC: App-to-App mTLS via GoRouter#1438

Open
rkoster wants to merge 2 commits intomainfrom
rfc-app-to-app-mtls-routing
Open

RFC: App-to-App mTLS via GoRouter#1438
rkoster wants to merge 2 commits intomainfrom
rfc-app-to-app-mtls-routing

Conversation

@rkoster
Copy link
Contributor

@rkoster rkoster commented Feb 17, 2026

Summary

This RFC proposes enabling authenticated and authorized app-to-app communication via GoRouter using mutual TLS (mTLS).

View the full RFC

Applications connect to a shared internal domain (apps.mtls.internal), where GoRouter:

  • Requires and validates client certificates (Instance Identity)
  • Enforces per-route access control using allowed_sources
  • Follows a default-deny model (aligned with C2C network policies)

Key Points

  • No new infrastructure: Uses existing GoRouter with domain-specific mTLS configuration
  • Default-deny security: Routes blocked unless explicitly allowed via allowed_sources
  • Internal-only domain: apps.mtls.internal is a separate domain tree, avoiding conflicts with existing apps.internal routes
  • Depends on RFC-0027: Route options framework required for allowed_sources support

Implementation Phases

  • Phase 1a (mTLS Infrastructure): GoRouter validates client certificates for the mTLS domain
  • Phase 1b (Authorization Enforcement): Per-route access control via allowed_sources (co-requisite with 1a)
  • Phase 2 (Optional): Egress HTTP proxy on port 8888 for simplified client adoption

cc @cloudfoundry/toc @cloudfoundry/wg-app-runtime-interfaces

@rkoster rkoster force-pushed the rfc-app-to-app-mtls-routing branch from bce2e1d to 5557aeb Compare February 17, 2026 15:47
@rkoster rkoster added toc rfc CFF community RFC labels Feb 17, 2026
@rkoster rkoster requested review from a team, Gerg, beyhan, cweibel and stephanme and removed request for a team February 17, 2026 15:55
@silvestre
Copy link
Member

I really like this proposal.

Just to be sure: It would be still possible to have an apps.mtls.internal route allowing access for any source app, so that the authorization check could be done in the app, right?

One use-case would be in the app-autoscaler service, where we expose an mTLS endpoint but check the authorization by determining if the app is bound to an autoscaler service instance, which is dynamic information we could not determine during route creation.

Enable authenticated and authorized app-to-app communication via GoRouter
using mutual TLS (mTLS). Applications connect to a shared internal domain
(apps.mtls.internal), where GoRouter validates client certificates and
enforces per-route access control using a default-deny model.

Key features:
- Phase 1a: Domain-specific mTLS in GoRouter (validates instance identity)
- Phase 1b: Authorization enforcement via allowed_sources route option
- Phase 2 (optional): Egress HTTP proxy for simplified client adoption

Depends on RFC-0027 (Generic Per-Route Features) for route options support.
@rkoster rkoster force-pushed the rfc-app-to-app-mtls-routing branch from 5557aeb to 8f3900a Compare February 17, 2026 19:04
@rkoster
Copy link
Contributor Author

rkoster commented Feb 17, 2026

I really like this proposal.

Just to be sure: It would be still possible to have an apps.mtls.internal route allowing access for any source app, so that the authorization check could be done in the app, right?

One use-case would be in the app-autoscaler service, where we expose an mTLS endpoint but check the authorization by determining if the app is bound to an autoscaler service instance, which is dynamic information we could not determine during route creation.

@silvestre I have update the RFC with:

applications:
- name: autoscaler-api
  routes:
  - route: autoscaler.apps.mtls.internal
    options:
      allowed_sources:
        any: true


## Proposal

### Architecture Overview
Copy link
Contributor

Choose a reason for hiding this comment

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

Hey @rkoster, I think this proposal is a great enhancement for app developers.

Do you think we could also integrate an operator-switch for people deploying a TLS-terminating reverse-proxy in front of gorouter? This proxy would need to take some parts of the logic, and set the XFCC header. The per-route logic would be similar, but gorouter gets the data from the header instead of the actual TLS handshake.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why would you want to use a TLS-terminating reverse-proxy in front of gorouter for app to app traffic? The idea is that bosh dns would point app 2 app traffic directly at the gorouters. Traffic would stay on the private network. How would bosh dns even know about this reverse-proxy? The idea is to make this feature self contained within CF.

@theghost5800
Copy link
Contributor

This idea is really interesting but will be possible to have communication to app containers on different ports or different protocol than http?

Give credit to Beyhan and Max for the initial work on this RFC
@rkoster
Copy link
Contributor Author

rkoster commented Feb 19, 2026

This idea is really interesting but will be possible to have communication to app containers on different ports or different protocol than http?

This RFC currently focuses on HTTP traffic via GoRouter, but non-HTTP protocol support is an interesting future direction.

Current constraints:

  • GoRouter uses Go's httputil.ReverseProxy which handles HTTP semantics (headers, paths, etc.)
  • Caller identity is forwarded via the XFCC HTTP header, which doesn't exist for raw TCP
  • GoRouter does not currently support HTTP CONNECT method for tunneling

What would be needed for non-HTTP support:

  1. HTTP CONNECT tunneling in GoRouter: GoRouter would need to detect CONNECT requests, validate mTLS + allowed_sources, then hijack the connection and relay raw TCP bytes to the backend. The pattern exists (similar to WebSocket upgrades), but would require new implementation.
  2. Identity forwarding challenge: Inside a TCP tunnel there's no XFCC header. Options include:
  • PROXY protocol v2 (GoRouter sends client cert info as TLV before the TCP stream)
  • Backend also requires mTLS and validates the client cert directly
  • Application-layer identity (less secure)
  1. Envoy egress proxy: The Phase 2 egress proxy (Envoy) already supports HTTP CONNECT tunneling, so apps could potentially use CONNECT backend.apps.mtls.internal:5432 to tunnel arbitrary protocols. But GoRouter still needs to support CONNECT for this to work end-to-end.

For now, this is out of scope to keep the RFC focused and achievable. But feel free to create a follow up RFC for Non-HTTP use cases.

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: Inbox

Development

Successfully merging this pull request may close these issues.

4 participants

Comments