Curl Kubernetes API

Wie frage ich die Kubernetes API mit curl ab?

Posted by eumel8 on August 17, 2023 · 5 mins read

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

Gist