When built-in RBAC policies are not flexible enough for your authorization requirements, Service Mesh (ASM) lets you delegate authorization decisions to an external service through Envoy's ext_authz filter. This topic explains how to build a gRPC-based authorization service that receives structured check requests from Envoy and returns allow or deny decisions.
For the HTTP-based approach, see Develop an HTTP-based custom authorization service.
How it works
When a sidecar proxy intercepts an incoming request, it forwards the request attributes to your external authorization service over gRPC. The authorization service inspects these attributes -- headers, source identity, request path, and more -- and returns an allow or deny decision. The sidecar proxy enforces this decision before forwarding the request upstream.
Client --> Sidecar Proxy --gRPC CheckRequest--> Authorization Service
| |
| <------- CheckResponse (allow/deny) --
|
(if allowed) --> Upstream ServiceUnlike the HTTP-based approach, a gRPC-based authorization service receives a structured CheckRequest proto message rather than a raw HTTP request. All request headers and metadata are available directly in the proto fields, with no additional header-forwarding configuration required.
Prerequisites
Before you begin, make sure you have:
An ASM instance with an associated ACK cluster
Familiarity with gRPC and Protocol Buffers
A Go development environment (the examples in this topic use Go)
The AuthorizationServer gRPC API
Implement the Envoy AuthorizationServer interface, which defines a single Check method:
type AuthorizationServer interface {
// Performs authorization check based on the attributes associated with the
// incoming request, and returns status `OK` or not `OK`.
Check(context.Context, *CheckRequest) (*CheckResponse, error)
}Check receives a CheckRequest containing request attributes from Envoy and returns a CheckResponse with the authorization decision.
For the complete field reference of CheckRequest, see the Envoy <code data-tag="code" class="inline-code___exakR" id="code_65a45c82">ext_authz</code> proto definition or the go-control-plane API docs.
Build the authorization service
ASM is compatible with open-source Istio. The Istio project provides a reference implementation that handles both HTTP and gRPC authorization protocols. The gRPC logic is defined in the extAuthzServerV3 struct:
type extAuthzServerV3 struct{}
func (s *extAuthzServerV3) Check(_ context.Context, request *authv3.CheckRequest) (*authv3.CheckResponse, error)
func (s *extAuthzServerV3) allow(request *authv3.CheckRequest) *authv3.CheckResponse
func (s *extAuthzServerV3) deny(request *authv3.CheckRequest) *authv3.CheckResponse
func (s *extAuthzServerV3) logRequest(allow string, request *authv3.CheckRequest)This struct implements AuthorizationServer. The four methods serve these purposes:
| Method | Purpose |
|---|---|
Check | Core logic -- inspects request attributes and returns allow or deny |
allow | Builds a CheckResponse that permits the request |
deny | Builds a CheckResponse that rejects the request |
logRequest | Logs the authorization decision for debugging |
The Check function
Check contains the authorization decision logic. The reference implementation uses two criteria:
Header check: If the request contains a specific header (
checkHeader), the function compares its value againstallowedValue.Identity check: If the header is absent, the function checks whether the source identity (
attrs.Source.Principal) matches a preset service account.
// Check implements gRPC v3 check request.
func (s *extAuthzServerV3) Check(_ context.Context, request *authv3.CheckRequest) (*authv3.CheckResponse, error) {
attrs := request.GetAttributes()
// Determine whether to allow or deny the request.
allow := false
checkHeaderValue, contains := attrs.GetRequest().GetHttp().GetHeaders()[checkHeader]
if contains {
allow = checkHeaderValue == allowedValue
} else {
allow = attrs.Source != nil && strings.HasSuffix(attrs.Source.Principal, "/sa/"+*serviceAccount)
}
if allow {
return s.allow(request), nil
}
return s.deny(request), nil
}Decision flow:
Extract request attributes from
CheckRequest.Look up
checkHeaderin the HTTP headers.If the header exists and its value equals
allowedValue, allow the request.If the header is absent, check whether the mTLS source identity (
Source.Principal) ends with/sa/<service-account-name>.Return the corresponding allow or deny response.
API version
Envoy has deprecated V2-related APIs. Implement only the V3 gRPC API as shown in the Check function signature above. The extAuthzServerV2 struct in the Istio sample is retained for backward compatibility only.
Register and activate the authorization service
After you deploy the custom authorization service to your ACK cluster:
Open the ASM console and navigate to the Define Custom Authorization Service page.
Register the gRPC-based authorization service.
Create or update an authorization policy to route authorization checks from specific sidecar proxies to your service.
For step-by-step instructions, see Implement custom authorization by using the gRPC protocol.
What to read next
Implement custom authorization by using the gRPC protocol -- Full configuration walkthrough
Develop an HTTP-based custom authorization service -- Alternative approach using HTTP
Envoy <code data-tag="code" class="inline-code___exakR" id="code_c29b572b">ext_authz</code> proto API -- Complete proto definition
go-control-plane v0.12.0 API reference -- Go bindings for the Envoy auth API