Skip to content

feat(core)!: serve platform services on connect-go v2 and authenticate before decoding - #4216

Open
alkalescent wants to merge 14 commits into
mainfrom
fix/connect-authn-request-gate
Open

alkalescent wants to merge 14 commits into
mainfrom
fix/connect-authn-request-gate

Conversation

@alkalescent

@alkalescent alkalescent commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Proposed Changes

Depends on #4237. After that protocol/go release, this PR imports the v2 stubs from protocol/go and drops service/internal/connectv2 and buf.gen.connectv2.yaml.

  • Authenticate before reading the body. connect-go v1 runs server interceptors after it reads and unmarshals a unary request. For services on connect-go v1, authentication moves into a request gate (connect-go v1.21.0) that runs once headers arrive; ConnectAuthNInterceptor skips authentication after the gate because validating the same DPoP proof twice trips jti replay detection. connect-go v2 runs server interceptors before it reads the body, so v2 services authenticate in ConnectAuthNInterceptorV2. Both read the HTTP method for DPoP htm binding.
  • Platform services on connect-go v2. Policy, authorization, entity resolution, KAS, well-known configuration, and health register on connect-go v2. Their v2 stubs are generated into service/internal/connectv2 (buf.gen.connectv2.yaml, package suffix connectv2), so protocol/go and the SDK stay on connect-go v1 and do not change.
  • v1 and v2 side by side. The service registry accepts ConnectRPCRegisterFunc (v2) next to ConnectRPCFunc (v1), so services built on the platform can move one at a time. Each v2 service gets its own server per mux with v2 forms of the authentication, authorization, IPC, client IP, validation, audit, and tracing interceptors. Authorization reads the request first only for unary procedures with a resource resolver and hands the same message to the handler; resolvers now receive the decoded proto.Message.
  • Unchanged wire errors. connect-go v2 sends only locally created *connect.Error values as written. connectcompat.ServerInterceptor sends every other error, including errors from SDK calls and db.StatusifyError, with the code, message, details, and metadata connect-go v1 sent, and connectcompat.CodeOf reads codes from both versions where handlers inspect SDK errors. The v2 validation interceptor returns the same message and violations as connectrpc.com/validate v0.6.0; validate releases that support v2 require protovalidate 1.4, which changes validation error messages.
  • Read limits on v2. External v2 services default to server.grpc.maxRecvMsgSize from fix(core): limit request message size on external Connect handlers #4215, with gzip decompression bounded at the same limit. Services set their own limits with ConnectRPCMountOptions, ConnectReadLimitOptions, and ConnectProcedureReadLimits. In-process calls stay unlimited, as on v1. The gzip bound no longer overflows when the limit is math.MaxInt64, so requests at that limit are accepted on v1 and v2.
  • Extra interceptors in both forms. WithConnectServerInterceptors, WithIPCServerInterceptors, and InterceptorFactory.ServerFactory take an interceptor's v1 and v2 forms. A service cannot be registered while an extra interceptor lacks the form for its version, and startup fails, so an interceptor never silently skips a service. WithConnectInterceptors and WithIPCInterceptors are deprecated.
  • Dependencies. connect-go v1.21.0 is the first release with WithRequestGate, and per chore(ci): limit dependabot version updates on published modules to internal deps #4129 the bump is limited to service/go.mod; it covers the service part of fix(deps): bump the external group across 1 directory with 36 updates #4124. connect-go v2, grpchealth/v2, and otelconnect v0.12.0 require Go 1.26, so go.work and service/go.mod move to Go 1.26. Other modules keep their Go versions.

Breaking changes:

  • service requires Go 1.26.
  • Platform service handlers, including the exported entity resolution implementations, take and return plain messages.
  • Startup fails while WithConnectInterceptors, WithIPCInterceptors, or a factory without ServerFactory is used, because those interceptors cannot run on the v2 platform services.
  • Health registers with connectrpc.com/grpchealth/v2.
  • Authorization resolvers receive proto.Message instead of connect.AnyRequest.
  • otelconnect v0.12.0 follows OpenTelemetry RPC semantic conventions v1.43.0 and records one rpc.server.call.duration metric.

