fix(ci): remove kubernetes-deploy workflow that leaked secrets to logs

The workflow ran on every push to every branch and deployed nothing.
It echoed the raw Vault login response, the Kanidm API token response
and the OIDC token response to the job log, dumped the environment,
and configured kubectl with --insecure-skip-tls-verify.

Deployment is handled by gitops-update.yaml. Docs updated to describe
that flow; T1 marked done in the cleanup task list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 11:48:35 +02:00
co-authored by Claude Opus 5.5
parent cfdc5cbb2a
commit 5b162d0030
5 changed files with 25 additions and 131 deletions
-111
View File
@@ -1,111 +0,0 @@
name: Deploy to K8s
on:
workflow_dispatch:
push:
branches:
- '**'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Debug - print Gitea Actions environment
run: |
echo "=== All environment variables ==="
env | sort
echo ""
echo "=== GITHUB_* / GITEA_* / ACTIONS_* vars ==="
env | grep -E '^(GITHUB|GITEA|ACTIONS)_' | sort
- name: Install kubectl
run: |
curl -sfLO "https://dl.k8s.io/release/$(curl -sfL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
install kubectl /usr/local/bin/
- name: Get Kanidm token from Vault
id: vault
run: |
set -euxo pipefail
VAULT_AUTH_RESPONSE=$(curl -f --request POST \
--data '{"role_id":"${{ secrets.VAULT_ROLE_ID }}","secret_id":"${{ secrets.VAULT_SECRET_ID }}"}' \
https://vault.hrajfrisbee.cz/v1/auth/approle/login)
echo "Vault auth response: $VAULT_AUTH_RESPONSE" >&2
VAULT_TOKEN=$(echo "$VAULT_AUTH_RESPONSE" | jq -r '.auth.client_token')
# Read the kanidm API token
SECRET_RESPONSE=$(curl -f \
-H "X-Vault-Token: ${VAULT_TOKEN}" \
https://vault.hrajfrisbee.cz/v1/secret/data/gitea/gitea-ci)
echo "Secret response: $SECRET_RESPONSE" >&2
API_TOKEN=$(echo "$SECRET_RESPONSE" | jq -r '.data.data.token')
echo "::add-mask::${API_TOKEN}"
echo "api_token=${API_TOKEN}" >> "$GITHUB_OUTPUT"
- name: Exchange for K8s OIDC token via Kanidm
id: k8s
run: |
API_TOKEN="${{ steps.vault.outputs.api_token }}"
echo "api_token length: ${#API_TOKEN}" >&2
echo "api_token prefix (first 8 chars): ${API_TOKEN:0:8}..." >&2
HTTP_BODY=$(mktemp)
HTTP_STATUS=$(curl -sS -X POST "https://idm.home.hrajfrisbee.cz/oauth2/token" \
-d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
-d "client_id=k8s" \
-d "subject_token=${API_TOKEN}" \
-d "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
-d "audience=k8s" \
-d "scope=openid groups" \
-o "$HTTP_BODY" -w "%{http_code}")
echo "HTTP status: $HTTP_STATUS" >&2
echo "Response body:" >&2
cat "$HTTP_BODY" >&2
RESPONSE=$(cat "$HTTP_BODY")
ID_TOKEN=$(echo "$RESPONSE" | jq -r '.id_token // empty')
if [ -z "$ID_TOKEN" ]; then
echo "::error::Kanidm token exchange failed (HTTP $HTTP_STATUS)"
exit 1
fi
echo "::add-mask::${ID_TOKEN}"
echo "id_token=${ID_TOKEN}" >> "$GITHUB_OUTPUT"
# Sanity check
# Warning - this is the part that is failing
# echo "$ID_TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq '{sub, groups, exp}'
- name: Debug - print environment before kubectl
run: env | sort
- name: Configure kubectl & deploy
run: |
echo "${{ secrets.K8S_CA_CERT }}" > /tmp/ca.crt
kubectl config set-cluster mycluster \
--server=https://192.168.0.31:6443 \
--insecure-skip-tls-verify=true
# --certificate-authority=/tmp/ca.crt \
kubectl config set-credentials gitea-ci \
--token="${{ steps.k8s.outputs.id_token }}"
kubectl config set-context gitea-ci \
--cluster=mycluster --user=gitea-ci
kubectl config use-context gitea-ci
kubectl auth whoami
kubectl get ns
# your deploy here
# kubectl apply -f k8s/
+6
View File
@@ -1,5 +1,11 @@
# Changelog
## 2026-10-08 11:48 CEST — fix(ci): remove kubernetes-deploy workflow that leaked secrets to logs
- Deleted `.gitea/workflows/kubernetes-deploy.yaml`. It ran on every push to every branch, deployed nothing, and echoed the Vault login response, the Kanidm API token response and the OIDC token response to the job log.
- Deployment is handled by `gitops-update.yaml`. Repo secrets `VAULT_ROLE_ID`, `VAULT_SECRET_ID` and `K8S_CA_CERT` are now unused.
- Follow-up outside the repo: rotate the Vault AppRole secret and the Kanidm API token, and clear old job logs.
## 2026-10-08 11:34 CEST — fix(python): return months_to_show from /api/adults and /api/juniors
- Go already returned `months_to_show` in the JSON API; Python only passed it to its HTML templates. Backported the key so the API contract matches and `make parity` reports 3/3 routes.
+1 -1
View File
@@ -182,7 +182,7 @@ fuj-management/
│
├── .gitea/workflows/
│ ├── build.yaml # CI: build + push Docker image
│ └── kubernetes-deploy.yaml # CD: deploy to K8s cluster
│ └── gitops-update.yaml # CD: open image-update PR in home-kubernetes
│
├── .secret/ # (gitignored) API credentials
├── docs/ # Project documentation
+12 -18
View File
@@ -129,32 +129,27 @@ The project uses two Gitea Actions workflows:
**Tag resolution**: Uses the git tag name. For manual dispatch, uses the provided input.
#### 2. Deploy to Kubernetes (`kubernetes-deploy.yaml`)
#### 2. GitOps image update (`gitops-update.yaml`)
**Triggers**:
- Push to any branch
- Manual dispatch
- Completion of a successful "Build and Push" run
- Manual dispatch (with `tag`, `dry_run` and `uh_cli_version` inputs)
**Steps**:
1. Checkout code
2. Install kubectl
3. Retrieve Kanidm token from HashiCorp Vault:
- Authenticate to Vault via AppRole (`VAULT_ROLE_ID` / `VAULT_SECRET_ID`)
- Fetch API token from `secret/data/gitea/gitea-ci`
4. Exchange API token for K8s OIDC token via Kanidm:
- POST to `https://idm.home.hrajfrisbee.cz/oauth2/token`
- Token exchange using `urn:ietf:params:oauth:grant-type:token-exchange`
5. Configure kubectl with the OIDC token
6. Run `kubectl auth whoami` and `kubectl get ns` (deploy commands are commented out — WIP)
1. Install `tea` and `uh-cli`
2. Resolve the image tag of the Go image that was just built
3. Open a PR in `kacerr/home-kubernetes` bumping the `fuj-management` Deployment (namespace `fuj`) to that image
The cluster picks the change up once that PR is merged. CI does not talk to the cluster directly.
> The earlier `kubernetes-deploy.yaml` workflow (Vault → Kanidm → `kubectl`) was removed on 2026-10-08. It never deployed anything and printed credentials to the job log.
**Required secrets**:
| Secret | Purpose |
|--------|---------|
| `REGISTRY_TOKEN` | Docker registry authentication |
| `VAULT_ROLE_ID` | HashiCorp Vault AppRole role ID |
| `VAULT_SECRET_ID` | HashiCorp Vault AppRole secret ID |
| `K8S_CA_CERT` | Kubernetes cluster CA certificate |
| `GITOPS_TOKEN` | Gitea token with write and PR access to `home-kubernetes` |
### Infrastructure Topology
@@ -164,8 +159,7 @@ Gitea (git push / tag)
├── build.yaml → Docker Build → Gitea Container Registry
│ (gitea.home.hrajfrisbee.cz)
│
└── kubernetes-deploy.yaml → Vault → Kanidm → K8s Cluster
(192.168.0.31:6443)
└── gitops-update.yaml → PR in home-kubernetes → K8s Cluster
```
This is a self-hosted infrastructure stack:
@@ -30,13 +30,18 @@ before new feature work starts. Companion to the Go rewrite tracker,
## Fix first
- [ ] **T1** Remove the secret leak in `.gitea/workflows/kubernetes-deploy.yaml`.
- [x] **T1** Remove the secret leak in `.gitea/workflows/kubernetes-deploy.yaml`.
Workflow deleted on 2026-10-08. Still open for the owner: rotate the
credentials and remove the now-unused repo secrets (see below).
- It runs on every push to every branch and deploys nothing.
- It echoes the raw Vault login response, the Kanidm token response and the
OIDC token response body to the log, and dumps the environment twice.
- It uses `--insecure-skip-tls-verify=true`.
- Delete or disable the workflow. Rotate the Vault AppRole secret and the
Kanidm API token if anyone else can read the CI logs.
- After deletion the repo secrets `VAULT_ROLE_ID`, `VAULT_SECRET_ID` and
`K8S_CA_CERT` are unused and can be removed. Old job logs still contain
the leaked tokens until they are deleted or expire.
- [ ] **T2** Confirm the fee rates for 2026-09 onward.
- `ADULT_FEE_MONTHLY_RATE` ends at 2026-08 in `scripts/attendance.py` and
`go/internal/domain/fees/fees.go`.