grpc/grpc-go · error

rbac: permission header matcher for %v is :scheme or starts

Error message

rbac: permission header matcher for %v is :scheme or starts with grpc

What it means

Raised by the RBAC HTTP filter's config validation (gRFC A41). A policy Permission is rejected if it contains a header matcher whose name is the ":scheme" pseudo-header or starts with "grpc-", because those headers are transport-managed in gRPC and cannot be meaningfully matched. The check happens in parseConfig while iterating policy.Permissions.

Source

Thrown at internal/xds/httpfilter/rbac/rbac.go:81

		if policy.Condition != nil {
			return nil, errors.New("rbac: Policy.condition is present")
		}
		if policy.CheckedCondition != nil {
			return nil, errors.New("rbac: policy.CheckedCondition is present")
		}

		// "It is also a validation failure if Permission or Principal has a
		// header matcher for a grpc- prefixed header name or :scheme." - A41
		for _, principal := range policy.Principals {
			name := principal.GetHeader().GetName()
			if name == ":scheme" || strings.HasPrefix(name, "grpc-") {
				return nil, fmt.Errorf("rbac: principal header matcher for %v is :scheme or starts with grpc", name)
			}
		}
		for _, permission := range policy.Permissions {
			name := permission.GetHeader().GetName()
			if name == ":scheme" || strings.HasPrefix(name, "grpc-") {
				return nil, fmt.Errorf("rbac: permission header matcher for %v is :scheme or starts with grpc", name)
			}
		}
	}

	// "Envoy aliases :authority and Host in its header map implementation, so
	// they should be treated equivalent for the RBAC matchers; there must be no
	// behavior change depending on which of the two header names is used in the
	// RBAC policy." - A41. Loop through config's principals and policies, change
	// any header matcher with value "host" to :authority", as that is what
	// grpc-go shifts both headers to in transport layer.
	for _, policy := range rbacCfg.GetRules().GetPolicies() {
		for _, principal := range policy.Principals {
			if principal.GetHeader().GetName() == "host" {
				principal.GetHeader().Name = ":authority"
			}
		}
		for _, permission := range policy.Permissions {
			if permission.GetHeader().GetName() == "host" {

View on GitHub (pinned to 03255a9237)

Solutions

  1. Remove the offending header matcher from the Permission in the RBAC policy.
  2. If you need to gate on gRPC metadata, use a Principal-based metadata matcher or a non-header matcher (path, method, destination_ip) instead of matching ":scheme" or grpc-* headers.
  3. Redeploy the control-plane LDS resource and confirm the new config reaches the server.

Example fix

// before (Envoy RBAC policy fragment)
// permissions:
//   - header:
//       name: grpc-status
//       safe_regex_match: { regex: ".*" }
//
// after
// permissions:
//   - url_header:
//       name: :path
//       safe_regex_match: { regex: "/pkg.Service/Method" }
Defensive patterns

Strategy: validation

Validate before calling

// Validate an RBAC policy before sending it from a control plane.
func validateRBACPolicy(rbac *rbacpb.RBAC) error {
	for _, policy := range rbac.GetRules().GetPolicies() {
		for _, p := range policy.Permissions {
			name := p.GetHeader().GetName()
			if name == ":scheme" || strings.HasPrefix(name, "grpc-") {
				return fmt.Errorf("permission header matcher %q is reserved", name)
			}
		}
		for _, pr := range policy.Principals {
			name := pr.GetHeader().GetName()
			if name == ":scheme" || strings.HasPrefix(name, "grpc-") {
				return fmt.Errorf("principal header matcher %q is reserved", name)
			}
		}
	}
	return nil
}

Prevention

When it happens

Trigger: An xDS RBAC policy delivered via LDS whose Permission list contains a header matcher with name ":scheme" or any name beginning with "grpc-" (e.g. grpc-status, grpc-encoding, grpc-trace-bin).

Common situations: Porting an Envoy HTTP RBAC rule verbatim into a gRPC xDS setup; Istio/Envoy authoring rules that attempt to match on gRPC reserved metadata; control-plane upgrade that emits previously-tolerated matchers.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/7f479b9ca2361c2b. Report an issue: GitHub.