Behavior changes:

  • Unauthenticated requests with malformed bodies return 401 instead of 400.
  • Rejections from the v1 gate produce no span; rejections from v2 interceptors are traced.
  • gRPC clients receive DPoP challenges from v2 services. On v1, Go's HTTP/2 server drops WWW-Authenticate from the trailers that carry gRPC error metadata.
  • On HTTP/1.1, Go closes the connection after an early rejection when more than 256 KiB of the body is unread, so a client still uploading can see a connection error instead of the 401.

Services that stay on ConnectRPCFunc keep working behind the gate and read limit, but any extra interceptors they install need a v2 form. Generated code sits in its own commit.

Checklist

  • I have added or updated unit tests
  • I have added or updated integration tests (if appropriate)
  • I have added or updated documentation

Testing Instructions

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
connect-go v2 and the matching otelconnect, validate, grpchealth, and grpcreflect releases require Go 1.26. Go 1.25 is no longer supported upstream. Other modules keep their go directives.

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
otelconnect v0.12.0 serves both connect-go v1 and v2. It removes WithoutTraceEvents and WithoutServerPeerAttributes because both behaviors are now the default, follows OpenTelemetry RPC semantic conventions v1.43.0, and records one rpc.server.call.duration metric.

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
buf.gen.connectv2.yaml generates connect-go v2 service stubs into service/internal/connectv2 with the connectv2 package suffix. They import the messages from protocol/go, so protocol/go and its consumers are unchanged.

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
… connect-go versions

Authorization resolvers receive the decoded request message instead of a connect-go v1 request, and the IPC, audit, and client IP interceptors move their logic into helpers that take plain headers and peer addresses. Behavior is unchanged.

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
Adds connect-go v2 forms of the authentication, authorization, IPC, client IP, audit, tracing, and validation interceptors. v2 runs server interceptors before it reads the request body, so authentication uses only the headers. Authorization reads the message first only for unary procedures with a registered resource resolver, and the handler receives that message unchanged.

connectcompat sends handler errors with the code, message, details, and metadata that connect-go v1 sent, and its CodeOf reads codes from both versions. ReadLimitMountOptions caps v2 request messages and bounds gzip decompression at the same limit.

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
Services can set ConnectRPCRegisterFunc to serve on connect-go v2 instead of ConnectRPCFunc, with ConnectRPCMountOptions for HTTP options such as read limits. Each v2 service gets its own server per mux with the platform's v2 interceptors, so v1 and v2 services share the external and in-process servers. External v2 services default to server.grpc.maxRecvMsgSize; in-process v2 services keep unlimited reads.

WithConnectServerInterceptors, WithIPCServerInterceptors, and InterceptorFactory.ServerFactory take interceptors in both connect-go forms. A service cannot be registered while an extra interceptor lacks the form for its version, and startup fails, so an interceptor is never skipped. WithConnectInterceptors and WithIPCInterceptors are deprecated.

BREAKING CHANGE: startup fails when an interceptor passed through WithConnectInterceptors, WithIPCInterceptors, or a factory without ServerFactory would not cover a connect-go v2 service.

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
Policy, authorization, entity resolution, KAS, well-known configuration, and health now register on connect-go v2 with the generated v2 stubs. Handlers take and return plain messages. Code that reads codes from SDK errors uses connectcompat.CodeOf, and connectcompat keeps the errors clients receive unchanged.

BREAKING CHANGE: handler methods of platform services, including the exported entity resolution implementations, take and return plain messages instead of connect.Request and connect.Response, and the health registration uses connectrpc.com/grpchealth/v2.

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
… limits

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
@github-actions github-actions Bot added the comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) label Oct 13, 2026
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 115 files, which is 15 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: ac874627-83bf-4ae8-b78f-020b34a05ee3
📥 Commits

Reviewing files that changed from the base of the PR and between b048476 and 9f69c13.

⛔ Files ignored due to path filters: 2
  • go.work is excluded by !**/*.work
  • service/go.sum is excluded by !**/*.sum
