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
- Set the RBAC policy's action to RBAC_ALLOW or RBAC_DENY before calling NewChainEngine.
- 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).
- 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
- Always set an explicit action (ALLOW or DENY) on RBAC policies; never rely on the zero value.
- If calling NewChainEngine directly, pre-validate the action and handle LOG/UNSPECIFIED at the caller level.
- Ensure the control plane always emits an explicit action field in RBAC rules.
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
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- server-side auth info is not of type alts.AuthInfo
- rbac: Policy.condition is present
- rbac: policy.CheckedCondition is present
- unknown header matcher type
- no SubConn is available
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/b00efed01e9b6936.
Report an issue: GitHub.