diff --git a/internal/xds/rbac/matchers.go b/internal/xds/rbac/matchers.go index 6f30c8016e2..9873da268db 100644 --- a/internal/xds/rbac/matchers.go +++ b/internal/xds/rbac/matchers.go @@ -122,8 +122,11 @@ func matchersFromPermissions(permissions []*v3rbacpb.Permission) ([]matcher, err } matchers = append(matchers, ¬Matcher{matcherToNot: mList[0]}) case *v3rbacpb.Permission_Metadata: - // Not supported in gRPC RBAC currently - a permission typed as - // Metadata in the initial config will be a no-op. + // Never matches - so no-op if not inverted, always match if + // inverted. + if permission.GetMetadata().GetInvert() { // Test metadata being no-op and also metadata with invert always matching + matchers = append(matchers, &alwaysMatcher{}) + } case *v3rbacpb.Permission_RequestedServerName: // Not supported in gRPC RBAC currently - a permission typed as // requested server name in the initial config will be a no-op. diff --git a/internal/xds/rbac/rbac_engine_test.go b/internal/xds/rbac/rbac_engine_test.go index e2e5d98c2a8..19bc4e8ca89 100644 --- a/internal/xds/rbac/rbac_engine_test.go +++ b/internal/xds/rbac/rbac_engine_test.go @@ -936,8 +936,78 @@ func (s) TestChainEngine(t *testing.T) { }, }, }, + // This test tests that an RBAC policy configured with a metadata + // matcher as a permission doesn't match with any incoming RPC. + { + name: "metadata-never-matches", + rbacConfigs: []*v3rbacpb.RBAC{ + { + Policies: map[string]*v3rbacpb.Policy{ + "metadata-never-matches": { + Permissions: []*v3rbacpb.Permission{ + {Rule: &v3rbacpb.Permission_Metadata{ + Metadata: &v3matcherpb.MetadataMatcher{}, + }}, + }, + Principals: []*v3rbacpb.Principal{ + {Identifier: &v3rbacpb.Principal_Any{Any: true}}, + }, + }, + }, + }, + }, + rbacQueries: []struct { + rpcData *rpcData + wantStatusCode codes.Code + }{ + { + rpcData: &rpcData{ + fullMethod: "some method", + peerInfo: &peer.Peer{ + Addr: &addr{ipAddress: "0.0.0.0"}, + }, + }, + wantStatusCode: codes.PermissionDenied, + }, + }, + }, + // This test tests that an RBAC policy configured with a metadata + // matcher with invert set to true as a permission always matches with + // any incoming RPC. + { + name: "metadata-invert-always-matches", + rbacConfigs: []*v3rbacpb.RBAC{ + { + Policies: map[string]*v3rbacpb.Policy{ + "metadata-invert-always-matches": { + Permissions: []*v3rbacpb.Permission{ + {Rule: &v3rbacpb.Permission_Metadata{ + Metadata: &v3matcherpb.MetadataMatcher{Invert: true}, + }}, + }, + Principals: []*v3rbacpb.Principal{ + {Identifier: &v3rbacpb.Principal_Any{Any: true}}, + }, + }, + }, + }, + }, + rbacQueries: []struct { + rpcData *rpcData + wantStatusCode codes.Code + }{ + { + rpcData: &rpcData{ + fullMethod: "some method", + peerInfo: &peer.Peer{ + Addr: &addr{ipAddress: "0.0.0.0"}, + }, + }, + wantStatusCode: codes.OK, + }, + }, + }, } - for _, test := range tests { t.Run(test.name, func(t *testing.T) { // Instantiate the chainedRBACEngine with different configurations that are