| Item | Link |
|---|---|
| Tracking Issue | cloudfoundry/community#1481 |
| RFC | cloudfoundry/community#1438 |
| routing-release | cloudfoundry/routing-release#535 |
| cloud_controller_ng | cloudfoundry/cloud_controller_ng#4910 |
| capi-release | cloudfoundry/capi-release#625 |
| CLI | cloudfoundry/cli#3758 (draft) |
- A BOSH director (bosh-lite works)
cf-deploymentcloned from main- Go toolchain (for running CLI from PR branch)
# routing-release
git clone --recurse-submodules https://github.com/cloudfoundry/routing-release.git
cd routing-release
git checkout feature/app-to-app-mtls-routing
bosh create-release --force --timestamp-version --name=routing
bosh upload-release
cd ..
# capi-release
git clone --recurse-submodules https://github.com/cloudfoundry/capi-release.git
cd capi-release
git checkout feature/app-to-app-mtls-routing
bosh create-release --force --timestamp-version --name=capi
bosh upload-release
cd ..Deploy using stock cf-deployment with the following ops-file saved as ops-enable-mtls-app-routing.yml:
---
# Use dev routing release
- type: replace
path: /releases/name=routing
value:
name: routing
version: latest
# Use dev capi release
- type: replace
path: /releases/name=capi
value:
name: capi
version: latest
# BOSH DNS alias: *.apps.identity -> router instances
- type: replace
path: /addons/name=bosh-dns-aliases/jobs/name=bosh-dns-aliases/properties/aliases/-
value:
domain: _.apps.identity
targets:
- deployment: cf
domain: bosh
instance_group: router
network: default
query: '*'
# Configure mTLS domain on gorouter
- type: replace
path: /instance_groups/name=router/jobs/name=gorouter/properties/router/domains?
value:
- name: "*.apps.identity"
ca_certs: ((diego_instance_identity_ca.certificate))
forwarded_client_cert: sanitize_set
xfcc_format: envoy
# Add *.apps.identity TLS cert to gorouter (served via SNI)
- type: replace
path: /instance_groups/name=router/jobs/name=gorouter/properties/router/tls_pem/-
value:
cert_chain: ((apps_identity_router_tls.certificate))
private_key: ((apps_identity_router_tls.private_key))
# Trust apps_identity_ca in app containers
- type: replace
path: /instance_groups/name=compute/jobs/name=cflinuxfs4-rootfs-setup/properties/cflinuxfs4-rootfs/trusted_certs/-
value: ((apps_identity_ca.certificate))
- type: replace
path: /instance_groups/name=compute/jobs/name=rep/properties/containers/trusted_ca_certificates/-
value: ((apps_identity_ca.certificate))
# BOSH variables
- type: replace
path: /variables/-
value:
name: apps_identity_ca
type: certificate
options:
common_name: apps-identity-ca
is_ca: true
- type: replace
path: /variables/-
value:
name: apps_identity_router_tls
type: certificate
options:
ca: apps_identity_ca
common_name: "*.apps.identity"
alternative_names:
- "*.apps.identity"
extended_key_usage:
- server_authbosh -d cf deploy cf-deployment/cf-deployment.yml \
-o cf-deployment/operations/bosh-lite.yml \
-o ops-enable-mtls-app-routing.yml \
--non-interactivegit clone https://github.com/cloudfoundry/cli.git
cd cli
git checkout feature/app-to-app-mtls-routing
# Use "go run" to invoke the CLI directly:
go run . login -a https://api.<system-domain> --skip-ssl-validation
go run . target -o <org> -s <space>For convenience, create an alias:
alias cf='go run .'# Push two simple apps (any app works)
cf push frontend
cf push backend
# Create the shared mTLS domain with access rule enforcement
cf create-shared-domain apps.identity --enforce-access-rules --scope any
# Map the backend to the mTLS domain
cf map-route backend apps.identity --hostname backendGIVEN backend has an mTLS route and no route policy exists
WHEN frontend calls backend using its instance identity cert
THEN 403 Forbidden
cf ssh frontend -c 'curl -s https://backend.apps.identity \
--cert "${CF_INSTANCE_CERT}" --key "${CF_INSTANCE_KEY}" \
--cacert <(cat /etc/cf-system-certificates/*)'
# Expected: 403 ForbiddenGIVEN a route policy allows the frontend app
WHEN frontend calls backend
THEN 200 OK with X-Forwarded-Client-Cert header delivered to backend
cf add-route-policy apps.identity --source-app frontend --hostname backend
cf ssh frontend -c 'curl -s https://backend.apps.identity \
--cert "${CF_INSTANCE_CERT}" --key "${CF_INSTANCE_KEY}" \
--cacert <(cat /etc/cf-system-certificates/*)'
# Expected: 200 OKGIVEN a route policy allows an entire space
WHEN any app in that space calls backend
THEN 200 OK
cf add-route-policy apps.identity \
--source "cf:space:$(cf space <space-name> --guid)" \
--hostname backend
cf ssh any-app-in-that-space -c 'curl -s https://backend.apps.identity \
--cert "${CF_INSTANCE_CERT}" --key "${CF_INSTANCE_KEY}" \
--cacert <(cat /etc/cf-system-certificates/*)'
# Expected: 200 OKGIVEN a route policy only allows frontend
WHEN a different (unauthorized) app calls backend
THEN 403 Forbidden
cf ssh unauthorized-app -c 'curl -s https://backend.apps.identity \
--cert "${CF_INSTANCE_CERT}" --key "${CF_INSTANCE_KEY}" \
--cacert <(cat /etc/cf-system-certificates/*)'
# Expected: 403 ForbiddenGIVEN the feature is deployed
WHEN normal HTTPS traffic flows to non-mTLS domains
THEN behavior is unchanged
curl -s https://frontend.<system-domain>
# Expected: 200 OK (normal routing unaffected)cf remove-route-policy apps.identity --source-app frontend --hostname backend -fAll component PRs are independently safe to merge — the feature is dormant unless the operator deploys with the ops-file and creates the shared domain with --enforce-access-rules. No strict ordering required, but recommend merging around the same time to minimize partial-support windows.