📒 Files selected for processing: 115
  • .gitattributes
  • Makefile
  • buf.gen.connectv2.yaml
  • docs/Configuring.md
  • service/README.md
  • service/authorization/authorization.go
  • service/authorization/authorization_entitleable_test.go
  • service/authorization/authorization_test.go
  • service/authorization/v2/authorization.go
  • service/authorization/v2/helpers.go
  • service/authorization/v2/validation.go
  • service/authorization/v2/validation_test.go
  • service/entityresolution/claims/entity_resolution.go
  • service/entityresolution/claims/v2/entity_resolution.go
  • service/entityresolution/claims/v2/entity_resolution_test.go
  • service/entityresolution/entityresolution.go
  • service/entityresolution/integration/claims_test.go
  • service/entityresolution/integration/entity_chain_comparison_test.go
  • service/entityresolution/integration/internal/chain_contract_tests.go
  • service/entityresolution/integration/internal/contract_framework_test.go
  • service/entityresolution/integration/internal/contract_tests.go
  • service/entityresolution/integration/internal/resolved_token_chain_contract.go
  • service/entityresolution/integration/multistrategy_comprehensive_test.go
  • service/entityresolution/integration/multistrategy_test.go
  • service/entityresolution/integration/multistrategy_v2_serialization_test.go
  • service/entityresolution/keycloak/entity_resolution.go
  • service/entityresolution/keycloak/entity_resolution_test.go
  • service/entityresolution/keycloak/v2/entity_resolution.go
  • service/entityresolution/keycloak/v2/entity_resolution_test.go
  • service/entityresolution/multi-strategy/registration.go
  • service/entityresolution/multi-strategy/registration_test.go
  • service/entityresolution/multi-strategy/v2/registration.go
  • service/entityresolution/multi-strategy/v2/registration_test.go
  • service/entityresolution/v2/entity_resolution.go
  • service/go.mod
  • service/health/health.go
  • service/health/health_test.go
  • service/internal/auth/README.md
  • service/internal/auth/authn.go
  • service/internal/auth/authz/resolver.go
  • service/internal/auth/authz/resolver_test.go
  • service/internal/auth/connect_gate.go
  • service/internal/auth/connect_gate_test.go
  • service/internal/auth/connect_v2.go
  • service/internal/auth/connect_v2_test.go
  • service/internal/auth/interceptor_authz_test.go
  • service/internal/auth/interceptor_authz_v2_test.go
  • service/internal/connectcompat/connectcompat.go
  • service/internal/connectcompat/connectcompat_test.go
  • service/internal/connectv2/authorization/authorizationconnectv2/authorization.connect.go
  • service/internal/connectv2/authorization/v2/authorizationv2connectv2/authorization.connect.go
  • service/internal/connectv2/entityresolution/entityresolutionconnectv2/entity_resolution.connect.go
  • service/internal/connectv2/entityresolution/v2/entityresolutionv2connectv2/entity_resolution.connect.go
  • service/internal/connectv2/kas/kasconnectv2/kas.connect.go
  • service/internal/connectv2/policy/actions/actionsconnectv2/actions.connect.go
  • service/internal/connectv2/policy/attributes/attributesconnectv2/attributes.connect.go
  • service/internal/connectv2/policy/dynamicvaluemapping/dynamicvaluemappingconnectv2/dynamic_value_mapping.connect.go
  • service/internal/connectv2/policy/kasregistry/kasregistryconnectv2/key_access_server_registry.connect.go
  • service/internal/connectv2/policy/keymanagement/keymanagementconnectv2/key_management.connect.go
  • service/internal/connectv2/policy/namespaces/namespacesconnectv2/namespaces.connect.go
  • service/internal/connectv2/policy/obligations/obligationsconnectv2/obligations.connect.go
  • service/internal/connectv2/policy/registeredresources/registeredresourcesconnectv2/registered_resources.connect.go
  • service/internal/connectv2/policy/resourcemapping/resourcemappingconnectv2/resource_mapping.connect.go
  • service/internal/connectv2/policy/subjectmapping/subjectmappingconnectv2/subject_mapping.connect.go
  • service/internal/connectv2/policy/unsafe/unsafeconnectv2/unsafe.connect.go
  • service/internal/connectv2/wellknownconfiguration/wellknownconfigurationconnectv2/wellknown_configuration.connect.go
  • service/internal/server/connect_limits.go
  • service/internal/server/connect_limits_test.go
  • service/internal/server/connect_limits_v2_test.go
  • service/internal/server/connect_v2.go
  • service/internal/server/connect_v2_test.go
  • service/internal/server/realip/realip.go
  • service/internal/server/realip/realip_test.go
  • service/internal/server/realip/realip_v2.go
  • service/internal/server/realip/realip_v2_test.go
  • service/internal/server/server.go
  • service/internal/server/server_test.go
  • service/internal/server/validate_v2.go
  • service/internal/server/validate_v2_test.go
  • service/kas/access/accessPdp.go
  • service/kas/access/publicKey.go
  • service/kas/access/publicKey_test.go
  • service/kas/access/rewrap.go
  • service/kas/access/rewrap_test.go
  • service/kas/kas.go
  • service/logger/audit/contextServerInterceptor.go
  • service/logger/audit/context_server_interceptor_v2_test.go
  • service/pkg/server/connect_interceptors_test.go
  • service/pkg/server/options.go
  • service/pkg/server/services.go
  • service/pkg/server/start.go
  • service/pkg/serviceregistry/connect_limits.go
  • service/pkg/serviceregistry/connect_registration_test.go
  • service/pkg/serviceregistry/serviceregistry.go
  • service/policy/actions/actions.go
  • service/policy/actions/actions_test.go
  • service/policy/attributes/attributes.go
  • service/policy/dynamicvaluemapping/dynamic_value_mapping.go
  • service/policy/kasregistry/authz_resolver.go
  • service/policy/kasregistry/authz_resolver_test.go
  • service/policy/kasregistry/key_access_server_registry.go
  • service/policy/keymanagement/key_management.go
  • service/policy/namespaces/namespaces.go
  • service/policy/obligations/obligations.go
  • service/policy/registeredresources/registered_resources.go
  • service/policy/registeredresources/registered_resources_test.go
  • service/policy/resourcemapping/resource_mapping.go
  • service/policy/resourcemapping/resource_mapping_test.go
  • service/policy/subjectmapping/subject_mapping.go
  • service/policy/subjectmapping/subject_mapping_test.go
  • service/policy/unsafe/unsafe.go
  • service/tracing/connect_interceptor.go
  • service/tracing/connect_interceptor_test.go
  • service/wellknownconfiguration/wellknown_configuration.go
  • service/wellknownconfiguration/wellknown_configuration_test.go

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 339.483171ms
Throughput 294.57 requests/second

