istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/security/trustdomain/bundle_test.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package trustdomain
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  )
    21  
    22  func TestReplaceTrustDomainAliases(t *testing.T) {
    23  	testCases := []struct {
    24  		name              string
    25  		trustDomainBundle Bundle
    26  		principals        []string
    27  		expect            []string
    28  	}{
    29  		{
    30  			name:              "No trust domain aliases (no change in trust domain)",
    31  			trustDomainBundle: NewBundle("cluster.local", nil),
    32  			principals:        []string{"cluster.local/ns/foo/sa/bar"},
    33  			expect:            []string{"cluster.local/ns/foo/sa/bar"},
    34  		},
    35  		{
    36  			name:              "Principal with *",
    37  			trustDomainBundle: NewBundle("cluster.local", nil),
    38  			principals:        []string{"*"},
    39  			expect:            []string{"*"},
    40  		},
    41  		{
    42  			name:              "Principal with * prefix",
    43  			trustDomainBundle: NewBundle("cluster.local", nil),
    44  			principals:        []string{"*/ns/foo/sa/bar"},
    45  			expect:            []string{"*/ns/foo/sa/bar"},
    46  		},
    47  		{
    48  			name:              "One trust domain alias, one principal",
    49  			trustDomainBundle: NewBundle("td2", []string{"td1"}),
    50  			principals:        []string{"td1/ns/foo/sa/bar"},
    51  			expect:            []string{"td2/ns/foo/sa/bar", "td1/ns/foo/sa/bar"},
    52  		},
    53  		{
    54  			name:              "One trust domain alias, two principals",
    55  			trustDomainBundle: NewBundle("td1", []string{"cluster.local"}),
    56  			principals:        []string{"cluster.local/ns/foo/sa/bar", "cluster.local/ns/yyy/sa/zzz"},
    57  			expect:            []string{"td1/ns/foo/sa/bar", "cluster.local/ns/foo/sa/bar", "td1/ns/yyy/sa/zzz", "cluster.local/ns/yyy/sa/zzz"},
    58  		},
    59  		{
    60  			name:              "One trust domain alias, principals with * as-is",
    61  			trustDomainBundle: NewBundle("td1", []string{"cluster.local"}),
    62  			principals:        []string{"*/ns/foo/sa/bar", "*sa/zzz", "*"},
    63  			expect:            []string{"*/ns/foo/sa/bar", "*sa/zzz", "*"},
    64  		},
    65  		{
    66  			name:              "Two trust domain aliases, two principals",
    67  			trustDomainBundle: NewBundle("td2", []string{"td1", "cluster.local"}),
    68  			principals:        []string{"cluster.local/ns/foo/sa/bar", "td1/ns/yyy/sa/zzz"},
    69  			expect: []string{
    70  				"td2/ns/foo/sa/bar", "td1/ns/foo/sa/bar", "cluster.local/ns/foo/sa/bar",
    71  				"td2/ns/yyy/sa/zzz", "td1/ns/yyy/sa/zzz", "cluster.local/ns/yyy/sa/zzz",
    72  			},
    73  		},
    74  		{
    75  			name:              "Two trust domain aliases with * prefix in trust domain",
    76  			trustDomainBundle: NewBundle("td2", []string{"foo-td1", "cluster.local"}),
    77  			principals:        []string{"*-td1/ns/foo/sa/bar"},
    78  			expect:            []string{"td2/ns/foo/sa/bar", "*-td1/ns/foo/sa/bar", "cluster.local/ns/foo/sa/bar"},
    79  		},
    80  		{
    81  			name:              "Principals not match any trust domains",
    82  			trustDomainBundle: NewBundle("td1", []string{"td2"}),
    83  			principals:        []string{"some-td/ns/foo/sa/bar"},
    84  			expect:            []string{"some-td/ns/foo/sa/bar"},
    85  		},
    86  		{
    87  			name:              "Principals match one alias",
    88  			trustDomainBundle: NewBundle("td1", []string{"td2", "some-td"}),
    89  			principals:        []string{"some-td/ns/foo/sa/bar"},
    90  			expect:            []string{"td1/ns/foo/sa/bar", "td2/ns/foo/sa/bar", "some-td/ns/foo/sa/bar"},
    91  		},
    92  		{
    93  			name:              "One principal match one alias",
    94  			trustDomainBundle: NewBundle("new-td", []string{"td2", "td3"}),
    95  			principals:        []string{"td1/ns/some-ns/sa/some-sa", "td2/ns/foo/sa/bar"},
    96  			expect: []string{
    97  				"td1/ns/some-ns/sa/some-sa", "new-td/ns/foo/sa/bar",
    98  				"td2/ns/foo/sa/bar", "td3/ns/foo/sa/bar",
    99  			},
   100  		},
   101  		{
   102  			name:              "Trust domain is empty string",
   103  			trustDomainBundle: NewBundle("new-td", []string{"td2", "td3"}),
   104  			principals:        []string{"/ns/some-ns/sa/some-sa"},
   105  			expect:            []string{"/ns/some-ns/sa/some-sa"},
   106  		},
   107  		{
   108  			name:              "No duplicated principals for prefix",
   109  			trustDomainBundle: NewBundle("new-td", []string{"old-td"}),
   110  			principals:        []string{"*-td/ns/some-ns/sa/some-sa"},
   111  			// Rather than output *-td/ns/some-ns/sa/some-sa once for each trust domain.
   112  			expect: []string{"*-td/ns/some-ns/sa/some-sa"},
   113  		},
   114  	}
   115  
   116  	for _, tc := range testCases {
   117  		got := tc.trustDomainBundle.ReplaceTrustDomainAliases(tc.principals)
   118  		if !reflect.DeepEqual(got, tc.expect) {
   119  			t.Errorf("%s failed. Expect: %s. Got: %s", tc.name, tc.expect, got)
   120  		}
   121  	}
   122  }
   123  
   124  func TestReplaceTrustDomainInPrincipal(t *testing.T) {
   125  	cases := []struct {
   126  		name          string
   127  		trustDomainIn string
   128  		principal     string
   129  		out           string
   130  		expectedError string
   131  	}{
   132  		{
   133  			name:          "Principal in wrong format with SPIFFE:// prefix",
   134  			principal:     "spiffe://cluster.local/ns/foo/sa/bar",
   135  			out:           "",
   136  			expectedError: "wrong SPIFFE format: spiffe://cluster.local/ns/foo/sa/bar",
   137  		},
   138  		{
   139  			name:          "Principal in wrong format with less components",
   140  			principal:     "sa/test-sa/ns/default",
   141  			out:           "",
   142  			expectedError: "wrong SPIFFE format: sa/test-sa/ns/default",
   143  		},
   144  		{
   145  			name:          "Replace td with domain name in principal",
   146  			trustDomainIn: "td",
   147  			principal:     "cluster.local/ns/foo/sa/bar",
   148  			out:           "td/ns/foo/sa/bar",
   149  			expectedError: "",
   150  		},
   151  		{
   152  			name:          "Replace td without domain name in principal",
   153  			trustDomainIn: "abc",
   154  			principal:     "xyz/ns/foo/sa/bar",
   155  			out:           "abc/ns/foo/sa/bar",
   156  			expectedError: "",
   157  		},
   158  	}
   159  
   160  	for _, c := range cases {
   161  		got, err := replaceTrustDomainInPrincipal(c.trustDomainIn, c.principal)
   162  		if err != nil {
   163  			if c.expectedError == "" {
   164  				t.Errorf("%s: replace trust domain in principal error: %v", c.name, err)
   165  			}
   166  			if got != "" {
   167  				t.Errorf("%s: Expected empty SPIFFE ID but obtained a non-empty one: %s.", c.name, got)
   168  			}
   169  			if err.Error() != c.expectedError {
   170  				t.Errorf("%s: Expected error: %s but got error: %s.", c.name, c.expectedError, err.Error())
   171  			}
   172  			continue
   173  		}
   174  
   175  		if got != c.out {
   176  			t.Errorf("%s failed. Expect %s, but got %s", c.name, c.out, got)
   177  		}
   178  	}
   179  }
   180  
   181  func TestGetTrustDomainFromSpiffeIdentity(t *testing.T) {
   182  	cases := []struct {
   183  		principal string
   184  		out       string
   185  	}{
   186  		{principal: "spiffe://cluster.local/ns/foo/sa/bar", out: ""},
   187  		{principal: "sa/test-sa/ns/default", out: ""},
   188  		{principal: "cluster.local/ns/foo/sa/bar", out: "cluster.local"},
   189  		{principal: "xyz/ns/foo/sa/bar", out: "xyz"},
   190  	}
   191  
   192  	for _, c := range cases {
   193  		got, _ := getTrustDomainFromSpiffeIdentity(c.principal)
   194  		if got != c.out {
   195  			t.Errorf("expect %s, but got %s", c.out, got)
   196  		}
   197  	}
   198  }
   199  
   200  func TestIsTrustDomainBeingEnforced(t *testing.T) {
   201  	cases := []struct {
   202  		principal string
   203  		want      bool
   204  	}{
   205  		{principal: "cluster.local/ns/foo/sa/bar", want: true},
   206  		{principal: "*/ns/foo/sa/bar", want: false},
   207  		{principal: "*-td/ns/foo/sa/bar", want: true},
   208  		{principal: "*/sa/bar", want: false},
   209  		{principal: "*", want: false},
   210  		{principal: "/ns/foo/sa/bar", want: true},
   211  	}
   212  
   213  	for _, c := range cases {
   214  		got := isTrustDomainBeingEnforced(c.principal)
   215  		if got != c.want {
   216  			t.Errorf("expect %v, but got %v", c.want, got)
   217  		}
   218  	}
   219  }