Skip to content

Add mTLS app-to-app routing support (RFC draft)#4910

Draft
rkoster wants to merge 11 commits intomainfrom
feature/app-to-app-mtls-routing
Draft

Add mTLS app-to-app routing support (RFC draft)#4910
rkoster wants to merge 11 commits intomainfrom
feature/app-to-app-mtls-routing

Conversation

@rkoster
Copy link
Copy Markdown
Contributor

@rkoster rkoster commented Mar 5, 2026

Summary

Adds RFC-0027 compliant mTLS authorization options to routes for app-to-app mTLS routing.

Note: This PR is a draft because the RFC for App-to-App mTLS Routing has not been approved yet.

Features

  • New flat mTLS options in route options (RFC-0027 compliant):
    • mtls_allowed_apps: Comma-separated app GUIDs
    • mtls_allowed_spaces: Comma-separated space GUIDs
    • mtls_allowed_orgs: Comma-separated org GUIDs
    • mtls_allow_any: Boolean to allow any authenticated app
  • GUID existence validation against database
  • Mutual exclusivity enforcement (mtls_allow_any vs specific GUIDs)
  • Gated by app_to_app_mtls_routing feature flag

API Example

POST /v3/routes
{
  "host": "my-backend",
  "relationships": {
    "domain": {"data": {"guid": "mtls-domain-guid"}},
    "space": {"data": {"guid": "space-guid"}}
  },
  "options": {
    "mtls_allowed_apps": "frontend-app-guid-1,frontend-app-guid-2",
    "mtls_allowed_spaces": "trusted-space-guid",
    "mtls_allowed_orgs": "trusted-org-guid"
  }
}

Files Changed

  • app/messages/route_options_message.rb - Validation for mTLS route options
  • spec/unit/messages/route_options_message_spec.rb - Unit tests

Related PRs

rkoster added 5 commits March 5, 2026 08:33
- Add app_to_app_mtls_routing feature flag (default: false)
- Add allowed_sources to RouteOptionsMessage with validation
- Validate allowed_sources structure (apps/spaces/orgs arrays, any boolean)
- Validate that app/space/org GUIDs exist in database
- Enforce mutual exclusivity of 'any' with apps/spaces/orgs lists
Tests cover:
- Feature flag disabled: allowed_sources rejected as unknown field
- Structure validation: object type, valid keys, array types, boolean any
- any exclusivity: cannot combine any:true with apps/spaces/orgs lists
- GUID existence validation: apps, spaces, orgs must exist in database
- Combined options: allowed_sources works with loadbalancing
Rails parses JSON with symbol keys, but validation was comparing
against string keys. Add normalized_allowed_sources helper to
transform keys to strings for consistent comparison.
Rename the route options field from allowed_sources to
mtls_allowed_sources for better clarity about its purpose
in mTLS app-to-app routing.

Updates RouteOptionsMessage to use the new field name in:
- Allowed keys registration
- Feature flag gating
- Validation methods
- All related tests
Change from nested mtls_allowed_sources object to flat options:
- mtls_allowed_apps: comma-separated app GUIDs (string)
- mtls_allowed_spaces: comma-separated space GUIDs (string)
- mtls_allowed_orgs: comma-separated org GUIDs (string)
- mtls_allow_any: boolean (true/false)

This complies with RFC-0027 which requires route options to only use
numbers, strings, and boolean values (no nested objects or arrays).
rkoster added 6 commits April 9, 2026 07:52
Replace POC route-options-based mTLS implementation with RFC-compliant architecture:

Domain model changes:
- Add enforce_access_rules (boolean) and access_rules_scope (any/org/space) to domains
- Fields are immutable after domain creation
- Update DomainCreateMessage, DomainPresenter, and DomainCreate action

Access Rules resource:
- New /v3/access_rules API with full CRUD operations
- RouteAccessRule model with guid, name, selector, route_id
- Selector format: cf:app:<uuid>, cf:space:<uuid>, cf:org:<uuid>, or cf:any
- Enforce cf:any exclusivity and per-route name/selector uniqueness
- Space Developer can manage rules for routes in their space

Diego sync path:
- Inject access_scope and access_rules into route options for GoRouter
- Filter internal mTLS keys (access_scope, access_rules) from public /v3/routes API
- Add access_rules to eager load to avoid N+1 queries

Tests:
- Unit tests for AccessRuleCreateMessage (selector validation, cf:any rules)
- Request specs for /v3/access_rules CRUD (create, show, list, delete, metadata update)
- Updated domain_create_message_spec for enforce_access_rules validation
- Updated routing_info_spec to verify mTLS options injection
- Updated route_presenter_spec to verify internal keys are filtered

Remove POC artifacts:
- Remove app_to_app_mtls_routing feature flag
- Remove mtls_allowed_* keys from route_options_message
- Replace non-existent readable_space_scoped_space_guids_query with proper subquery
- Use readable_space_scoped_spaces_query for non-global readers
- Handle global readers separately with all routes
- Add after_create and after_destroy callbacks to touch associated processes
- Updates process.updated_at to trigger Diego ProcessesSync immediately
- Eliminates 30-second wait for access rule changes to propagate to GoRouter
- Add comprehensive unit tests for callbacks and validations
- Ensure RouteAccessRule model is loaded in app/models.rb

This enables automatic synchronization of access rules to Diego/GoRouter
within seconds instead of requiring manual app restarts or waiting for
the next sync cycle.
- Add include parameter support to AccessRulesListMessage
- Refactor IncludeAccessRuleSelectorResourceDecorator to match RFC format:
  - Return separate arrays for apps, spaces, organizations instead of selector_resources
  - Include full resource details using appropriate presenters
  - Batch resource fetching by type with eager loading
  - Auto-deduplicate resources
  - Gracefully handle stale/missing resources
- Wire up decorator to AccessRulesController
- Add comprehensive request specs for include=selector_resource

Fixes: uninitialized constant error by adding proper require statement
Implement space-based filtering for access rules endpoint to enable
querying all access rules within a given space using ?space_guids=<guid>
query parameter.

Changes:
- Add space_guids to AccessRulesListMessage with array validation
- Implement space filtering in AccessRulesController#build_dataset
- Add comprehensive unit tests for AccessRulesListMessage
- Add request specs for single/multiple space filtering and combinations
- Follow existing CAPI patterns for space_guids filtering

The filter joins through the routes table to filter access rules by
the space_id of their associated routes.
Add support for including route resources when listing access rules
via the ?include=route query parameter.

Changes:
- Create IncludeAccessRuleRouteDecorator to handle route inclusion
- Wire up decorator in AccessRulesController
- Add comprehensive request specs for include=route
- Test single/multiple routes, uniqueness, and combining with selector_resource
- Follow existing CAPI decorator patterns for resource inclusion

The decorator fetches and presents Route resources referenced by the
access rules, adding them to the 'included' section of the response.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant