1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#!/usr/bin/env bash
# Makes a scoped kubeconfig for knotless-run from a tenant admin
# kubeconfig: a ServiceAccount, a namespaced Role for Jobs, pods, exec,
# logs, events and NetworkPolicies, and a 24-hour token.
#
# The token is written only into the output kubeconfig, mode 0600. It is
# not printed. Re-run this before the 24 hours are up.
#
# Environment:
# ADMIN_KUBECONFIG tenant admin kubeconfig
# OUT scoped kubeconfig to write
# NAMESPACE namespace (default knotless-runs)
# SERVICE_ACCOUNT service account (default knotless-runner)
set -euo pipefail
ADMIN_KUBECONFIG=${ADMIN_KUBECONFIG:-$HOME/.tmp/knotless-runner-k8s/tenant/knotless-poc.kubeconfig.yaml}
OUT=${OUT:-$HOME/.tmp/knotless-runner-k8s/tenant/knotless-runner.kubeconfig.yaml}
NAMESPACE=${NAMESPACE:-knotless-runs}
SERVICE_ACCOUNT=${SERVICE_ACCOUNT:-knotless-runner}
admin() { kubectl --kubeconfig "$ADMIN_KUBECONFIG" "$@"; }
admin create namespace "$NAMESPACE" --dry-run=client -o yaml | admin apply -f - >/dev/null
admin -n "$NAMESPACE" create serviceaccount "$SERVICE_ACCOUNT" --dry-run=client -o yaml | admin apply -f - >/dev/null
admin apply -f - >/dev/null <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: knotless-runner
namespace: $NAMESPACE
rules:
- apiGroups: [""]
resources: ["pods", "pods/log", "pods/exec", "events"]
verbs: ["get", "list", "watch", "create"]
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: ["networking.k8s.io"]
resources: ["networkpolicies"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: knotless-runner
namespace: $NAMESPACE
subjects:
- kind: ServiceAccount
name: $SERVICE_ACCOUNT
namespace: $NAMESPACE
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: knotless-runner
EOF
SERVER=$(admin config view --minify -o jsonpath='{.clusters[0].cluster.server}')
TOKEN=$(admin -n "$NAMESPACE" create token "$SERVICE_ACCOUNT" --duration=24h)
tmp=$(mktemp "$OUT.XXXXXX")
trap 'rm -f "$tmp"' EXIT
chmod 0600 "$tmp"
{
printf 'apiVersion: v1\nkind: Config\n'
printf 'clusters:\n- name: tenant\n cluster:\n server: "%s"\n' "$SERVER"
printf 'contexts:\n- name: %s\n context:\n cluster: tenant\n user: %s\n namespace: %s\n' "$NAMESPACE" "$SERVICE_ACCOUNT" "$NAMESPACE"
printf 'current-context: %s\n' "$NAMESPACE"
printf 'users:\n- name: %s\n user:\n token: "%s"\n' "$SERVICE_ACCOUNT" "$TOKEN"
} > "$tmp"
mv "$tmp" "$OUT"
chmod 0600 "$OUT"
trap - EXIT
if [ "$(kubectl --kubeconfig "$OUT" auth can-i create jobs -n "$NAMESPACE")" != yes ]; then
echo "scoped-kubeconfig: the token cannot create Jobs" >&2
exit 1
fi
if [ "$(kubectl --kubeconfig "$OUT" auth can-i get nodes)" != no ]; then
echo "scoped-kubeconfig: the token is not scoped: it can read nodes" >&2
exit 1
fi
printf '%s\n' "$OUT"