grpc/grpc-go · error

message authentication failed

Error message

message authentication failed

What it means

Thrown by newEngine when the RBAC policy's action field is neither RBAC_ALLOW nor RBAC_DENY. The gRPC RBAC engine only supports ALLOW and DENY actions. RBAC_LOG is handled earlier (at the HTTP filter level in parseConfig, which treats LOG as a no-op), and RBAC_UNSPECIFIED (the zero value / action not set) reaches newEngine only if the filter-level no-op check is bypassed. The error includes config.Action (the proto enum name) for diagnosis.

Source

Thrown at credentials/alts/internal/conn/common.go:35

 */

package conn

import (
	"encoding/binary"
	"errors"
	"fmt"
)

const (
	// GcmTagSize is the GCM tag size is the difference in length between
	// plaintext and ciphertext. From crypto/cipher/gcm.go in Go crypto
	// library.
	GcmTagSize = 16
)

// ErrAuth occurs on authentication failure.
var ErrAuth = errors.New("message authentication failed")

// SliceForAppend takes a slice and a requested number of bytes. It returns a
// slice with the contents of the given slice followed by that many bytes and a
// second slice that aliases into it and contains only the extra bytes. If the
// original slice has sufficient capacity then no allocation is performed.
func SliceForAppend(in []byte, n int) (head, tail []byte) {
	if total := len(in) + n; cap(in) >= total {
		head = in[:total]
	} else {
		head = make([]byte, total)
		copy(head, in)
	}
	tail = head[len(in):]
	return head, tail
}

// ParseFramedMsg parse the provided buffer and returns a frame of the format
// msgLength+msg and any remaining bytes in that buffer.

View on GitHub (pinned to 0c51461d27)

Solutions

  1. Set the RBAC policy's action to RBAC_ALLOW or RBAC_DENY before calling NewChainEngine.
  2. If calling NewChainEngine directly, validate that config.GetAction() is ALLOW or DENY before invoking, and handle LOG/UNSPECIFIED at the caller level (as the HTTP filter does).
  3. If the action is genuinely UNSPECIFIED in the xDS resource, fix the control plane to always set an explicit action.

Example fix

// before: policy with unspecified action
policy := &v3rbacpb.RBAC{
    // action defaults to RBAC_UNSPECIFIED (0)
    Policies: map[string]*v3rbacpb.Policy{...},
}
engine, err := rbac.NewChainEngine([]*v3rbacpb.RBAC{policy}, "")
// err = "unsupported action UNSPECIFIED"

// after: explicitly set ALLOW or DENY
policy := &v3rbacpb.RBAC{
    Action:   v3rbacpb.RBAC_ALLOW,
    Policies: map[string]*v3rbacpb.Policy{...},
}
engine, err := rbac.NewChainEngine([]*v3rbacpb.RBAC{policy}, "")
Defensive patterns

Strategy: validation

Validate before calling

// Validate the action before calling NewChainEngine:
func validateRBACAction(rbac *v3rbacpb.RBAC) error {
    switch rbac.GetAction() {
    case v3rbacpb.RBAC_ALLOW, v3rbacpb.RBAC_DENY:
        return nil
    case v3rbacpb.RBAC_LOG:
        return fmt.Errorf("LOG action should be handled as no-op before reaching the engine")
    default:
        return fmt.Errorf("unsupported RBAC action: %s (must be ALLOW or DENY)", rbac.GetAction())
    }
}

// Call before:
if err := validateRBACAction(policy); err != nil { return err }
engine, err := rbac.NewChainEngine([]*v3rbacpb.RBAC{policy}, "")

Prevention

When it happens

Trigger: NewChainEngine is called directly (not through the HTTP filter's parseConfig) with a policy whose action is RBAC_LOG or RBAC_UNSPECIFIED. In the normal xDS flow, parseConfig handles LOG by returning an empty config (no-op) before calling NewChainEngine, so this error typically surfaces only when application code or tests construct a ChainEngine directly with an unsupported action. It can also surface if parseConfig's LOG check has a bug or if the action is UNSPECIFIED (0) which parseConfig does not special-case.

Common situations: Application code calling rbac.NewChainEngine directly with a hand-built policy that leaves action unset (defaults to UNSPECIFIED) or explicitly sets LOG. A test that exercises the engine directly. A control plane bug that sends an UNSPECIFIED action past the filter-level no-op guard (the guard checks for LOG specifically, not UNSPECIFIED).

Understand the failure class

Related errors


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