...

Source file src/k8s.io/kubernetes/pkg/securitycontext/accessors_test.go

Documentation: k8s.io/kubernetes/pkg/securitycontext

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package securitycontext
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  
    23  	"k8s.io/apimachinery/pkg/util/diff"
    24  	api "k8s.io/kubernetes/pkg/apis/core"
    25  	"k8s.io/utils/pointer"
    26  )
    27  
    28  func TestPodSecurityContextAccessor(t *testing.T) {
    29  	fsGroup := int64(2)
    30  	runAsUser := int64(1)
    31  	runAsGroup := int64(1)
    32  	runAsNonRoot := true
    33  
    34  	testcases := []*api.PodSecurityContext{
    35  		nil,
    36  		{},
    37  		{FSGroup: &fsGroup},
    38  		{HostIPC: true},
    39  		{HostNetwork: true},
    40  		{HostPID: true},
    41  		{RunAsNonRoot: &runAsNonRoot},
    42  		{RunAsUser: &runAsUser},
    43  		{RunAsGroup: &runAsGroup},
    44  		{SELinuxOptions: &api.SELinuxOptions{User: "bob"}},
    45  		{SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeRuntimeDefault}},
    46  		{SupplementalGroups: []int64{1, 2, 3}},
    47  	}
    48  
    49  	for i, tc := range testcases {
    50  		expected := tc
    51  		if expected == nil {
    52  			expected = &api.PodSecurityContext{}
    53  		}
    54  
    55  		a := NewPodSecurityContextAccessor(tc)
    56  
    57  		if v := a.FSGroup(); !reflect.DeepEqual(expected.FSGroup, v) {
    58  			t.Errorf("%d: expected %#v, got %#v", i, expected.FSGroup, v)
    59  		}
    60  		if v := a.HostIPC(); !reflect.DeepEqual(expected.HostIPC, v) {
    61  			t.Errorf("%d: expected %#v, got %#v", i, expected.HostIPC, v)
    62  		}
    63  		if v := a.HostNetwork(); !reflect.DeepEqual(expected.HostNetwork, v) {
    64  			t.Errorf("%d: expected %#v, got %#v", i, expected.HostNetwork, v)
    65  		}
    66  		if v := a.HostPID(); !reflect.DeepEqual(expected.HostPID, v) {
    67  			t.Errorf("%d: expected %#v, got %#v", i, expected.HostPID, v)
    68  		}
    69  		if v := a.RunAsNonRoot(); !reflect.DeepEqual(expected.RunAsNonRoot, v) {
    70  			t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsNonRoot, v)
    71  		}
    72  		if v := a.RunAsUser(); !reflect.DeepEqual(expected.RunAsUser, v) {
    73  			t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsUser, v)
    74  		}
    75  		if v := a.RunAsGroup(); !reflect.DeepEqual(expected.RunAsGroup, v) {
    76  			t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsGroup, v)
    77  		}
    78  		if v := a.SeccompProfile(); !reflect.DeepEqual(expected.SeccompProfile, v) {
    79  			t.Errorf("%d: expected %#v, got %#v", i, expected.SeccompProfile, v)
    80  		}
    81  		if v := a.SELinuxOptions(); !reflect.DeepEqual(expected.SELinuxOptions, v) {
    82  			t.Errorf("%d: expected %#v, got %#v", i, expected.SELinuxOptions, v)
    83  		}
    84  		if v := a.SupplementalGroups(); !reflect.DeepEqual(expected.SupplementalGroups, v) {
    85  			t.Errorf("%d: expected %#v, got %#v", i, expected.SupplementalGroups, v)
    86  		}
    87  	}
    88  }
    89  
    90  func TestPodSecurityContextMutator(t *testing.T) {
    91  	testcases := map[string]struct {
    92  		newSC func() *api.PodSecurityContext
    93  	}{
    94  		"nil": {
    95  			newSC: func() *api.PodSecurityContext { return nil },
    96  		},
    97  		"zero": {
    98  			newSC: func() *api.PodSecurityContext { return &api.PodSecurityContext{} },
    99  		},
   100  		"populated": {
   101  			newSC: func() *api.PodSecurityContext {
   102  				return &api.PodSecurityContext{
   103  					HostNetwork:        true,
   104  					HostIPC:            true,
   105  					HostPID:            true,
   106  					SELinuxOptions:     &api.SELinuxOptions{},
   107  					RunAsUser:          nil,
   108  					RunAsGroup:         nil,
   109  					RunAsNonRoot:       nil,
   110  					SeccompProfile:     nil,
   111  					SupplementalGroups: nil,
   112  					FSGroup:            nil,
   113  				}
   114  			},
   115  		},
   116  	}
   117  
   118  	nonNilSC := func(sc *api.PodSecurityContext) *api.PodSecurityContext {
   119  		if sc == nil {
   120  			return &api.PodSecurityContext{}
   121  		}
   122  		return sc
   123  	}
   124  
   125  	for k, tc := range testcases {
   126  		{
   127  			sc := tc.newSC()
   128  			originalSC := tc.newSC()
   129  			m := NewPodSecurityContextMutator(sc)
   130  
   131  			// no-op sets should not modify the object
   132  			m.SetFSGroup(m.FSGroup())
   133  			m.SetHostNetwork(m.HostNetwork())
   134  			m.SetHostIPC(m.HostIPC())
   135  			m.SetHostPID(m.HostPID())
   136  			m.SetRunAsNonRoot(m.RunAsNonRoot())
   137  			m.SetRunAsUser(m.RunAsUser())
   138  			m.SetRunAsGroup(m.RunAsGroup())
   139  			m.SetSeccompProfile(m.SeccompProfile())
   140  			m.SetSELinuxOptions(m.SELinuxOptions())
   141  			m.SetSupplementalGroups(m.SupplementalGroups())
   142  			if !reflect.DeepEqual(sc, originalSC) {
   143  				t.Errorf("%s: unexpected mutation: %#v, %#v", k, sc, originalSC)
   144  			}
   145  			if !reflect.DeepEqual(m.PodSecurityContext(), originalSC) {
   146  				t.Errorf("%s: unexpected mutation: %#v, %#v", k, m.PodSecurityContext(), originalSC)
   147  			}
   148  		}
   149  
   150  		// FSGroup
   151  		{
   152  			modifiedSC := nonNilSC(tc.newSC())
   153  			m := NewPodSecurityContextMutator(tc.newSC())
   154  			i := int64(1123)
   155  			modifiedSC.FSGroup = &i
   156  			m.SetFSGroup(&i)
   157  			if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
   158  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
   159  				continue
   160  			}
   161  		}
   162  
   163  		// HostNetwork
   164  		{
   165  			modifiedSC := nonNilSC(tc.newSC())
   166  			m := NewPodSecurityContextMutator(tc.newSC())
   167  			modifiedSC.HostNetwork = !modifiedSC.HostNetwork
   168  			m.SetHostNetwork(!m.HostNetwork())
   169  			if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
   170  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
   171  				continue
   172  			}
   173  		}
   174  
   175  		// HostIPC
   176  		{
   177  			modifiedSC := nonNilSC(tc.newSC())
   178  			m := NewPodSecurityContextMutator(tc.newSC())
   179  			modifiedSC.HostIPC = !modifiedSC.HostIPC
   180  			m.SetHostIPC(!m.HostIPC())
   181  			if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
   182  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
   183  				continue
   184  			}
   185  		}
   186  
   187  		// HostPID
   188  		{
   189  			modifiedSC := nonNilSC(tc.newSC())
   190  			m := NewPodSecurityContextMutator(tc.newSC())
   191  			modifiedSC.HostPID = !modifiedSC.HostPID
   192  			m.SetHostPID(!m.HostPID())
   193  			if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
   194  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
   195  				continue
   196  			}
   197  		}
   198  
   199  		// RunAsNonRoot
   200  		{
   201  			modifiedSC := nonNilSC(tc.newSC())
   202  			m := NewPodSecurityContextMutator(tc.newSC())
   203  			b := true
   204  			modifiedSC.RunAsNonRoot = &b
   205  			m.SetRunAsNonRoot(&b)
   206  			if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
   207  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
   208  				continue
   209  			}
   210  		}
   211  
   212  		// RunAsUser
   213  		{
   214  			modifiedSC := nonNilSC(tc.newSC())
   215  			m := NewPodSecurityContextMutator(tc.newSC())
   216  			i := int64(1123)
   217  			modifiedSC.RunAsUser = &i
   218  			m.SetRunAsUser(&i)
   219  			if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
   220  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
   221  				continue
   222  			}
   223  		}
   224  
   225  		// RunAsGroup
   226  		{
   227  			modifiedSC := nonNilSC(tc.newSC())
   228  			m := NewPodSecurityContextMutator(tc.newSC())
   229  			i := int64(1123)
   230  			modifiedSC.RunAsGroup = &i
   231  			m.SetRunAsGroup(&i)
   232  			if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
   233  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
   234  				continue
   235  			}
   236  		}
   237  
   238  		// SELinuxOptions
   239  		{
   240  			modifiedSC := nonNilSC(tc.newSC())
   241  			m := NewPodSecurityContextMutator(tc.newSC())
   242  			modifiedSC.SELinuxOptions = &api.SELinuxOptions{User: "bob"}
   243  			m.SetSELinuxOptions(&api.SELinuxOptions{User: "bob"})
   244  			if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
   245  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
   246  				continue
   247  			}
   248  		}
   249  
   250  		// SeccompProfile
   251  		{
   252  			modifiedSC := nonNilSC(tc.newSC())
   253  			m := NewPodSecurityContextMutator(tc.newSC())
   254  			modifiedSC.SeccompProfile = &api.SeccompProfile{Type: api.SeccompProfileTypeLocalhost, LocalhostProfile: pointer.String("verylocalhostey")}
   255  			m.SetSeccompProfile(&api.SeccompProfile{Type: api.SeccompProfileTypeLocalhost, LocalhostProfile: pointer.String("verylocalhostey")})
   256  			if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
   257  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
   258  				continue
   259  			}
   260  		}
   261  
   262  		// SupplementalGroups
   263  		{
   264  			modifiedSC := nonNilSC(tc.newSC())
   265  			m := NewPodSecurityContextMutator(tc.newSC())
   266  			modifiedSC.SupplementalGroups = []int64{1, 1, 2, 3}
   267  			m.SetSupplementalGroups([]int64{1, 1, 2, 3})
   268  			if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
   269  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
   270  				continue
   271  			}
   272  		}
   273  	}
   274  }
   275  
   276  func TestContainerSecurityContextAccessor(t *testing.T) {
   277  	privileged := true
   278  	runAsUser := int64(1)
   279  	runAsGroup := int64(1)
   280  	runAsNonRoot := true
   281  	readOnlyRootFilesystem := true
   282  	allowPrivilegeEscalation := true
   283  
   284  	testcases := []*api.SecurityContext{
   285  		nil,
   286  		{},
   287  		{Capabilities: &api.Capabilities{Drop: []api.Capability{"test"}}},
   288  		{Privileged: &privileged},
   289  		{SELinuxOptions: &api.SELinuxOptions{User: "bob"}},
   290  		{RunAsUser: &runAsUser},
   291  		{RunAsGroup: &runAsGroup},
   292  		{RunAsNonRoot: &runAsNonRoot},
   293  		{ReadOnlyRootFilesystem: &readOnlyRootFilesystem},
   294  		{SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeRuntimeDefault}},
   295  		{AllowPrivilegeEscalation: &allowPrivilegeEscalation},
   296  	}
   297  
   298  	for i, tc := range testcases {
   299  		expected := tc
   300  		if expected == nil {
   301  			expected = &api.SecurityContext{}
   302  		}
   303  
   304  		a := NewContainerSecurityContextAccessor(tc)
   305  
   306  		if v := a.Capabilities(); !reflect.DeepEqual(expected.Capabilities, v) {
   307  			t.Errorf("%d: expected %#v, got %#v", i, expected.Capabilities, v)
   308  		}
   309  		if v := a.Privileged(); !reflect.DeepEqual(expected.Privileged, v) {
   310  			t.Errorf("%d: expected %#v, got %#v", i, expected.Privileged, v)
   311  		}
   312  		if v := a.RunAsNonRoot(); !reflect.DeepEqual(expected.RunAsNonRoot, v) {
   313  			t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsNonRoot, v)
   314  		}
   315  		if v := a.RunAsUser(); !reflect.DeepEqual(expected.RunAsUser, v) {
   316  			t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsUser, v)
   317  		}
   318  		if v := a.RunAsGroup(); !reflect.DeepEqual(expected.RunAsGroup, v) {
   319  			t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsGroup, v)
   320  		}
   321  		if v := a.SELinuxOptions(); !reflect.DeepEqual(expected.SELinuxOptions, v) {
   322  			t.Errorf("%d: expected %#v, got %#v", i, expected.SELinuxOptions, v)
   323  		}
   324  		if v := a.ReadOnlyRootFilesystem(); !reflect.DeepEqual(expected.ReadOnlyRootFilesystem, v) {
   325  			t.Errorf("%d: expected %#v, got %#v", i, expected.ReadOnlyRootFilesystem, v)
   326  		}
   327  		if v := a.SeccompProfile(); !reflect.DeepEqual(expected.SeccompProfile, v) {
   328  			t.Errorf("%d: expected %#v, got %#v", i, expected.SeccompProfile, v)
   329  		}
   330  		if v := a.AllowPrivilegeEscalation(); !reflect.DeepEqual(expected.AllowPrivilegeEscalation, v) {
   331  			t.Errorf("%d: expected %#v, got %#v", i, expected.AllowPrivilegeEscalation, v)
   332  		}
   333  	}
   334  }
   335  
   336  func TestContainerSecurityContextMutator(t *testing.T) {
   337  	testcases := map[string]struct {
   338  		newSC func() *api.SecurityContext
   339  	}{
   340  		"nil": {
   341  			newSC: func() *api.SecurityContext { return nil },
   342  		},
   343  		"zero": {
   344  			newSC: func() *api.SecurityContext { return &api.SecurityContext{} },
   345  		},
   346  		"populated": {
   347  			newSC: func() *api.SecurityContext {
   348  				return &api.SecurityContext{
   349  					Capabilities:   &api.Capabilities{Drop: []api.Capability{"test"}},
   350  					SELinuxOptions: &api.SELinuxOptions{},
   351  					SeccompProfile: &api.SeccompProfile{},
   352  				}
   353  			},
   354  		},
   355  	}
   356  
   357  	nonNilSC := func(sc *api.SecurityContext) *api.SecurityContext {
   358  		if sc == nil {
   359  			return &api.SecurityContext{}
   360  		}
   361  		return sc
   362  	}
   363  
   364  	for k, tc := range testcases {
   365  		{
   366  			sc := tc.newSC()
   367  			originalSC := tc.newSC()
   368  			m := NewContainerSecurityContextMutator(sc)
   369  
   370  			// no-op sets should not modify the object
   371  			m.SetAllowPrivilegeEscalation(m.AllowPrivilegeEscalation())
   372  			m.SetCapabilities(m.Capabilities())
   373  			m.SetPrivileged(m.Privileged())
   374  			m.SetReadOnlyRootFilesystem(m.ReadOnlyRootFilesystem())
   375  			m.SetRunAsNonRoot(m.RunAsNonRoot())
   376  			m.SetRunAsUser(m.RunAsUser())
   377  			m.SetRunAsGroup(m.RunAsGroup())
   378  			m.SetSELinuxOptions(m.SELinuxOptions())
   379  			if !reflect.DeepEqual(sc, originalSC) {
   380  				t.Errorf("%s: unexpected mutation: %#v, %#v", k, sc, originalSC)
   381  			}
   382  			if !reflect.DeepEqual(m.ContainerSecurityContext(), originalSC) {
   383  				t.Errorf("%s: unexpected mutation: %#v, %#v", k, m.ContainerSecurityContext(), originalSC)
   384  			}
   385  		}
   386  
   387  		// AllowPrivilegeEscalation
   388  		{
   389  			modifiedSC := nonNilSC(tc.newSC())
   390  			m := NewContainerSecurityContextMutator(tc.newSC())
   391  			b := true
   392  			modifiedSC.AllowPrivilegeEscalation = &b
   393  			m.SetAllowPrivilegeEscalation(&b)
   394  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   395  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   396  				continue
   397  			}
   398  		}
   399  
   400  		// Capabilities
   401  		{
   402  			modifiedSC := nonNilSC(tc.newSC())
   403  			m := NewContainerSecurityContextMutator(tc.newSC())
   404  			modifiedSC.Capabilities = &api.Capabilities{Drop: []api.Capability{"test2"}}
   405  			m.SetCapabilities(&api.Capabilities{Drop: []api.Capability{"test2"}})
   406  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   407  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   408  				continue
   409  			}
   410  		}
   411  
   412  		// Privileged
   413  		{
   414  			modifiedSC := nonNilSC(tc.newSC())
   415  			m := NewContainerSecurityContextMutator(tc.newSC())
   416  			b := true
   417  			modifiedSC.Privileged = &b
   418  			m.SetPrivileged(&b)
   419  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   420  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   421  				continue
   422  			}
   423  		}
   424  
   425  		// ReadOnlyRootFilesystem
   426  		{
   427  			modifiedSC := nonNilSC(tc.newSC())
   428  			m := NewContainerSecurityContextMutator(tc.newSC())
   429  			b := true
   430  			modifiedSC.ReadOnlyRootFilesystem = &b
   431  			m.SetReadOnlyRootFilesystem(&b)
   432  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   433  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   434  				continue
   435  			}
   436  		}
   437  
   438  		// RunAsNonRoot
   439  		{
   440  			modifiedSC := nonNilSC(tc.newSC())
   441  			m := NewContainerSecurityContextMutator(tc.newSC())
   442  			b := true
   443  			modifiedSC.RunAsNonRoot = &b
   444  			m.SetRunAsNonRoot(&b)
   445  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   446  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   447  				continue
   448  			}
   449  		}
   450  
   451  		// RunAsUser
   452  		{
   453  			modifiedSC := nonNilSC(tc.newSC())
   454  			m := NewContainerSecurityContextMutator(tc.newSC())
   455  			i := int64(1123)
   456  			modifiedSC.RunAsUser = &i
   457  			m.SetRunAsUser(&i)
   458  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   459  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   460  				continue
   461  			}
   462  		}
   463  
   464  		// RunAsGroup
   465  		{
   466  			modifiedSC := nonNilSC(tc.newSC())
   467  			m := NewContainerSecurityContextMutator(tc.newSC())
   468  			i := int64(1123)
   469  			modifiedSC.RunAsGroup = &i
   470  			m.SetRunAsGroup(&i)
   471  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   472  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   473  				continue
   474  			}
   475  		}
   476  
   477  		// SeccompProfile
   478  		{
   479  			modifiedSC := nonNilSC(tc.newSC())
   480  			m := NewContainerSecurityContextMutator(tc.newSC())
   481  			modifiedSC.SeccompProfile = &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined}
   482  			m.SetSeccompProfile(&api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined})
   483  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   484  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   485  				continue
   486  			}
   487  		}
   488  
   489  		// SELinuxOptions
   490  		{
   491  			modifiedSC := nonNilSC(tc.newSC())
   492  			m := NewContainerSecurityContextMutator(tc.newSC())
   493  			modifiedSC.SELinuxOptions = &api.SELinuxOptions{User: "bob"}
   494  			m.SetSELinuxOptions(&api.SELinuxOptions{User: "bob"})
   495  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   496  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   497  				continue
   498  			}
   499  		}
   500  	}
   501  }
   502  
   503  func TestEffectiveContainerSecurityContextAccessor(t *testing.T) {
   504  	privileged := true
   505  	runAsUser := int64(1)
   506  	runAsUserPod := int64(12)
   507  	runAsGroup := int64(1)
   508  	runAsGroupPod := int64(12)
   509  	runAsNonRoot := true
   510  	runAsNonRootPod := false
   511  	readOnlyRootFilesystem := true
   512  	allowPrivilegeEscalation := true
   513  
   514  	testcases := []struct {
   515  		PodSC     *api.PodSecurityContext
   516  		SC        *api.SecurityContext
   517  		Effective *api.SecurityContext
   518  	}{
   519  		{
   520  			PodSC:     nil,
   521  			SC:        nil,
   522  			Effective: nil,
   523  		},
   524  		{
   525  			PodSC:     &api.PodSecurityContext{},
   526  			SC:        &api.SecurityContext{},
   527  			Effective: &api.SecurityContext{},
   528  		},
   529  		{
   530  			PodSC: &api.PodSecurityContext{
   531  				SELinuxOptions: &api.SELinuxOptions{User: "bob"},
   532  				SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined},
   533  				RunAsUser:      &runAsUser,
   534  				RunAsNonRoot:   &runAsNonRoot,
   535  			},
   536  			SC: nil,
   537  			Effective: &api.SecurityContext{
   538  				SELinuxOptions: &api.SELinuxOptions{User: "bob"},
   539  				SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined},
   540  				RunAsUser:      &runAsUser,
   541  				RunAsNonRoot:   &runAsNonRoot,
   542  			},
   543  		},
   544  		{
   545  			PodSC: &api.PodSecurityContext{
   546  				SELinuxOptions: &api.SELinuxOptions{User: "bob"},
   547  				SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined},
   548  				RunAsUser:      &runAsUserPod,
   549  				RunAsNonRoot:   &runAsNonRootPod,
   550  			},
   551  			SC: &api.SecurityContext{},
   552  			Effective: &api.SecurityContext{
   553  				SELinuxOptions: &api.SELinuxOptions{User: "bob"},
   554  				SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined},
   555  				RunAsUser:      &runAsUserPod,
   556  				RunAsNonRoot:   &runAsNonRootPod,
   557  			},
   558  		},
   559  		{
   560  			PodSC: &api.PodSecurityContext{
   561  				SELinuxOptions: &api.SELinuxOptions{User: "bob"},
   562  				SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined},
   563  				RunAsUser:      &runAsUserPod,
   564  				RunAsNonRoot:   &runAsNonRootPod,
   565  			},
   566  			SC: &api.SecurityContext{
   567  				AllowPrivilegeEscalation: &allowPrivilegeEscalation,
   568  				Capabilities:             &api.Capabilities{Drop: []api.Capability{"test"}},
   569  				Privileged:               &privileged,
   570  				ReadOnlyRootFilesystem:   &readOnlyRootFilesystem,
   571  				RunAsUser:                &runAsUser,
   572  				RunAsNonRoot:             &runAsNonRoot,
   573  				SELinuxOptions:           &api.SELinuxOptions{User: "bob"},
   574  				SeccompProfile:           &api.SeccompProfile{Type: api.SeccompProfileTypeRuntimeDefault},
   575  			},
   576  			Effective: &api.SecurityContext{
   577  				AllowPrivilegeEscalation: &allowPrivilegeEscalation,
   578  				Capabilities:             &api.Capabilities{Drop: []api.Capability{"test"}},
   579  				Privileged:               &privileged,
   580  				ReadOnlyRootFilesystem:   &readOnlyRootFilesystem,
   581  				RunAsUser:                &runAsUser,
   582  				RunAsNonRoot:             &runAsNonRoot,
   583  				SELinuxOptions:           &api.SELinuxOptions{User: "bob"},
   584  				SeccompProfile:           &api.SeccompProfile{Type: api.SeccompProfileTypeRuntimeDefault},
   585  			},
   586  		},
   587  		{
   588  			PodSC: &api.PodSecurityContext{
   589  				RunAsGroup: &runAsGroup,
   590  			},
   591  			SC: nil,
   592  			Effective: &api.SecurityContext{
   593  				RunAsGroup: &runAsGroup,
   594  			},
   595  		},
   596  		{
   597  			PodSC: &api.PodSecurityContext{
   598  				RunAsGroup: &runAsGroupPod,
   599  			},
   600  			SC: &api.SecurityContext{
   601  				RunAsGroup: &runAsGroup,
   602  			},
   603  			Effective: &api.SecurityContext{
   604  				RunAsGroup: &runAsGroup,
   605  			},
   606  		},
   607  	}
   608  
   609  	for i, tc := range testcases {
   610  		expected := tc.Effective
   611  		if expected == nil {
   612  			expected = &api.SecurityContext{}
   613  		}
   614  
   615  		a := NewEffectiveContainerSecurityContextAccessor(
   616  			NewPodSecurityContextAccessor(tc.PodSC),
   617  			NewContainerSecurityContextMutator(tc.SC),
   618  		)
   619  
   620  		if v := a.Capabilities(); !reflect.DeepEqual(expected.Capabilities, v) {
   621  			t.Errorf("%d: expected %#v, got %#v", i, expected.Capabilities, v)
   622  		}
   623  		if v := a.Privileged(); !reflect.DeepEqual(expected.Privileged, v) {
   624  			t.Errorf("%d: expected %#v, got %#v", i, expected.Privileged, v)
   625  		}
   626  		if v := a.RunAsNonRoot(); !reflect.DeepEqual(expected.RunAsNonRoot, v) {
   627  			t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsNonRoot, v)
   628  		}
   629  		if v := a.RunAsUser(); !reflect.DeepEqual(expected.RunAsUser, v) {
   630  			t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsUser, v)
   631  		}
   632  		if v := a.RunAsGroup(); !reflect.DeepEqual(expected.RunAsGroup, v) {
   633  			t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsGroup, v)
   634  		}
   635  		if v := a.SELinuxOptions(); !reflect.DeepEqual(expected.SELinuxOptions, v) {
   636  			t.Errorf("%d: expected %#v, got %#v", i, expected.SELinuxOptions, v)
   637  		}
   638  		if v := a.ReadOnlyRootFilesystem(); !reflect.DeepEqual(expected.ReadOnlyRootFilesystem, v) {
   639  			t.Errorf("%d: expected %#v, got %#v", i, expected.ReadOnlyRootFilesystem, v)
   640  		}
   641  		if v := a.AllowPrivilegeEscalation(); !reflect.DeepEqual(expected.AllowPrivilegeEscalation, v) {
   642  			t.Errorf("%d: expected %#v, got %#v", i, expected.AllowPrivilegeEscalation, v)
   643  		}
   644  	}
   645  }
   646  
   647  func TestEffectiveContainerSecurityContextMutator(t *testing.T) {
   648  	runAsNonRootPod := false
   649  	runAsUserPod := int64(12)
   650  
   651  	testcases := map[string]struct {
   652  		newPodSC func() *api.PodSecurityContext
   653  		newSC    func() *api.SecurityContext
   654  	}{
   655  		"nil": {
   656  			newPodSC: func() *api.PodSecurityContext { return nil },
   657  			newSC:    func() *api.SecurityContext { return nil },
   658  		},
   659  		"zero": {
   660  			newPodSC: func() *api.PodSecurityContext { return &api.PodSecurityContext{} },
   661  			newSC:    func() *api.SecurityContext { return &api.SecurityContext{} },
   662  		},
   663  		"populated pod sc": {
   664  			newPodSC: func() *api.PodSecurityContext {
   665  				return &api.PodSecurityContext{
   666  					SELinuxOptions: &api.SELinuxOptions{User: "poduser"},
   667  					SeccompProfile: &api.SeccompProfile{},
   668  					RunAsNonRoot:   &runAsNonRootPod,
   669  					RunAsUser:      &runAsUserPod,
   670  				}
   671  			},
   672  			newSC: func() *api.SecurityContext {
   673  				return &api.SecurityContext{}
   674  			},
   675  		},
   676  		"populated sc": {
   677  			newPodSC: func() *api.PodSecurityContext { return nil },
   678  			newSC: func() *api.SecurityContext {
   679  				return &api.SecurityContext{
   680  					Capabilities:   &api.Capabilities{Drop: []api.Capability{"test"}},
   681  					SELinuxOptions: &api.SELinuxOptions{},
   682  					SeccompProfile: &api.SeccompProfile{},
   683  				}
   684  			},
   685  		},
   686  	}
   687  
   688  	nonNilSC := func(sc *api.SecurityContext) *api.SecurityContext {
   689  		if sc == nil {
   690  			return &api.SecurityContext{}
   691  		}
   692  		return sc
   693  	}
   694  
   695  	for k, tc := range testcases {
   696  		{
   697  			podSC := tc.newPodSC()
   698  			sc := tc.newSC()
   699  			originalPodSC := tc.newPodSC()
   700  			originalSC := tc.newSC()
   701  			m := NewEffectiveContainerSecurityContextMutator(
   702  				NewPodSecurityContextAccessor(podSC),
   703  				NewContainerSecurityContextMutator(sc),
   704  			)
   705  
   706  			// no-op sets should not modify the object
   707  			m.SetAllowPrivilegeEscalation(m.AllowPrivilegeEscalation())
   708  			m.SetCapabilities(m.Capabilities())
   709  			m.SetPrivileged(m.Privileged())
   710  			m.SetReadOnlyRootFilesystem(m.ReadOnlyRootFilesystem())
   711  			m.SetRunAsNonRoot(m.RunAsNonRoot())
   712  			m.SetRunAsUser(m.RunAsUser())
   713  			m.SetRunAsGroup(m.RunAsGroup())
   714  			m.SetSELinuxOptions(m.SELinuxOptions())
   715  			m.SetSeccompProfile(m.SeccompProfile())
   716  			if !reflect.DeepEqual(podSC, originalPodSC) {
   717  				t.Errorf("%s: unexpected mutation: %#v, %#v", k, podSC, originalPodSC)
   718  			}
   719  			if !reflect.DeepEqual(sc, originalSC) {
   720  				t.Errorf("%s: unexpected mutation: %#v, %#v", k, sc, originalSC)
   721  			}
   722  			if !reflect.DeepEqual(m.ContainerSecurityContext(), originalSC) {
   723  				t.Errorf("%s: unexpected mutation: %#v, %#v", k, m.ContainerSecurityContext(), originalSC)
   724  			}
   725  		}
   726  
   727  		// AllowPrivilegeEscalation
   728  		{
   729  			modifiedSC := nonNilSC(tc.newSC())
   730  			m := NewEffectiveContainerSecurityContextMutator(
   731  				NewPodSecurityContextAccessor(tc.newPodSC()),
   732  				NewContainerSecurityContextMutator(tc.newSC()),
   733  			)
   734  			b := true
   735  			modifiedSC.AllowPrivilegeEscalation = &b
   736  			m.SetAllowPrivilegeEscalation(&b)
   737  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   738  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   739  				continue
   740  			}
   741  		}
   742  
   743  		// Capabilities
   744  		{
   745  			modifiedSC := nonNilSC(tc.newSC())
   746  			m := NewEffectiveContainerSecurityContextMutator(
   747  				NewPodSecurityContextAccessor(tc.newPodSC()),
   748  				NewContainerSecurityContextMutator(tc.newSC()),
   749  			)
   750  			modifiedSC.Capabilities = &api.Capabilities{Drop: []api.Capability{"test2"}}
   751  			m.SetCapabilities(&api.Capabilities{Drop: []api.Capability{"test2"}})
   752  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   753  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   754  				continue
   755  			}
   756  		}
   757  
   758  		// Privileged
   759  		{
   760  			modifiedSC := nonNilSC(tc.newSC())
   761  			m := NewEffectiveContainerSecurityContextMutator(
   762  				NewPodSecurityContextAccessor(tc.newPodSC()),
   763  				NewContainerSecurityContextMutator(tc.newSC()),
   764  			)
   765  			b := true
   766  			modifiedSC.Privileged = &b
   767  			m.SetPrivileged(&b)
   768  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   769  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   770  				continue
   771  			}
   772  		}
   773  
   774  		// ReadOnlyRootFilesystem
   775  		{
   776  			modifiedSC := nonNilSC(tc.newSC())
   777  			m := NewEffectiveContainerSecurityContextMutator(
   778  				NewPodSecurityContextAccessor(tc.newPodSC()),
   779  				NewContainerSecurityContextMutator(tc.newSC()),
   780  			)
   781  			b := true
   782  			modifiedSC.ReadOnlyRootFilesystem = &b
   783  			m.SetReadOnlyRootFilesystem(&b)
   784  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   785  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   786  				continue
   787  			}
   788  		}
   789  
   790  		// RunAsNonRoot
   791  		{
   792  			modifiedSC := nonNilSC(tc.newSC())
   793  			m := NewEffectiveContainerSecurityContextMutator(
   794  				NewPodSecurityContextAccessor(tc.newPodSC()),
   795  				NewContainerSecurityContextMutator(tc.newSC()),
   796  			)
   797  			b := true
   798  			modifiedSC.RunAsNonRoot = &b
   799  			m.SetRunAsNonRoot(&b)
   800  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   801  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   802  				continue
   803  			}
   804  		}
   805  
   806  		// RunAsUser
   807  		{
   808  			modifiedSC := nonNilSC(tc.newSC())
   809  			m := NewEffectiveContainerSecurityContextMutator(
   810  				NewPodSecurityContextAccessor(tc.newPodSC()),
   811  				NewContainerSecurityContextMutator(tc.newSC()),
   812  			)
   813  			i := int64(1123)
   814  			modifiedSC.RunAsUser = &i
   815  			m.SetRunAsUser(&i)
   816  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   817  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   818  				continue
   819  			}
   820  		}
   821  
   822  		// RunAsGroup
   823  		{
   824  			modifiedSC := nonNilSC(tc.newSC())
   825  			m := NewEffectiveContainerSecurityContextMutator(
   826  				NewPodSecurityContextAccessor(tc.newPodSC()),
   827  				NewContainerSecurityContextMutator(tc.newSC()),
   828  			)
   829  			i := int64(1123)
   830  			modifiedSC.RunAsGroup = &i
   831  			m.SetRunAsGroup(&i)
   832  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   833  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   834  				continue
   835  			}
   836  		}
   837  
   838  		// SeccompProfile
   839  		{
   840  			modifiedSC := nonNilSC(tc.newSC())
   841  			m := NewContainerSecurityContextMutator(tc.newSC())
   842  			modifiedSC.SeccompProfile = &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined}
   843  			m.SetSeccompProfile(&api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined})
   844  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   845  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   846  				continue
   847  			}
   848  		}
   849  
   850  		// SELinuxOptions
   851  		{
   852  			modifiedSC := nonNilSC(tc.newSC())
   853  			m := NewEffectiveContainerSecurityContextMutator(
   854  				NewPodSecurityContextAccessor(tc.newPodSC()),
   855  				NewContainerSecurityContextMutator(tc.newSC()),
   856  			)
   857  			modifiedSC.SELinuxOptions = &api.SELinuxOptions{User: "bob"}
   858  			m.SetSELinuxOptions(&api.SELinuxOptions{User: "bob"})
   859  			if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
   860  				t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
   861  				continue
   862  			}
   863  		}
   864  	}
   865  }
   866  

View as plain text