google.golang.org/grpc@v1.62.1/authz/rbac_translator_test.go (about)

     1  /*
     2   *
     3   * Copyright 2021 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package authz
    20  
    21  import (
    22  	"strings"
    23  	"testing"
    24  
    25  	v1xdsudpatypepb "github.com/cncf/xds/go/udpa/type/v1"
    26  	"github.com/google/go-cmp/cmp"
    27  	"google.golang.org/protobuf/testing/protocmp"
    28  	"google.golang.org/protobuf/types/known/anypb"
    29  	"google.golang.org/protobuf/types/known/structpb"
    30  
    31  	v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    32  	v3rbacpb "github.com/envoyproxy/go-control-plane/envoy/config/rbac/v3"
    33  	v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
    34  	v3matcherpb "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
    35  )
    36  
    37  func TestTranslatePolicy(t *testing.T) {
    38  	tests := map[string]struct {
    39  		authzPolicy    string
    40  		wantErr        string
    41  		wantPolicies   []*v3rbacpb.RBAC
    42  		wantPolicyName string
    43  	}{
    44  		"valid policy": {
    45  			authzPolicy: `{
    46  						"name": "authz",
    47  						"deny_rules": [
    48  						{
    49  							"name": "deny_policy_1",
    50  							"source": {
    51  								"principals":[
    52  								"spiffe://foo.abc",
    53  								"spiffe://bar*",
    54  								"*baz",
    55  								"spiffe://abc.*.com"
    56  								]
    57  							}
    58  						}],
    59  						"allow_rules": [
    60  						{
    61  							"name": "allow_policy_1",
    62  							"source": {
    63  								"principals":["*"]
    64  							},
    65  							"request": {
    66  								"paths": ["path-foo*"]
    67  							}
    68  						},
    69  						{
    70  							"name": "allow_policy_2",
    71  							"request": {
    72  								"paths": [
    73  								"path-bar",
    74  								"*baz"
    75  								],
    76  								"headers": [
    77  								{
    78  									"key": "key-1",
    79  									"values": ["foo", "*bar"]
    80  								},
    81  								{
    82  									"key": "key-2",
    83  									"values": ["baz*"]
    84  								}
    85  								]
    86  							}
    87  						}]
    88  					}`,
    89  			wantPolicies: []*v3rbacpb.RBAC{
    90  				{
    91  					Action: v3rbacpb.RBAC_DENY,
    92  					Policies: map[string]*v3rbacpb.Policy{
    93  						"authz_deny_policy_1": {
    94  							Principals: []*v3rbacpb.Principal{
    95  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
    96  									Ids: []*v3rbacpb.Principal{
    97  										{Identifier: &v3rbacpb.Principal_Authenticated_{
    98  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
    99  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "spiffe://foo.abc"},
   100  											}},
   101  										}},
   102  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   103  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   104  												MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "spiffe://bar"},
   105  											}},
   106  										}},
   107  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   108  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   109  												MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "baz"},
   110  											}},
   111  										}},
   112  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   113  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   114  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "spiffe://abc.*.com"},
   115  											}},
   116  										}},
   117  									},
   118  								}}},
   119  							},
   120  							Permissions: []*v3rbacpb.Permission{
   121  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   122  							},
   123  						},
   124  					},
   125  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{},
   126  				},
   127  				{
   128  					Action: v3rbacpb.RBAC_ALLOW,
   129  					Policies: map[string]*v3rbacpb.Policy{
   130  						"authz_allow_policy_1": {
   131  							Principals: []*v3rbacpb.Principal{
   132  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   133  									Ids: []*v3rbacpb.Principal{
   134  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   135  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   136  												MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}},
   137  											}},
   138  										}},
   139  									},
   140  								}}},
   141  							},
   142  							Permissions: []*v3rbacpb.Permission{
   143  								{Rule: &v3rbacpb.Permission_AndRules{AndRules: &v3rbacpb.Permission_Set{
   144  									Rules: []*v3rbacpb.Permission{
   145  										{Rule: &v3rbacpb.Permission_OrRules{OrRules: &v3rbacpb.Permission_Set{
   146  											Rules: []*v3rbacpb.Permission{
   147  												{Rule: &v3rbacpb.Permission_UrlPath{
   148  													UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{
   149  														MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "path-foo"},
   150  													}}},
   151  												}},
   152  											},
   153  										}}},
   154  									},
   155  								}}},
   156  							},
   157  						},
   158  						"authz_allow_policy_2": {
   159  							Principals: []*v3rbacpb.Principal{
   160  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   161  							},
   162  							Permissions: []*v3rbacpb.Permission{
   163  								{Rule: &v3rbacpb.Permission_AndRules{AndRules: &v3rbacpb.Permission_Set{
   164  									Rules: []*v3rbacpb.Permission{
   165  										{Rule: &v3rbacpb.Permission_OrRules{OrRules: &v3rbacpb.Permission_Set{
   166  											Rules: []*v3rbacpb.Permission{
   167  												{Rule: &v3rbacpb.Permission_UrlPath{
   168  													UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{
   169  														MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "path-bar"},
   170  													}}},
   171  												}},
   172  												{Rule: &v3rbacpb.Permission_UrlPath{
   173  													UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{
   174  														MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "baz"},
   175  													}}},
   176  												}},
   177  											},
   178  										}}},
   179  										{Rule: &v3rbacpb.Permission_AndRules{AndRules: &v3rbacpb.Permission_Set{
   180  											Rules: []*v3rbacpb.Permission{
   181  												{Rule: &v3rbacpb.Permission_OrRules{OrRules: &v3rbacpb.Permission_Set{
   182  													Rules: []*v3rbacpb.Permission{
   183  														{Rule: &v3rbacpb.Permission_Header{
   184  															Header: &v3routepb.HeaderMatcher{
   185  																Name: "key-1", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_ExactMatch{ExactMatch: "foo"},
   186  															},
   187  														}},
   188  														{Rule: &v3rbacpb.Permission_Header{
   189  															Header: &v3routepb.HeaderMatcher{
   190  																Name: "key-1", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_SuffixMatch{SuffixMatch: "bar"},
   191  															},
   192  														}},
   193  													},
   194  												}}},
   195  												{Rule: &v3rbacpb.Permission_OrRules{OrRules: &v3rbacpb.Permission_Set{
   196  													Rules: []*v3rbacpb.Permission{
   197  														{Rule: &v3rbacpb.Permission_Header{
   198  															Header: &v3routepb.HeaderMatcher{
   199  																Name: "key-2", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_PrefixMatch{PrefixMatch: "baz"},
   200  															},
   201  														}},
   202  													},
   203  												}}},
   204  											},
   205  										}}},
   206  									},
   207  								}}},
   208  							},
   209  						},
   210  					},
   211  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{},
   212  				},
   213  			},
   214  			wantPolicyName: "authz",
   215  		},
   216  		"allow authenticated": {
   217  			authzPolicy: `{
   218  						"name": "authz",
   219  						"allow_rules": [
   220  						{
   221  							"name": "allow_authenticated",
   222  							"source": {
   223  								"principals":["*", ""]
   224  							}
   225  						}]
   226  					}`,
   227  			wantPolicies: []*v3rbacpb.RBAC{
   228  				{
   229  					Action: v3rbacpb.RBAC_ALLOW,
   230  					Policies: map[string]*v3rbacpb.Policy{
   231  						"authz_allow_authenticated": {
   232  							Principals: []*v3rbacpb.Principal{
   233  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   234  									Ids: []*v3rbacpb.Principal{
   235  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   236  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   237  												MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}},
   238  											}},
   239  										}},
   240  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   241  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   242  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: ""},
   243  											}},
   244  										}},
   245  									},
   246  								}}},
   247  							},
   248  							Permissions: []*v3rbacpb.Permission{
   249  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   250  							},
   251  						},
   252  					},
   253  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{},
   254  				},
   255  			},
   256  		},
   257  		"audit_logging_ALLOW empty config": {
   258  			authzPolicy: `{
   259  				"name": "authz",
   260  				"allow_rules": [
   261  				{
   262  					"name": "allow_authenticated",
   263  					"source": {
   264  						"principals":["*", ""]
   265  					}
   266  				}],
   267  				"deny_rules": [
   268  				{
   269  					"name": "deny_policy_1",
   270  					"source": {
   271  						"principals":[
   272  						"spiffe://foo.abc"
   273  						]
   274  					}
   275  				}],
   276  				"audit_logging_options": {
   277  					"audit_condition": "ON_ALLOW",
   278  					"audit_loggers": [
   279  						{
   280  							"name": "stdout_logger",
   281  							"config": {},
   282  							"is_optional": false
   283  						}
   284  					]
   285  				}
   286  			}`,
   287  			wantPolicies: []*v3rbacpb.RBAC{
   288  				{
   289  					Action: v3rbacpb.RBAC_DENY,
   290  					Policies: map[string]*v3rbacpb.Policy{
   291  						"authz_deny_policy_1": {
   292  							Principals: []*v3rbacpb.Principal{
   293  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   294  									Ids: []*v3rbacpb.Principal{
   295  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   296  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   297  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "spiffe://foo.abc"},
   298  											}},
   299  										}},
   300  									},
   301  								}}},
   302  							},
   303  							Permissions: []*v3rbacpb.Permission{
   304  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   305  							},
   306  						},
   307  					},
   308  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   309  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_NONE,
   310  						LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
   311  							{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]any{}, "stdout_logger")},
   312  								IsOptional: false,
   313  							},
   314  						},
   315  					},
   316  				},
   317  				{
   318  					Action: v3rbacpb.RBAC_ALLOW,
   319  					Policies: map[string]*v3rbacpb.Policy{
   320  						"authz_allow_authenticated": {
   321  							Principals: []*v3rbacpb.Principal{
   322  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   323  									Ids: []*v3rbacpb.Principal{
   324  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   325  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   326  												MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}},
   327  											}},
   328  										}},
   329  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   330  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   331  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: ""},
   332  											}},
   333  										}},
   334  									},
   335  								}}},
   336  							},
   337  							Permissions: []*v3rbacpb.Permission{
   338  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   339  							},
   340  						},
   341  					},
   342  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   343  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_ON_ALLOW,
   344  						LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
   345  							{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]any{}, "stdout_logger")},
   346  								IsOptional: false,
   347  							},
   348  						},
   349  					},
   350  				},
   351  			},
   352  		},
   353  		"audit_logging_DENY_AND_ALLOW": {
   354  			authzPolicy: `{
   355  				"name": "authz",
   356  				"allow_rules": [
   357  				{
   358  					"name": "allow_authenticated",
   359  					"source": {
   360  						"principals":["*", ""]
   361  					}
   362  				}],
   363  				"deny_rules": [
   364  				{
   365  					"name": "deny_policy_1",
   366  					"source": {
   367  						"principals":[
   368  						"spiffe://foo.abc"
   369  						]
   370  					}
   371  				}],
   372  				"audit_logging_options": {
   373  					"audit_condition": "ON_DENY_AND_ALLOW",
   374  					"audit_loggers": [
   375  						{
   376  							"name": "stdout_logger",
   377  							"config": {},
   378  							"is_optional": false
   379  						}
   380  					]
   381  				}
   382  			}`,
   383  			wantPolicies: []*v3rbacpb.RBAC{
   384  				{
   385  					Action: v3rbacpb.RBAC_DENY,
   386  					Policies: map[string]*v3rbacpb.Policy{
   387  						"authz_deny_policy_1": {
   388  							Principals: []*v3rbacpb.Principal{
   389  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   390  									Ids: []*v3rbacpb.Principal{
   391  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   392  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   393  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "spiffe://foo.abc"},
   394  											}},
   395  										}},
   396  									},
   397  								}}},
   398  							},
   399  							Permissions: []*v3rbacpb.Permission{
   400  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   401  							},
   402  						},
   403  					},
   404  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   405  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_ON_DENY,
   406  						LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
   407  							{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]any{}, "stdout_logger")},
   408  								IsOptional: false,
   409  							},
   410  						},
   411  					},
   412  				},
   413  				{
   414  					Action: v3rbacpb.RBAC_ALLOW,
   415  					Policies: map[string]*v3rbacpb.Policy{
   416  						"authz_allow_authenticated": {
   417  							Principals: []*v3rbacpb.Principal{
   418  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   419  									Ids: []*v3rbacpb.Principal{
   420  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   421  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   422  												MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}},
   423  											}},
   424  										}},
   425  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   426  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   427  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: ""},
   428  											}},
   429  										}},
   430  									},
   431  								}}},
   432  							},
   433  							Permissions: []*v3rbacpb.Permission{
   434  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   435  							},
   436  						},
   437  					},
   438  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   439  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_ON_DENY_AND_ALLOW,
   440  						LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
   441  							{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]any{}, "stdout_logger")},
   442  								IsOptional: false,
   443  							},
   444  						},
   445  					},
   446  				},
   447  			},
   448  		},
   449  		"audit_logging_NONE": {
   450  			authzPolicy: `{
   451  				"name": "authz",
   452  				"allow_rules": [
   453  				{
   454  					"name": "allow_authenticated",
   455  					"source": {
   456  						"principals":["*", ""]
   457  					}
   458  				}],
   459  				"deny_rules": [
   460  				{
   461  					"name": "deny_policy_1",
   462  					"source": {
   463  						"principals":[
   464  						"spiffe://foo.abc"
   465  						]
   466  					}
   467  				}],
   468  				"audit_logging_options": {
   469  					"audit_condition": "NONE",
   470  					"audit_loggers": [
   471  						{
   472  							"name": "stdout_logger",
   473  							"config": {},
   474  							"is_optional": false
   475  						}
   476  					]
   477  				}
   478  			}`,
   479  			wantPolicies: []*v3rbacpb.RBAC{
   480  				{
   481  					Action: v3rbacpb.RBAC_DENY,
   482  					Policies: map[string]*v3rbacpb.Policy{
   483  						"authz_deny_policy_1": {
   484  							Principals: []*v3rbacpb.Principal{
   485  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   486  									Ids: []*v3rbacpb.Principal{
   487  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   488  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   489  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "spiffe://foo.abc"},
   490  											}},
   491  										}},
   492  									},
   493  								}}},
   494  							},
   495  							Permissions: []*v3rbacpb.Permission{
   496  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   497  							},
   498  						},
   499  					},
   500  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   501  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_NONE,
   502  						LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
   503  							{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]any{}, "stdout_logger")},
   504  								IsOptional: false,
   505  							},
   506  						},
   507  					},
   508  				},
   509  				{
   510  					Action: v3rbacpb.RBAC_ALLOW,
   511  					Policies: map[string]*v3rbacpb.Policy{
   512  						"authz_allow_authenticated": {
   513  							Principals: []*v3rbacpb.Principal{
   514  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   515  									Ids: []*v3rbacpb.Principal{
   516  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   517  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   518  												MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}},
   519  											}},
   520  										}},
   521  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   522  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   523  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: ""},
   524  											}},
   525  										}},
   526  									},
   527  								}}},
   528  							},
   529  							Permissions: []*v3rbacpb.Permission{
   530  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   531  							},
   532  						},
   533  					},
   534  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   535  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_NONE,
   536  						LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
   537  							{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]any{}, "stdout_logger")},
   538  								IsOptional: false,
   539  							},
   540  						},
   541  					},
   542  				},
   543  			},
   544  		},
   545  		"audit_logging_custom_config simple": {
   546  			authzPolicy: `{
   547  				"name": "authz",
   548  				"allow_rules": [
   549  				{
   550  					"name": "allow_authenticated",
   551  					"source": {
   552  						"principals":["*", ""]
   553  					}
   554  				}],
   555  				"deny_rules": [
   556  				{
   557  					"name": "deny_policy_1",
   558  					"source": {
   559  						"principals":[
   560  						"spiffe://foo.abc"
   561  						]
   562  					}
   563  				}],
   564  				"audit_logging_options": {
   565  					"audit_condition": "NONE",
   566  					"audit_loggers": [
   567  						{
   568  							"name": "stdout_logger",
   569  							"config": {"abc":123, "xyz":"123"},
   570  							"is_optional": false
   571  						}
   572  					]
   573  				}
   574  			}`,
   575  			wantPolicies: []*v3rbacpb.RBAC{
   576  				{
   577  					Action: v3rbacpb.RBAC_DENY,
   578  					Policies: map[string]*v3rbacpb.Policy{
   579  						"authz_deny_policy_1": {
   580  							Principals: []*v3rbacpb.Principal{
   581  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   582  									Ids: []*v3rbacpb.Principal{
   583  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   584  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   585  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "spiffe://foo.abc"},
   586  											}},
   587  										}},
   588  									},
   589  								}}},
   590  							},
   591  							Permissions: []*v3rbacpb.Permission{
   592  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   593  							},
   594  						},
   595  					},
   596  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   597  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_NONE,
   598  						LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
   599  							{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]any{"abc": 123, "xyz": "123"}, "stdout_logger")},
   600  								IsOptional: false,
   601  							},
   602  						},
   603  					},
   604  				},
   605  				{
   606  					Action: v3rbacpb.RBAC_ALLOW,
   607  					Policies: map[string]*v3rbacpb.Policy{
   608  						"authz_allow_authenticated": {
   609  							Principals: []*v3rbacpb.Principal{
   610  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   611  									Ids: []*v3rbacpb.Principal{
   612  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   613  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   614  												MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}},
   615  											}},
   616  										}},
   617  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   618  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   619  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: ""},
   620  											}},
   621  										}},
   622  									},
   623  								}}},
   624  							},
   625  							Permissions: []*v3rbacpb.Permission{
   626  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   627  							},
   628  						},
   629  					},
   630  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   631  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_NONE,
   632  						LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
   633  							{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]any{"abc": 123, "xyz": "123"}, "stdout_logger")},
   634  								IsOptional: false,
   635  							},
   636  						},
   637  					},
   638  				},
   639  			},
   640  		},
   641  		"audit_logging_custom_config nested": {
   642  			authzPolicy: `{
   643  				"name": "authz",
   644  				"allow_rules": [
   645  				{
   646  					"name": "allow_authenticated",
   647  					"source": {
   648  						"principals":["*", ""]
   649  					}
   650  				}],
   651  				"audit_logging_options": {
   652  					"audit_condition": "NONE",
   653  					"audit_loggers": [
   654  						{
   655  							"name": "stdout_logger",
   656  							"config": {"abc":123, "xyz":{"abc":123}},
   657  							"is_optional": false
   658  						}
   659  					]
   660  				}
   661  			}`,
   662  			wantPolicies: []*v3rbacpb.RBAC{
   663  				{
   664  					Action: v3rbacpb.RBAC_ALLOW,
   665  					Policies: map[string]*v3rbacpb.Policy{
   666  						"authz_allow_authenticated": {
   667  							Principals: []*v3rbacpb.Principal{
   668  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   669  									Ids: []*v3rbacpb.Principal{
   670  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   671  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   672  												MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}},
   673  											}},
   674  										}},
   675  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   676  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   677  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: ""},
   678  											}},
   679  										}},
   680  									},
   681  								}}},
   682  							},
   683  							Permissions: []*v3rbacpb.Permission{
   684  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   685  							},
   686  						},
   687  					},
   688  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   689  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_NONE,
   690  						LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
   691  							{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]any{"abc": 123, "xyz": map[string]any{"abc": 123}}, "stdout_logger")},
   692  								IsOptional: false,
   693  							},
   694  						},
   695  					},
   696  				},
   697  			},
   698  		},
   699  		"missing audit logger config": {
   700  			authzPolicy: `{
   701  				"name": "authz",
   702  				"allow_rules": [
   703  				{
   704  					"name": "allow_authenticated",
   705  					"source": {
   706  						"principals":["*", ""]
   707  					}
   708  				}],
   709  				"audit_logging_options": {
   710  					"audit_condition": "NONE"
   711  				}
   712  			}`,
   713  			wantPolicies: []*v3rbacpb.RBAC{
   714  				{
   715  					Action: v3rbacpb.RBAC_ALLOW,
   716  					Policies: map[string]*v3rbacpb.Policy{
   717  						"authz_allow_authenticated": {
   718  							Principals: []*v3rbacpb.Principal{
   719  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   720  									Ids: []*v3rbacpb.Principal{
   721  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   722  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   723  												MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}},
   724  											}},
   725  										}},
   726  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   727  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   728  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: ""},
   729  											}},
   730  										}},
   731  									},
   732  								}}},
   733  							},
   734  							Permissions: []*v3rbacpb.Permission{
   735  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   736  							},
   737  						},
   738  					},
   739  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   740  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_NONE,
   741  						LoggerConfigs:  []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{},
   742  					},
   743  				},
   744  			},
   745  		},
   746  		"missing audit condition": {
   747  			authzPolicy: `{
   748  				"name": "authz",
   749  				"allow_rules": [
   750  				{
   751  					"name": "allow_authenticated",
   752  					"source": {
   753  						"principals":["*", ""]
   754  					}
   755  				}],
   756  				"audit_logging_options": {
   757  					"audit_loggers": [
   758  						{
   759  							"name": "stdout_logger",
   760  							"config": {},
   761  							"is_optional": false
   762  						}
   763  					]
   764  				}
   765  			}`,
   766  			wantPolicies: []*v3rbacpb.RBAC{
   767  				{
   768  					Action: v3rbacpb.RBAC_ALLOW,
   769  					Policies: map[string]*v3rbacpb.Policy{
   770  						"authz_allow_authenticated": {
   771  							Principals: []*v3rbacpb.Principal{
   772  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   773  									Ids: []*v3rbacpb.Principal{
   774  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   775  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   776  												MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}},
   777  											}},
   778  										}},
   779  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   780  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   781  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: ""},
   782  											}},
   783  										}},
   784  									},
   785  								}}},
   786  							},
   787  							Permissions: []*v3rbacpb.Permission{
   788  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   789  							},
   790  						},
   791  					},
   792  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   793  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_NONE,
   794  						LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
   795  							{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]any{}, "stdout_logger")},
   796  								IsOptional: false,
   797  							},
   798  						},
   799  					},
   800  				},
   801  			},
   802  		},
   803  		"missing custom config audit logger": {
   804  			authzPolicy: `{
   805  				"name": "authz",
   806  				"allow_rules": [
   807  				{
   808  					"name": "allow_authenticated",
   809  					"source": {
   810  						"principals":["*", ""]
   811  					}
   812  				}],
   813  				"deny_rules": [
   814  				{
   815  					"name": "deny_policy_1",
   816  					"source": {
   817  						"principals":[
   818  						"spiffe://foo.abc"
   819  						]
   820  					}
   821  				}],
   822  				"audit_logging_options": {
   823  					"audit_condition": "ON_DENY",
   824  					"audit_loggers": [
   825  						{
   826  							"name": "stdout_logger",
   827  							"is_optional": false
   828  						}
   829  					]
   830  				}
   831  			}`,
   832  			wantPolicies: []*v3rbacpb.RBAC{
   833  				{
   834  					Action: v3rbacpb.RBAC_DENY,
   835  					Policies: map[string]*v3rbacpb.Policy{
   836  						"authz_deny_policy_1": {
   837  							Principals: []*v3rbacpb.Principal{
   838  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   839  									Ids: []*v3rbacpb.Principal{
   840  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   841  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   842  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "spiffe://foo.abc"},
   843  											}},
   844  										}},
   845  									},
   846  								}}},
   847  							},
   848  							Permissions: []*v3rbacpb.Permission{
   849  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   850  							},
   851  						},
   852  					},
   853  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   854  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_ON_DENY,
   855  						LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
   856  							{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]any{}, "stdout_logger")},
   857  								IsOptional: false,
   858  							},
   859  						},
   860  					},
   861  				},
   862  				{
   863  					Action: v3rbacpb.RBAC_ALLOW,
   864  					Policies: map[string]*v3rbacpb.Policy{
   865  						"authz_allow_authenticated": {
   866  							Principals: []*v3rbacpb.Principal{
   867  								{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   868  									Ids: []*v3rbacpb.Principal{
   869  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   870  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   871  												MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}},
   872  											}},
   873  										}},
   874  										{Identifier: &v3rbacpb.Principal_Authenticated_{
   875  											Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
   876  												MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: ""},
   877  											}},
   878  										}},
   879  									},
   880  								}}},
   881  							},
   882  							Permissions: []*v3rbacpb.Permission{
   883  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   884  							},
   885  						},
   886  					},
   887  					AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
   888  						AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_ON_DENY,
   889  						LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
   890  							{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]any{}, "stdout_logger")},
   891  								IsOptional: false,
   892  							},
   893  						},
   894  					},
   895  				},
   896  			},
   897  		},
   898  		"unknown field": {
   899  			authzPolicy: `{"random": 123}`,
   900  			wantErr:     "failed to unmarshal policy",
   901  		},
   902  		"missing name field": {
   903  			authzPolicy: `{}`,
   904  			wantErr:     `"name" is not present`,
   905  		},
   906  		"invalid field type": {
   907  			authzPolicy: `{"name": 123}`,
   908  			wantErr:     "failed to unmarshal policy",
   909  		},
   910  		"missing allow rules field": {
   911  			authzPolicy: `{"name": "authz-foo"}`,
   912  			wantErr:     `"allow_rules" is not present`,
   913  		},
   914  		"missing rule name field": {
   915  			authzPolicy: `{
   916  				"name": "authz-foo",
   917  				"allow_rules": [{}]
   918  			}`,
   919  			wantErr: `"allow_rules" 0: "name" is not present`,
   920  		},
   921  		"missing header key": {
   922  			authzPolicy: `{
   923  				"name": "authz",
   924  				"allow_rules": [{
   925  					"name": "allow_policy_1",
   926  					"request": {"headers":[{"key":"key-a", "values": ["value-a"]}, {}]}
   927  				}]
   928  			}`,
   929  			wantErr: `"allow_rules" 0: "headers" 1: "key" is not present`,
   930  		},
   931  		"missing header values": {
   932  			authzPolicy: `{
   933  				"name": "authz",
   934  				"allow_rules": [{
   935  					"name": "allow_policy_1",
   936  					"request": {"headers":[{"key":"key-a"}]}
   937  				}]
   938  			}`,
   939  			wantErr: `"allow_rules" 0: "headers" 0: "values" is not present`,
   940  		},
   941  		"unsupported header": {
   942  			authzPolicy: `{
   943  				"name": "authz",
   944  				"allow_rules": [{
   945  					"name": "allow_policy_1",
   946  					"request": {"headers":[{"key":":method", "values":["GET"]}]}
   947  				}]
   948  			}`,
   949  			wantErr: `"allow_rules" 0: "headers" 0: unsupported "key" :method`,
   950  		},
   951  		"bad audit condition": {
   952  			authzPolicy: `{
   953  				"name": "authz",
   954  				"allow_rules": [
   955  				{
   956  					"name": "allow_authenticated",
   957  					"source": {
   958  						"principals":["*", ""]
   959  					}
   960  				}],
   961  				"audit_logging_options": {
   962  					"audit_condition": "ABC",
   963  					"audit_loggers": [
   964  						{
   965  							"name": "stdout_logger",
   966  							"config": {},
   967  							"is_optional": false
   968  						}
   969  					]
   970  				}
   971  			}`,
   972  			wantErr: `failed to parse AuditCondition ABC`,
   973  		},
   974  		"bad audit logger config": {
   975  			authzPolicy: `{
   976  				"name": "authz",
   977  				"allow_rules": [
   978  				{
   979  					"name": "allow_authenticated",
   980  					"source": {
   981  						"principals":["*", ""]
   982  					}
   983  				}],
   984  				"audit_logging_options": {
   985  					"audit_condition": "NONE",
   986  					"audit_loggers": [
   987  						{
   988  							"name": "stdout_logger",
   989  							"config": "abc",
   990  							"is_optional": false
   991  						}
   992  					]
   993  				}
   994  			}`,
   995  			wantErr: `failed to unmarshal policy`,
   996  		},
   997  		"missing audit logger name": {
   998  			authzPolicy: `{
   999  				"name": "authz",
  1000  				"allow_rules": [
  1001  				{
  1002  					"name": "allow_authenticated",
  1003  					"source": {
  1004  						"principals":["*", ""]
  1005  					}
  1006  				}],
  1007  				"audit_logging_options": {
  1008  					"audit_condition": "NONE",
  1009  					"audit_loggers": [
  1010  						{
  1011  							"name": "",
  1012  							"config": {},
  1013  							"is_optional": false
  1014  						}
  1015  					]
  1016  				}
  1017  			}`,
  1018  			wantErr: `missing required field: name`,
  1019  		},
  1020  	}
  1021  	for name, test := range tests {
  1022  		t.Run(name, func(t *testing.T) {
  1023  			gotPolicies, gotPolicyName, gotErr := translatePolicy(test.authzPolicy)
  1024  			if gotErr != nil && !strings.HasPrefix(gotErr.Error(), test.wantErr) {
  1025  				t.Fatalf("unexpected error\nwant:%v\ngot:%v", test.wantErr, gotErr)
  1026  			}
  1027  			if diff := cmp.Diff(gotPolicies, test.wantPolicies, protocmp.Transform()); diff != "" {
  1028  				t.Fatalf("unexpected policy\ndiff (-want +got):\n%s", diff)
  1029  			}
  1030  			if test.wantPolicyName != "" && gotPolicyName != test.wantPolicyName {
  1031  				t.Fatalf("unexpected policy name\nwant:%v\ngot:%v", test.wantPolicyName, gotPolicyName)
  1032  			}
  1033  		})
  1034  	}
  1035  }
  1036  
  1037  func anyPbHelper(t *testing.T, in map[string]any, name string) *anypb.Any {
  1038  	t.Helper()
  1039  	pb, err := structpb.NewStruct(in)
  1040  	typedStruct := &v1xdsudpatypepb.TypedStruct{
  1041  		TypeUrl: typeURLPrefix + name,
  1042  		Value:   pb,
  1043  	}
  1044  	if err != nil {
  1045  		t.Fatal(err)
  1046  	}
  1047  	customConfig, err := anypb.New(typedStruct)
  1048  	if err != nil {
  1049  		t.Fatal(err)
  1050  	}
  1051  	return customConfig
  1052  }