func parseConfig()

in xds/httpfilter/rbac/rbac.go [89:155]


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
		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" {
				permission.GetHeader().Name = ":authority"
			}
		}
	}

	// Two cases where this HTTP Filter is a no op:
	// "If absent, no enforcing RBAC policy will be applied" - RBAC
	// Documentation for Rules field.
	// "At this time, if the RBAC.action is Action.LOG then the policy will be
	// completely ignored, as if RBAC was not configurated." - A41
	if rbacCfg.Rules == nil || rbacCfg.GetRules().GetAction() == v3rbacpb.RBAC_LOG {
		return config{}, nil
	}

	ce, err := rbac.NewChainEngine([]*v3rbacpb.RBAC{rbacCfg.GetRules()})
	if err != nil {
		// "At this time, if the RBAC.action is Action.LOG then the policy will be
		// completely ignored, as if RBAC was not configurated." - A41
		if rbacCfg.GetRules().GetAction() != v3rbacpb.RBAC_LOG {
			return nil, fmt.Errorf("rbac: error constructing matching engine: %v", err)
		}
	}

	return config{chainEngine: ce}, nil
}