...
1
16
17 package pod
18
19 import (
20 "flag"
21 "fmt"
22
23 "github.com/onsi/ginkgo/v2"
24 "github.com/onsi/gomega"
25
26 v1 "k8s.io/api/core/v1"
27 imageutils "k8s.io/kubernetes/test/utils/image"
28 psaapi "k8s.io/pod-security-admission/api"
29 psapolicy "k8s.io/pod-security-admission/policy"
30 "k8s.io/utils/pointer"
31 )
32
33
34
35
36
37
38 func NodeOSDistroIs(distro string) bool {
39 var nodeOsDistro *flag.Flag = flag.Lookup("node-os-distro")
40 if nodeOsDistro != nil && nodeOsDistro.Value.String() == distro {
41 return true
42 }
43 return false
44 }
45
46
47 func GenerateScriptCmd(command string) []string {
48 var commands []string
49 commands = []string{"/bin/sh", "-c", command}
50 return commands
51 }
52
53
54
55
56
57 func GetDefaultTestImage() string {
58 return imageutils.GetE2EImage(GetDefaultTestImageID())
59 }
60
61
62
63
64
65 func GetDefaultTestImageID() imageutils.ImageID {
66 return GetTestImageID(imageutils.BusyBox)
67 }
68
69
70
71
72 func GetTestImage(id imageutils.ImageID) string {
73 if NodeOSDistroIs("windows") {
74 return imageutils.GetE2EImage(imageutils.Agnhost)
75 }
76 return imageutils.GetE2EImage(id)
77 }
78
79
80
81
82 func GetTestImageID(id imageutils.ImageID) imageutils.ImageID {
83 if NodeOSDistroIs("windows") {
84 return imageutils.Agnhost
85 }
86 return id
87 }
88
89
90
91
92 func GetDefaultNonRootUser() *int64 {
93 if NodeOSDistroIs("windows") {
94 return nil
95 }
96 return pointer.Int64(DefaultNonRootUser)
97 }
98
99
100
101
102 func GeneratePodSecurityContext(fsGroup *int64, seLinuxOptions *v1.SELinuxOptions) *v1.PodSecurityContext {
103 if NodeOSDistroIs("windows") {
104 return nil
105 }
106 return &v1.PodSecurityContext{
107 FSGroup: fsGroup,
108 SELinuxOptions: seLinuxOptions,
109 }
110 }
111
112
113
114
115 func GenerateContainerSecurityContext(level psaapi.Level) *v1.SecurityContext {
116 if NodeOSDistroIs("windows") {
117 return nil
118 }
119
120 switch level {
121 case psaapi.LevelBaseline:
122 return &v1.SecurityContext{
123 Privileged: pointer.Bool(false),
124 }
125 case psaapi.LevelPrivileged:
126 return &v1.SecurityContext{
127 Privileged: pointer.Bool(true),
128 }
129 case psaapi.LevelRestricted:
130 return GetRestrictedContainerSecurityContext()
131 default:
132 ginkgo.Fail(fmt.Sprintf("unknown k8s.io/pod-security-admission/policy.Level %q", level))
133 panic("not reached")
134 }
135 }
136
137
138
139 func GetLinuxLabel() *v1.SELinuxOptions {
140 if NodeOSDistroIs("windows") {
141 return nil
142 }
143 return &v1.SELinuxOptions{
144 Level: "s0:c0,c1"}
145 }
146
147
148 const DefaultNonRootUser = 1000
149
150
151 const DefaultNonRootUserName = "ContainerUser"
152
153
154
155
156 func GetRestrictedPodSecurityContext() *v1.PodSecurityContext {
157 psc := &v1.PodSecurityContext{
158 RunAsNonRoot: pointer.Bool(true),
159 RunAsUser: GetDefaultNonRootUser(),
160 SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeRuntimeDefault},
161 }
162
163 if NodeOSDistroIs("windows") {
164 psc.WindowsOptions = &v1.WindowsSecurityContextOptions{}
165 psc.WindowsOptions.RunAsUserName = pointer.String(DefaultNonRootUserName)
166 }
167
168 return psc
169 }
170
171
172 func GetRestrictedContainerSecurityContext() *v1.SecurityContext {
173 return &v1.SecurityContext{
174 AllowPrivilegeEscalation: pointer.Bool(false),
175 Capabilities: &v1.Capabilities{Drop: []v1.Capability{"ALL"}},
176 }
177 }
178
179 var psaEvaluator, _ = psapolicy.NewEvaluator(psapolicy.DefaultChecks())
180
181
182
183 func MustMixinRestrictedPodSecurity(pod *v1.Pod) *v1.Pod {
184 err := MixinRestrictedPodSecurity(pod)
185 gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
186 return pod
187 }
188
189
190
191
192
193 func MixinRestrictedPodSecurity(pod *v1.Pod) error {
194 if pod.Spec.SecurityContext == nil {
195 pod.Spec.SecurityContext = GetRestrictedPodSecurityContext()
196 } else {
197 if pod.Spec.SecurityContext.RunAsNonRoot == nil {
198 pod.Spec.SecurityContext.RunAsNonRoot = pointer.Bool(true)
199 }
200 if pod.Spec.SecurityContext.RunAsUser == nil {
201 pod.Spec.SecurityContext.RunAsUser = GetDefaultNonRootUser()
202 }
203 if pod.Spec.SecurityContext.SeccompProfile == nil {
204 pod.Spec.SecurityContext.SeccompProfile = &v1.SeccompProfile{Type: v1.SeccompProfileTypeRuntimeDefault}
205 }
206 if NodeOSDistroIs("windows") && pod.Spec.SecurityContext.WindowsOptions == nil {
207 pod.Spec.SecurityContext.WindowsOptions = &v1.WindowsSecurityContextOptions{}
208 pod.Spec.SecurityContext.WindowsOptions.RunAsUserName = pointer.String(DefaultNonRootUserName)
209 }
210 }
211 for i := range pod.Spec.Containers {
212 mixinRestrictedContainerSecurityContext(&pod.Spec.Containers[i])
213 }
214 for i := range pod.Spec.InitContainers {
215 mixinRestrictedContainerSecurityContext(&pod.Spec.InitContainers[i])
216 }
217
218
219 restricted := psaapi.LevelVersion{
220 Level: psaapi.LevelRestricted,
221 Version: psaapi.LatestVersion(),
222 }
223 if agg := psapolicy.AggregateCheckResults(psaEvaluator.EvaluatePod(restricted, &pod.ObjectMeta, &pod.Spec)); !agg.Allowed {
224 return fmt.Errorf("failed to make pod %s restricted: %s", pod.Name, agg.ForbiddenDetail())
225 }
226
227 return nil
228 }
229
230
231
232
233 func mixinRestrictedContainerSecurityContext(container *v1.Container) {
234 if container.SecurityContext == nil {
235 container.SecurityContext = GetRestrictedContainerSecurityContext()
236 } else {
237 if container.SecurityContext.AllowPrivilegeEscalation == nil {
238 container.SecurityContext.AllowPrivilegeEscalation = pointer.Bool(false)
239 }
240 if container.SecurityContext.Capabilities == nil {
241 container.SecurityContext.Capabilities = &v1.Capabilities{}
242 }
243 if len(container.SecurityContext.Capabilities.Drop) == 0 {
244 container.SecurityContext.Capabilities.Drop = []v1.Capability{"ALL"}
245 }
246 }
247 }
248
249
250 func FindPodConditionByType(podStatus *v1.PodStatus, conditionType v1.PodConditionType) *v1.PodCondition {
251 for _, cond := range podStatus.Conditions {
252 if cond.Type == conditionType {
253 return &cond
254 }
255 }
256 return nil
257 }
258
259
260 func FindContainerStatusInPod(pod *v1.Pod, containerName string) *v1.ContainerStatus {
261 for _, containerStatus := range pod.Status.InitContainerStatuses {
262 if containerStatus.Name == containerName {
263 return &containerStatus
264 }
265 }
266 for _, containerStatus := range pod.Status.ContainerStatuses {
267 if containerStatus.Name == containerName {
268 return &containerStatus
269 }
270 }
271 for _, containerStatus := range pod.Status.EphemeralContainerStatuses {
272 if containerStatus.Name == containerName {
273 return &containerStatus
274 }
275 }
276 return nil
277 }
278
View as plain text