From 89a0aacbd75cb397ad339dca83421a8705d786be Mon Sep 17 00:00:00 2001 From: Mukul Sharma Date: Sun, 6 Sep 2026 21:17:45 +0530 Subject: [PATCH] Add toolshed-harbor-cleanup: a delete-scoped Harbor robot for builder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deliberately separate from harbor-robot-dockerconfig, which is mounted into build pods running arbitrary user Dockerfiles and is scoped to push+pull only. This one is held by builder itself — a trusted platform service that never executes user code directly — and carries a permission the other should never have: delete. A leaked build-pod credential can never delete anything this way, and a leaked cleanup credential can never push. Used by toolshed's cleanupImage (internal/builder/builder.go) to remove an app's Harbor repository when the app itself is deleted. Nothing destructive happens until the Vault path this pulls from is actually populated — builder logs and skips that step otherwise, per its own code comment. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Wajog7nELA3i8JWTjxYGHF --- secretstores/toolshed-harbor-cleanup.yaml | 49 +++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 secretstores/toolshed-harbor-cleanup.yaml diff --git a/secretstores/toolshed-harbor-cleanup.yaml b/secretstores/toolshed-harbor-cleanup.yaml new file mode 100644 index 0000000..ca69708 --- /dev/null +++ b/secretstores/toolshed-harbor-cleanup.yaml @@ -0,0 +1,49 @@ +# Harbor management-API credentials for toolshed's builder, used only to +# delete a repository (every tagged image an app's builds ever pushed) when +# the app itself is deleted. +# +# Deliberately a separate robot account from harbor-robot-dockerconfig +# (secretstores/harbor-robot-dockerconfig.yaml), not a reuse of it. That one +# is mounted into build pods, which run arbitrary user-supplied Dockerfiles — +# scoped to push+pull only. This one is held by builder itself, a trusted +# platform service that never executes user code directly, and needs a +# permission the other should never carry: delete. Keeping them on separate +# credentials means a leaked build-pod credential can never delete anything, +# and a leaked cleanup credential can never push. +# +# Create the robot in Harbor's UI: homelab project -> Robot Accounts -> +# New Robot Account. Scope it to that one project, permission "Delete +# repository" (and "Delete artifact") only — leave push/pull unchecked, it +# never needs them. Harbor shows the generated secret exactly once. +# +# kubectl -n vault exec -i vault-0 -- sh -lc ' +# vault login >/dev/null && +# vault kv put secret/harbor/toolshed-cleanup \ +# username="robot\$homelab+toolshed-cleanup" \ +# password=""' +# +# Until this exists, builder logs "no management credentials, leaving its +# image alone" for every app deletion and does nothing destructive — see +# internal/builder/builder.go's cleanupImage in the toolshed repo. +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: toolshed-harbor-cleanup + namespace: toolshed +spec: + refreshInterval: 1h + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: toolshed-harbor-cleanup + creationPolicy: Owner + data: + - secretKey: username + remoteRef: + key: harbor/toolshed-cleanup + property: username + - secretKey: password + remoteRef: + key: harbor/toolshed-cleanup + property: password