├── tests ├── clean.sh ├── 0-ns.yaml ├── 3-pod.yaml ├── 4-pod.yaml ├── 5-pod.yaml ├── 6-pod.yaml ├── 2-dep-sec-cont.yaml ├── tests.sh └── 1-ok.yaml ├── CODE_OF_CONDUCT.md ├── LICENSE ├── CONTRIBUTING.md └── README.md /tests/clean.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #set -o errexit 3 | 4 | CMD_KUBECTL="kubectl" 5 | 6 | ${CMD_KUBECTL} delete ns policy-test 2>&1 7 | 8 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /tests/0-ns.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: policy-test 5 | labels: 6 | # pod-security.kubernetes.io/enforce-version: "v1.23" 7 | # pod-security.kubernetes.io/audit-version: "v1.23" 8 | # pod-security.kubernetes.io/warn-version: "v1.23" 9 | 10 | # pod-security.kubernetes.io/enforce: privileged 11 | # pod-security.kubernetes.io/audit: privileged 12 | # pod-security.kubernetes.io/warn: privileged 13 | 14 | # pod-security.kubernetes.io/enforce: baseline 15 | # pod-security.kubernetes.io/audit: baseline 16 | # pod-security.kubernetes.io/warn: baseline 17 | 18 | # pod-security.kubernetes.io/enforce: restricted 19 | # pod-security.kubernetes.io/audit: restricted 20 | # pod-security.kubernetes.io/warn: restricted 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /tests/3-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: test 5 | namespace: policy-test 6 | labels: 7 | app: test 8 | owner: jimmy 9 | env: dev 10 | billing: lob-cc 11 | spec: 12 | containers: 13 | - name: test 14 | image: public.ecr.aws/r2l1x4g2/go-http-server:v0.1.0-23ffe0a715 15 | imagePullPolicy: IfNotPresent 16 | ports: 17 | - containerPort: 8080 18 | resources: 19 | limits: 20 | cpu: 200m 21 | memory: 20Mi 22 | requests: 23 | cpu: 100m 24 | memory: 10Mi 25 | readinessProbe: 26 | tcpSocket: 27 | port: 8080 28 | initialDelaySeconds: 5 29 | periodSeconds: 10 30 | livenessProbe: 31 | tcpSocket: 32 | port: 8080 33 | initialDelaySeconds: 15 34 | periodSeconds: 20 35 | volumeMounts: 36 | - mountPath: /tmp 37 | name: tmp 38 | volumes: 39 | - name: tmp 40 | emptyDir: {} 41 | -------------------------------------------------------------------------------- /tests/4-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: test2 5 | namespace: policy-test 6 | labels: 7 | app: test 8 | owner: jimmy 9 | env: dev 10 | billing: lob-cc 11 | spec: 12 | securityContext: 13 | runAsUser: 1000 14 | runAsNonRoot: true 15 | containers: 16 | - name: test 17 | image: public.ecr.aws/r2l1x4g2/go-http-server:v0.1.0-23ffe0a715 18 | imagePullPolicy: IfNotPresent 19 | ports: 20 | - containerPort: 8080 21 | resources: 22 | limits: 23 | cpu: 200m 24 | memory: 20Mi 25 | requests: 26 | cpu: 100m 27 | memory: 10Mi 28 | readinessProbe: 29 | tcpSocket: 30 | port: 8080 31 | initialDelaySeconds: 5 32 | periodSeconds: 10 33 | livenessProbe: 34 | tcpSocket: 35 | port: 8080 36 | initialDelaySeconds: 15 37 | periodSeconds: 20 38 | volumeMounts: 39 | - mountPath: /tmp 40 | name: tmp 41 | volumes: 42 | - name: tmp 43 | emptyDir: {} 44 | -------------------------------------------------------------------------------- /tests/5-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: test3 5 | namespace: policy-test 6 | labels: 7 | app: test 8 | owner: jimmy 9 | env: dev 10 | billing: lob-cc 11 | spec: 12 | containers: 13 | - name: test 14 | image: public.ecr.aws/r2l1x4g2/go-http-server:v0.1.0-23ffe0a715 15 | imagePullPolicy: IfNotPresent 16 | securityContext: 17 | allowPrivilegeEscalation: true 18 | runAsUser: 1000 19 | readOnlyRootFilesystem: false 20 | runAsNonRoot: false 21 | capabilities: 22 | drop: ["ALL"] 23 | seccompProfile: 24 | type: "RuntimeDefault" 25 | ports: 26 | - containerPort: 8080 27 | resources: 28 | limits: 29 | cpu: 200m 30 | memory: 20Mi 31 | requests: 32 | cpu: 100m 33 | memory: 10Mi 34 | readinessProbe: 35 | tcpSocket: 36 | port: 8080 37 | initialDelaySeconds: 5 38 | periodSeconds: 10 39 | livenessProbe: 40 | tcpSocket: 41 | port: 8080 42 | initialDelaySeconds: 15 43 | periodSeconds: 20 44 | volumeMounts: 45 | - mountPath: /tmp 46 | name: tmp 47 | volumes: 48 | - name: tmp 49 | emptyDir: {} 50 | -------------------------------------------------------------------------------- /tests/6-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: test4 5 | namespace: policy-test 6 | labels: 7 | app: test 8 | owner: jimmy 9 | env: dev 10 | billing: lob-cc 11 | spec: 12 | hostNetwork: true 13 | hostPID: true 14 | hostIPC: true 15 | containers: 16 | - name: test 17 | image: public.ecr.aws/r2l1x4g2/go-http-server:v0.1.0-23ffe0a715 18 | imagePullPolicy: IfNotPresent 19 | securityContext: 20 | allowPrivilegeEscalation: false 21 | runAsUser: 1000 22 | readOnlyRootFilesystem: true 23 | runAsNonRoot: true 24 | capabilities: 25 | drop: ["ALL"] 26 | seccompProfile: 27 | type: "RuntimeDefault" 28 | ports: 29 | - containerPort: 8080 30 | resources: 31 | limits: 32 | cpu: 200m 33 | memory: 20Mi 34 | requests: 35 | cpu: 100m 36 | memory: 10Mi 37 | readinessProbe: 38 | tcpSocket: 39 | port: 8080 40 | initialDelaySeconds: 5 41 | periodSeconds: 10 42 | livenessProbe: 43 | tcpSocket: 44 | port: 8080 45 | initialDelaySeconds: 15 46 | periodSeconds: 20 47 | volumeMounts: 48 | - mountPath: /tmp 49 | name: tmp 50 | volumes: 51 | - name: tmp 52 | emptyDir: {} 53 | -------------------------------------------------------------------------------- /tests/2-dep-sec-cont.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test 5 | namespace: policy-test 6 | labels: 7 | app: test 8 | owner: jimmy 9 | env: dev 10 | billing: lob-cc 11 | spec: 12 | selector: 13 | matchLabels: 14 | app: test 15 | replicas: 1 16 | strategy: 17 | type: RollingUpdate 18 | rollingUpdate: 19 | maxSurge: 5 20 | maxUnavailable: 1 21 | template: 22 | metadata: 23 | labels: 24 | app: test 25 | owner: jimmy 26 | env: dev 27 | billing: lob-cc 28 | spec: 29 | containers: 30 | - name: test 31 | image: public.ecr.aws/r2l1x4g2/go-http-server:v0.1.0-23ffe0a715 32 | imagePullPolicy: IfNotPresent 33 | ports: 34 | - containerPort: 8080 35 | resources: 36 | limits: 37 | cpu: 200m 38 | memory: 20Mi 39 | requests: 40 | cpu: 100m 41 | memory: 10Mi 42 | readinessProbe: 43 | tcpSocket: 44 | port: 8080 45 | initialDelaySeconds: 5 46 | periodSeconds: 10 47 | livenessProbe: 48 | tcpSocket: 49 | port: 8080 50 | initialDelaySeconds: 15 51 | periodSeconds: 20 52 | volumeMounts: 53 | - mountPath: /tmp 54 | name: tmp 55 | volumes: 56 | - name: tmp 57 | emptyDir: {} 58 | -------------------------------------------------------------------------------- /tests/tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #set -o errexit 3 | 4 | NEWLINE=$'\n' 5 | CMD_KUBECTL="kubectl" 6 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 7 | PREFIX="$SCRIPT_DIR/" 8 | #clear 9 | 10 | ${CMD_KUBECTL} apply -f ${PREFIX}0-ns.yaml 11 | 12 | echo "${NEWLINE}" 13 | 14 | echo ">>> 1. Good config..." 15 | ${CMD_KUBECTL} apply -f ${PREFIX}1-ok.yaml 16 | sleep 2 17 | ${CMD_KUBECTL} delete -f ${PREFIX}1-ok.yaml 18 | sleep 2 19 | 20 | echo "${NEWLINE}" 21 | 22 | echo ">>> 2. Deployment - Missing container security context element..." 23 | ${CMD_KUBECTL} apply -f ${PREFIX}2-dep-sec-cont.yaml 24 | sleep 2 25 | 26 | echo "${NEWLINE}" 27 | 28 | echo ">>> 3. Pod - Missing container security context element..." 29 | ${CMD_KUBECTL} apply -f ${PREFIX}3-pod.yaml 30 | sleep 2 31 | 32 | echo "${NEWLINE}" 33 | 34 | echo ">>> 4. Pod - Pod security context, but Missing container security context element..." 35 | ${CMD_KUBECTL} apply -f ${PREFIX}4-pod.yaml 36 | sleep 2 37 | 38 | echo "${NEWLINE}" 39 | 40 | echo ">>> 5. Pod - Container security context element present, with incorrect settings..." 41 | ${CMD_KUBECTL} apply -f ${PREFIX}5-pod.yaml 42 | sleep 2 43 | 44 | echo "${NEWLINE}" 45 | 46 | echo ">>> 6. Pod - Container security context element present, with incorrect spec.hostNetwork, spec.hostPID, spec.hostIPC settings..." 47 | ${CMD_KUBECTL} apply -f ${PREFIX}6-pod.yaml 48 | sleep 2 49 | 50 | echo "${NEWLINE}" 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /tests/1-ok.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test 5 | namespace: policy-test 6 | labels: 7 | app: test 8 | owner: jimmy 9 | env: dev 10 | billing: lob-cc 11 | spec: 12 | selector: 13 | matchLabels: 14 | app: test 15 | replicas: 1 16 | strategy: 17 | type: RollingUpdate 18 | rollingUpdate: 19 | maxSurge: 5 20 | maxUnavailable: 1 21 | template: 22 | metadata: 23 | labels: 24 | app: test 25 | owner: jimmy 26 | env: dev 27 | billing: lob-cc 28 | spec: 29 | containers: 30 | - name: test 31 | image: public.ecr.aws/r2l1x4g2/go-http-server:v0.1.0-23ffe0a715 32 | imagePullPolicy: IfNotPresent 33 | securityContext: 34 | allowPrivilegeEscalation: false 35 | runAsUser: 1000 36 | readOnlyRootFilesystem: true 37 | runAsNonRoot: true 38 | capabilities: 39 | drop: ["ALL"] 40 | seccompProfile: 41 | type: "RuntimeDefault" 42 | ports: 43 | - containerPort: 8080 44 | resources: 45 | limits: 46 | cpu: 200m 47 | memory: 20Mi 48 | requests: 49 | cpu: 100m 50 | memory: 10Mi 51 | readinessProbe: 52 | tcpSocket: 53 | port: 8080 54 | initialDelaySeconds: 5 55 | periodSeconds: 10 56 | livenessProbe: 57 | tcpSocket: 58 | port: 8080 59 | initialDelaySeconds: 15 60 | periodSeconds: 20 61 | volumeMounts: 62 | - mountPath: /tmp 63 | name: tmp 64 | volumes: 65 | - name: tmp 66 | emptyDir: {} 67 | 68 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pod Security Admission (PSA) Testing for Kubernetes 1.23 2 | 3 | ## Testing Summary 4 | 5 | Several test scenarios were executed against a Kubernetes 1.23 cluster, with [Pod Security Admission (PSA)](https://kubernetes.io/docs/concepts/security/pod-security-admission/) and [Pod Security Standards (PSS)](https://kubernetes.io/docs/concepts/security/pod-security-standards/) _Privileged_ profile enabled by default. The testing was designed to exercise different PSA modes and PSS profiles, while producing the following responses: 6 | 7 | * Allowing Pods that meet profile requirements 8 | * Disallowing pods that don’t meet profile requirements 9 | * Allowing Deployments, even if Pods did not meet PSS profile requirements 10 | * Failure (forbidden) responses to Kubernetes API server clients when Pods don’t meet profile requirements 11 | * Deployment resource statuses, reflecting failed (forbidden) Pods 12 | * Kubernetes API server logs with PSA controller responses, reflecting failed (forbidden) Pods 13 | * Warning messages to Kubernetes API server clients when Deployments contained Pod specs that failed PSS profile requirements 14 | 15 | ## Testing Outcomes 16 | 17 | * PSA functions correctly in Kubernetes 1.23 18 | * PSS profiles (Privileged, Baseline, and Restricted) function as expected in Kubenetes 1.23 19 | * PSA modes (audit, enforce, and warn) function as expected in Kubernetes 1.23 20 | 21 | ## Testing Assumptions 22 | 23 | * PSA _Enforce_ mode only affects Pods, and does not affect workload resource controllers (Deployment, etc.) that create Pods. 24 | * No PSA exemptions are configured at API server startup, for the PSA controller. 25 | * The _Privileged_ PSS profile is configured by default for all PSA modes, and set to latest versions. 26 | 27 | ``` 28 | apiVersion: apiserver.config.k8s.io/v1 29 | kind: AdmissionConfiguration 30 | plugins: 31 | - name: PodSecurity 32 | configuration: 33 | apiVersion: pod-security.admission.config.k8s.io/v1beta1 34 | kind: PodSecurityConfiguration 35 | # Defaults applied when a mode label is not set. 36 | # 37 | # Level label values must be one of: 38 | # - "privileged" (default) 39 | # - "baseline" 40 | # - "restricted" 41 | # 42 | # Version label values must be one of: 43 | # - "latest" (default) 44 | # - specific version like "v1.24" 45 | defaults: 46 | enforce: "privileged" 47 | enforce-version: "latest" 48 | audit: "privileged" 49 | audit-version: "latest" 50 | warn: "privileged" 51 | warn-version: "latest" 52 | exemptions: 53 | # Array of authenticated usernames to exempt. 54 | usernames: [] 55 | # Array of runtime class names to exempt. 56 | runtimeClasses: [] 57 | # Array of namespaces to exempt. 58 | namespaces: [] 59 | ``` 60 | 61 | ## Testing Setup and Execution 62 | 63 | * policy-test Namespace created 64 | 65 | ``` 66 | apiVersion: v1 67 | kind: Namespace 68 | metadata: 69 | name: policy-test 70 | labels: 71 | # pod-security.kubernetes.io/enforce: privileged 72 | # pod-security.kubernetes.io/audit: privileged 73 | # pod-security.kubernetes.io/warn: privileged 74 | 75 | # pod-security.kubernetes.io/enforce: baseline 76 | # pod-security.kubernetes.io/audit: baseline 77 | # pod-security.kubernetes.io/warn: baseline 78 | 79 | # pod-security.kubernetes.io/enforce: restricted 80 | # pod-security.kubernetes.io/audit: restricted 81 | # pod-security.kubernetes.io/warn: restricted 82 | ``` 83 | 84 | * Known good Kubernetes Deployment created and then deleted 85 | 86 | ``` 87 | apiVersion: apps/v1 88 | kind: Deployment 89 | namespace: policy-test 90 | ... 91 | spec: 92 | containers: 93 | - name: test 94 | image: public.ecr.aws/r2l1x4g2/go-http-server:v0.1.0-23ffe0a715 95 | imagePullPolicy: IfNotPresent 96 | securityContext: 97 | allowPrivilegeEscalation: false 98 | runAsUser: 1000 99 | readOnlyRootFilesystem: true 100 | runAsNonRoot: true 101 | capabilities: 102 | drop: ["ALL"] 103 | seccompProfile: 104 | type: "RuntimeDefault" 105 | ports: 106 | - containerPort: 8080 107 | ... 108 | ``` 109 | 110 | * Known bad Kubernetes Deployment created 111 | * No securityContext element at the Pod level 112 | * No securityContext element at the Container level 113 | 114 | ``` 115 | apiVersion: apps/v1 116 | kind: Deployment 117 | metadata: 118 | name: test 119 | namespace: policy-test 120 | ... 121 | spec: 122 | containers: 123 | - name: test 124 | image: public.ecr.aws/r2l1x4g2/go-http-server:v0.1.0-23ffe0a715 125 | imagePullPolicy: IfNotPresent 126 | ports: 127 | - containerPort: 8080 128 | ... 129 | ``` 130 | 131 | * Known bad Pod created 132 | * No securityContext element at the Pod level 133 | * No securityContext element at the Container level 134 | 135 | ``` 136 | apiVersion: v1 137 | kind: Pod 138 | metadata: 139 | name: test 140 | namespace: policy-test 141 | ... 142 | spec: 143 | containers: 144 | - name: test 145 | image: public.ecr.aws/r2l1x4g2/go-http-server:v0.1.0-23ffe0a715 146 | imagePullPolicy: IfNotPresent 147 | ports: 148 | - containerPort: 8080 149 | ... 150 | ``` 151 | 152 | * Known bad Pod created 153 | * securityContext element at the Pod level exists with valid runAsUser and runAsNonRoot elements. 154 | * No securityContext element at the Container level 155 | 156 | ``` 157 | apiVersion: v1 158 | kind: Pod 159 | metadata: 160 | name: test2 161 | namespace: policy-test 162 | ... 163 | spec: 164 | securityContext: 165 | runAsUser: 1000 166 | runAsNonRoot: true 167 | containers: 168 | - name: test 169 | image: public.ecr.aws/r2l1x4g2/go-http-server:v0.1.0-23ffe0a715 170 | imagePullPolicy: IfNotPresent 171 | ports: 172 | - containerPort: 8080 173 | ... 174 | ``` 175 | 176 | * Known bad Pod created 177 | * No securityContext element at the Pod level. 178 | * securityContext element at the Container level exists with incorrect settings for allowPrivilegeEscalation, readOnlyRootFilesystem, and runAsNonRoot 179 | 180 | ``` 181 | apiVersion: v1 182 | kind: Pod 183 | metadata: 184 | name: test3 185 | namespace: policy-test 186 | ... 187 | spec: 188 | containers: 189 | - name: test 190 | image: public.ecr.aws/r2l1x4g2/go-http-server:v0.1.0-23ffe0a715 191 | imagePullPolicy: IfNotPresent 192 | securityContext: 193 | allowPrivilegeEscalation: true 194 | runAsUser: 1000 195 | readOnlyRootFilesystem: false 196 | runAsNonRoot: false 197 | capabilities: 198 | drop: ["ALL"] 199 | seccompProfile: 200 | type: "RuntimeDefault" 201 | ports: 202 | ... 203 | ``` 204 | 205 | * Known bad Pod created 206 | * No securityContext element at the Pod level. 207 | * securityContext element at the Container level exists with correct settings 208 | * Pod spec has incorrect hostNetwork, hostPID, and hostIPC settings 209 | 210 | ``` 211 | apiVersion: v1 212 | kind: Pod 213 | metadata: 214 | name: test4 215 | namespace: policy-test 216 | ... 217 | spec: 218 | hostNetwork: true 219 | hostPID: true 220 | hostIPC: true 221 | containers: 222 | - name: test 223 | image: public.ecr.aws/r2l1x4g2/go-http-server:v0.1.0-23ffe0a715 224 | imagePullPolicy: IfNotPresent 225 | securityContext: 226 | allowPrivilegeEscalation: false 227 | runAsUser: 1000 228 | readOnlyRootFilesystem: true 229 | runAsNonRoot: true 230 | capabilities: 231 | drop: ["ALL"] 232 | seccompProfile: 233 | type: "RuntimeDefault" 234 | ports: 235 | - containerPort: 8080 236 | ... 237 | ``` 238 | 239 | ## Testing Scenarios 240 | 241 | ### PSA Modes Enabled with Default (Cluster Level) PSS Privileged Profile 242 | 243 | * Namespace Config (no Namespace-level settings) 244 | 245 | ``` 246 | apiVersion: v1 247 | kind: Namespace 248 | metadata: 249 | name: policy-test 250 | labels: 251 | # pod-security.kubernetes.io/enforce: privileged 252 | # pod-security.kubernetes.io/audit: privileged 253 | # pod-security.kubernetes.io/warn: privileged 254 | 255 | # pod-security.kubernetes.io/enforce: baseline 256 | # pod-security.kubernetes.io/audit: baseline 257 | # pod-security.kubernetes.io/warn: baseline 258 | 259 | # pod-security.kubernetes.io/enforce: restricted 260 | # pod-security.kubernetes.io/audit: restricted 261 | # pod-security.kubernetes.io/warn: restricted 262 | ``` 263 | 264 | * Test Output - Default PSS Privileged Profile Applied (5 Pods allowed, 0 Pods disallowed) 265 | 266 | ``` 267 | namespace/policy-test created 268 | 269 | 270 | >>> 1. Good config... 271 | deployment.apps/test created 272 | deployment.apps "test" deleted 273 | 274 | 275 | >>> 2. Deployment - Missing container security context element... 276 | deployment.apps/test created 277 | 278 | 279 | >>> 3. Pod - Missing container security context element... 280 | pod/test created 281 | 282 | 283 | >>> 4. Pod - Pod security context, but Missing container security context element... 284 | pod/test2 created 285 | 286 | 287 | >>> 5. Pod - Container security context element present, with incorrect settings... 288 | pod/test3 created 289 | 290 | 291 | >>> 6. Pod - Container security context element present, with incorrect spec.hostNetwork, spec.hostPID, spec.hostIPC settings... 292 | pod/test4 created 293 | 294 | k -n policy-test get po 295 | NAME READY STATUS RESTARTS AGE 296 | test 1/1 Running 0 70s 297 | test-59955f994-djtqz 1/1 Running 0 76s 298 | test2 1/1 Running 0 65s 299 | test3 1/1 Running 0 59s 300 | test4 1/1 Running 0 55s 301 | ``` 302 | 303 | ### All PSA Modes Enabled for Privileged PSS Profile (Namespace Level) 304 | 305 | * Namespace Config 306 | 307 | ``` 308 | apiVersion: v1 309 | kind: Namespace 310 | metadata: 311 | name: policy-test 312 | labels: 313 | pod-security.kubernetes.io/enforce: privileged 314 | pod-security.kubernetes.io/audit: privileged 315 | pod-security.kubernetes.io/warn: privileged 316 | 317 | # pod-security.kubernetes.io/enforce: baseline 318 | # pod-security.kubernetes.io/audit: baseline 319 | # pod-security.kubernetes.io/warn: baseline 320 | 321 | # pod-security.kubernetes.io/enforce: restricted 322 | # pod-security.kubernetes.io/audit: restricted 323 | # pod-security.kubernetes.io/warn: restricted 324 | ``` 325 | 326 | * Test Output - Namespace-level PSS Privileged Profile Applied (5 Pods allowed, 0 Pods disallowed) 327 | 328 | ``` 329 | namespace/policy-test created 330 | 331 | 332 | >>> 1. Good config... 333 | deployment.apps/test created 334 | deployment.apps "test" deleted 335 | 336 | 337 | >>> 2. Deployment - Missing container security context element... 338 | deployment.apps/test created 339 | 340 | 341 | >>> 3. Pod - Missing container security context element... 342 | pod/test created 343 | 344 | 345 | >>> 4. Pod - Pod security context, but Missing container security context element... 346 | pod/test2 created 347 | 348 | 349 | >>> 5. Pod - Container security context element present, with incorrect settings... 350 | pod/test3 created 351 | 352 | 353 | >>> 6. Pod - Container security context element present, with incorrect spec.hostNetwork, spec.hostPID, spec.hostIPC settings... 354 | pod/test4 created 355 | 356 | k -n policy-test get po 357 | NAME READY STATUS RESTARTS AGE 358 | test 1/1 Running 0 54s 359 | test-59955f994-cssz9 1/1 Running 0 59s 360 | test2 1/1 Running 0 48s 361 | test3 1/1 Running 0 42s 362 | test4 1/1 Running 0 38s 363 | ``` 364 | 365 | ### All PSA Modes Enabled for Baseline PSS Profile (Namespace Level) 366 | 367 | * Namespace Config 368 | 369 | ``` 370 | apiVersion: v1 371 | kind: Namespace 372 | metadata: 373 | name: policy-test 374 | labels: 375 | # pod-security.kubernetes.io/enforce: privileged 376 | # pod-security.kubernetes.io/audit: privileged 377 | # pod-security.kubernetes.io/warn: privileged 378 | 379 | pod-security.kubernetes.io/enforce: baseline 380 | pod-security.kubernetes.io/audit: baseline 381 | pod-security.kubernetes.io/warn: baseline 382 | 383 | # pod-security.kubernetes.io/enforce: restricted 384 | # pod-security.kubernetes.io/audit: restricted 385 | # pod-security.kubernetes.io/warn: restricted 386 | ``` 387 | 388 | * Test Output - Namespace-level PSS Baseline Profile Applied (4 Pods allowed, 1 Pod disallowed) 389 | 390 | ``` 391 | namespace/policy-test created 392 | 393 | 394 | >>> 1. Good config... 395 | deployment.apps/test created 396 | deployment.apps "test" deleted 397 | 398 | 399 | >>> 2. Deployment - Missing container security context element... 400 | deployment.apps/test created 401 | 402 | 403 | >>> 3. Pod - Missing container security context element... 404 | pod/test created 405 | 406 | 407 | >>> 4. Pod - Pod security context, but Missing container security context element... 408 | pod/test2 created 409 | 410 | 411 | >>> 5. Pod - Container security context element present, with incorrect settings... 412 | pod/test3 created 413 | 414 | 415 | >>> 6. Pod - Container security context element present, with incorrect spec.hostNetwork, spec.hostPID, spec.hostIPC settings... 416 | Error from server (Forbidden): error when creating "policy/psa-pss/tests/6-pod.yaml": pods "test4" is forbidden: violates PodSecurity "baseline:latest": host namespaces (hostNetwork=true, hostPID=true, hostIPC=true), hostPort (container "test" uses hostPort 8080) 417 | 418 | k -n policy-test get po 419 | NAME READY STATUS RESTARTS AGE 420 | test 1/1 Running 0 46s 421 | test-59955f994-6tbj7 1/1 Running 0 52s 422 | test2 1/1 Running 0 42s 423 | test3 1/1 Running 0 37s 424 | ``` 425 | 426 | ### All PSA Modes Enabled for Restricted PSS Profile (Namespace Level) 427 | 428 | * Namespace Config 429 | 430 | ``` 431 | apiVersion: v1 432 | kind: Namespace 433 | metadata: 434 | name: policy-test 435 | labels: 436 | # pod-security.kubernetes.io/enforce: privileged 437 | # pod-security.kubernetes.io/audit: privileged 438 | # pod-security.kubernetes.io/warn: privileged 439 | 440 | # pod-security.kubernetes.io/enforce: baseline 441 | # pod-security.kubernetes.io/audit: baseline 442 | # pod-security.kubernetes.io/warn: baseline 443 | 444 | pod-security.kubernetes.io/enforce: restricted 445 | pod-security.kubernetes.io/audit: restricted 446 | pod-security.kubernetes.io/warn: restricted 447 | ``` 448 | 449 | * Test Output - Namespace-level PSS Restricted Profile Applied (0 Pods allowed, 5 Pods disallowed) 450 | * 1 Deployment created, with 0 Pods allowed 451 | 452 | ``` 453 | namespace/policy-test created 454 | 455 | 456 | >>> 1. Good config... 457 | deployment.apps/test created 458 | deployment.apps "test" deleted 459 | 460 | 461 | >>> 2. Deployment - Missing container security context element... 462 | Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "test" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "test" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "test" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "test" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost") 463 | deployment.apps/test created 464 | 465 | 466 | >>> 3. Pod - Missing container security context element... 467 | Error from server (Forbidden): error when creating "policy/psa-pss/tests/3-pod.yaml": pods "test" is forbidden: violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "test" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "test" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "test" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "test" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost") 468 | 469 | 470 | >>> 4. Pod - Pod security context, but Missing container security context element... 471 | Error from server (Forbidden): error when creating "policy/psa-pss/tests/4-pod.yaml": pods "test2" is forbidden: violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "test" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "test" must set securityContext.capabilities.drop=["ALL"]), seccompProfile (pod or container "test" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost") 472 | 473 | 474 | >>> 5. Pod - Container security context element present, with incorrect settings... 475 | Error from server (Forbidden): error when creating "policy/psa-pss/tests/5-pod.yaml": pods "test3" is forbidden: violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "test" must set securityContext.allowPrivilegeEscalation=false), runAsNonRoot != true (container "test" must not set securityContext.runAsNonRoot=false) 476 | 477 | 478 | >>> 6. Pod - Container security context element present, with incorrect spec.hostNetwork, spec.hostPID, spec.hostIPC settings... 479 | Error from server (Forbidden): error when creating "policy/psa-pss/tests/6-pod.yaml": pods "test4" is forbidden: violates PodSecurity "restricted:latest": host namespaces (hostNetwork=true, hostPID=true, hostIPC=true), hostPort (container "test" uses hostPort 8080) 480 | 481 | k -n policy-test get po 482 | No resources found in policy-test namespace. 483 | 484 | k -n policy-test get deploy test -oyaml 485 | ... 486 | status: 487 | conditions: 488 | ... 489 | - lastTransitionTime: "2022-07-12T23:56:10Z" 490 | lastUpdateTime: "2022-07-12T23:56:10Z" 491 | message: 'pods "test-59955f994-wl8hf" is forbidden: violates PodSecurity "restricted:latest": 492 | allowPrivilegeEscalation != false (container "test" must set securityContext.allowPrivilegeEscalation=false), 493 | unrestricted capabilities (container "test" must set securityContext.capabilities.drop=["ALL"]), 494 | runAsNonRoot != true (pod or container "test" must set securityContext.runAsNonRoot=true), 495 | seccompProfile (pod or container "test" must set securityContext.seccompProfile.type 496 | to "RuntimeDefault" or "Localhost")' 497 | reason: FailedCreate 498 | status: "True" 499 | type: ReplicaFailure 500 | ... 501 | ``` 502 | 503 | ## Useful Commands 504 | ### Label Namespace 505 | ``` 506 | kubectl label --overwrite ns policy-test pod-security.kubernetes.io/enforce=restricted \ 507 | pod-security.kubernetes.io/warn=restricted pod-security.kubernetes.io/audit=restricted 508 | ``` 509 | ### Check Namespace Labels 510 | ``` 511 | kubectl get ns policy-test -L pod-security.kubernetes.io/enforce \ 512 | -L pod-security.kubernetes.io/warn -L pod-security.kubernetes.io/audit 513 | ``` 514 | 515 | ## References 516 | * https://aws.github.io/aws-eks-best-practices/security/docs/pods/#pod-security-standards-pss-and-pod-security-admission-psa 517 | * https://kubernetes.io/docs/concepts/security/pod-security-standards/ 518 | * https://kubernetes.io/docs/concepts/security/pod-security-admission/ 519 | 520 | ## Security 521 | 522 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 523 | 524 | ## License 525 | 526 | This library is licensed under the MIT-0 License. See the LICENSE file. 527 | 528 | --------------------------------------------------------------------------------