...

Source file src/k8s.io/kubectl/pkg/cmd/debug/profiles_test.go

Documentation: k8s.io/kubectl/pkg/cmd/debug

     1  /*
     2  Copyright 2020 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 debug
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  
    25  	corev1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	"k8s.io/utils/pointer"
    29  )
    30  
    31  var testNode = &corev1.Node{
    32  	ObjectMeta: metav1.ObjectMeta{
    33  		Name: "node-XXX",
    34  	},
    35  }
    36  
    37  func TestGeneralProfile(t *testing.T) {
    38  	pod := &corev1.Pod{
    39  		ObjectMeta: metav1.ObjectMeta{Name: "pod"},
    40  		Spec: corev1.PodSpec{EphemeralContainers: []corev1.EphemeralContainer{
    41  			{
    42  				EphemeralContainerCommon: corev1.EphemeralContainerCommon{
    43  					Name: "dbg", Image: "dbgimage",
    44  				},
    45  			},
    46  		}},
    47  	}
    48  
    49  	tests := map[string]struct {
    50  		pod           *corev1.Pod
    51  		containerName string
    52  		target        runtime.Object
    53  		expectPod     *corev1.Pod
    54  		expectErr     bool
    55  	}{
    56  		"bad inputs results in error": {
    57  			pod:           nil,
    58  			containerName: "dbg",
    59  			target:        runtime.Object(nil),
    60  			expectErr:     true,
    61  		},
    62  		"debug by ephemeral container": {
    63  			pod:           pod,
    64  			containerName: "dbg",
    65  			target:        pod,
    66  			expectPod: &corev1.Pod{
    67  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
    68  				Spec: corev1.PodSpec{EphemeralContainers: []corev1.EphemeralContainer{
    69  					{
    70  						EphemeralContainerCommon: corev1.EphemeralContainerCommon{
    71  							Name: "dbg", Image: "dbgimage",
    72  							SecurityContext: &corev1.SecurityContext{
    73  								Capabilities: &corev1.Capabilities{
    74  									Add: []corev1.Capability{"SYS_PTRACE"},
    75  								},
    76  							},
    77  						},
    78  					},
    79  				}},
    80  			},
    81  		},
    82  		"debug by pod copy": {
    83  			pod: &corev1.Pod{
    84  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
    85  				Spec: corev1.PodSpec{
    86  					Containers: []corev1.Container{
    87  						{Name: "app", Image: "appimage"},
    88  						{
    89  							Name:  "dbg",
    90  							Image: "dbgimage",
    91  							SecurityContext: &corev1.SecurityContext{
    92  								Capabilities: &corev1.Capabilities{
    93  									Add: []corev1.Capability{"NET_ADMIN"},
    94  								},
    95  							},
    96  						},
    97  					},
    98  				},
    99  			},
   100  			containerName: "dbg",
   101  			target: &corev1.Pod{
   102  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   103  				Spec: corev1.PodSpec{
   104  					Containers: []corev1.Container{
   105  						{Name: "app", Image: "appimage"},
   106  					},
   107  				},
   108  			},
   109  			expectPod: &corev1.Pod{
   110  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   111  				Spec: corev1.PodSpec{
   112  					Containers: []corev1.Container{
   113  						{Name: "app", Image: "appimage"},
   114  						{
   115  							Name:  "dbg",
   116  							Image: "dbgimage",
   117  							SecurityContext: &corev1.SecurityContext{
   118  								Capabilities: &corev1.Capabilities{
   119  									Add: []corev1.Capability{"NET_ADMIN", "SYS_PTRACE"},
   120  								},
   121  							},
   122  						},
   123  					},
   124  					ShareProcessNamespace: pointer.Bool(true),
   125  				},
   126  			},
   127  		},
   128  		"debug by node": {
   129  			pod: &corev1.Pod{
   130  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   131  				Spec: corev1.PodSpec{
   132  					Containers: []corev1.Container{
   133  						{Name: "dbg", Image: "dbgimage"},
   134  					},
   135  				},
   136  			},
   137  			containerName: "dbg",
   138  			target:        testNode,
   139  			expectPod: &corev1.Pod{
   140  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   141  				Spec: corev1.PodSpec{
   142  					HostNetwork: true,
   143  					HostPID:     true,
   144  					HostIPC:     true,
   145  					Containers: []corev1.Container{
   146  						{
   147  							Name:  "dbg",
   148  							Image: "dbgimage",
   149  							VolumeMounts: []corev1.VolumeMount{
   150  								{
   151  									MountPath: "/host",
   152  									Name:      "host-root",
   153  								},
   154  							},
   155  						},
   156  					},
   157  					Volumes: []corev1.Volume{
   158  						{
   159  							Name: "host-root",
   160  							VolumeSource: corev1.VolumeSource{
   161  								HostPath: &corev1.HostPathVolumeSource{Path: "/"},
   162  							},
   163  						},
   164  					},
   165  				},
   166  			},
   167  		},
   168  	}
   169  
   170  	for name, test := range tests {
   171  		t.Run(name, func(t *testing.T) {
   172  			err := (&generalProfile{}).Apply(test.pod, test.containerName, test.target)
   173  			if (err != nil) != test.expectErr {
   174  				t.Fatalf("expect error: %v, got error: %v", test.expectErr, (err != nil))
   175  			}
   176  			if err != nil {
   177  				return
   178  			}
   179  			if diff := cmp.Diff(test.expectPod, test.pod); diff != "" {
   180  				t.Error("unexpected diff in generated object: (-want +got):\n", diff)
   181  			}
   182  		})
   183  	}
   184  }
   185  
   186  func TestBaselineProfile(t *testing.T) {
   187  	pod := &corev1.Pod{
   188  		ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   189  		Spec: corev1.PodSpec{EphemeralContainers: []corev1.EphemeralContainer{
   190  			{
   191  				EphemeralContainerCommon: corev1.EphemeralContainerCommon{
   192  					Name: "dbg", Image: "dbgimage",
   193  					SecurityContext: &corev1.SecurityContext{
   194  						Capabilities: &corev1.Capabilities{
   195  							Add: []corev1.Capability{"SYS_PTRACE"},
   196  						},
   197  					},
   198  				},
   199  			},
   200  		}},
   201  	}
   202  
   203  	tests := map[string]struct {
   204  		pod           *corev1.Pod
   205  		containerName string
   206  		target        runtime.Object
   207  		expectPod     *corev1.Pod
   208  		expectErr     bool
   209  	}{
   210  		"bad inputs results in error": {
   211  			pod:           nil,
   212  			containerName: "dbg",
   213  			target:        runtime.Object(nil),
   214  			expectErr:     true,
   215  		},
   216  		"debug by ephemeral container": {
   217  			pod:           pod,
   218  			containerName: "dbg",
   219  			target:        pod,
   220  			expectPod: &corev1.Pod{
   221  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   222  				Spec: corev1.PodSpec{EphemeralContainers: []corev1.EphemeralContainer{
   223  					{
   224  						EphemeralContainerCommon: corev1.EphemeralContainerCommon{
   225  							Name: "dbg", Image: "dbgimage",
   226  						},
   227  					},
   228  				}},
   229  			},
   230  		},
   231  		"debug by pod copy": {
   232  			pod: &corev1.Pod{
   233  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   234  				Spec: corev1.PodSpec{
   235  					Containers: []corev1.Container{
   236  						{Name: "app", Image: "appimage"},
   237  						{Name: "dbg", Image: "dbgimage"},
   238  					},
   239  				},
   240  			},
   241  			containerName: "dbg",
   242  			target: &corev1.Pod{
   243  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   244  				Spec: corev1.PodSpec{
   245  					Containers: []corev1.Container{
   246  						{Name: "app", Image: "appimage"},
   247  					},
   248  				},
   249  			},
   250  			expectPod: &corev1.Pod{
   251  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   252  				Spec: corev1.PodSpec{
   253  					ShareProcessNamespace: pointer.Bool(true),
   254  					Containers: []corev1.Container{
   255  						{Name: "app", Image: "appimage"},
   256  						{
   257  							Name:  "dbg",
   258  							Image: "dbgimage",
   259  						},
   260  					},
   261  				},
   262  			},
   263  		},
   264  		"debug by node": {
   265  			pod: &corev1.Pod{
   266  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   267  				Spec: corev1.PodSpec{
   268  					Containers: []corev1.Container{
   269  						{Name: "dbg", Image: "dbgimage"},
   270  					},
   271  				},
   272  			},
   273  			containerName: "dbg",
   274  			target:        testNode,
   275  			expectPod: &corev1.Pod{
   276  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   277  				Spec: corev1.PodSpec{
   278  					Containers: []corev1.Container{
   279  						{
   280  							Name:  "dbg",
   281  							Image: "dbgimage",
   282  						},
   283  					},
   284  				},
   285  			},
   286  		},
   287  	}
   288  
   289  	for name, test := range tests {
   290  		t.Run(name, func(t *testing.T) {
   291  			err := (&baselineProfile{}).Apply(test.pod, test.containerName, test.target)
   292  			if (err != nil) != test.expectErr {
   293  				t.Fatalf("expect error: %v, got error: %v", test.expectErr, (err != nil))
   294  			}
   295  			if err != nil {
   296  				return
   297  			}
   298  			if diff := cmp.Diff(test.expectPod, test.pod); diff != "" {
   299  				t.Error("unexpected diff in generated object: (-want +got):\n", diff)
   300  			}
   301  		})
   302  	}
   303  }
   304  
   305  func TestRestrictedProfile(t *testing.T) {
   306  	pod := &corev1.Pod{
   307  		ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   308  		Spec: corev1.PodSpec{EphemeralContainers: []corev1.EphemeralContainer{
   309  			{
   310  				EphemeralContainerCommon: corev1.EphemeralContainerCommon{
   311  					Name: "dbg", Image: "dbgimage",
   312  					SecurityContext: &corev1.SecurityContext{
   313  						Capabilities: &corev1.Capabilities{
   314  							Add: []corev1.Capability{"SYS_PTRACE"},
   315  						},
   316  					},
   317  				},
   318  			},
   319  		}},
   320  	}
   321  
   322  	tests := map[string]struct {
   323  		pod           *corev1.Pod
   324  		containerName string
   325  		target        runtime.Object
   326  		expectPod     *corev1.Pod
   327  		expectErr     bool
   328  	}{
   329  		"bad inputs results in error": {
   330  			pod:           nil,
   331  			containerName: "dbg",
   332  			target:        runtime.Object(nil),
   333  			expectErr:     true,
   334  		},
   335  		"debug by ephemeral container": {
   336  			pod:           pod,
   337  			containerName: "dbg",
   338  			target:        pod,
   339  			expectPod: &corev1.Pod{
   340  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   341  				Spec: corev1.PodSpec{EphemeralContainers: []corev1.EphemeralContainer{
   342  					{
   343  						EphemeralContainerCommon: corev1.EphemeralContainerCommon{
   344  							Name: "dbg", Image: "dbgimage",
   345  							SecurityContext: &corev1.SecurityContext{
   346  								RunAsNonRoot: pointer.Bool(true),
   347  								Capabilities: &corev1.Capabilities{
   348  									Drop: []corev1.Capability{"ALL"},
   349  								},
   350  								AllowPrivilegeEscalation: pointer.Bool(false),
   351  								SeccompProfile:           &corev1.SeccompProfile{Type: "RuntimeDefault"},
   352  							},
   353  						},
   354  					},
   355  				}},
   356  			},
   357  		},
   358  		"debug by pod copy": {
   359  			pod: &corev1.Pod{
   360  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   361  				Spec: corev1.PodSpec{
   362  					Containers: []corev1.Container{
   363  						{Name: "app", Image: "appimage"},
   364  						{Name: "dbg", Image: "dbgimage"},
   365  					},
   366  				},
   367  			},
   368  			containerName: "dbg",
   369  			target: &corev1.Pod{
   370  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   371  				Spec: corev1.PodSpec{
   372  					Containers: []corev1.Container{
   373  						{Name: "app", Image: "appimage"},
   374  					},
   375  				},
   376  			},
   377  			expectPod: &corev1.Pod{
   378  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   379  				Spec: corev1.PodSpec{
   380  					ShareProcessNamespace: pointer.Bool(true),
   381  					Containers: []corev1.Container{
   382  						{Name: "app", Image: "appimage"},
   383  						{
   384  							Name:  "dbg",
   385  							Image: "dbgimage",
   386  							SecurityContext: &corev1.SecurityContext{
   387  								RunAsNonRoot: pointer.Bool(true),
   388  								Capabilities: &corev1.Capabilities{
   389  									Drop: []corev1.Capability{"ALL"},
   390  								},
   391  								AllowPrivilegeEscalation: pointer.Bool(false),
   392  								SeccompProfile:           &corev1.SeccompProfile{Type: "RuntimeDefault"},
   393  							},
   394  						},
   395  					},
   396  				},
   397  			},
   398  		},
   399  		"debug by node": {
   400  			pod: &corev1.Pod{
   401  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   402  				Spec: corev1.PodSpec{
   403  					Containers: []corev1.Container{
   404  						{
   405  							Name:  "dbg",
   406  							Image: "dbgimage",
   407  							SecurityContext: &corev1.SecurityContext{
   408  								Capabilities: &corev1.Capabilities{
   409  									Add: []corev1.Capability{"ALL"},
   410  								},
   411  								AllowPrivilegeEscalation: pointer.Bool(false),
   412  								SeccompProfile:           &corev1.SeccompProfile{Type: "RuntimeDefault"},
   413  							},
   414  						},
   415  					},
   416  				},
   417  			},
   418  			containerName: "dbg",
   419  			target:        testNode,
   420  			expectPod: &corev1.Pod{
   421  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   422  				Spec: corev1.PodSpec{
   423  					Containers: []corev1.Container{
   424  						{
   425  							Name:  "dbg",
   426  							Image: "dbgimage",
   427  							SecurityContext: &corev1.SecurityContext{
   428  								RunAsNonRoot: pointer.Bool(true),
   429  								Capabilities: &corev1.Capabilities{
   430  									Drop: []corev1.Capability{"ALL"},
   431  								},
   432  								AllowPrivilegeEscalation: pointer.Bool(false),
   433  								SeccompProfile:           &corev1.SeccompProfile{Type: "RuntimeDefault"},
   434  							},
   435  						},
   436  					},
   437  				},
   438  			},
   439  		},
   440  	}
   441  
   442  	for name, test := range tests {
   443  		t.Run(name, func(t *testing.T) {
   444  			err := (&restrictedProfile{}).Apply(test.pod, test.containerName, test.target)
   445  			if (err != nil) != test.expectErr {
   446  				t.Fatalf("expect error: %v, got error: %v", test.expectErr, (err != nil))
   447  			}
   448  			if err != nil {
   449  				return
   450  			}
   451  			if diff := cmp.Diff(test.expectPod, test.pod); diff != "" {
   452  				t.Error("unexpected diff in generated object: (-want +got):\n", diff)
   453  			}
   454  		})
   455  	}
   456  }
   457  
   458  func TestNetAdminProfile(t *testing.T) {
   459  	pod := &corev1.Pod{
   460  		ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   461  		Spec: corev1.PodSpec{EphemeralContainers: []corev1.EphemeralContainer{
   462  			{
   463  				EphemeralContainerCommon: corev1.EphemeralContainerCommon{
   464  					Name: "dbg", Image: "dbgimage",
   465  				},
   466  			},
   467  		}},
   468  	}
   469  
   470  	tests := []struct {
   471  		name          string
   472  		pod           *corev1.Pod
   473  		containerName string
   474  		target        runtime.Object
   475  		expectPod     *corev1.Pod
   476  		expectErr     error
   477  	}{
   478  		{
   479  			name:          "nil target",
   480  			pod:           pod,
   481  			containerName: "dbg",
   482  			target:        nil,
   483  			expectErr:     fmt.Errorf("netadmin profile: objects of type <nil> are not supported"),
   484  		},
   485  		{
   486  			name:          "debug by ephemeral container",
   487  			pod:           pod,
   488  			containerName: "dbg",
   489  			target:        pod,
   490  			expectPod: &corev1.Pod{
   491  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   492  				Spec: corev1.PodSpec{EphemeralContainers: []corev1.EphemeralContainer{
   493  					{
   494  						EphemeralContainerCommon: corev1.EphemeralContainerCommon{
   495  							Name: "dbg", Image: "dbgimage",
   496  							SecurityContext: &corev1.SecurityContext{
   497  								Capabilities: &corev1.Capabilities{
   498  									Add: []corev1.Capability{"NET_ADMIN", "NET_RAW"},
   499  								},
   500  							},
   501  						},
   502  					},
   503  				}},
   504  			},
   505  		},
   506  		{
   507  			name: "debug by pod copy",
   508  			pod: &corev1.Pod{
   509  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   510  				Spec: corev1.PodSpec{
   511  					Containers: []corev1.Container{
   512  						{Name: "app", Image: "appimage"},
   513  						{Name: "dbg", Image: "dbgimage"},
   514  					},
   515  				},
   516  			},
   517  			containerName: "dbg",
   518  			target: &corev1.Pod{
   519  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   520  				Spec: corev1.PodSpec{
   521  					Containers: []corev1.Container{
   522  						{Name: "app", Image: "appimage"},
   523  					},
   524  				},
   525  			},
   526  			expectPod: &corev1.Pod{
   527  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   528  				Spec: corev1.PodSpec{
   529  					ShareProcessNamespace: pointer.Bool(true),
   530  					Containers: []corev1.Container{
   531  						{Name: "app", Image: "appimage"},
   532  						{
   533  							Name:  "dbg",
   534  							Image: "dbgimage",
   535  							SecurityContext: &corev1.SecurityContext{
   536  								Capabilities: &corev1.Capabilities{
   537  									Add: []corev1.Capability{"NET_ADMIN", "NET_RAW"},
   538  								},
   539  							},
   540  						},
   541  					},
   542  				},
   543  			},
   544  		},
   545  		{
   546  			name: "debug by pod copy preserve existing capability",
   547  			pod: &corev1.Pod{
   548  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   549  				Spec: corev1.PodSpec{
   550  					Containers: []corev1.Container{
   551  						{Name: "app", Image: "appimage"},
   552  						{
   553  							Name:  "dbg",
   554  							Image: "dbgimage",
   555  							SecurityContext: &corev1.SecurityContext{
   556  								Capabilities: &corev1.Capabilities{
   557  									Add: []corev1.Capability{"SYS_PTRACE"},
   558  								},
   559  							},
   560  						},
   561  					},
   562  				},
   563  			},
   564  			containerName: "dbg",
   565  			target: &corev1.Pod{
   566  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   567  				Spec: corev1.PodSpec{
   568  					Containers: []corev1.Container{
   569  						{Name: "app", Image: "appimage"},
   570  					},
   571  				},
   572  			},
   573  			expectPod: &corev1.Pod{
   574  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   575  				Spec: corev1.PodSpec{
   576  					ShareProcessNamespace: pointer.Bool(true),
   577  					Containers: []corev1.Container{
   578  						{Name: "app", Image: "appimage"},
   579  						{
   580  							Name:  "dbg",
   581  							Image: "dbgimage",
   582  							SecurityContext: &corev1.SecurityContext{
   583  								Capabilities: &corev1.Capabilities{
   584  									Add: []corev1.Capability{"SYS_PTRACE", "NET_ADMIN", "NET_RAW"},
   585  								},
   586  							},
   587  						},
   588  					},
   589  				},
   590  			},
   591  		},
   592  		{
   593  			name: "debug by node",
   594  			pod: &corev1.Pod{
   595  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   596  				Spec: corev1.PodSpec{
   597  					Containers: []corev1.Container{
   598  						{Name: "dbg", Image: "dbgimage"},
   599  					},
   600  				},
   601  			},
   602  			containerName: "dbg",
   603  			target:        testNode,
   604  			expectPod: &corev1.Pod{
   605  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   606  				Spec: corev1.PodSpec{
   607  					HostNetwork: true,
   608  					HostPID:     true,
   609  					HostIPC:     true,
   610  					Containers: []corev1.Container{
   611  						{
   612  							Name:  "dbg",
   613  							Image: "dbgimage",
   614  							SecurityContext: &corev1.SecurityContext{
   615  								Capabilities: &corev1.Capabilities{
   616  									Add: []corev1.Capability{"NET_ADMIN", "NET_RAW"},
   617  								},
   618  							},
   619  						},
   620  					},
   621  				},
   622  			},
   623  		},
   624  		{
   625  			name: "debug by node preserve existing capability",
   626  			pod: &corev1.Pod{
   627  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   628  				Spec: corev1.PodSpec{
   629  					Containers: []corev1.Container{
   630  						{
   631  							Name:  "dbg",
   632  							Image: "dbgimage",
   633  							SecurityContext: &corev1.SecurityContext{
   634  								Capabilities: &corev1.Capabilities{
   635  									Add: []corev1.Capability{"SYS_PTRACE"},
   636  								},
   637  							},
   638  						},
   639  					},
   640  				},
   641  			},
   642  			containerName: "dbg",
   643  			target:        testNode,
   644  			expectPod: &corev1.Pod{
   645  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   646  				Spec: corev1.PodSpec{
   647  					HostNetwork: true,
   648  					HostPID:     true,
   649  					HostIPC:     true,
   650  					Containers: []corev1.Container{
   651  						{
   652  							Name:  "dbg",
   653  							Image: "dbgimage",
   654  							SecurityContext: &corev1.SecurityContext{
   655  								Capabilities: &corev1.Capabilities{
   656  									Add: []corev1.Capability{"SYS_PTRACE", "NET_ADMIN", "NET_RAW"},
   657  								},
   658  							},
   659  						},
   660  					},
   661  				},
   662  			},
   663  		},
   664  	}
   665  
   666  	for _, test := range tests {
   667  		t.Run(test.name, func(t *testing.T) {
   668  			err := (&netadminProfile{}).Apply(test.pod, test.containerName, test.target)
   669  			if (err == nil) != (test.expectErr == nil) || (err != nil && test.expectErr != nil && err.Error() != test.expectErr.Error()) {
   670  				t.Fatalf("expect error: %v, got error: %v", test.expectErr, err)
   671  			}
   672  			if err != nil {
   673  				return
   674  			}
   675  			if diff := cmp.Diff(test.expectPod, test.pod); diff != "" {
   676  				t.Error("unexpected diff in generated object: (-want +got):\n", diff)
   677  			}
   678  		})
   679  	}
   680  }
   681  
   682  func TestSysAdminProfile(t *testing.T) {
   683  	pod := &corev1.Pod{
   684  		ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   685  		Spec: corev1.PodSpec{EphemeralContainers: []corev1.EphemeralContainer{
   686  			{
   687  				EphemeralContainerCommon: corev1.EphemeralContainerCommon{
   688  					Name: "dbg", Image: "dbgimage",
   689  				},
   690  			},
   691  		}},
   692  	}
   693  
   694  	tests := []struct {
   695  		name          string
   696  		pod           *corev1.Pod
   697  		containerName string
   698  		target        runtime.Object
   699  		expectPod     *corev1.Pod
   700  		expectErr     error
   701  	}{
   702  		{
   703  			name:          "nil target",
   704  			pod:           pod,
   705  			containerName: "dbg",
   706  			target:        nil,
   707  			expectErr:     fmt.Errorf("sysadmin profile: objects of type <nil> are not supported"),
   708  		},
   709  		{
   710  			name:          "debug by ephemeral container",
   711  			pod:           pod,
   712  			containerName: "dbg",
   713  			target:        pod,
   714  			expectPod: &corev1.Pod{
   715  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   716  				Spec: corev1.PodSpec{EphemeralContainers: []corev1.EphemeralContainer{
   717  					{
   718  						EphemeralContainerCommon: corev1.EphemeralContainerCommon{
   719  							Name: "dbg", Image: "dbgimage",
   720  							SecurityContext: &corev1.SecurityContext{
   721  								Privileged: pointer.Bool(true),
   722  							},
   723  						},
   724  					},
   725  				}},
   726  			},
   727  		},
   728  		{
   729  			name: "debug by pod copy",
   730  			pod: &corev1.Pod{
   731  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   732  				Spec: corev1.PodSpec{
   733  					Containers: []corev1.Container{
   734  						{Name: "app", Image: "appimage"},
   735  						{Name: "dbg", Image: "dbgimage"},
   736  					},
   737  				},
   738  			},
   739  			containerName: "dbg",
   740  			target: &corev1.Pod{
   741  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   742  				Spec: corev1.PodSpec{
   743  					Containers: []corev1.Container{
   744  						{Name: "app", Image: "appimage"},
   745  					},
   746  				},
   747  			},
   748  			expectPod: &corev1.Pod{
   749  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   750  				Spec: corev1.PodSpec{
   751  					Containers: []corev1.Container{
   752  						{Name: "app", Image: "appimage"},
   753  						{
   754  							Name:  "dbg",
   755  							Image: "dbgimage",
   756  							SecurityContext: &corev1.SecurityContext{
   757  								Privileged: pointer.Bool(true),
   758  							},
   759  						},
   760  					},
   761  					ShareProcessNamespace: pointer.Bool(true),
   762  				},
   763  			},
   764  		},
   765  		{
   766  			name: "debug by pod copy preserve existing capability",
   767  			pod: &corev1.Pod{
   768  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   769  				Spec: corev1.PodSpec{
   770  					Containers: []corev1.Container{
   771  						{Name: "app", Image: "appimage"},
   772  						{
   773  							Name:  "dbg",
   774  							Image: "dbgimage",
   775  							SecurityContext: &corev1.SecurityContext{
   776  								Capabilities: &corev1.Capabilities{
   777  									Add: []corev1.Capability{"SYS_PTRACE"},
   778  								},
   779  							},
   780  						},
   781  					},
   782  				},
   783  			},
   784  			containerName: "dbg",
   785  			target: &corev1.Pod{
   786  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   787  				Spec: corev1.PodSpec{
   788  					Containers: []corev1.Container{
   789  						{Name: "app", Image: "appimage"},
   790  					},
   791  				},
   792  			},
   793  			expectPod: &corev1.Pod{
   794  				ObjectMeta: metav1.ObjectMeta{Name: "podcopy"},
   795  				Spec: corev1.PodSpec{
   796  					Containers: []corev1.Container{
   797  						{Name: "app", Image: "appimage"},
   798  						{
   799  							Name:  "dbg",
   800  							Image: "dbgimage",
   801  							SecurityContext: &corev1.SecurityContext{
   802  								Privileged: pointer.Bool(true),
   803  								Capabilities: &corev1.Capabilities{
   804  									Add: []corev1.Capability{"SYS_PTRACE"},
   805  								},
   806  							},
   807  						},
   808  					},
   809  					ShareProcessNamespace: pointer.Bool(true),
   810  				},
   811  			},
   812  		},
   813  		{
   814  			name: "debug by node",
   815  			pod: &corev1.Pod{
   816  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   817  				Spec: corev1.PodSpec{
   818  					Containers: []corev1.Container{
   819  						{Name: "dbg", Image: "dbgimage"},
   820  					},
   821  				},
   822  			},
   823  			containerName: "dbg",
   824  			target:        testNode,
   825  			expectPod: &corev1.Pod{
   826  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   827  				Spec: corev1.PodSpec{
   828  					HostNetwork: true,
   829  					HostPID:     true,
   830  					HostIPC:     true,
   831  					Volumes: []corev1.Volume{
   832  						{
   833  							Name:         "host-root",
   834  							VolumeSource: corev1.VolumeSource{HostPath: &corev1.HostPathVolumeSource{Path: "/"}},
   835  						},
   836  					},
   837  					Containers: []corev1.Container{
   838  						{
   839  							Name:  "dbg",
   840  							Image: "dbgimage",
   841  							SecurityContext: &corev1.SecurityContext{
   842  								Privileged: pointer.Bool(true),
   843  							},
   844  							VolumeMounts: []corev1.VolumeMount{{Name: "host-root", MountPath: "/host"}},
   845  						},
   846  					},
   847  				},
   848  			},
   849  		},
   850  		{
   851  			name: "debug by node preserve existing capability",
   852  			pod: &corev1.Pod{
   853  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   854  				Spec: corev1.PodSpec{
   855  					Containers: []corev1.Container{
   856  						{
   857  							Name:  "dbg",
   858  							Image: "dbgimage",
   859  							SecurityContext: &corev1.SecurityContext{
   860  								Capabilities: &corev1.Capabilities{
   861  									Add: []corev1.Capability{"SYS_PTRACE"},
   862  								},
   863  							},
   864  						},
   865  					},
   866  				},
   867  			},
   868  			containerName: "dbg",
   869  			target:        testNode,
   870  			expectPod: &corev1.Pod{
   871  				ObjectMeta: metav1.ObjectMeta{Name: "pod"},
   872  				Spec: corev1.PodSpec{
   873  					HostNetwork: true,
   874  					HostPID:     true,
   875  					HostIPC:     true,
   876  					Volumes: []corev1.Volume{
   877  						{
   878  							Name:         "host-root",
   879  							VolumeSource: corev1.VolumeSource{HostPath: &corev1.HostPathVolumeSource{Path: "/"}},
   880  						},
   881  					},
   882  					Containers: []corev1.Container{
   883  						{
   884  							Name:  "dbg",
   885  							Image: "dbgimage",
   886  							SecurityContext: &corev1.SecurityContext{
   887  								Privileged: pointer.Bool(true),
   888  								Capabilities: &corev1.Capabilities{
   889  									Add: []corev1.Capability{"SYS_PTRACE"},
   890  								},
   891  							},
   892  							VolumeMounts: []corev1.VolumeMount{{Name: "host-root", MountPath: "/host"}},
   893  						},
   894  					},
   895  				},
   896  			},
   897  		},
   898  	}
   899  
   900  	for _, test := range tests {
   901  		t.Run(test.name, func(t *testing.T) {
   902  			err := (&sysadminProfile{}).Apply(test.pod, test.containerName, test.target)
   903  			if (err == nil) != (test.expectErr == nil) || (err != nil && test.expectErr != nil && err.Error() != test.expectErr.Error()) {
   904  				t.Fatalf("expect error: %v, got error: %v", test.expectErr, err)
   905  			}
   906  			if err != nil {
   907  				return
   908  			}
   909  			if diff := cmp.Diff(test.expectPod, test.pod); diff != "" {
   910  				t.Error("unexpected diff in generated object: (-want +got):\n", diff)
   911  			}
   912  		})
   913  	}
   914  }
   915  

View as plain text