Skip to content

[Bug bash] Streaming RPCs skip authorization; only login is checked. #3231

Closed

Description

Streaming RPCs skip authorization; only login is checked.

The stream interceptor chain in main.go has apiauthn and preview but no authz interceptor. Because reflection.Register(mux) is enabled, any principal that can log in (with the Google provider, any Google account) can list the API. Worse, the documented promise "an RPC with no rule is denied" doesn't hold for streams, so any streaming RPC added later would skip authorization silently.

Reproduced on main (ffed855) on GKE. dave is a ServiceAccount with no access policy bindings.

grpcurl -insecure localhost:18443 list
# Unauthenticated: missing bearer token

grpcurl -insecure -H "authorization: Bearer $(cat dave.token)" localhost:18443 list
# grpc.reflection.v1.ServerReflection
# grpc.reflection.v1alpha.ServerReflection
# substrate.ateapi.v1.Control
# substrate.ateapi.v1.WorkerService

grpcurl -insecure -H "authorization: Bearer $(cat dave.token)" localhost:18443 describe substrate.ateapi.v1.Control.MintActorJwt
# rpc MintActorJwt ( .substrate.ateapi.v1.MintActorJwtRequest ) returns ( .substrate.ateapi.v1.MintActorJwtResponse ) ...

Every unary call dave makes is denied, so the gap is limited to streams.

grpc.ChainStreamInterceptor in cmd/ateapi/main.go has only apiauthn.StreamServerInterceptor and preview.StreamServerInterceptor. authz.UnaryServerInterceptor has no streaming counterpart.

Correction to the last sentence above: TestDefaultRPCPermissions_CoversEveryServedRPC in cmd/ateapi/internal/authz/registry_test.go fails if ateapi.proto gains a streaming RPC, so a new streaming RPC on Control or WorkerService would fail the build. The test only looks at ateapi.proto, though. Reflection, and any other service registered on the same server, skips authorization. docs/authorization.md ("Every RPC") says "An RPC with no rule is denied", which isn't true for these.

Impact today is low, since the API schema is public. The concern is that the "deny RPCs with no rule" guarantee doesn't hold for streams. With the Google provider configured as docs/authentication.md shows, any Google account can authenticate and reach these.

Possible fixes: add an authz stream interceptor that denies any method without a rule (and give reflection an explicit rule, or allow it only for a role), or stop registering reflection by default.

Found during the authorization bug bash, with help from an AI agent.

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

Metadata

Metadata

Labels

area/securitySecurity related issue/prbug-bashkind/bugSomething isn't working / bugfixes

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions