grpc/grpc-go · error

rbac: policy.CheckedCondition is present

Error message

rbac: policy.CheckedCondition is present

What it means

Symmetric to error 72: gRFC A41 also requires that the `checked_condition` field of an RBAC Policy cause a validation failure if present. parseConfig (rbac.go:67-68) returns this error for any policy whose `CheckedCondition` is non-nil. gRPC's RBAC engine does not implement checked conditions (a conditional-CEL feature in Envoy), so it refuses the config outright.

Solutions

  1. Remove the `checked_condition` field from RBAC policies delivered to gRPC clients.
  2. Re-express the authorization logic using the supported permission/principal matcher primitives (header, path, source IP, JWT claim, etc.).
  3. Use RBACPerRoute or separate filter chains to keep the Envoy-only policy away from gRPC.

Example fix

// before
policies:
  p1:
    checkedCondition:
      condition: "connection.requested_server_name == 'a'"
    permissions: [...]

// after
policies:
  p1:
    permissions: [{ any: true }]
    principals:
      - authenticated: { principalName: { exact: "spiffe://acme/a" } }
Defensive patterns

Strategy: validation

Validate before calling

func validateRBACPolicyForGRPC(rbac *rpb.RBAC) error {
    for name, p := range rbac.GetRules().GetPolicies() {
        if p.GetCheckedCondition() != nil {
            return fmt.Errorf("policy %q: gRPC does not support Policy.checked_condition", name)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: Triggered when an xDS-delivered RBAC config sets `checked_condition` on any policy within Rules.Policies. Caught during resource parsing, causing the resource to be NACK'd.

Common situations: Reusing an Envoy-targeted RBAC policy that uses checked_condition with a gRPC xDS client; an Istio authorization policy that compiles to checked_condition being delivered to gRPC; a control-plane upgrade that started emitting checked_condition.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/d3d3682d66b1b985. Report an issue: GitHub.

Appendix: source

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

func (builder) TypeURLs() []string {
	return []string{
		"type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC",
		"type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBACPerRoute",
	}
}

// Parsing is the same for the base config and the override config.
func parseConfig(rbacCfg *rpb.RBAC) (httpfilter.FilterConfig, error) {
	// All the validation logic described in A41.
	for _, policy := range rbacCfg.GetRules().GetPolicies() {
		// "Policy.condition and Policy.checked_condition must cause a
		// validation failure if present." - A41
		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.
		//
		// "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. Any header matcher with value "host"
		// is rewritten to ":authority", as that is what grpc-go shifts both
		// headers to in the transport layer.
		//
		// Both rules apply to header matchers nested inside and/or/not rules, so
		// the whole permission and principal trees are walked.
		for _, principal := range policy.GetPrincipals() {
			if err := normalizePrincipalHeaders(principal); err != nil {
				return nil, err
			}

View on GitHub (pinned to 0c51461d27)