TDF3 Benchmark Results

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 38.847275707s
Average Latency 387.352943ms
Throughput 128.71 requests/second

Base automatically changed from fix/connect-request-size-limit to main October 14, 2026 17:40
…uest-gate

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>

# Conflicts:
#	docs/Configuring.md
#	service/internal/server/connect_limits.go
#	service/internal/server/connect_limits_test.go
#	service/internal/server/server.go
#	service/wellknownconfiguration/wellknown_configuration_test.go
Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 342.844975ms
Throughput 291.68 requests/second

TDF3 Benchmark Results

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 40.60802177s
Average Latency 405.222403ms
Throughput 123.13 requests/second

…uest-gate

Rewrap reads key lookup error codes with connectcompat.CodeOf because SDK errors are connect-go v1, and the new Rewrap tests call the v2 handler signature.

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
@alkalescent
alkalescent marked this pull request as ready for review October 16, 2026 17:22
@alkalescent
alkalescent requested review from a team as code owners October 16, 2026 17:22
@alkalescent
alkalescent requested review from a team as code owners October 16, 2026 17:22
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 447.083886ms
Throughput 223.67 requests/second

TDF3 Benchmark Results

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 48.832409859s
Average Latency 487.414043ms
Throughput 102.39 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Govulncheck found vulnerabilities ⚠️

The following modules have known vulnerabilities:

  • otdfctl
  • sdk
  • service
  • tests-bdd

See the workflow run for details.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:authorization comp:kas Key Access Server comp:middleware:auth comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) docs Documentation size/xl

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant