From ce45e69e3827858746bfb6db6a47dcda9e8f221a Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Sat, 9 May 2026 11:26:47 +0000 Subject: [PATCH] ci(woodpecker): generate kubeconfig from projected SA token MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit terragrunt.hcl injects -var kube_config_path=${repo_root}/config for every terraform invocation, but the pipeline never created that file. Every commit that touched a TF stack since #545 (2026-05-08) failed with 'config_path refers to an invalid path: \"../../config\": no such file or directory' followed by the kubernetes provider falling back to localhost:80. Add a step that writes a kubeconfig at /config using the projected SA token + cluster CA. The woodpecker namespace's default SA is already cluster-admin (woodpecker-default ClusterRoleBinding), so the projected token is sufficient for any stack apply. Using tokenFile (not an inline token) lets the provider re-read it if kubelet rotates the projected token mid-pipeline. #545 was the last green run because that commit only changed the build-cli pipeline — 0 stacks applied so the missing kubeconfig never mattered. --- .woodpecker/default.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/.woodpecker/default.yml b/.woodpecker/default.yml index 05a579ea..5661bccd 100644 --- a/.woodpecker/default.yml +++ b/.woodpecker/default.yml @@ -73,6 +73,38 @@ steps: # the env var is unset. umask 077; printf '%s' "$VAULT_TOKEN" > "$HOME/.vault-token" + # ── Generate kubeconfig from projected SA token ── + # terragrunt.hcl injects `-var kube_config_path=/config` for every + # terraform invocation, so we need a kubeconfig file at that path. The + # `default` SA in the woodpecker namespace is cluster-admin (via the + # `woodpecker-default` ClusterRoleBinding), so the projected token is + # sufficient to apply any stack. Using `tokenFile` (not an inline token) + # so the provider re-reads it if kubelet rotates the projected token + # mid-pipeline. + - | + cat > config <<'EOF' + apiVersion: v1 + kind: Config + clusters: + - name: kubernetes + cluster: + server: https://10.0.20.100:6443 + certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + contexts: + - name: ci + context: + cluster: kubernetes + user: ci + current-context: ci + users: + - name: ci + user: + tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + EOF + chmod 600 config + # Sanity check: kubeconfig works + kubectl --kubeconfig=config get ns kube-system -o name >/dev/null + # ── Detect changed stacks ── - | PLATFORM_STACKS="dbaas authentik crowdsec monitoring nvidia mailserver cloudflared kyverno metallb redis traefik technitium headscale rbac k8s-portal vaultwarden reverse-proxy metrics-server vpa nfs-csi iscsi-csi cnpg sealed-secrets uptime-kuma wireguard xray infra-maintenance platform vault reloader descheduler external-secrets"