Skip to content

Commit ee43af1

Browse files
committed
Add 2020 - March challenge
1 parent f5d9ab9 commit ee43af1

18 files changed

+1757
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ When you want to be a goose and want a Kubernetes cluster for a garden.
55
This will be where the previous challenge's challenge-specific data resides. In the future we will also post all run commands, output, and results.
66

77
## Previous Challenges
8-
[2019-12-20 - Holiday Beta NA](./challenges/2019-12-20/)
8+
[2019-December - Holiday Beta NA](./challenges/2019-december/)
9+
[2020-March](./challenges/2020-march)

challenges/2020-march/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# A Honking Good Time
2+
3+
Save the bell, save the world.
4+
5+
## Results
6+
7+
In order of who completed the challenge:
8+
9+
1. [Ian Coldwater], [Brad Geesaman], and [Duffie Cooley]
10+
2. [Anthony Weems]
11+
12+
## Setup
13+
14+
The cluster is a vanilla instance of [kind] (v0.7.0) with some very strict RBAC
15+
rules and Pod Security Policies configured for several accounts and namespaces.
16+
You start as the "goose" in the "garden" namespace and must enumerate your
17+
environment and discover the challenge itself. It does **NOT** require
18+
exploiting the host in any way. It is 100% achievable through Kubernetes.
19+
20+
21+
To replicate the setup execute the following from this directory:
22+
1. `kind create cluster --config=kind-config.yaml --name honkctl`
23+
2. `kubectl apply -f manifests/01`
24+
3. `kubectl apply -f manifests/02`
25+
4. `kubectl apply -f manifests/03`
26+
5. `./goose.sh`
27+
28+
29+
## Solution
30+
31+
The solution and greater explanation can be found in [solution.md].
32+
33+
Trying not to spoil the fun if folks want to give it a go :)
34+
35+
36+
[kind]: https://kind.sigs.k8s.io
37+
[solution.md]: solution.md
38+
[Ian Coldwater]: https://twitter.com/IanColdwater
39+
[Brad Geesaman]: https://twitter.com/bradgeesaman
40+
[Duffie Cooley]: https://twitter.com/mauilion
41+
[Anthony Weems]: https://twitter.com/amlweems

