├── manifests ├── nginx-signed.yaml ├── nginx-unsigned.yaml ├── base │ ├── ingress.yaml │ ├── cosign-system.yaml │ ├── sigstore-system.yaml │ ├── sigstore-ns1.yaml │ └── sigstore-ns2.yaml ├── sigstore-demo │ ├── Chart.yaml │ ├── values.yaml │ └── templates │ │ ├── service.yaml │ │ ├── ingress.yaml │ │ └── deployment.yaml ├── cosign-action-image.yaml ├── kind-config.yaml ├── imagePolicy.yaml └── ingress-controller │ └── deploy.yaml └── README.md /manifests/nginx-signed.yaml: -------------------------------------------------------------------------------- 1 | name: nginx-demo-signed 2 | 3 | image: 4 | repository: ghcr.io/{GITHUB_USER}/nginx 5 | tag: signed 6 | -------------------------------------------------------------------------------- /manifests/nginx-unsigned.yaml: -------------------------------------------------------------------------------- 1 | name: nginx-demo-unsigned 2 | 3 | image: 4 | repository: ghcr.io/{$GITHUB_USERNAME}/nginx2 5 | tag: unsigned 6 | -------------------------------------------------------------------------------- /manifests/base/ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: ingress-nginx 5 | labels: 6 | kubernetes.io/metadata.name: ingress-nginx -------------------------------------------------------------------------------- /manifests/sigstore-demo/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | appVersion: "1.0" 3 | description: A Helm chart for sigstore-demo 4 | name: sigstore-demo 5 | version: 0.0.1 6 | -------------------------------------------------------------------------------- /manifests/base/cosign-system.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: sigstore-system 5 | labels: 6 | kubernetes.io/metadata.name: sigstore-system -------------------------------------------------------------------------------- /manifests/base/sigstore-system.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: sigstore-system 5 | labels: 6 | kubernetes.io/metadata.name: sigstore-system -------------------------------------------------------------------------------- /manifests/cosign-action-image.yaml: -------------------------------------------------------------------------------- 1 | name: cosign-keyless-action 2 | 3 | image: 4 | repository: ghcr.io/lukehinds/cosign-keyless-action 5 | # ghcr.io/lukehinds/sigstore-nginx:latest 6 | tag: main 7 | -------------------------------------------------------------------------------- /manifests/sigstore-demo/values.yaml: -------------------------------------------------------------------------------- 1 | name: sigstore-demo 2 | 3 | image: 4 | repository: ghcr.io/lukehinds/cosign-demo 5 | tag: main 6 | pullPolicy: Always 7 | 8 | annotations: {} 9 | podAnnotations: {} -------------------------------------------------------------------------------- /manifests/base/sigstore-ns1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: sigstore-ns1 5 | labels: 6 | kubernetes.io/metadata.name: sigstore-ns1 7 | policy.sigstore.dev/include: "true" -------------------------------------------------------------------------------- /manifests/base/sigstore-ns2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: sigstore-ns2 5 | labels: 6 | kubernetes.io/metadata.name: sigstore-ns2 7 | policy.sigstore.dev/include: "true" -------------------------------------------------------------------------------- /manifests/sigstore-demo/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: "{{ .Values.name }}" 5 | namespace: "{{ .Values.namespace }}" 6 | labels: 7 | app.kubernetes.io/name: "{{ .Values.name }}" 8 | spec: 9 | type: ClusterIP 10 | ports: 11 | - name: http 12 | port: 8080 13 | targetPort: 8080 14 | protocol: TCP 15 | selector: 16 | app.kubernetes.io/name: "{{ .Values.name }}" -------------------------------------------------------------------------------- /manifests/kind-config.yaml: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.x-k8s.io/v1alpha4 3 | nodes: 4 | - role: control-plane 5 | extraPortMappings: 6 | - containerPort: 80 7 | hostPort: 80 8 | protocol: TCP 9 | - containerPort: 443 10 | hostPort: 443 11 | protocol: TCP 12 | kubeadmConfigPatches: 13 | - | 14 | kind: InitConfiguration 15 | nodeRegistration: 16 | kubeletExtraArgs: 17 | node-labels: "ingress-ready=true" 18 | - role: worker 19 | -------------------------------------------------------------------------------- /manifests/imagePolicy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: policy.sigstore.dev/v1beta1 2 | kind: ClusterImagePolicy 3 | metadata: 4 | name: sigstore-demo 5 | spec: 6 | images: 7 | - glob: "**" 8 | authorities: 9 | - keyless: 10 | identities: 11 | # - issuer: https://accounts.google.com 12 | # subject: {$EMAIL}@gmail.com 13 | - issuer: https://token.actions.githubusercontent.com 14 | subject: https://github.com/{$GITHUB_USERNAME}/cosign-keyless-action/.github/workflows/build-push-sign.yml@refs/heads/main -------------------------------------------------------------------------------- /manifests/sigstore-demo/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: "{{ .Values.name }}" 5 | namespace: "{{ .Values.namespace }}" 6 | labels: 7 | app.kubernetes.io/name: "{{ .Values.name }}" 8 | spec: 9 | ingressClassName: nginx 10 | rules: 11 | - host: "{{ .Values.name }}.localtest.me" 12 | http: 13 | paths: 14 | - backend: 15 | service: 16 | name: "{{ .Values.name }}" 17 | port: 18 | number: 8080 19 | path: / 20 | pathType: ImplementationSpecific -------------------------------------------------------------------------------- /manifests/sigstore-demo/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: "{{ .Values.name }}" 5 | namespace: "{{ .Values.namespace }}" 6 | labels: 7 | app.kubernetes.io/name: "{{ .Values.name }}" 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app.kubernetes.io/name: "{{ .Values.name }}" 13 | template: 14 | metadata: 15 | labels: 16 | app.kubernetes.io/name: "{{ .Values.name }}" 17 | spec: 18 | containers: 19 | - name: "{{ .Values.name }}" 20 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 21 | imagePullPolicy: "{{ .Values.image.pullPolicy }}" 22 | ports: 23 | - name: http 24 | containerPort: 8080 25 | protocol: TCP 26 | livenessProbe: 27 | failureThreshold: 3 28 | httpGet: 29 | path: /healthy 30 | port: 8080 31 | scheme: HTTP 32 | initialDelaySeconds: 10 33 | periodSeconds: 5 34 | readinessProbe: 35 | httpGet: 36 | path: /ready 37 | port: 8080 38 | scheme: HTTP 39 | periodSeconds: 10 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sigstore policy controller demo 2 | 3 | This demo will show you how to use the sigstore policy (admission) controller 4 | to verify keyless sigstore signatures. 5 | 6 | ## Huh, what the hell is keyless? 7 | 8 | Keyless is the slight of hand we use to perform crypto signing with no need for 9 | long term key management. 10 | 11 | The flow is in general terms: 12 | 13 | An ecdsa key pair is generated (encoded to memory, never to touch any disk). 14 | 15 | A user connects to sigstores fulcio CA to request a signing certificate. 16 | 17 | Fulcio directs them to an OpenID connect provider of their choosing (such as Github, 18 | Google, Microsoft etc). 19 | 20 | If the user auths correctly, an ID Token is provided. 21 | 22 | The user then presents their OAuth2 ID Token to the sigstore fulcio CA and 23 | requests a X509 certificate. 24 | 25 | The certificate contains: 26 | 27 | * The Public Key of the ephemeral key pair. 28 | * The email address (stuck in a SAN) 29 | * It has a chain to the sigstore root CA 30 | 31 | The user then signs an artifact (container in this instance), and the digest / x509 32 | cert are stored in sigstore rekor (transparency log) 33 | 34 | We can then drop the private key, as that signing event is effectively frozen 35 | in time. 36 | 37 | We can now look at the transparency log and know that: 38 | 39 | At X time, a user with control of X OpenID account, was in possession of X key 40 | pair, and X key pair signed X container digest. 41 | 42 | Using the policy controller, we can then allow / deny an image, based on which 43 | OAuth2 account signed the image. 44 | 45 | As a follow up, I will add details of how we can use this for a sort of code 46 | provenance using GitHubs OpenID ambient credentials. 47 | 48 | ## Prerequisites 49 | 50 | Five tools are required to run this demo: 51 | - [cosign](https://github.com/sigstore/cosign) 52 | - [cosign-policy-controller](https://github.com/sigstore/policy-controller) (installed as part of the demo later on) 53 | - [kind](https://kind.sigs.k8s.io/) 54 | - [kubectl](https://github.com/kubernetes/kubernetes) 55 | - [helm](https://helm.sh/) 56 | 57 | 58 | Grab the nginx image: 59 | 60 | ```shell 61 | docker pull nginxdemos/nginx-hello 62 | ``` 63 | 64 | Tag to images: 65 | 66 | ```shell 67 | docker tag nginxdemos/nginx-hello ghcr.io/{$GITHUB_USERNAME}/nginx:signed 68 | 69 | docker tag nginxdemos/nginx-hello ghcr.io/{$GITHUB_USERNAME}/nginx2:unsigned 70 | 71 | docker push ghcr.io/{$GITHUB_USERNAME}/nginx:signed 72 | 73 | docker push ghcr.io/{$GITHUB_USERNAME}/nginx2:unsigned 74 | ``` 75 | 76 | Create a kind cluster: 77 | 78 | ```shell 79 | kind create cluster --name sigstore-demo --config manifests/kind-config.yaml 80 | ``` 81 | ```shell 82 | kubectl config use-context kind-sigstore-demo 83 | ``` 84 | 85 | Apply manifests: 86 | 87 | ```shell 88 | kubectl apply -f manifests/base 89 | ``` 90 | 91 | ```shell 92 | kubectl apply -f manifests/ingress-controller 93 | ``` 94 | 95 | Setup the policy controller helm chart and install: 96 | 97 | ```shell 98 | helm repo add sigstore https://sigstore.github.io/helm-charts 99 | ``` 100 | 101 | ```shell 102 | helm repo update 103 | ``` 104 | 105 | ```shell 106 | helm install policy-controller -n sigstore-system sigstore/policy-controller 107 | ``` 108 | 109 | Wait for ready STATUS 110 | 111 | ```shell 112 | $ kubectl get pod -n sigstore-system 113 | NAME READY STATUS RESTARTS AGE 114 | policy-controller-policy-webhook-767d96744d-n2tf4 1/1 Running 0 59s 115 | policy-controller-webhook-55587bc76d-v5j9w 1/1 Running 0 116 | ``` 117 | 118 | Apply the image policy, but first set the email account you plan to sign with: 119 | 120 | ```shell 121 | - keyless: 122 | identities: 123 | - issuer: https://accounts.google.com 124 | subject: jdoe@gmail.com 125 | ``` 126 | 127 | ```shell 128 | $ kubectl apply -f manifests/imagePolicy.yaml 129 | ``` 130 | 131 | Ensure webhooks are set correctly: 132 | 133 | 134 | ```shell 135 | $ kubectl get validatingwebhookconfiguration 136 | NAME WEBHOOKS AGE 137 | ingress-sigstore-admission 1 52m 138 | policy.sigstore.dev 1 79s 139 | validating.clusterimagepolicy.sigstore.dev 1 79s 140 | 141 | $ kubectl get mutatingwebhookconfiguration 142 | NAME WEBHOOKS AGE 143 | defaulting.clusterimagepolicy.sigstore.dev 1 83s 144 | policy.sigstore.dev 145 | 146 | ``` 147 | 148 | Ensure the policy is applied to the correct namespace 149 | 150 | ```shell 151 | $ kubectl get ns sigstore-ns1 -o jsonpath='{.metadata.labels}' 152 | {"kubernetes.io/metadata.name":"nginx-ns1","policy.sigstore.dev/include":"true"} 153 | ``` 154 | 155 | # Deploy images 156 | 157 | Sign the image with cosign 158 | 159 | ```shell 160 | cosign sign ghcr.io/{$GITHUB_USERNAME}/nginx:signed 161 | ``` 162 | 163 | Attempt to deploy the signed version (should succeed) 164 | 165 | ```shell 166 | $ helm install cosign-action --atomic -n sigstore-ns1 ./manifests/sigstore-demo -f manifests/cosign-action-image.yaml 167 | 168 | NAME: nginx-signed 169 | LAST DEPLOYED: Fri Sep 2 18:55:28 2022 170 | NAMESPACE: nginx-ns1 171 | STATUS: deployed 172 | REVISION: 1 173 | TEST SUITE: None 174 | ``` 175 | 176 | Attempt to deploy the unsigned version (should fail) 177 | 178 | 179 | ```shell 180 | $ helm install nginx-unsigned --atomic -n nginx-ns1 ./manifests/nginx-demo -f manifests/cosign-action-image.yaml 181 | 182 | Error: INSTALLATION FAILED: release nginx-unsigned failed, and has been uninstalled due to atomic being set: admission webhook "policy.sigstore.dev" denied the request: validation failed: failed policy: sigstore-demo: spec.template.spec.containers[0].image 183 | ghcr.io/lukehinds/nginx2@sha256:32d4567494509b13a40899885dfbee46cec32ce918e39125161ac4de8337339c signature keyless validation failed for authority authority-0 for ghcr.io/lukehinds/cosign-keyless-action@sha256:32d4567494509b13a40899885dfbee46cec32ce918e39125161ac4de8337339c: no matching signatures: 184 | ``` 185 | 186 | Altenatively, you can use a different email address to sign the unsigned image, 187 | which should also fail 188 | 189 | ```shell 190 | & helm install nginx-unsigned --atomic -n nginx-ns1 ./manifests/nginx-demo -f manifests/nginx-unsigned.yaml 191 | 192 | Error: INSTALLATION FAILED: release nginx-unsigned failed, and has been uninstalled due to atomic being set: admission webhook "policy.sigstore.dev" denied the request: validation failed: failed policy: sigstore-demo: spec.template.spec.containers[0].image 193 | ghcr.io/lukehinds/nginx2@sha256:32d4567494509b13a40899885dfbee46cec32ce918e39125161ac4de8337339c signature keyless validation failed for authority authority-0 for ghcr.io/lukehinds/nginx2@sha256:32d4567494509b13a40899885dfbee46cec32ce918e39125161ac4de8337339c: no matching signatures: 194 | none of the expected identities matched what was in the certificate 195 | ``` 196 | 197 | ### credits 198 | 199 | A lot of the k8s configs was lifted from [here](https://medium.com/@slimm609/image-signing-validation-on-k8s-4b3202dbcd6c), so thanks due to @slimm609 / Brian Davis. 200 | -------------------------------------------------------------------------------- /manifests/ingress-controller/deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | labels: 5 | app.kubernetes.io/instance: ingress-nginx 6 | app.kubernetes.io/name: ingress-nginx 7 | name: ingress-nginx 8 | --- 9 | apiVersion: v1 10 | automountServiceAccountToken: true 11 | kind: ServiceAccount 12 | metadata: 13 | labels: 14 | app.kubernetes.io/component: controller 15 | app.kubernetes.io/instance: ingress-nginx 16 | app.kubernetes.io/name: ingress-nginx 17 | app.kubernetes.io/part-of: ingress-nginx 18 | app.kubernetes.io/version: 1.2.1 19 | name: ingress-nginx 20 | namespace: ingress-nginx 21 | --- 22 | apiVersion: v1 23 | kind: ServiceAccount 24 | metadata: 25 | labels: 26 | app.kubernetes.io/component: admission-webhook 27 | app.kubernetes.io/instance: ingress-nginx 28 | app.kubernetes.io/name: ingress-nginx 29 | app.kubernetes.io/part-of: ingress-nginx 30 | app.kubernetes.io/version: 1.2.1 31 | name: ingress-nginx-admission 32 | namespace: ingress-nginx 33 | --- 34 | apiVersion: rbac.authorization.k8s.io/v1 35 | kind: Role 36 | metadata: 37 | labels: 38 | app.kubernetes.io/component: controller 39 | app.kubernetes.io/instance: ingress-nginx 40 | app.kubernetes.io/name: ingress-nginx 41 | app.kubernetes.io/part-of: ingress-nginx 42 | app.kubernetes.io/version: 1.2.1 43 | name: ingress-nginx 44 | namespace: ingress-nginx 45 | rules: 46 | - apiGroups: 47 | - "" 48 | resources: 49 | - namespaces 50 | verbs: 51 | - get 52 | - apiGroups: 53 | - "" 54 | resources: 55 | - configmaps 56 | - pods 57 | - secrets 58 | - endpoints 59 | verbs: 60 | - get 61 | - list 62 | - watch 63 | - apiGroups: 64 | - "" 65 | resources: 66 | - services 67 | verbs: 68 | - get 69 | - list 70 | - watch 71 | - apiGroups: 72 | - networking.k8s.io 73 | resources: 74 | - ingresses 75 | verbs: 76 | - get 77 | - list 78 | - watch 79 | - apiGroups: 80 | - networking.k8s.io 81 | resources: 82 | - ingresses/status 83 | verbs: 84 | - update 85 | - apiGroups: 86 | - networking.k8s.io 87 | resources: 88 | - ingressclasses 89 | verbs: 90 | - get 91 | - list 92 | - watch 93 | - apiGroups: 94 | - "" 95 | resourceNames: 96 | - ingress-controller-leader 97 | resources: 98 | - configmaps 99 | verbs: 100 | - get 101 | - update 102 | - apiGroups: 103 | - "" 104 | resources: 105 | - configmaps 106 | verbs: 107 | - create 108 | - apiGroups: 109 | - "" 110 | resources: 111 | - events 112 | verbs: 113 | - create 114 | - patch 115 | --- 116 | apiVersion: rbac.authorization.k8s.io/v1 117 | kind: Role 118 | metadata: 119 | labels: 120 | app.kubernetes.io/component: admission-webhook 121 | app.kubernetes.io/instance: ingress-nginx 122 | app.kubernetes.io/name: ingress-nginx 123 | app.kubernetes.io/part-of: ingress-nginx 124 | app.kubernetes.io/version: 1.2.1 125 | name: ingress-nginx-admission 126 | namespace: ingress-nginx 127 | rules: 128 | - apiGroups: 129 | - "" 130 | resources: 131 | - secrets 132 | verbs: 133 | - get 134 | - create 135 | --- 136 | apiVersion: rbac.authorization.k8s.io/v1 137 | kind: ClusterRole 138 | metadata: 139 | labels: 140 | app.kubernetes.io/instance: ingress-nginx 141 | app.kubernetes.io/name: ingress-nginx 142 | app.kubernetes.io/part-of: ingress-nginx 143 | app.kubernetes.io/version: 1.2.1 144 | name: ingress-nginx 145 | rules: 146 | - apiGroups: 147 | - "" 148 | resources: 149 | - configmaps 150 | - endpoints 151 | - nodes 152 | - pods 153 | - secrets 154 | - namespaces 155 | verbs: 156 | - list 157 | - watch 158 | - apiGroups: 159 | - "" 160 | resources: 161 | - nodes 162 | verbs: 163 | - get 164 | - apiGroups: 165 | - "" 166 | resources: 167 | - services 168 | verbs: 169 | - get 170 | - list 171 | - watch 172 | - apiGroups: 173 | - networking.k8s.io 174 | resources: 175 | - ingresses 176 | verbs: 177 | - get 178 | - list 179 | - watch 180 | - apiGroups: 181 | - "" 182 | resources: 183 | - events 184 | verbs: 185 | - create 186 | - patch 187 | - apiGroups: 188 | - networking.k8s.io 189 | resources: 190 | - ingresses/status 191 | verbs: 192 | - update 193 | - apiGroups: 194 | - networking.k8s.io 195 | resources: 196 | - ingressclasses 197 | verbs: 198 | - get 199 | - list 200 | - watch 201 | --- 202 | apiVersion: rbac.authorization.k8s.io/v1 203 | kind: ClusterRole 204 | metadata: 205 | labels: 206 | app.kubernetes.io/component: admission-webhook 207 | app.kubernetes.io/instance: ingress-nginx 208 | app.kubernetes.io/name: ingress-nginx 209 | app.kubernetes.io/part-of: ingress-nginx 210 | app.kubernetes.io/version: 1.2.1 211 | name: ingress-nginx-admission 212 | rules: 213 | - apiGroups: 214 | - admissionregistration.k8s.io 215 | resources: 216 | - validatingwebhookconfigurations 217 | verbs: 218 | - get 219 | - update 220 | --- 221 | apiVersion: rbac.authorization.k8s.io/v1 222 | kind: RoleBinding 223 | metadata: 224 | labels: 225 | app.kubernetes.io/component: controller 226 | app.kubernetes.io/instance: ingress-nginx 227 | app.kubernetes.io/name: ingress-nginx 228 | app.kubernetes.io/part-of: ingress-nginx 229 | app.kubernetes.io/version: 1.2.1 230 | name: ingress-nginx 231 | namespace: ingress-nginx 232 | roleRef: 233 | apiGroup: rbac.authorization.k8s.io 234 | kind: Role 235 | name: ingress-nginx 236 | subjects: 237 | - kind: ServiceAccount 238 | name: ingress-nginx 239 | namespace: ingress-nginx 240 | --- 241 | apiVersion: rbac.authorization.k8s.io/v1 242 | kind: RoleBinding 243 | metadata: 244 | labels: 245 | app.kubernetes.io/component: admission-webhook 246 | app.kubernetes.io/instance: ingress-nginx 247 | app.kubernetes.io/name: ingress-nginx 248 | app.kubernetes.io/part-of: ingress-nginx 249 | app.kubernetes.io/version: 1.2.1 250 | name: ingress-nginx-admission 251 | namespace: ingress-nginx 252 | roleRef: 253 | apiGroup: rbac.authorization.k8s.io 254 | kind: Role 255 | name: ingress-nginx-admission 256 | subjects: 257 | - kind: ServiceAccount 258 | name: ingress-nginx-admission 259 | namespace: ingress-nginx 260 | --- 261 | apiVersion: rbac.authorization.k8s.io/v1 262 | kind: ClusterRoleBinding 263 | metadata: 264 | labels: 265 | app.kubernetes.io/instance: ingress-nginx 266 | app.kubernetes.io/name: ingress-nginx 267 | app.kubernetes.io/part-of: ingress-nginx 268 | app.kubernetes.io/version: 1.2.1 269 | name: ingress-nginx 270 | roleRef: 271 | apiGroup: rbac.authorization.k8s.io 272 | kind: ClusterRole 273 | name: ingress-nginx 274 | subjects: 275 | - kind: ServiceAccount 276 | name: ingress-nginx 277 | namespace: ingress-nginx 278 | --- 279 | apiVersion: rbac.authorization.k8s.io/v1 280 | kind: ClusterRoleBinding 281 | metadata: 282 | labels: 283 | app.kubernetes.io/component: admission-webhook 284 | app.kubernetes.io/instance: ingress-nginx 285 | app.kubernetes.io/name: ingress-nginx 286 | app.kubernetes.io/part-of: ingress-nginx 287 | app.kubernetes.io/version: 1.2.1 288 | name: ingress-nginx-admission 289 | roleRef: 290 | apiGroup: rbac.authorization.k8s.io 291 | kind: ClusterRole 292 | name: ingress-nginx-admission 293 | subjects: 294 | - kind: ServiceAccount 295 | name: ingress-nginx-admission 296 | namespace: ingress-nginx 297 | --- 298 | apiVersion: v1 299 | data: 300 | allow-snippet-annotations: "true" 301 | kind: ConfigMap 302 | metadata: 303 | labels: 304 | app.kubernetes.io/component: controller 305 | app.kubernetes.io/instance: ingress-nginx 306 | app.kubernetes.io/name: ingress-nginx 307 | app.kubernetes.io/part-of: ingress-nginx 308 | app.kubernetes.io/version: 1.2.1 309 | name: ingress-nginx-controller 310 | namespace: ingress-nginx 311 | --- 312 | apiVersion: v1 313 | kind: Service 314 | metadata: 315 | labels: 316 | app.kubernetes.io/component: controller 317 | app.kubernetes.io/instance: ingress-nginx 318 | app.kubernetes.io/name: ingress-nginx 319 | app.kubernetes.io/part-of: ingress-nginx 320 | app.kubernetes.io/version: 1.2.1 321 | name: ingress-nginx-controller 322 | namespace: ingress-nginx 323 | spec: 324 | ports: 325 | - appProtocol: http 326 | name: http 327 | port: 80 328 | protocol: TCP 329 | targetPort: http 330 | - appProtocol: https 331 | name: https 332 | port: 443 333 | protocol: TCP 334 | targetPort: https 335 | selector: 336 | app.kubernetes.io/component: controller 337 | app.kubernetes.io/instance: ingress-nginx 338 | app.kubernetes.io/name: ingress-nginx 339 | type: NodePort 340 | --- 341 | apiVersion: v1 342 | kind: Service 343 | metadata: 344 | labels: 345 | app.kubernetes.io/component: controller 346 | app.kubernetes.io/instance: ingress-nginx 347 | app.kubernetes.io/name: ingress-nginx 348 | app.kubernetes.io/part-of: ingress-nginx 349 | app.kubernetes.io/version: 1.2.1 350 | name: ingress-nginx-controller-admission 351 | namespace: ingress-nginx 352 | spec: 353 | ports: 354 | - appProtocol: https 355 | name: https-webhook 356 | port: 443 357 | targetPort: webhook 358 | selector: 359 | app.kubernetes.io/component: controller 360 | app.kubernetes.io/instance: ingress-nginx 361 | app.kubernetes.io/name: ingress-nginx 362 | type: ClusterIP 363 | --- 364 | apiVersion: apps/v1 365 | kind: Deployment 366 | metadata: 367 | labels: 368 | app.kubernetes.io/component: controller 369 | app.kubernetes.io/instance: ingress-nginx 370 | app.kubernetes.io/name: ingress-nginx 371 | app.kubernetes.io/part-of: ingress-nginx 372 | app.kubernetes.io/version: 1.2.1 373 | name: ingress-nginx-controller 374 | namespace: ingress-nginx 375 | spec: 376 | minReadySeconds: 0 377 | revisionHistoryLimit: 10 378 | selector: 379 | matchLabels: 380 | app.kubernetes.io/component: controller 381 | app.kubernetes.io/instance: ingress-nginx 382 | app.kubernetes.io/name: ingress-nginx 383 | strategy: 384 | rollingUpdate: 385 | maxUnavailable: 1 386 | type: RollingUpdate 387 | template: 388 | metadata: 389 | labels: 390 | app.kubernetes.io/component: controller 391 | app.kubernetes.io/instance: ingress-nginx 392 | app.kubernetes.io/name: ingress-nginx 393 | spec: 394 | containers: 395 | - args: 396 | - /nginx-ingress-controller 397 | - --election-id=ingress-controller-leader 398 | - --controller-class=k8s.io/ingress-nginx 399 | - --ingress-class=nginx 400 | - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller 401 | - --validating-webhook=:8443 402 | - --validating-webhook-certificate=/usr/local/certificates/cert 403 | - --validating-webhook-key=/usr/local/certificates/key 404 | - --watch-ingress-without-class=true 405 | - --publish-status-address=localhost 406 | env: 407 | - name: POD_NAME 408 | valueFrom: 409 | fieldRef: 410 | fieldPath: metadata.name 411 | - name: POD_NAMESPACE 412 | valueFrom: 413 | fieldRef: 414 | fieldPath: metadata.namespace 415 | - name: LD_PRELOAD 416 | value: /usr/local/lib/libmimalloc.so 417 | image: registry.k8s.io/ingress-nginx/controller:v1.2.1@sha256:5516d103a9c2ecc4f026efbd4b40662ce22dc1f824fb129ed121460aaa5c47f8 418 | imagePullPolicy: IfNotPresent 419 | lifecycle: 420 | preStop: 421 | exec: 422 | command: 423 | - /wait-shutdown 424 | livenessProbe: 425 | failureThreshold: 5 426 | httpGet: 427 | path: /healthz 428 | port: 10254 429 | scheme: HTTP 430 | initialDelaySeconds: 10 431 | periodSeconds: 10 432 | successThreshold: 1 433 | timeoutSeconds: 1 434 | name: controller 435 | ports: 436 | - containerPort: 80 437 | hostPort: 80 438 | name: http 439 | protocol: TCP 440 | - containerPort: 443 441 | hostPort: 443 442 | name: https 443 | protocol: TCP 444 | - containerPort: 8443 445 | name: webhook 446 | protocol: TCP 447 | readinessProbe: 448 | failureThreshold: 3 449 | httpGet: 450 | path: /healthz 451 | port: 10254 452 | scheme: HTTP 453 | initialDelaySeconds: 10 454 | periodSeconds: 10 455 | successThreshold: 1 456 | timeoutSeconds: 1 457 | resources: 458 | requests: 459 | cpu: 100m 460 | memory: 90Mi 461 | securityContext: 462 | allowPrivilegeEscalation: true 463 | capabilities: 464 | add: 465 | - NET_BIND_SERVICE 466 | drop: 467 | - ALL 468 | runAsUser: 101 469 | volumeMounts: 470 | - mountPath: /usr/local/certificates/ 471 | name: webhook-cert 472 | readOnly: true 473 | dnsPolicy: ClusterFirst 474 | nodeSelector: 475 | ingress-ready: "true" 476 | kubernetes.io/os: linux 477 | serviceAccountName: ingress-nginx 478 | terminationGracePeriodSeconds: 0 479 | tolerations: 480 | - effect: NoSchedule 481 | key: node-role.kubernetes.io/master 482 | operator: Equal 483 | - effect: NoSchedule 484 | key: node-role.kubernetes.io/control-plane 485 | operator: Equal 486 | volumes: 487 | - name: webhook-cert 488 | secret: 489 | secretName: ingress-nginx-admission 490 | --- 491 | apiVersion: batch/v1 492 | kind: Job 493 | metadata: 494 | labels: 495 | app.kubernetes.io/component: admission-webhook 496 | app.kubernetes.io/instance: ingress-nginx 497 | app.kubernetes.io/name: ingress-nginx 498 | app.kubernetes.io/part-of: ingress-nginx 499 | app.kubernetes.io/version: 1.2.1 500 | name: ingress-nginx-admission-create 501 | namespace: ingress-nginx 502 | spec: 503 | template: 504 | metadata: 505 | labels: 506 | app.kubernetes.io/component: admission-webhook 507 | app.kubernetes.io/instance: ingress-nginx 508 | app.kubernetes.io/name: ingress-nginx 509 | app.kubernetes.io/part-of: ingress-nginx 510 | app.kubernetes.io/version: 1.2.1 511 | name: ingress-nginx-admission-create 512 | spec: 513 | containers: 514 | - args: 515 | - create 516 | - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc 517 | - --namespace=$(POD_NAMESPACE) 518 | - --secret-name=ingress-nginx-admission 519 | env: 520 | - name: POD_NAMESPACE 521 | valueFrom: 522 | fieldRef: 523 | fieldPath: metadata.namespace 524 | image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660 525 | imagePullPolicy: IfNotPresent 526 | name: create 527 | securityContext: 528 | allowPrivilegeEscalation: false 529 | nodeSelector: 530 | kubernetes.io/os: linux 531 | restartPolicy: OnFailure 532 | securityContext: 533 | fsGroup: 2000 534 | runAsNonRoot: true 535 | runAsUser: 2000 536 | serviceAccountName: ingress-nginx-admission 537 | --- 538 | apiVersion: batch/v1 539 | kind: Job 540 | metadata: 541 | labels: 542 | app.kubernetes.io/component: admission-webhook 543 | app.kubernetes.io/instance: ingress-nginx 544 | app.kubernetes.io/name: ingress-nginx 545 | app.kubernetes.io/part-of: ingress-nginx 546 | app.kubernetes.io/version: 1.2.1 547 | name: ingress-nginx-admission-patch 548 | namespace: ingress-nginx 549 | spec: 550 | template: 551 | metadata: 552 | labels: 553 | app.kubernetes.io/component: admission-webhook 554 | app.kubernetes.io/instance: ingress-nginx 555 | app.kubernetes.io/name: ingress-nginx 556 | app.kubernetes.io/part-of: ingress-nginx 557 | app.kubernetes.io/version: 1.2.1 558 | name: ingress-nginx-admission-patch 559 | spec: 560 | containers: 561 | - args: 562 | - patch 563 | - --webhook-name=ingress-nginx-admission 564 | - --namespace=$(POD_NAMESPACE) 565 | - --patch-mutating=false 566 | - --secret-name=ingress-nginx-admission 567 | - --patch-failure-policy=Fail 568 | env: 569 | - name: POD_NAMESPACE 570 | valueFrom: 571 | fieldRef: 572 | fieldPath: metadata.namespace 573 | image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660 574 | imagePullPolicy: IfNotPresent 575 | name: patch 576 | securityContext: 577 | allowPrivilegeEscalation: false 578 | nodeSelector: 579 | kubernetes.io/os: linux 580 | restartPolicy: OnFailure 581 | securityContext: 582 | fsGroup: 2000 583 | runAsNonRoot: true 584 | runAsUser: 2000 585 | serviceAccountName: ingress-nginx-admission 586 | --- 587 | apiVersion: networking.k8s.io/v1 588 | kind: IngressClass 589 | metadata: 590 | labels: 591 | app.kubernetes.io/component: controller 592 | app.kubernetes.io/instance: ingress-nginx 593 | app.kubernetes.io/name: ingress-nginx 594 | app.kubernetes.io/part-of: ingress-nginx 595 | app.kubernetes.io/version: 1.2.1 596 | name: nginx 597 | spec: 598 | controller: k8s.io/ingress-nginx 599 | --- 600 | apiVersion: admissionregistration.k8s.io/v1 601 | kind: ValidatingWebhookConfiguration 602 | metadata: 603 | labels: 604 | app.kubernetes.io/component: admission-webhook 605 | app.kubernetes.io/instance: ingress-nginx 606 | app.kubernetes.io/name: ingress-nginx 607 | app.kubernetes.io/part-of: ingress-nginx 608 | app.kubernetes.io/version: 1.2.1 609 | name: ingress-nginx-admission 610 | webhooks: 611 | - admissionReviewVersions: 612 | - v1 613 | clientConfig: 614 | service: 615 | name: ingress-nginx-controller-admission 616 | namespace: ingress-nginx 617 | path: /networking/v1/ingresses 618 | failurePolicy: Fail 619 | matchPolicy: Equivalent 620 | name: validate.nginx.ingress.kubernetes.io 621 | rules: 622 | - apiGroups: 623 | - networking.k8s.io 624 | apiVersions: 625 | - v1 626 | operations: 627 | - CREATE 628 | - UPDATE 629 | resources: 630 | - ingresses 631 | sideEffects: None 632 | --------------------------------------------------------------------------------