Develop a gRPC-based custom authorization service

Updated at:

Service Mesh (ASM) supports custom authorization services based on HTTP and gRPC protocols. A gRPC-based authorization service receives a gRPC CheckRequest message from Envoy, inspects the request attributes, and returns an allow or deny decision. This guide walks you through implementing such a service and registering it with ASM.

For the overall architecture of custom authorization services, see Develop an HTTP-based custom authorization service.

Unlike an HTTP-based custom authorization service, a gRPC-based service has no header-related configurations. All request headers are embedded directly in the gRPC CheckRequest message from Envoy.

Prerequisites

Before you begin, make sure you have:

Implement the authorization server

ASM is compatible with open-source Istio. Istio provides a reference implementation that covers both HTTP and gRPC custom authorization. The gRPC-specific logic lives 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 the Envoy AuthorizationServer interface, which requires a single 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)
}

Core authorization logic

The Check method extracts request attributes, evaluates them, and returns an allow or deny response:

// 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
}

The decision follows two paths:

  1. Header-based check -- If the request contains the checkHeader header, the service compares its value against allowedValue. A match grants access.

  2. Identity-based fallback -- If the header is absent, the service checks whether the source identity (attrs.Source.Principal) ends with /sa/<serviceAccount>. This allows requests from a specific Kubernetes service account.

CheckRequest fields reference

For the full list of fields in authv3.CheckRequest, see:

API version

Envoy has deprecated v2 APIs. Implement only the v3 gRPC API as shown in the Check method signature above.

Register and apply the authorization service

After you deploy the authorization service to your ACK cluster:

  1. Open the ASM console and go to the Define Custom Authorization Service page.

  2. Register the gRPC-based authorization service.

  3. Create an authorization policy that specifies which mesh proxy uses the authorization service.

For detailed steps, see Implement custom authorization by using the gRPC protocol.

What's next