Unlängst stellte sich die Frage: Wie kann ich die Kubernetes-API mit curl abfragen? In der Kubernetes-Doku gibt es eine Anleitung, in der kubectl proxy verwendet wird, also die extern zur Verfügung gestellte Authentifizierung, und damit dann die Kubernetes API curlen. Es gibt aber auch die innerCluster Kommunikation, also der Weg von einem Pod im Cluster zur Kubernetes-API.
Dazu werden in jedem Pod automatisch Token gemountet mit einem Default-ServiceAccount im Namespace. Das Feature kann man zwar im Cluster abschalten, aber dieser Account hat sowieso keine Rechte. Die müssen wir uns erst besorgen über eine Role, die dann mit einem RoleBinding an einen ServiceAccount gebunden wird, den wir uns am besten auch noch erstellen. Das ganze läuft in einem StatefulSet mit einem Image, was das curl beinhaltet, sowie eine Shell und etwa jq, um Json-Output zu parsen.
Manifest:
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app: curl-client
name: curl-client
spec:
serviceName: curl-client
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: curl-client
template:
metadata:
labels:
app: curl-client
spec:
containers:
- image: mtr.devops.telekom.de/mcsps/mysql-client:0.0.6
imagePullPolicy: Always
command: ['sh', '-c']
args: ["tail -f /dev/null"]
name: curl-client
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
runAsUser: 1000
runAsGroup: 1000
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- name: workdir
mountPath: /home/appuser
- name: tmp
mountPath: /tmp
dnsPolicy: ClusterFirst
hostNetwork: false
restartPolicy: Always
schedulerName: default-scheduler
securityContext:
fsGroup: 1000
supplementalGroups:
- 1000
terminationGracePeriodSeconds: 3
serviceAccountName: curl-client
volumes:
- name: workdir
emptyDir: {}
- name: tmp
emptyDir:
medium: Memory
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: curl-client
name: curl-client
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
app: curl-client
name: curl-client
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- pods
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app: curl-client
name: curl-client
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: curl-client
subjects:
- kind: ServiceAccount
name: curl-client
Unser ServiceAccount curl-client
kann also Services, Pods und Endpoints abfragen.
Im Pod haben wir das Cluster-Zertifikat liegen und einen Token als Secret gemountet, was wir zur Abfrage verwenden können:
% kubectl -n demoapp exec -it curl-client-0 -- sh
$ export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
$ curl -v https://10.43.0.1/openapi/v2 -H "Authorization: Bearer $TOKEN" --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
$ curl https://10.43.0.1/api/v1/namespaces/demoapp/pods -H "Authorization: Bearer $TOKEN" --cacert /var/run/secrets/kubernetes.io
/serviceaccount/ca.crt
$ curl -s https://10.43.0.1/api/v1/namespaces/demoapp/pods -H "Authorization: Bearer $TOKEN" --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt | jq -r '.items[].metadata.name'
demoapp-57bf45f76-bgkwb
curl-client-0