├── .gitignore
├── README.ja.md
├── README.md
├── docs
├── requirements.ja.md
├── requirements.md
├── setup.ja.md
└── setup.md
├── manifests
├── 00_namespaces
│ └── namespace.yml
├── 01_challenges
│ ├── can-you-keep-a-secret
│ │ ├── README.ja.md
│ │ ├── README.md
│ │ ├── flag.yaml
│ │ └── victim.yaml
│ ├── mountme
│ │ ├── README.ja.md
│ │ ├── README.md
│ │ ├── job-sa.yaml
│ │ └── victim.yaml
│ ├── mountme2
│ │ ├── README.ja.md
│ │ ├── README.md
│ │ ├── flag
│ │ │ └── FLAG.txt
│ │ ├── job-sa.yaml
│ │ └── victim.yaml
│ ├── sniff
│ │ ├── README.ja.md
│ │ ├── README.md
│ │ ├── client.yaml
│ │ ├── server.yaml
│ │ ├── service.yml
│ │ └── victim.yaml
│ └── treasure-hunt
│ │ ├── README.md
│ │ ├── docker-registry
│ │ ├── certs
│ │ │ ├── ca.crt
│ │ │ └── ca.key
│ │ ├── deployment.yml
│ │ ├── htpasswd
│ │ ├── registry-config.yml
│ │ ├── secrets.yml
│ │ └── service.yml
│ │ ├── flag
│ │ ├── Dockerfile
│ │ ├── FLAG.txt
│ │ └── docker-registry-password
│ │ └── victim.yaml
├── flags
│ ├── mountme
│ │ └── FLAG.txt
│ └── mountme2
│ │ └── FLAG.txt
└── gatekeeper
│ ├── 00_gatekeeper.yaml
│ └── hostpath
│ ├── 00_template.yaml
│ └── 01_constraint.yaml
└── setup.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | manifests/01_challenges/can-you-keep-a-secret/*.crt
2 | manifests/01_challenges/can-you-keep-a-secret/*.key
3 |
4 | manifests/01_challenges/can-you-keep-a-secret/writeup
5 | manifests/01_challenges/mountme/writeup
6 | manifests/01_challenges/mountme2/writeup
7 | manifests/01_challenges/sniff/writeup
8 | manifests/01_challenges/treasure-hunt/writeup
9 |
--------------------------------------------------------------------------------
/README.ja.md:
--------------------------------------------------------------------------------
1 | # kubectf
2 |
3 | # Requirements
4 |
5 | * minikube
6 | * kubectl
7 | * Docker Engine
8 | * Add `{ "insecure-registries": ["docker.for.mac.localhost:5000"] }` to Docker configuration.
9 |
10 | more information [docs/requirements.md](docs/requirements.md)
11 |
12 | # Getting Started
13 |
14 | ```shell
15 | $ minikube start --driver=virtualbox
16 | $ ./setup.sh
17 | ```
18 |
19 | # Rule
20 |
21 | Pod の一つに侵入することができたという想定で、権限昇格を行って `k8sctf{...}` というフォーマットの文字列(flag)を探し出します。
22 | 各問題の namespace に victim- プレフィックスのついた名前を持つ Pod がいますので、その Pod に入って問題に取り組んでください。
23 |
24 | ```shell
25 | $ kubens mountme
26 | ❯ kubectl get pods
27 | NAME READY STATUS RESTARTS AGE
28 | victim-7c5745b4dc-jxd5t 1/1 Running 0 14m
29 |
30 | ❯ kubectl exec -it victim-7c5745b4dc-jxd5t bash
31 | I have no name!@victim-7c5745b4dc-jxd5t:/$
32 | ```
33 |
34 | 以下細かい点です。
35 |
36 | * このリポジトリの中には答えである flag が入っているので、真面目に問題を解きたいひとは見ないようにしてください。
37 | * クラスタ管理者という立場ではなく、victim という Pod に何らかの手段で侵入できた攻撃者という立場で取り組んでください。
38 | * なので manifest の変更等は禁止です。victim Pod の中から実行可能な範囲のみで取り組んでください。
39 |
40 | # Challenges
41 |
42 | | Title | Difficulty | Description |
43 | |:-----:|:---------:|:----------:|
44 | | Mount me | 🔥 | [Link](manifests/01_challenges/mountme/README.md) |
45 | | Can You Keep A Secret? | 🔥 | [Link](manifests/01_challenges/can-you-keep-a-secret/README.md) |
46 | | Treasure Hunt | 🔥🔥 | [Link](manifests/01_challenges/treasure-hunt/README.md) |
47 | | Mount me 2 | 🔥🔥 | [Link](manifests/01_challenges/mountme2/README.md) |
48 | | Sniff | 🔥🔥 | [Link](manifests/01_challenges/sniff/README.md) |
49 |
50 | # Writeups
51 |
52 | 2020 年年末に公開します
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # kubectf
2 |
3 | # Requirements
4 |
5 | * minikube
6 | * kubectl
7 | * Docker Engine
8 | * Add `{ "insecure-registries": ["docker.for.mac.localhost:5000"] }` to Docker configuration.
9 |
10 | more information [docs/requirements.md](docs/requirements.md)
11 |
12 | # Getting Started
13 |
14 | ```shell
15 | $ minikube start --driver=virtualbox
16 | $ ./setup.sh
17 | ```
18 |
19 | # Rule
20 |
21 | Assuming you've penetrated a vulnerable Pod, perform a privilege escalation and look for a Flag (a string of the format `k8sctf{...}` ).
22 | There is a victim pod in the namespace for each problem, and you enter into this pod to challenge the problem.
23 | No changes should be made to anifests. You should work within Pod as a attacker.
24 |
25 | ```shell
26 | $ kubens mountme
27 | ❯ kubectl get pods
28 | NAME READY STATUS RESTARTS AGE
29 | victim-7c5745b4dc-jxd5t 1/1 Running 0 14m
30 |
31 | ❯ kubectl exec -it victim-7c5745b4dc-jxd5t bash
32 | I have no name!@victim-7c5745b4dc-jxd5t:/$
33 | ```
34 |
35 | # Challenges
36 |
37 | | Title | Difficulty | Description |
38 | |:-----:|:---------:|:----------:|
39 | | Mount me | 🔥 | [Link](manifests/01_challenges/mountme/README.md) |
40 | | Can You Keep A Secret? | 🔥 | [Link](manifests/01_challenges/can-you-keep-a-secret/README.md) |
41 | | Treasure Hunt | 🔥🔥 | [Link](manifests/01_challenges/treasure-hunt/README.md) |
42 | | Mount me 2 | 🔥🔥 | [Link](manifests/01_challenges/mountme2/README.md) |
43 | | Sniff | 🔥🔥 | [Link](manifests/01_challenges/sniff/README.md) |
44 |
45 | # Writeups
46 |
47 | TBD
48 |
49 |
--------------------------------------------------------------------------------
/docs/requirements.ja.md:
--------------------------------------------------------------------------------
1 | # Requirements
2 |
3 | ## 1. minikube のインストール
4 |
5 | https://kubernetes.io/ja/docs/tasks/tools/install-minikube/ を参考に minikube をインストールします。
6 |
7 | ## 2. insecure registry の登録
8 |
9 | 手元の Docker for Mac の Docker Engine の設定に次の内容を追加します。
10 | アプリケーションバーから Docker を選択して Preferences -> Docker Engine で追加できます。
11 |
12 | ```json
13 | {
14 | "insecure-registries": [
15 | "docker.for.mac.localhost:5000"
16 | ]
17 | }
18 | ```
19 |
20 |
--------------------------------------------------------------------------------
/docs/requirements.md:
--------------------------------------------------------------------------------
1 | # Requirements
2 |
3 | ## 1. Install minikube
4 |
5 | see https://kubernetes.io/ja/docs/tasks/tools/install-minikube
6 |
7 | ## 2. Register Insecure Registry
8 |
9 | Add Insecure Registry to Docker Engine on your local machine (e.g. On Mac, Preferences -> Docker Engine).
10 |
11 | ```json
12 | {
13 | "insecure-registries": [
14 | "docker.for.mac.localhost:5000"
15 | ]
16 | }
17 | ```
18 |
19 |
--------------------------------------------------------------------------------
/docs/setup.ja.md:
--------------------------------------------------------------------------------
1 | # Requirements
2 |
3 | ## 1. クラスタの構築
4 |
5 | ```shell
6 | $ minikube start --driver=virtualbox
7 | ```
8 |
9 | ## 2. 問題の登録
10 |
11 | ```shell
12 | $ ./setup.sh
13 | ```
14 |
15 | 特にエラーもなく、次のような namespace が作成されていれば OK です。
16 |
17 | ```shell
18 | ❯ kubectl get ns
19 | NAME STATUS AGE
20 | can-you-keep-a-secret Active 13m
21 | default Active 14m
22 | kube-node-lease Active 14m
23 | kube-public Active 14m
24 | kube-system Active 14m
25 | mountme Active 13m
26 | mountme2 Active 13m
27 | treasure-hunt Active 13m
28 | ```
29 |
--------------------------------------------------------------------------------
/docs/setup.md:
--------------------------------------------------------------------------------
1 | # Requirements
2 |
3 | ## 1. Create a cluster
4 |
5 | ```shell
6 | $ minikube start --driver=virtualbox
7 | ```
8 |
9 | ## 2. Setup challenges
10 |
11 | ```shell
12 | $ ./setup.sh
13 | ```
14 |
15 | Make sure you have the following namespace.
16 |
17 | ```
18 | ❯ kubectl get ns
19 | NAME STATUS AGE
20 | can-you-keep-a-secret Active 13m
21 | default Active 14m
22 | kube-node-lease Active 14m
23 | kube-public Active 14m
24 | kube-system Active 14m
25 | mountme Active 13m
26 | mountme2 Active 13m
27 | treasure-hunt Active 13m
28 | ```
29 |
--------------------------------------------------------------------------------
/manifests/00_namespaces/namespace.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | creationTimestamp: null
5 | name: treasure-hunt
6 |
7 | ---
8 | apiVersion: v1
9 | kind: Namespace
10 | metadata:
11 | creationTimestamp: null
12 | name: mountme
13 |
14 | ---
15 | apiVersion: v1
16 | kind: Namespace
17 | metadata:
18 | creationTimestamp: null
19 | name: mountme2
20 |
21 | ---
22 | apiVersion: v1
23 | kind: Namespace
24 | metadata:
25 | creationTimestamp: null
26 | name: can-you-keep-a-secret
27 |
28 | ---
29 | apiVersion: v1
30 | kind: Namespace
31 | metadata:
32 | creationTimestamp: null
33 | name: sniff
34 |
35 |
--------------------------------------------------------------------------------
/manifests/01_challenges/can-you-keep-a-secret/README.ja.md:
--------------------------------------------------------------------------------
1 | # Can You Keep A Secret?
2 |
3 | victim Pod は Kubernetes クラスタの etcd を操作するための Pod です。
4 | `kube-system` に flag という secret があるので、それを取得してください。
5 |
6 | ```shell
7 | $ kubens can-you-keep-a-secret
8 | ❯ kubectl get pods
9 | NAME READY STATUS RESTARTS AGE
10 | victim-56958dffc6-8chjx 1/1 Running 0 27m
11 | ❯ kubectl exec -it victim-56958dffc6-8chjx sh
12 | / #
13 | ```
14 |
15 |
16 | Hint 1
17 | Network Namespace が分離されていないということは...?
18 |
19 |
--------------------------------------------------------------------------------
/manifests/01_challenges/can-you-keep-a-secret/README.md:
--------------------------------------------------------------------------------
1 | # Can You Keep A Secret?
2 |
3 | The victim pod is for operating etcd on Kubernetes cluster.
4 | Flag is in `secret` in `kube-system` namespace.
5 |
6 | ```shell
7 | $ kubens can-you-keep-a-secret
8 | ❯ kubectl get pods
9 | NAME READY STATUS RESTARTS AGE
10 | victim-56958dffc6-8chjx 1/1 Running 0 27m
11 | ❯ kubectl exec -it victim-56958dffc6-8chjx sh
12 | / #
13 | ```
14 |
15 |
16 | Hint 1
17 | Network namespace is not isolated.
18 |
19 |
20 |
--------------------------------------------------------------------------------
/manifests/01_challenges/can-you-keep-a-secret/flag.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | data:
3 | flag: azhzY3Rmezk0ZDViY2RmNjFlMDRjNjNjNGU3ZGRkNTIzZDIyMzI1ZmNmMzNkZWZ9
4 | kind: Secret
5 | metadata:
6 | creationTimestamp: null
7 | name: flag
8 | namespace: kube-system
9 |
--------------------------------------------------------------------------------
/manifests/01_challenges/can-you-keep-a-secret/victim.yaml:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: victim
5 | namespace: can-you-keep-a-secret
6 | spec:
7 | replicas: 1
8 | selector:
9 | matchLabels:
10 | app: victim
11 | template:
12 | metadata:
13 | labels:
14 | app: victim
15 | spec:
16 | hostNetwork: true
17 | containers:
18 | - name: victim
19 | image: gcr.io/etcd-development/etcd
20 | command: ["tail", "-f", "/dev/null"]
21 | volumeMounts:
22 | - name: etcd-credentials
23 | mountPath: /mnt/etcd-credentials
24 | volumes:
25 | - name: etcd-credentials
26 | secret:
27 | secretName: etcd-credentials
28 |
29 |
--------------------------------------------------------------------------------
/manifests/01_challenges/mountme/README.ja.md:
--------------------------------------------------------------------------------
1 | # Mount me
2 |
3 | ## Red Challenge
4 |
5 | フラグはノードの /home/docker/mount1 にあります。
6 |
7 | ```shell
8 | $ kubens mountme
9 | $ kubectl exec -it vicitm-7c5745b4dc-jxd5t bash
10 | ```
11 |
12 |
13 | Hint 1
14 | マウントされている ServiceAccount の権限は?
15 |
16 |
17 |
18 | Hint 2
19 | hostPath マウント
20 |
21 |
22 | ## Blue Challenge
23 |
24 | * Disable hostPath mount with OPA
25 | * Detect hostPath mount with falco
26 |
--------------------------------------------------------------------------------
/manifests/01_challenges/mountme/README.md:
--------------------------------------------------------------------------------
1 | # Mount me
2 |
3 | ## Red Challenge
4 |
5 | Flag is in /home/docker/mount1 directory at node.
6 |
7 | ```shell
8 | $ kubens mountme
9 | $ kubectl exec -it vicitm-7c5745b4dc-jxd5t bash
10 | ```
11 |
12 |
13 | Hint 1
14 | What are the privileges of the mounted ServiceAccount?
15 |
16 |
17 |
18 | Hint 2
19 | hostPath mount
20 |
21 |
22 | ## Blue Challenge
23 |
24 | * Disable hostPath mount with OPA
25 | * Detect hostPath mount with falco
26 |
--------------------------------------------------------------------------------
/manifests/01_challenges/mountme/job-sa.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: runner
6 | namespace: mountme
7 | automountServiceAccountToken: false
8 |
9 | ---
10 | kind: Role
11 | apiVersion: rbac.authorization.k8s.io/v1
12 | metadata:
13 | name: job-runner
14 | namespace: mountme
15 | rules:
16 | - apiGroups: ["batch", "extensions"]
17 | resources: ["jobs", "job/status"]
18 | verbs: ["*"]
19 | - apiGroups: [""]
20 | resources: ["pods", "pods/binding", "pods/log", "pods/status"]
21 | verbs: ["get", "list"]
22 |
23 | ---
24 | kind: RoleBinding
25 | apiVersion: rbac.authorization.k8s.io/v1
26 | metadata:
27 | name: job-runner
28 | namespace: mountme
29 | subjects:
30 | - kind: ServiceAccount
31 | name: runner
32 | namespace: mountme
33 | roleRef:
34 | kind: Role
35 | name: job-runner
36 | apiGroup: rbac.authorization.k8s.io
37 |
--------------------------------------------------------------------------------
/manifests/01_challenges/mountme/victim.yaml:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: victim
5 | namespace: mountme
6 | spec:
7 | replicas: 1
8 | selector:
9 | matchLabels:
10 | app: victim
11 | template:
12 | metadata:
13 | labels:
14 | app: victim
15 | spec:
16 | serviceAccountName: runner
17 | automountServiceAccountToken: true
18 | containers:
19 | - name: victim
20 | image: bitnami/kubectl:1.19.4
21 | command: ["tail", "-f", "/dev/null"]
22 |
--------------------------------------------------------------------------------
/manifests/01_challenges/mountme2/README.ja.md:
--------------------------------------------------------------------------------
1 | # Mount me 2
2 |
3 | ## Red Challenge
4 |
5 | Node の `/home/docker/mountme2` に flag があります。
6 |
7 | ```shell
8 | ❯ kubens mountme2
9 |
10 | ❯ kubectl get pods
11 | NAME READY STATUS RESTARTS AGE
12 | victim-7c5745b4dc-42mx8 1/1 Running 0 53m
13 |
14 | ❯ kubectl exec -it victim-7c5745b4dc-42mx8 bash
15 | I have no name!@victim-7c5745b4dc-42mx8:/$
16 | ```
17 |
18 |
19 | Hint 1
20 | hostPath マウントは Gatekeeper で禁止されています。
21 |
22 |
23 |
24 | Hint 2
25 | Namespace
26 |
27 |
28 |
29 | ## Blue Challenge
30 |
31 | * Disable create privileged container with OPA
32 | * Detect create privileged container with falco
33 |
--------------------------------------------------------------------------------
/manifests/01_challenges/mountme2/README.md:
--------------------------------------------------------------------------------
1 | # Mount me 2
2 |
3 | ## Red Challenge
4 |
5 | Flag is in /home/docker/mount2 directory at node.
6 |
7 | ```shell
8 | ❯ kubens mountme2
9 |
10 | ❯ kubectl get pods
11 | NAME READY STATUS RESTARTS AGE
12 | victim-7c5745b4dc-42mx8 1/1 Running 0 53m
13 |
14 | ❯ kubectl exec -it victim-7c5745b4dc-42mx8 bash
15 | I have no name!@victim-7c5745b4dc-42mx8:/$
16 | ```
17 |
18 |
19 | Hint 1
20 | hostPath mount is prohibited by Gatekeeper.
21 |
22 |
23 |
24 | Hint 2
25 | Namespace
26 |
27 |
28 |
29 | ## Blue Challenge
30 |
31 | * Disable create privileged container with OPA
32 | * Detect create privileged container with falco
33 |
--------------------------------------------------------------------------------
/manifests/01_challenges/mountme2/flag/FLAG.txt:
--------------------------------------------------------------------------------
1 | k8sctf{396b1bc80afa7234a2977f709d35e787b9c7cfa3}
2 |
--------------------------------------------------------------------------------
/manifests/01_challenges/mountme2/job-sa.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: runner
6 | namespace: mountme2
7 |
8 | ---
9 | kind: ClusterRole
10 | apiVersion: rbac.authorization.k8s.io/v1
11 | metadata:
12 | name: job-runner
13 | rules:
14 | - apiGroups: ["policy"]
15 | resources: ["podsecuritypolicies"]
16 | resourceNames: ["restricted"]
17 | verbs: ["use"]
18 | - apiGroups: ["batch", "extensions"]
19 | resources: ["jobs", "job/status"]
20 | verbs: ["*"]
21 | - apiGroups: [""]
22 | resources: ["pods", "pods/binding", "pods/log", "pods/status"]
23 | verbs: ["get", "list", "create"]
24 |
25 | ---
26 | kind: RoleBinding
27 | apiVersion: rbac.authorization.k8s.io/v1
28 | metadata:
29 | name: runner
30 | namespace: mountme2
31 | subjects:
32 | - kind: ServiceAccount
33 | name: runner
34 | namespace: mountme2
35 | roleRef:
36 | kind: ClusterRole
37 | name: job-runner
38 | apiGroup: rbac.authorization.k8s.io
39 |
--------------------------------------------------------------------------------
/manifests/01_challenges/mountme2/victim.yaml:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: victim
5 | namespace: mountme2
6 | spec:
7 | replicas: 1
8 | selector:
9 | matchLabels:
10 | app: victim
11 | template:
12 | metadata:
13 | labels:
14 | app: victim
15 | spec:
16 | serviceAccountName: runner
17 | automountServiceAccountToken: true
18 | containers:
19 | - name: victim
20 | image: bitnami/kubectl:1.19.4
21 | command: ["tail", "-f", "/dev/null"]
22 |
--------------------------------------------------------------------------------
/manifests/01_challenges/sniff/README.ja.md:
--------------------------------------------------------------------------------
1 | # Sniff
2 |
3 | ## Red Challenge
4 |
5 | find a flag.
6 |
7 | ```shell
8 | $ kubectl get pods -n sniff
9 | NAME READY STATUS RESTARTS AGE
10 | client-66b6f5cdcf-v5n9j 1/1 Running 0 3m24s
11 | server-79b88f567-v4xsp 1/1 Running 0 3m26s
12 | victim-cb9b4c946-d7vkq 1/1 Running 0 15m
13 |
14 | $ kubectl exec -it victim-cb9b4c946-d7vkq bash
15 | ```
16 |
17 |
18 | Hint 1
19 | Client から Server に HTTP リクエストが送られているので盗聴しよう
20 |
21 |
22 |
23 | Hint 2
24 | DNS Spoofing
25 |
26 |
27 | ## Blue Challenge
28 |
29 | * Drop `CAP_NET_RAW`
30 | * Add a OPA policy to validate `CAP_NET_RAW`
31 |
--------------------------------------------------------------------------------
/manifests/01_challenges/sniff/README.md:
--------------------------------------------------------------------------------
1 | # Sniff
2 |
3 | ## Red Challenge
4 |
5 | Find a flag.
6 |
7 | ```shell
8 | $ kubectl get pods -n sniff
9 | NAME READY STATUS RESTARTS AGE
10 | client-66b6f5cdcf-v5n9j 1/1 Running 0 3m24s
11 | server-79b88f567-v4xsp 1/1 Running 0 3m26s
12 | victim-cb9b4c946-d7vkq 1/1 Running 0 15m
13 |
14 | $ kubectl exec -it victim-cb9b4c946-d7vkq bash
15 | ```
16 |
17 |
18 | Hint 1
19 | An HTTP request is being sent from the client to the server.
20 |
21 |
22 |
23 | Hint 2
24 | DNS Spoofing
25 |
26 |
27 | ## Blue Challenge
28 |
29 | * Drop `CAP_NET_RAW`
30 | * Add a OPA policy to validate `CAP_NET_RAW`
31 |
--------------------------------------------------------------------------------
/manifests/01_challenges/sniff/client.yaml:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: client
5 | namespace: sniff
6 | spec:
7 | replicas: 1
8 | selector:
9 | matchLabels:
10 | app: client
11 | template:
12 | metadata:
13 | labels:
14 | app: client
15 | spec:
16 | containers:
17 | - name: client
18 | image: nicolaka/netshoot:latest
19 | command: ["sh", "-c", "while true; do curl -X POST -d \"k8sctf{25cb1d440f87baf0cf09e8bd3d349df2204c4481}\" server.sniff.svc.cluster.local; sleep 5; done"]
20 |
--------------------------------------------------------------------------------
/manifests/01_challenges/sniff/server.yaml:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: server
5 | namespace: sniff
6 | spec:
7 | replicas: 1
8 | selector:
9 | matchLabels:
10 | app: server
11 | template:
12 | metadata:
13 | labels:
14 | app: server
15 | spec:
16 | containers:
17 | - name: server
18 | image: nginx:latest
19 |
--------------------------------------------------------------------------------
/manifests/01_challenges/sniff/service.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: server
5 | namespace: sniff
6 | spec:
7 | selector:
8 | app: server
9 | ports:
10 | - port: 80
11 |
--------------------------------------------------------------------------------
/manifests/01_challenges/sniff/victim.yaml:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: victim
5 | namespace: sniff
6 | spec:
7 | replicas: 1
8 | selector:
9 | matchLabels:
10 | app: victim
11 | template:
12 | metadata:
13 | labels:
14 | app: victim
15 | spec:
16 | containers:
17 | - name: victim
18 | image: python:latest
19 | command: ["tail", "-f", "/dev/null"]
20 |
--------------------------------------------------------------------------------
/manifests/01_challenges/treasure-hunt/README.md:
--------------------------------------------------------------------------------
1 | # Treasure Hunt
2 |
3 | ## Red Challenge
4 |
5 | Find a flag.
6 |
7 | ```shell
8 | ❯ kubens treasure-hunt
9 |
10 | ❯ kubectl get pods
11 | NAME READY STATUS RESTARTS AGE
12 | docker-registry-6b5b55b44-zgvxf 1/1 Running 0 42m
13 | victim-68bcd4465f-q4pkb 1/1 Running 0 42m
14 |
15 | ❯ kubectl exec -it victim-68bcd4465f-q4pkb sh
16 | / #
17 | ```
18 |
19 |
20 | Hint 1
21 | Where are the Docker Registry credentials?
22 |
23 |
24 |
25 | Hint 2
26 | Overlayfs
27 |
28 |
29 | ## Blue Challenge
30 |
31 | * Restricted access betweeen pods
32 | * Detect access to Docker Registry with falco
33 |
--------------------------------------------------------------------------------
/manifests/01_challenges/treasure-hunt/docker-registry/certs/ca.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICljCCAX4CCQCp4Seu4/CjazANBgkqhkiG9w0BAQsFADANMQswCQYDVQQGEwJK
3 | UDAeFw0yMDExMjQwNjUwMzZaFw0zMDExMjIwNjUwMzZaMA0xCzAJBgNVBAYTAkpQ
4 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp1t6BfCXf8EKry29x7ZD
5 | LUJSYQ7aW3WhoW70rz9XZobx5028EazH371qVcrk1xiBDouE4FyzZph2PL6QkN7S
6 | 9Kfic9QT8DvYv3MSkRTkzwO8EotGiQzkWbHCs/ewboq48BiXgcgAB45zexNg2Q92
7 | qTPry7axtKcv5CuejnKjrM+Gh6BZlnP9+wfzk9VIffYWXOwqV+PfzexeAn0rnlW/
8 | sQl8gcQtf3SibbwSzvZU5v6edLHjo9ykCDTu5K0gJGOEMIMhwn5Ou6V0+RVDs2hZ
9 | 753mb9KT193aeh8kxuhjchSGchVf7DwfsBgZ2uUffov45eBd52CicjKt9jFwCbAq
10 | HQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQB0eeDxhqcz3NRfnJcix2ekdu0K0aoT
11 | sctOs2zAnSIZuAH6d7CQVscW6I387VWlKZPWqq9KogaeZm1sF80Wey+Oxjzno9KG
12 | 0ZJuz0iGzyrQ3esZegyWUxCaLBrHihIIQKl9Pk302os/QEeK7lW8jrIsKhF0YIGj
13 | UUUju8fSwJbUEKjRx2B2XtkJGuNZX0OHCQCwIqh/poj6X4sWT/3sZptJimokkzU9
14 | K6n4AeDHVS65RT15A1gVapf5PFUB5cSVD2L6dKx1Nl1HuAatgZkUqleTGCHVqK62
15 | 3ZB6wShdaxYLlHM1utZ2MWpMO+8eZ4549E4y4q2mpgnUYJ/9kiLLVUf+
16 | -----END CERTIFICATE-----
17 |
--------------------------------------------------------------------------------
/manifests/01_challenges/treasure-hunt/docker-registry/certs/ca.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQCnW3oF8Jd/wQqv
3 | Lb3HtkMtQlJhDtpbdaGhbvSvP1dmhvHnTbwRrMffvWpVyuTXGIEOi4TgXLNmmHY8
4 | vpCQ3tL0p+Jz1BPwO9i/cxKRFOTPA7wSi0aJDORZscKz97BuirjwGJeByAAHjnN7
5 | E2DZD3apM+vLtrG0py/kK56OcqOsz4aHoFmWc/37B/OT1Uh99hZc7CpX49/N7F4C
6 | fSueVb+xCXyBxC1/dKJtvBLO9lTm/p50seOj3KQINO7krSAkY4QwgyHCfk67pXT5
7 | FUOzaFnvneZv0pPX3dp6HyTG6GNyFIZyFV/sPB+wGBna5R9+i/jl4F3nYKJyMq32
8 | MXAJsCodAgMBAAECggEBAJnUq8Tp8VesyXVcRiVck0L2w2ITlQKcjYUlyCONxXio
9 | cZJ7EXPtrYsrQKK7bL2J+Ja2B91zWDPl0EjloVyIdMAN0UlGl00qtYDE9TwGSItA
10 | k484Fg3Dm+IWUzG5aqMxP+zxrdHNVLmdZuiqV0stu5Sr9QG7XH0BcDP7JDMrjOc6
11 | HY8B2Z2uW2U9iZRqyDygIZ/xg3mJyLGW3UiME/Y469a3xdk8aZ7QUZy7OQ1kFxKc
12 | Thnbf8fpXUTmz9SM+5bvWi5SNzlWNSvbVcmob3zCKwBVXdj/ZqAscK9u5RFHJa/Z
13 | ij/svN7dhzUmO/mmnPKGIR30UK/MR4JXg0y6BpZSxgECgYEA0gWgv7Dpcvd8PLPt
14 | VekCYesiZ6H4QUhTNo2Da1GuaPiIlVjTXPRwejpi2EeT/FtsDIAIinbCuJXfvjpn
15 | J5X6qI4PfN/13xR81bUrxjgWzyJx5Lp9dH4iRhS9nieRXL4O7EWAPowkSZHcq8U/
16 | f0zgvsy+wxNzv8vvHkMS0pKMUIUCgYEAy/7FbdaMaIZ3L1pYj547T4pAvJy0vO9m
17 | XexVoHfX8jnhz1uE5RkD0LQ2QTlFOaWrC5Jvt0QuOmVUFQLQ4itc4toWMiD2hqBb
18 | aDyCGXCAFehvq0tFwdwQxftPn8eb4A1wLMxoihsaML5e2bh7toaDXdiUyyeSWnZD
19 | iY/o4p1QMrkCgYEAp4w72JFPPBt57odwELhp4SoPcXOCtLn5QK0WqbgpFq8nb1XE
20 | kQSk8q2/i2FXCtz4TuSZa7Ug1Ncj/wNipe79YBis/GdDJCuZB3iYKnM2pxqIl/u6
21 | +ANkXlpPh2tziPRKvW0YyU1N6a9Gx3X9mRYAudZnXQMYtWsBIThLPNgSvm0CgYEA
22 | gdq95ntqiab++3+xXErHSoyhRO8kBhkGuscUgr+HEURTP+HsKMHRserlloNUU6vn
23 | w8gFoU2fd8DE01MlkLM1v5pAAs0E4RH23dWWo4b/ofKCEzIpR4xEiSK+vuEbknY7
24 | b+j2quMxutGUI1fSOJBL01No9CFOgpNBzrFy975YLNECgYEAjcpg64eV3z6on2Jn
25 | DQRRPbkUzhg+Wmo2h6lUUdi/uSuS1ntCRnIUH6FY+2l6AIGxiIH4InL7oAhgJzi1
26 | tRXYJHh0X1s6JDr8FnXVL/A7ApvesMTaRLXNt3ySTFmb9KOmp0JXnJqfrvNdjUlb
27 | 2sY4yPTZZGL0zlM5W+aUadQGEuE=
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/manifests/01_challenges/treasure-hunt/docker-registry/deployment.yml:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: docker-registry
5 | namespace: treasure-hunt
6 | labels:
7 | app: docker-registry
8 | spec:
9 | replicas: 1
10 | selector:
11 | matchLabels:
12 | app: docker-registry
13 | template:
14 | metadata:
15 | labels:
16 | app: docker-registry
17 | spec:
18 | containers:
19 | - name: docker-registry
20 | image: registry:2.7
21 | volumeMounts:
22 | - mountPath: "/var/lib/registry"
23 | name: registry
24 | - mountPath: "/auth/"
25 | name: docker-registry-secret
26 | - name: registry-config
27 | mountPath: /etc/docker/registry/
28 | ports:
29 | - containerPort: 5000
30 | env:
31 | - name: REGISTRY_AUTH
32 | value: htpasswd
33 | - name: REGISTRY_AUTH_HTPASSWD_REALM
34 | value: "Registry Realm"
35 | - name: REGISTRY_AUTH_HTPASSWD_PATH
36 | value: "/auth/docker-registry-htpasswd"
37 | - name: REGISTRY_HTTP_TLS_CERTIFICATE
38 | value: "/auth/ca.crt"
39 | - name: REGISTRY_HTTP_TLS_KEY
40 | value: "/auth/ca.key"
41 | - name: REGISTRY_HTTP_ADDR
42 | value: 0.0.0.0:5000
43 | volumes:
44 | - name: registry-config
45 | configMap:
46 | name: registry-config
47 | - name: registry
48 | hostPath:
49 | path: /data/registry
50 | type: DirectoryOrCreate
51 | - name: docker-registry-secret
52 | secret:
53 | secretName: docker-registry-secret
54 | items:
55 | - key: REGISTRY_AUTH_HTPASSWD
56 | path: "docker-registry-htpasswd"
57 | - key: REGISTRY_HTTP_TLS_CERTIFICATE
58 | path: "ca.crt"
59 | - key: REGISTRY_HTTP_TLS_KEY
60 | path: "ca.key"
61 |
--------------------------------------------------------------------------------
/manifests/01_challenges/treasure-hunt/docker-registry/htpasswd:
--------------------------------------------------------------------------------
1 | ctf:$2y$05$4hTo.jGtSsQc7cuW5bWz0.CQQ.pCQ6df6L8pokeXNo1f9gVAgx2bK
2 |
3 |
--------------------------------------------------------------------------------
/manifests/01_challenges/treasure-hunt/docker-registry/registry-config.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | data:
3 | config.yml: |
4 | version: 0.1
5 | log:
6 | level: debug
7 | fields:
8 | service: registry
9 | storage:
10 | cache:
11 | blobdescriptor: inmemory
12 | filesystem:
13 | rootdirectory: /var/lib/registry
14 | http:
15 | addr: :5000
16 | headers:
17 | X-Content-Type-Options: [nosniff]
18 | health:
19 | storagedriver:
20 | enabled: true
21 | interval: 10s
22 | threshold: 3
23 | kind: ConfigMap
24 | metadata:
25 | creationTimestamp: null
26 | name: registry-config
27 | namespace: treasure-hunt
28 |
--------------------------------------------------------------------------------
/manifests/01_challenges/treasure-hunt/docker-registry/secrets.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | data:
3 | REGISTRY_AUTH_HTPASSWD: Y3RmOiQyeSQwNSQ0aFRvLmpHdFNzUWM3Y3VXNWJXejAuQ1FRLnBDUTZkZjZMOHBva2VYTm8xZjlnVkFneDJiSwoK
4 | REGISTRY_HTTP_TLS_CERTIFICATE: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNsakNDQVg0Q0NRQ3A0U2V1NC9DamF6QU5CZ2txaGtpRzl3MEJBUXNGQURBTk1Rc3dDUVlEVlFRR0V3SksKVURBZUZ3MHlNREV4TWpRd05qVXdNelphRncwek1ERXhNakl3TmpVd016WmFNQTB4Q3pBSkJnTlZCQVlUQWtwUQpNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXAxdDZCZkNYZjhFS3J5Mjl4N1pECkxVSlNZUTdhVzNXaG9XNzByejlYWm9ieDUwMjhFYXpIMzcxcVZjcmsxeGlCRG91RTRGeXpacGgyUEw2UWtON1MKOUtmaWM5UVQ4RHZZdjNNU2tSVGt6d084RW90R2lRemtXYkhDcy9ld2JvcTQ4QmlYZ2NnQUI0NXpleE5nMlE5MgpxVFByeTdheHRLY3Y1Q3Vlam5LanJNK0doNkJabG5QOSt3ZnprOVZJZmZZV1hPd3FWK1BmemV4ZUFuMHJubFcvCnNRbDhnY1F0ZjNTaWJid1N6dlpVNXY2ZWRMSGpvOXlrQ0RUdTVLMGdKR09FTUlNaHduNU91NlYwK1JWRHMyaFoKNzUzbWI5S1QxOTNhZWg4a3h1aGpjaFNHY2hWZjdEd2ZzQmdaMnVVZmZvdjQ1ZUJkNTJDaWNqS3Q5akZ3Q2JBcQpIUUlEQVFBQk1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQjBlZUR4aHFjejNOUmZuSmNpeDJla2R1MEswYW9UCnNjdE9zMnpBblNJWnVBSDZkN0NRVnNjVzZJMzg3VldsS1pQV3FxOUtvZ2FlWm0xc0Y4MFdleStPeGp6bm85S0cKMFpKdXowaUd6eXJRM2VzWmVneVdVeENhTEJySGloSUlRS2w5UGszMDJvcy9RRWVLN2xXOGpySXNLaEYwWUlHagpVVVVqdThmU3dKYlVFS2pSeDJCMlh0a0pHdU5aWDBPSENRQ3dJcWgvcG9qNlg0c1dULzNzWnB0Smltb2trelU5Cks2bjRBZURIVlM2NVJUMTVBMWdWYXBmNVBGVUI1Y1NWRDJMNmRLeDFObDFIdUFhdGdaa1VxbGVUR0NIVnFLNjIKM1pCNndTaGRheFlMbEhNMXV0WjJNV3BNTys4ZVo0NTQ5RTR5NHEybXBnblVZSi85a2lMTFZVZisKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
5 | REGISTRY_HTTP_TLS_KEY: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV3QUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktvd2dnU21BZ0VBQW9JQkFRQ25XM29GOEpkL3dRcXYKTGIzSHRrTXRRbEpoRHRwYmRhR2hidlN2UDFkbWh2SG5UYndSck1mZnZXcFZ5dVRYR0lFT2k0VGdYTE5tbUhZOAp2cENRM3RMMHArSnoxQlB3TzlpL2N4S1JGT1RQQTd3U2kwYUpET1Jac2NLejk3QnVpcmp3R0plQnlBQUhqbk43CkUyRFpEM2FwTSt2THRyRzBweS9rSzU2T2NxT3N6NGFIb0ZtV2MvMzdCL09UMVVoOTloWmM3Q3BYNDkvTjdGNEMKZlN1ZVZiK3hDWHlCeEMxL2RLSnR2QkxPOWxUbS9wNTBzZU9qM0tRSU5PN2tyU0FrWTRRd2d5SENmazY3cFhUNQpGVU96YUZudm5lWnYwcFBYM2RwNkh5VEc2R055RklaeUZWL3NQQit3R0JuYTVSOStpL2psNEYzbllLSnlNcTMyCk1YQUpzQ29kQWdNQkFBRUNnZ0VCQUpuVXE4VHA4VmVzeVhWY1JpVmNrMEwydzJJVGxRS2NqWVVseUNPTnhYaW8KY1pKN0VYUHRyWXNyUUtLN2JMMkorSmEyQjkxeldEUGwwRWpsb1Z5SWRNQU4wVWxHbDAwcXRZREU5VHdHU0l0QQprNDg0RmczRG0rSVdVekc1YXFNeFArenhyZEhOVkxtZFp1aXFWMHN0dTVTcjlRRzdYSDBCY0RQN0pETXJqT2M2CkhZOEIyWjJ1VzJVOWlaUnF5RHlnSVoveGczbUp5TEdXM1VpTUUvWTQ2OWEzeGRrOGFaN1FVWnk3T1Exa0Z4S2MKVGhuYmY4ZnBYVVRtejlTTSs1YnZXaTVTTnpsV05TdmJWY21vYjN6Q0t3QlZYZGovWnFBc2NLOXU1UkZISmEvWgppai9zdk43ZGh6VW1PL21tblBLR0lSMzBVSy9NUjRKWGcweTZCcFpTeGdFQ2dZRUEwZ1dndjdEcGN2ZDhQTFB0ClZla0NZZXNpWjZINFFVaFRObzJEYTFHdWFQaUlsVmpUWFBSd2VqcGkyRWVUL0Z0c0RJQUlpbmJDdUpYZnZqcG4KSjVYNnFJNFBmTi8xM3hSODFiVXJ4amdXenlKeDVMcDlkSDRpUmhTOW5pZVJYTDRPN0VXQVBvd2tTWkhjcThVLwpmMHpndnN5K3d4Tnp2OHZ2SGtNUzBwS01VSVVDZ1lFQXkvN0ZiZGFNYUlaM0wxcFlqNTQ3VDRwQXZKeTB2TzltClhleFZvSGZYOGpuaHoxdUU1UmtEMExRMlFUbEZPYVdyQzVKdnQwUXVPbVZVRlFMUTRpdGM0dG9XTWlEMmhxQmIKYUR5Q0dYQ0FGZWh2cTB0Rndkd1F4ZnRQbjhlYjRBMXdMTXhvaWhzYU1MNWUyYmg3dG9hRFhkaVV5eWVTV25aRAppWS9vNHAxUU1ya0NnWUVBcDR3NzJKRlBQQnQ1N29kd0VMaHA0U29QY1hPQ3RMbjVRSzBXcWJncEZxOG5iMVhFCmtRU2s4cTIvaTJGWEN0ejRUdVNaYTdVZzFOY2ovd05pcGU3OVlCaXMvR2RESkN1WkIzaVlLbk0ycHhxSWwvdTYKK0FOa1hscFBoMnR6aVBSS3ZXMFl5VTFONmE5R3gzWDltUllBdWRablhRTVl0V3NCSVRoTFBOZ1N2bTBDZ1lFQQpnZHE5NW50cWlhYisrMyt4WEVySFNveWhSTzhrQmhrR3VzY1VncitIRVVSVFArSHNLTUhSc2VybGxvTlVVNnZuCnc4Z0ZvVTJmZDhERTAxTWxrTE0xdjVwQUFzMEU0UkgyM2RXV280Yi9vZktDRXpJcFI0eEVpU0srdnVFYmtuWTcKYitqMnF1TXh1dEdVSTFmU09KQkwwMU5vOUNGT2dwTkJ6ckZ5OTc1WUxORUNnWUVBamNwZzY0ZVYzejZvbjJKbgpEUVJSUGJrVXpoZytXbW8yaDZsVVVkaS91U3VTMW50Q1JuSVVINkZZKzJsNkFJR3hpSUg0SW5MN29BaGdKemkxCnRSWFlKSGgwWDFzNkpEcjhGblhWTC9BN0FwdmVzTVRhUkxYTnQzeVNURm1iOUtPbXAwSlhuSnFmcnZOZGpVbGIKMnNZNHlQVFpaR0wwemxNNVcrYVVhZFFHRXVFPQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==
6 | kind: Secret
7 | metadata:
8 | creationTimestamp: null
9 | name: docker-registry-secret
10 | namespace: treasure-hunt
11 |
--------------------------------------------------------------------------------
/manifests/01_challenges/treasure-hunt/docker-registry/service.yml:
--------------------------------------------------------------------------------
1 | kind: Service
2 | apiVersion: v1
3 | metadata:
4 | name: docker-registry
5 | namespace: treasure-hunt
6 | spec:
7 | selector:
8 | app: docker-registry
9 | type: ClusterIP
10 | ports:
11 | - protocol: TCP
12 | port: 5000
13 | targetPort: 5000
14 | name: docker-registry-http
15 |
--------------------------------------------------------------------------------
/manifests/01_challenges/treasure-hunt/flag/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:latest
2 |
3 | ADD FLAG.txt /FLAG.txt
4 | RUN rm /FLAG.txt
5 |
--------------------------------------------------------------------------------
/manifests/01_challenges/treasure-hunt/flag/FLAG.txt:
--------------------------------------------------------------------------------
1 | k8sctf{cb5639e30f2f7ae7af0b319e6bc5571cb81a4e49}
2 |
--------------------------------------------------------------------------------
/manifests/01_challenges/treasure-hunt/flag/docker-registry-password:
--------------------------------------------------------------------------------
1 | fj8ur3gy837nbt8g7r89yfbrwye89
2 |
--------------------------------------------------------------------------------
/manifests/01_challenges/treasure-hunt/victim.yaml:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: victim
5 | namespace: treasure-hunt
6 | spec:
7 | replicas: 1
8 | selector:
9 | matchLabels:
10 | app: victim
11 | template:
12 | metadata:
13 | labels:
14 | app: victim
15 | spec:
16 | containers:
17 | - name: victim
18 | image: nicolaka/netshoot:latest
19 | command: ["tail", "-f", "/dev/null"]
20 | env:
21 | - name: DOCKER_USERNAME
22 | value: ctf
23 | - name: DOCKER_PASSWORD
24 | value: fj8ur3gy837nbt8g7r89yfbrwye89
25 |
26 |
--------------------------------------------------------------------------------
/manifests/flags/mountme/FLAG.txt:
--------------------------------------------------------------------------------
1 | k8sctf{396b1bc80afa7234a2977f709d35e787b9c7cfa3}
2 |
--------------------------------------------------------------------------------
/manifests/flags/mountme2/FLAG.txt:
--------------------------------------------------------------------------------
1 | k8sctf{ec7738c6d0ca58dd8005906a5c8da8129be4bf74}
2 |
--------------------------------------------------------------------------------
/manifests/gatekeeper/00_gatekeeper.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | labels:
5 | admission.gatekeeper.sh/ignore: no-self-managing
6 | control-plane: controller-manager
7 | gatekeeper.sh/system: "yes"
8 | name: gatekeeper-system
9 | ---
10 | apiVersion: apiextensions.k8s.io/v1beta1
11 | kind: CustomResourceDefinition
12 | metadata:
13 | annotations:
14 | controller-gen.kubebuilder.io/version: v0.3.0
15 | creationTimestamp: null
16 | labels:
17 | gatekeeper.sh/system: "yes"
18 | name: configs.config.gatekeeper.sh
19 | spec:
20 | group: config.gatekeeper.sh
21 | names:
22 | kind: Config
23 | listKind: ConfigList
24 | plural: configs
25 | singular: config
26 | scope: Namespaced
27 | validation:
28 | openAPIV3Schema:
29 | description: Config is the Schema for the configs API
30 | properties:
31 | apiVersion:
32 | description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
33 | type: string
34 | kind:
35 | description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
36 | type: string
37 | metadata:
38 | type: object
39 | spec:
40 | description: ConfigSpec defines the desired state of Config
41 | properties:
42 | match:
43 | description: Configuration for namespace exclusion
44 | items:
45 | properties:
46 | excludedNamespaces:
47 | items:
48 | type: string
49 | type: array
50 | processes:
51 | items:
52 | type: string
53 | type: array
54 | type: object
55 | type: array
56 | readiness:
57 | description: Configuration for readiness tracker
58 | properties:
59 | statsEnabled:
60 | type: boolean
61 | type: object
62 | sync:
63 | description: Configuration for syncing k8s objects
64 | properties:
65 | syncOnly:
66 | description: If non-empty, only entries on this list will be replicated into OPA
67 | items:
68 | properties:
69 | group:
70 | type: string
71 | kind:
72 | type: string
73 | version:
74 | type: string
75 | type: object
76 | type: array
77 | type: object
78 | validation:
79 | description: Configuration for validation
80 | properties:
81 | traces:
82 | description: List of requests to trace. Both "user" and "kinds" must be specified
83 | items:
84 | properties:
85 | dump:
86 | description: Also dump the state of OPA with the trace. Set to `All` to dump everything.
87 | type: string
88 | kind:
89 | description: Only trace requests of the following GroupVersionKind
90 | properties:
91 | group:
92 | type: string
93 | kind:
94 | type: string
95 | version:
96 | type: string
97 | type: object
98 | user:
99 | description: Only trace requests from the specified user
100 | type: string
101 | type: object
102 | type: array
103 | type: object
104 | type: object
105 | status:
106 | description: ConfigStatus defines the observed state of Config
107 | type: object
108 | type: object
109 | version: v1alpha1
110 | versions:
111 | - name: v1alpha1
112 | served: true
113 | storage: true
114 | status:
115 | acceptedNames:
116 | kind: ""
117 | plural: ""
118 | conditions: []
119 | storedVersions: []
120 | ---
121 | apiVersion: apiextensions.k8s.io/v1beta1
122 | kind: CustomResourceDefinition
123 | metadata:
124 | annotations:
125 | controller-gen.kubebuilder.io/version: v0.3.0
126 | creationTimestamp: null
127 | labels:
128 | gatekeeper.sh/system: "yes"
129 | name: constraintpodstatuses.status.gatekeeper.sh
130 | spec:
131 | group: status.gatekeeper.sh
132 | names:
133 | kind: ConstraintPodStatus
134 | listKind: ConstraintPodStatusList
135 | plural: constraintpodstatuses
136 | singular: constraintpodstatus
137 | scope: Namespaced
138 | validation:
139 | openAPIV3Schema:
140 | description: ConstraintPodStatus is the Schema for the constraintpodstatuses API
141 | properties:
142 | apiVersion:
143 | description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
144 | type: string
145 | kind:
146 | description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
147 | type: string
148 | metadata:
149 | type: object
150 | status:
151 | description: ConstraintPodStatusStatus defines the observed state of ConstraintPodStatus
152 | properties:
153 | constraintUID:
154 | description: Storing the constraint UID allows us to detect drift, such as when a constraint has been recreated after its CRD was deleted out from under it, interrupting the watch
155 | type: string
156 | enforced:
157 | type: boolean
158 | errors:
159 | items:
160 | description: Error represents a single error caught while adding a constraint to OPA
161 | properties:
162 | code:
163 | type: string
164 | location:
165 | type: string
166 | message:
167 | type: string
168 | required:
169 | - code
170 | - message
171 | type: object
172 | type: array
173 | id:
174 | type: string
175 | observedGeneration:
176 | format: int64
177 | type: integer
178 | operations:
179 | items:
180 | type: string
181 | type: array
182 | type: object
183 | type: object
184 | version: v1beta1
185 | versions:
186 | - name: v1beta1
187 | served: true
188 | storage: true
189 | status:
190 | acceptedNames:
191 | kind: ""
192 | plural: ""
193 | conditions: []
194 | storedVersions: []
195 | ---
196 | apiVersion: apiextensions.k8s.io/v1beta1
197 | kind: CustomResourceDefinition
198 | metadata:
199 | annotations:
200 | controller-gen.kubebuilder.io/version: v0.3.0
201 | creationTimestamp: null
202 | labels:
203 | gatekeeper.sh/system: "yes"
204 | name: constrainttemplatepodstatuses.status.gatekeeper.sh
205 | spec:
206 | group: status.gatekeeper.sh
207 | names:
208 | kind: ConstraintTemplatePodStatus
209 | listKind: ConstraintTemplatePodStatusList
210 | plural: constrainttemplatepodstatuses
211 | singular: constrainttemplatepodstatus
212 | scope: Namespaced
213 | validation:
214 | openAPIV3Schema:
215 | description: ConstraintTemplatePodStatus is the Schema for the constrainttemplatepodstatuses API
216 | properties:
217 | apiVersion:
218 | description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
219 | type: string
220 | kind:
221 | description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
222 | type: string
223 | metadata:
224 | type: object
225 | status:
226 | description: ConstraintTemplatePodStatusStatus defines the observed state of ConstraintTemplatePodStatus
227 | properties:
228 | errors:
229 | items:
230 | description: CreateCRDError represents a single error caught during parsing, compiling, etc.
231 | properties:
232 | code:
233 | type: string
234 | location:
235 | type: string
236 | message:
237 | type: string
238 | required:
239 | - code
240 | - message
241 | type: object
242 | type: array
243 | id:
244 | description: 'Important: Run "make" to regenerate code after modifying this file'
245 | type: string
246 | observedGeneration:
247 | format: int64
248 | type: integer
249 | operations:
250 | items:
251 | type: string
252 | type: array
253 | templateUID:
254 | description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
255 | type: string
256 | type: object
257 | type: object
258 | version: v1beta1
259 | versions:
260 | - name: v1beta1
261 | served: true
262 | storage: true
263 | status:
264 | acceptedNames:
265 | kind: ""
266 | plural: ""
267 | conditions: []
268 | storedVersions: []
269 | ---
270 | apiVersion: apiextensions.k8s.io/v1beta1
271 | kind: CustomResourceDefinition
272 | metadata:
273 | creationTimestamp: null
274 | labels:
275 | controller-tools.k8s.io: "1.0"
276 | gatekeeper.sh/system: "yes"
277 | name: constrainttemplates.templates.gatekeeper.sh
278 | spec:
279 | group: templates.gatekeeper.sh
280 | names:
281 | kind: ConstraintTemplate
282 | plural: constrainttemplates
283 | scope: Cluster
284 | subresources:
285 | status: {}
286 | validation:
287 | openAPIV3Schema:
288 | properties:
289 | apiVersion:
290 | description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
291 | type: string
292 | kind:
293 | description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
294 | type: string
295 | metadata:
296 | type: object
297 | spec:
298 | properties:
299 | crd:
300 | properties:
301 | spec:
302 | properties:
303 | names:
304 | properties:
305 | kind:
306 | type: string
307 | shortNames:
308 | items:
309 | type: string
310 | type: array
311 | type: object
312 | validation:
313 | type: object
314 | type: object
315 | type: object
316 | targets:
317 | items:
318 | properties:
319 | libs:
320 | items:
321 | type: string
322 | type: array
323 | rego:
324 | type: string
325 | target:
326 | type: string
327 | type: object
328 | type: array
329 | type: object
330 | status:
331 | properties:
332 | byPod:
333 | items:
334 | properties:
335 | errors:
336 | items:
337 | properties:
338 | code:
339 | type: string
340 | location:
341 | type: string
342 | message:
343 | type: string
344 | required:
345 | - code
346 | - message
347 | type: object
348 | type: array
349 | id:
350 | description: a unique identifier for the pod that wrote the status
351 | type: string
352 | observedGeneration:
353 | format: int64
354 | type: integer
355 | type: object
356 | type: array
357 | created:
358 | type: boolean
359 | type: object
360 | version: v1beta1
361 | versions:
362 | - name: v1beta1
363 | served: true
364 | storage: true
365 | - name: v1alpha1
366 | served: true
367 | storage: false
368 | status:
369 | acceptedNames:
370 | kind: ""
371 | plural: ""
372 | conditions: []
373 | storedVersions: []
374 | ---
375 | apiVersion: v1
376 | kind: ServiceAccount
377 | metadata:
378 | labels:
379 | gatekeeper.sh/system: "yes"
380 | name: gatekeeper-admin
381 | namespace: gatekeeper-system
382 | ---
383 | apiVersion: rbac.authorization.k8s.io/v1
384 | kind: Role
385 | metadata:
386 | creationTimestamp: null
387 | labels:
388 | gatekeeper.sh/system: "yes"
389 | name: gatekeeper-manager-role
390 | namespace: gatekeeper-system
391 | rules:
392 | - apiGroups:
393 | - ""
394 | resources:
395 | - events
396 | verbs:
397 | - create
398 | - patch
399 | - apiGroups:
400 | - ""
401 | resources:
402 | - secrets
403 | verbs:
404 | - create
405 | - delete
406 | - get
407 | - list
408 | - patch
409 | - update
410 | - watch
411 | ---
412 | apiVersion: rbac.authorization.k8s.io/v1
413 | kind: ClusterRole
414 | metadata:
415 | creationTimestamp: null
416 | labels:
417 | gatekeeper.sh/system: "yes"
418 | name: gatekeeper-manager-role
419 | rules:
420 | - apiGroups:
421 | - '*'
422 | resources:
423 | - '*'
424 | verbs:
425 | - get
426 | - list
427 | - watch
428 | - apiGroups:
429 | - apiextensions.k8s.io
430 | resources:
431 | - customresourcedefinitions
432 | verbs:
433 | - create
434 | - delete
435 | - get
436 | - list
437 | - patch
438 | - update
439 | - watch
440 | - apiGroups:
441 | - config.gatekeeper.sh
442 | resources:
443 | - configs
444 | verbs:
445 | - create
446 | - delete
447 | - get
448 | - list
449 | - patch
450 | - update
451 | - watch
452 | - apiGroups:
453 | - config.gatekeeper.sh
454 | resources:
455 | - configs/status
456 | verbs:
457 | - get
458 | - patch
459 | - update
460 | - apiGroups:
461 | - constraints.gatekeeper.sh
462 | resources:
463 | - '*'
464 | verbs:
465 | - create
466 | - delete
467 | - get
468 | - list
469 | - patch
470 | - update
471 | - watch
472 | - apiGroups:
473 | - policy
474 | resources:
475 | - podsecuritypolicies
476 | verbs:
477 | - use
478 | - apiGroups:
479 | - status.gatekeeper.sh
480 | resources:
481 | - '*'
482 | verbs:
483 | - create
484 | - delete
485 | - get
486 | - list
487 | - patch
488 | - update
489 | - watch
490 | - apiGroups:
491 | - templates.gatekeeper.sh
492 | resources:
493 | - constrainttemplates
494 | verbs:
495 | - create
496 | - delete
497 | - get
498 | - list
499 | - patch
500 | - update
501 | - watch
502 | - apiGroups:
503 | - templates.gatekeeper.sh
504 | resources:
505 | - constrainttemplates/finalizers
506 | verbs:
507 | - delete
508 | - get
509 | - patch
510 | - update
511 | - apiGroups:
512 | - templates.gatekeeper.sh
513 | resources:
514 | - constrainttemplates/status
515 | verbs:
516 | - get
517 | - patch
518 | - update
519 | - apiGroups:
520 | - admissionregistration.k8s.io
521 | resourceNames:
522 | - gatekeeper-validating-webhook-configuration
523 | resources:
524 | - validatingwebhookconfigurations
525 | verbs:
526 | - create
527 | - delete
528 | - get
529 | - list
530 | - patch
531 | - update
532 | - watch
533 | ---
534 | apiVersion: rbac.authorization.k8s.io/v1
535 | kind: RoleBinding
536 | metadata:
537 | labels:
538 | gatekeeper.sh/system: "yes"
539 | name: gatekeeper-manager-rolebinding
540 | namespace: gatekeeper-system
541 | roleRef:
542 | apiGroup: rbac.authorization.k8s.io
543 | kind: Role
544 | name: gatekeeper-manager-role
545 | subjects:
546 | - kind: ServiceAccount
547 | name: gatekeeper-admin
548 | namespace: gatekeeper-system
549 | ---
550 | apiVersion: rbac.authorization.k8s.io/v1
551 | kind: ClusterRoleBinding
552 | metadata:
553 | labels:
554 | gatekeeper.sh/system: "yes"
555 | name: gatekeeper-manager-rolebinding
556 | roleRef:
557 | apiGroup: rbac.authorization.k8s.io
558 | kind: ClusterRole
559 | name: gatekeeper-manager-role
560 | subjects:
561 | - kind: ServiceAccount
562 | name: gatekeeper-admin
563 | namespace: gatekeeper-system
564 | ---
565 | apiVersion: v1
566 | kind: Secret
567 | metadata:
568 | labels:
569 | gatekeeper.sh/system: "yes"
570 | name: gatekeeper-webhook-server-cert
571 | namespace: gatekeeper-system
572 | ---
573 | apiVersion: v1
574 | kind: Service
575 | metadata:
576 | labels:
577 | gatekeeper.sh/system: "yes"
578 | name: gatekeeper-webhook-service
579 | namespace: gatekeeper-system
580 | spec:
581 | ports:
582 | - port: 443
583 | targetPort: 8443
584 | selector:
585 | control-plane: controller-manager
586 | gatekeeper.sh/operation: webhook
587 | gatekeeper.sh/system: "yes"
588 | ---
589 | apiVersion: apps/v1
590 | kind: Deployment
591 | metadata:
592 | labels:
593 | control-plane: controller-manager
594 | gatekeeper.sh/operation: audit
595 | gatekeeper.sh/system: "yes"
596 | name: gatekeeper-audit
597 | namespace: gatekeeper-system
598 | spec:
599 | replicas: 1
600 | selector:
601 | matchLabels:
602 | control-plane: audit-controller
603 | gatekeeper.sh/operation: audit
604 | gatekeeper.sh/system: "yes"
605 | template:
606 | metadata:
607 | annotations:
608 | container.seccomp.security.alpha.kubernetes.io/manager: runtime/default
609 | labels:
610 | control-plane: audit-controller
611 | gatekeeper.sh/operation: audit
612 | gatekeeper.sh/system: "yes"
613 | spec:
614 | containers:
615 | - args:
616 | - --operation=audit
617 | - --operation=status
618 | - --logtostderr
619 | command:
620 | - /manager
621 | env:
622 | - name: POD_NAMESPACE
623 | valueFrom:
624 | fieldRef:
625 | apiVersion: v1
626 | fieldPath: metadata.namespace
627 | - name: POD_NAME
628 | valueFrom:
629 | fieldRef:
630 | fieldPath: metadata.name
631 | image: openpolicyagent/gatekeeper:v3.1.3
632 | imagePullPolicy: Always
633 | livenessProbe:
634 | httpGet:
635 | path: /healthz
636 | port: 9090
637 | name: manager
638 | ports:
639 | - containerPort: 8888
640 | name: metrics
641 | protocol: TCP
642 | - containerPort: 9090
643 | name: healthz
644 | protocol: TCP
645 | readinessProbe:
646 | httpGet:
647 | path: /readyz
648 | port: 9090
649 | resources:
650 | limits:
651 | cpu: 1000m
652 | memory: 512Mi
653 | requests:
654 | cpu: 100m
655 | memory: 256Mi
656 | securityContext:
657 | allowPrivilegeEscalation: false
658 | capabilities:
659 | drop:
660 | - all
661 | runAsGroup: 999
662 | runAsNonRoot: true
663 | runAsUser: 1000
664 | nodeSelector:
665 | kubernetes.io/os: linux
666 | serviceAccountName: gatekeeper-admin
667 | terminationGracePeriodSeconds: 60
668 | ---
669 | apiVersion: apps/v1
670 | kind: Deployment
671 | metadata:
672 | labels:
673 | control-plane: controller-manager
674 | gatekeeper.sh/operation: webhook
675 | gatekeeper.sh/system: "yes"
676 | name: gatekeeper-controller-manager
677 | namespace: gatekeeper-system
678 | spec:
679 | replicas: 3
680 | selector:
681 | matchLabels:
682 | control-plane: controller-manager
683 | gatekeeper.sh/operation: webhook
684 | gatekeeper.sh/system: "yes"
685 | template:
686 | metadata:
687 | annotations:
688 | container.seccomp.security.alpha.kubernetes.io/manager: runtime/default
689 | labels:
690 | control-plane: controller-manager
691 | gatekeeper.sh/operation: webhook
692 | gatekeeper.sh/system: "yes"
693 | spec:
694 | affinity:
695 | podAntiAffinity:
696 | preferredDuringSchedulingIgnoredDuringExecution:
697 | - podAffinityTerm:
698 | labelSelector:
699 | matchExpressions:
700 | - key: gatekeeper.sh/operation
701 | operator: In
702 | values:
703 | - webhook
704 | topologyKey: kubernetes.io/hostname
705 | weight: 100
706 | containers:
707 | - args:
708 | - --port=8443
709 | - --logtostderr
710 | - --exempt-namespace=gatekeeper-system
711 | - --operation=webhook
712 | command:
713 | - /manager
714 | env:
715 | - name: POD_NAMESPACE
716 | valueFrom:
717 | fieldRef:
718 | apiVersion: v1
719 | fieldPath: metadata.namespace
720 | - name: POD_NAME
721 | valueFrom:
722 | fieldRef:
723 | fieldPath: metadata.name
724 | image: openpolicyagent/gatekeeper:v3.1.3
725 | imagePullPolicy: Always
726 | livenessProbe:
727 | httpGet:
728 | path: /healthz
729 | port: 9090
730 | name: manager
731 | ports:
732 | - containerPort: 8443
733 | name: webhook-server
734 | protocol: TCP
735 | - containerPort: 8888
736 | name: metrics
737 | protocol: TCP
738 | - containerPort: 9090
739 | name: healthz
740 | protocol: TCP
741 | readinessProbe:
742 | httpGet:
743 | path: /readyz
744 | port: 9090
745 | resources:
746 | limits:
747 | cpu: 1000m
748 | memory: 512Mi
749 | requests:
750 | cpu: 100m
751 | memory: 256Mi
752 | securityContext:
753 | allowPrivilegeEscalation: false
754 | capabilities:
755 | drop:
756 | - all
757 | runAsGroup: 999
758 | runAsNonRoot: true
759 | runAsUser: 1000
760 | volumeMounts:
761 | - mountPath: /certs
762 | name: cert
763 | readOnly: true
764 | nodeSelector:
765 | kubernetes.io/os: linux
766 | serviceAccountName: gatekeeper-admin
767 | terminationGracePeriodSeconds: 60
768 | volumes:
769 | - name: cert
770 | secret:
771 | defaultMode: 420
772 | secretName: gatekeeper-webhook-server-cert
773 | ---
774 | apiVersion: admissionregistration.k8s.io/v1beta1
775 | kind: ValidatingWebhookConfiguration
776 | metadata:
777 | creationTimestamp: null
778 | labels:
779 | gatekeeper.sh/system: "yes"
780 | name: gatekeeper-validating-webhook-configuration
781 | webhooks:
782 | - clientConfig:
783 | caBundle: Cg==
784 | service:
785 | name: gatekeeper-webhook-service
786 | namespace: gatekeeper-system
787 | path: /v1/admit
788 | failurePolicy: Ignore
789 | name: validation.gatekeeper.sh
790 | namespaceSelector:
791 | matchExpressions:
792 | - key: admission.gatekeeper.sh/ignore
793 | operator: DoesNotExist
794 | rules:
795 | - apiGroups:
796 | - '*'
797 | apiVersions:
798 | - '*'
799 | operations:
800 | - CREATE
801 | - UPDATE
802 | resources:
803 | - '*'
804 | sideEffects: None
805 | timeoutSeconds: 3
806 | - clientConfig:
807 | caBundle: Cg==
808 | service:
809 | name: gatekeeper-webhook-service
810 | namespace: gatekeeper-system
811 | path: /v1/admitlabel
812 | failurePolicy: Fail
813 | name: check-ignore-label.gatekeeper.sh
814 | rules:
815 | - apiGroups:
816 | - ""
817 | apiVersions:
818 | - '*'
819 | operations:
820 | - CREATE
821 | - UPDATE
822 | resources:
823 | - namespaces
824 | sideEffects: None
825 | timeoutSeconds: 3
826 |
--------------------------------------------------------------------------------
/manifests/gatekeeper/hostpath/00_template.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: templates.gatekeeper.sh/v1beta1
2 | kind: ConstraintTemplate
3 | metadata:
4 | name: k8spsphostfilesystem
5 | spec:
6 | crd:
7 | spec:
8 | names:
9 | kind: K8sPSPHostFilesystem
10 | validation:
11 | openAPIV3Schema:
12 | properties:
13 | allowedHostPaths:
14 | type: array
15 | items:
16 | type: object
17 | properties:
18 | readOnly:
19 | type: boolean
20 | pathPrefix:
21 | type: string
22 | targets:
23 | - target: admission.k8s.gatekeeper.sh
24 | rego: |
25 | package k8spsphostfilesystem
26 | violation[{"msg": msg, "details": {}}] {
27 | volume := input_hostpath_volumes[_]
28 | allowedPaths := get_allowed_paths(input)
29 | input_hostpath_violation(allowedPaths, volume)
30 | msg := sprintf("HostPath volume %v is not allowed, pod: %v. Allowed path: %v", [volume, input.review.object.metadata.name, allowedPaths])
31 | }
32 | input_hostpath_violation(allowedPaths, volume) {
33 | allowedPaths == []
34 | }
35 | input_hostpath_violation(allowedPaths, volume) {
36 | not input_hostpath_allowed(allowedPaths, volume)
37 | }
38 | get_allowed_paths(arg) = out {
39 | not arg.parameters
40 | out = []
41 | }
42 | get_allowed_paths(arg) = out {
43 | not arg.parameters.allowedHostPaths
44 | out = []
45 | }
46 | get_allowed_paths(arg) = out {
47 | out = arg.parameters.allowedHostPaths
48 | }
49 | input_hostpath_allowed(allowedPaths, volume) {
50 | allowedHostPath := allowedPaths[_]
51 | path_matches(allowedHostPath.pathPrefix, volume.hostPath.path)
52 | not allowedHostPath.readOnly == true
53 | }
54 | input_hostpath_allowed(allowedPaths, volume) {
55 | allowedHostPath := allowedPaths[_]
56 | path_matches(allowedHostPath.pathPrefix, volume.hostPath.path)
57 | allowedHostPath.readOnly
58 | not writeable_input_volume_mounts(volume.name)
59 | }
60 | writeable_input_volume_mounts(volume_name) {
61 | container := input_containers[_]
62 | mount := container.volumeMounts[_]
63 | mount.name == volume_name
64 | not mount.readOnly
65 | }
66 | path_matches(prefix, path) {
67 | a := split(trim(prefix, "/"), "/")
68 | b := split(trim(path, "/"), "/")
69 | prefix_matches(a, b)
70 | }
71 | prefix_matches(a, b) {
72 | count(a) <= count(b)
73 | not any_not_equal_upto(a, b, count(a))
74 | }
75 | any_not_equal_upto(a, b, n) {
76 | a[i] != b[i]
77 | i < n
78 | }
79 | input_hostpath_volumes[v] {
80 | v := input.review.object.spec.volumes[_]
81 | has_field(v, "hostPath")
82 | }
83 | has_field(object, field) = true {
84 | object[field]
85 | }
86 | input_containers[c] {
87 | c := input.review.object.spec.containers[_]
88 | }
89 | input_containers[c] {
90 | c := input.review.object.spec.initContainers[_]
91 | }
92 |
--------------------------------------------------------------------------------
/manifests/gatekeeper/hostpath/01_constraint.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: constraints.gatekeeper.sh/v1beta1
2 | kind: K8sPSPHostFilesystem
3 | metadata:
4 | name: psp-host-filesystem
5 | spec:
6 | match:
7 | kinds:
8 | - apiGroups: [""]
9 | kinds: ["Pod"]
10 | parameters:
11 | allowedHostPaths:
12 | - readOnly: true
13 | pathPrefix: "/data"
14 | - readOnly: true
15 | pathPrefix: "/home/docker/mountme1"
16 |
--------------------------------------------------------------------------------
/setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | kubectl apply -Rf manifests/00_namespaces/
4 | echo "✅ Create namespace"
5 |
6 | kubectl apply -f manifests/gatekeeper/00_gatekeeper.yaml
7 | kubectl apply -f manifests/gatekeeper/hostpath/00_template.yaml
8 | echo "✅ Create Gatekeeper"
9 |
10 | # mountme
11 | minikube ssh -- mkdir -p /home/docker/mountme1
12 | scp -o StrictHostKeyChecking=no -i $(minikube ssh-key) manifests/flags/mountme/FLAG.txt docker@$(minikube ip):/home/docker/mountme1/FLAG.txt
13 |
14 | kubectl apply -f manifests/01_challenges/mountme/job-sa.yaml
15 | kubectl apply -f manifests/01_challenges/mountme/victim.yaml
16 |
17 | echo "✅ mountme OK"
18 |
19 | # mountme2
20 | minikube ssh -- mkdir -p /home/docker/mountme2
21 | scp -o StrictHostKeyChecking=no -i $(minikube ssh-key) manifests/flags/mountme2/FLAG.txt docker@$(minikube ip):/home/docker/mountme2/FLAG.txt
22 |
23 | kubectl apply -f manifests/01_challenges/mountme2/job-sa.yaml
24 | kubectl apply -f manifests/01_challenges/mountme2/victim.yaml
25 | echo "✅ mountme2 OK"
26 |
27 | # treasure hunt
28 | kubectl apply -f manifests/01_challenges/treasure-hunt/victim.yaml
29 | kubectl apply -f manifests/01_challenges/treasure-hunt/docker-registry/secrets.yml
30 | kubectl apply -f manifests/01_challenges/treasure-hunt/docker-registry/deployment.yml
31 | kubectl apply -f manifests/01_challenges/treasure-hunt/docker-registry/registry-config.yml
32 | kubectl apply -f manifests/01_challenges/treasure-hunt/docker-registry/service.yml
33 |
34 | cd manifests/01_challenges/treasure-hunt/flag
35 |
36 | while :
37 | do
38 | kubectl get pods -n treasure-hunt | grep docker-registry | grep Running
39 | if [ $? = 0 ]; then
40 | break
41 | fi
42 | echo "🕒 Waiting for a pod to running..."
43 | sleep 5
44 | done
45 |
46 | kubectl -n treasure-hunt port-forward svc/docker-registry 5000 &
47 | sleep 10
48 |
49 | cat docker-registry-password | docker -D login --username ctf --password-stdin https://docker.for.mac.localhost:5000
50 | docker build -t docker.for.mac.localhost:5000/flag/image:latest .
51 | docker push docker.for.mac.localhost:5000/flag/image:latest
52 | pkill -f 'kubectl -n treasure-hunt port-forward'
53 | cd ../../../../
54 |
55 | echo "✅ treasure-hunt OK"
56 |
57 | # can you keep a secret?
58 | minikube ssh -- sudo cat /var/lib/minikube/certs/etcd/ca.crt > manifests/01_challenges/can-you-keep-a-secret/ca.crt
59 | minikube ssh -- sudo cat /var/lib/minikube/certs/etcd/healthcheck-client.key > manifests/01_challenges/can-you-keep-a-secret/healthcheck-client.key
60 | minikube ssh -- sudo cat /var/lib/minikube/certs/etcd/healthcheck-client.crt > manifests/01_challenges/can-you-keep-a-secret/healthcheck-client.crt
61 | kubectl -n can-you-keep-a-secret create secret generic etcd-credentials --from-file=ETCD_CA=manifests/01_challenges/can-you-keep-a-secret/ca.crt --from-file=ETCD_CRT=manifests/01_challenges/can-you-keep-a-secret/healthcheck-client.crt --from-file=ETCD_KEY=manifests/01_challenges/can-you-keep-a-secret/healthcheck-client.key
62 |
63 | kubectl apply -f manifests/01_challenges/can-you-keep-a-secret/victim.yaml
64 | kubectl apply -f manifests/01_challenges/can-you-keep-a-secret/flag.yaml
65 | echo "✅ can you keep a secret? OK"
66 |
67 | # sniff
68 | kubectl apply -f manifests/01_challenges/sniff/service.yml
69 | kubectl apply -f manifests/01_challenges/sniff/server.yaml
70 | kubectl apply -f manifests/01_challenges/sniff/victim.yaml
71 | kubectl apply -f manifests/01_challenges/sniff/client.yaml
72 | echo "✅ sniff OK"
73 |
74 | kubectl apply -f manifests/gatekeeper/hostpath/01_constraint.yaml
75 | echo "✅ Create Gatekeeper Constraint"
76 | echo "✅ All Done !!1"
77 |
--------------------------------------------------------------------------------