challenges/2020-march/goose.sh

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
set -o pipefail
4+
5+
# Thanks to innovia
6+
# https://gist.github.com/innovia/fbba8259042f71db98ea8d4ad19bd708
7+
8+
SERVICE_ACCOUNT_NAME=goose
9+
NAMESPACE="garden"
10+
KUBECFG_FILE_NAME="/tmp/kube/k8s-${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-conf"
11+
TARGET_FOLDER="/tmp/kube"
12+
13+
create_target_folder() {
14+
echo -n "Creating target directory to hold files in ${TARGET_FOLDER}..."
15+
mkdir -p "${TARGET_FOLDER}"
16+
printf "done"
17+
}
18+
19+
create_service_account() {
20+
echo -e "\\nCreating a service account in ${NAMESPACE} namespace: ${SERVICE_ACCOUNT_NAME}"
21+
kubectl create sa "${SERVICE_ACCOUNT_NAME}" --namespace "${NAMESPACE}"
22+
}
23+
24+
get_secret_name_from_service_account() {
25+
echo -e "\\nGetting secret of service account ${SERVICE_ACCOUNT_NAME} on ${NAMESPACE}"
26+
SECRET_NAME=$(kubectl get sa "${SERVICE_ACCOUNT_NAME}" --namespace="${NAMESPACE}" -o json | jq -r .secrets[].name)
27+
echo "Secret name: ${SECRET_NAME}"
28+
}
29+
30+
extract_ca_crt_from_secret() {
31+
echo -e -n "\\nExtracting ca.crt from secret..."
32+
kubectl get secret --namespace "${NAMESPACE}" "${SECRET_NAME}" -o json | jq \
33+
-r '.data["ca.crt"]' | base64 -d > "${TARGET_FOLDER}/ca.crt"
34+
printf "done"
35+
}
36+
37+
get_user_token_from_secret() {
38+
echo -e -n "\\nGetting user token from secret..."
39+
USER_TOKEN=$(kubectl get secret --namespace "${NAMESPACE}" "${SECRET_NAME}" -o json | jq -r '.data["token"]' | base64 -d)
40+
printf "done"
41+
}
42+
43+
set_kube_config_values() {
44+
context=$(kubectl config current-context)
45+
echo -e "\\nSetting current context to: $context"
46+
47+
CLUSTER_NAME=$(kubectl config get-contexts "$context" | awk '{print $3}' | tail -n 1)
48+
echo "Cluster name: ${CLUSTER_NAME}"
49+
50+
ENDPOINT=$(kubectl config view \
51+
-o jsonpath="{.clusters[?(@.name == \"${CLUSTER_NAME}\")].cluster.server}")
52+
echo "Endpoint: ${ENDPOINT}"
53+
54+
# Set up the config
55+
echo -e "\\nPreparing k8s-${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-conf"
56+
echo -n "Setting a cluster entry in kubeconfig..."
57+
kubectl config set-cluster "${CLUSTER_NAME}" \
58+
--server="${ENDPOINT}" \
59+
--certificate-authority="${TARGET_FOLDER}/ca.crt" \
60+
--embed-certs=true
61+
62+
echo -n "Setting token credentials entry in kubeconfig..."
63+
kubectl config set-credentials \
64+
"${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-${CLUSTER_NAME}" \
65+
--token="${USER_TOKEN}"
66+
67+
echo -n "Setting a context entry in kubeconfig..."
68+
kubectl config set-context \
69+
"${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-${CLUSTER_NAME}" \
70+
--cluster="${CLUSTER_NAME}" \
71+
--user="${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-${CLUSTER_NAME}" \
72+
--namespace="${NAMESPACE}"
73+
74+
echo -n "Setting the current-context in the kubeconfig file..."
75+
kubectl config use-context "${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-${CLUSTER_NAME}"
76+
}
77+
78+
create_target_folder
79+
get_secret_name_from_service_account
80+
extract_ca_crt_from_secret
81+
get_user_token_from_secret
82+
set_kube_config_values
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
kind: Cluster
2+
apiVersion: kind.x-k8s.io/v1alpha4
3+
kubeadmConfigPatches:
4+
- |
5+
kind: ClusterConfiguration
6+
metadata:
7+
name: config
8+
apiServer:
9+
extraArgs:
10+
enable-admission-plugins: NodeRestriction,PodSecurityPolicy
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
apiVersion: policy/v1beta1
2+
kind: PodSecurityPolicy
3+
metadata:
4+
annotations:
5+
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
6+
seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
7+
name: default
8+
spec:
9+
defaultAddCapabilities:
10+
- AUDIT_WRITE # OCI Spec default
11+
- NET_BIND_SERVICE # OCI Spec default
12+
- KILL # OCI Spec default
13+
- CHOWN # needed for nginx
14+
- SETUID # needed for nginx
15+
- SETGID # needed for nginx
16+
requiredDropCapabilities:
17+
- ALL
18+
allowPrivilegeEscalation: false
19+
hostIPC: false
20+
hostNetwork: false
21+
hostPID: false
22+
privileged: false
23+
readOnlyRootFilesystem: false
24+
runAsUser:
25+
rule: 'RunAsAny'
26+
seLinux:
27+
rule: 'RunAsAny'
28+
supplementalGroups:
29+
rule: 'RunAsAny'
30+
fsGroup:
31+
rule: 'RunAsAny'
32+
volumes:
33+
- 'configMap'
34+
- 'downwardAPI'
35+
- 'emptyDir'
36+
- 'persistentVolumeClaim'
37+
- 'projected'
38+
- 'secret'
39+
---
40+
apiVersion: rbac.authorization.k8s.io/v1
41+
kind: ClusterRole
42+
metadata:
43+
name: psp-default
44+
rules:
45+
- apiGroups:
46+
- policy
47+
resourceNames:
48+
- default
49+
resources:
50+
- podsecuritypolicies
51+
verbs:
52+
- use
53+
---
54+
apiVersion: rbac.authorization.k8s.io/v1
55+
kind: ClusterRoleBinding
56+
metadata:
57+
name: psp-default
58+
roleRef:
59+
apiGroup: rbac.authorization.k8s.io
60+
kind: ClusterRole
61+
name: psp-default
62+
subjects:
63+
- kind: Group
64+
name: system:authenticated
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
apiVersion: policy/v1beta1
2+
kind: PodSecurityPolicy
3+
metadata:
4+
annotations:
5+
seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
6+
name: privileged
7+
spec:
8+
allowedCapabilities:
9+
- '*'
10+
allowPrivilegeEscalation: true
11+
fsGroup:
12+
rule: 'RunAsAny'
13+
hostIPC: true
14+
hostNetwork: true
15+
hostPID: true
16+
hostPorts:
17+
- min: 0
18+
max: 65535
19+
privileged: true
20+
readOnlyRootFilesystem: false
21+
runAsUser:
22+
rule: 'RunAsAny'
23+
seLinux:
24+
rule: 'RunAsAny'
25+
supplementalGroups:
26+
rule: 'RunAsAny'
27+
volumes:
28+
- '*'
29+
---
30+
apiVersion: rbac.authorization.k8s.io/v1
31+
kind: ClusterRole
32+
metadata:
33+
name: psp-privileged
34+
rules:
35+
- apiGroups:
36+
- policy
37+
resourceNames:
38+
- privileged
39+
resources:
40+
- podsecuritypolicies
41+
verbs:
42+
- use
43+
---
44+
apiVersion: rbac.authorization.k8s.io/v1
45+
kind: RoleBinding
46+
metadata:
47+
name: psp-privileged
48+
namespace: kube-system
49+
roleRef:
50+
apiGroup: rbac.authorization.k8s.io
51+
kind: ClusterRole
52+
name: psp-privileged
53+
subjects:
54+
- apiGroup: rbac.authorization.k8s.io
55+
kind: Group
56+
name: system:nodes
57+
- apiGroup: rbac.authorization.k8s.io
58+
kind: Group
59+
name: system:serviceaccounts:kube-system
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# ALL the namespaces are created first to prevent clashing when resolving cross
2+
# namespace references in [cluster]roles.
3+
---
4+
apiVersion: v1
5+
kind: Namespace
6+
metadata:
7+
name: home
8+
labels:
9+
location: etc-kubernetes-manifests
10+
---
11+
apiVersion: v1
12+
kind: Namespace
13+
metadata:
14+
name: garden
15+
---
16+
apiVersion: v1
17+
kind: Namespace
18+
metadata:
19+
name: pub
20+
---
21+
apiVersion: v1
22+
kind: Namespace
23+
metadata:
24+
name: model-village
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
apiVersion: apiextensions.k8s.io/v1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: todos.honk.ci
5+
spec:
6+
group: honk.ci
7+
versions:
8+
- name: v1
9+
served: true
10+
storage: true
11+
schema:
12+
openAPIV3Schema:
13+
type: object
14+
properties:
15+
spec:
16+
type: object
17+
properties:
18+
hint:
19+
type: string
20+
todo:
21+
type: string
22+
required:
23+
- todo
24+
additionalPrinterColumns:
25+
- name: Todo
26+
type: string
27+
description: "An important task"
28+
jsonPath: ".spec.todo"
29+
scope: Cluster
30+
names:
31+
plural: todos
32+
singular: todo
33+
kind: Todo
34+
shortNames:
35+
- td
36+
---
37+
kind: ClusterRole
38+
apiVersion: rbac.authorization.k8s.io/v1
39+
metadata:
40+
name: todo-view-crd
41+
labels:
42+
rbac.authorization.k8s.io/aggregate-to-admin: "true"
43+
rbac.authorization.k8s.io/aggregate-to-edit: "true"
44+
rbac.authorization.k8s.io/aggregate-to-view: "true"
45+
rules:
46+
- apiGroups: ["honk.ci"]
47+
resources: ["todos"]
48+
verbs: ["get", "list", "watch"]
49+
---
50+
# Allow EVERYONE to view todo items
51+
apiVersion: rbac.authorization.k8s.io/v1
52+
kind: ClusterRoleBinding
53+
metadata:
54+
name: authenticated-view-todo-crd
55+
roleRef:
56+
apiGroup: rbac.authorization.k8s.io
57+
kind: ClusterRole
58+
name: todo-view-crd
59+
subjects:
60+
- kind: Group
61+
name: system:authenticated
62+
---
63+
kind: ClusterRole
64+
apiVersion: rbac.authorization.k8s.io/v1
65+
metadata:
66+
name: authenticated-view-cluster-crds
67+
labels:
68+
rbac.authorization.k8s.io/aggregate-to-admin: "true"
69+
rbac.authorization.k8s.io/aggregate-to-edit: "true"
70+
rbac.authorization.k8s.io/aggregate-to-view: "true"
71+
rules:
72+
- apiGroups: ["apiextensions.k8s.io"]
73+
resources: ["customresourcedefinitions"]
74+
verbs: ["get", "list", "watch"]
75+
---
76+
# Allow EVERYONE to view cluster level CRDs so that they may find todos
77+
apiVersion: rbac.authorization.k8s.io/v1
78+
kind: ClusterRoleBinding
79+
metadata:
80+
name: authenticated-view-cluster-crd
81+
roleRef:
82+
apiGroup: rbac.authorization.k8s.io
83+
kind: ClusterRole
84+
name: authenticated-view-cluster-crds
85+
subjects:
86+
- kind: Group
87+
name: system:authenticated

0 commit comments

Comments
 (0)