From b13a8cec785639b72a6975e1f95883713be0b56f Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Sat, 15 Aug 2026 15:22:11 +1000 Subject: [PATCH 1/4] Add CA-baked plugin-docker-buildx image + buildah CI Bake the internal Vault-PKI CA into a rebuild of woodpeckerci/plugin-docker-buildx so k8s buildx jobs can push to artifactapi's docker-internal registry over TLS. - Dockerfile: copy unkin-ca.crt into /etc/docker/certs.d//ca.crt and the system trust store - unkin-ca.crt: vault-ca-cert bundle (root + intermediate) - .woodpecker/build.yaml: PR gate, buildah build-only - .woodpecker/release.yaml: on v* tag, buildah build + credless push to docker-internal with --tls-verify=false (bootstrap) --- .woodpecker/build.yaml | 20 +++++++++++++++++++ .woodpecker/release.yaml | 32 ++++++++++++++++++++++++++++++ Dockerfile | 6 ++++++ README.md | 29 ++++++++++++++++++++++++++- unkin-ca.crt | 42 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 .woodpecker/build.yaml create mode 100644 .woodpecker/release.yaml create mode 100644 Dockerfile create mode 100644 unkin-ca.crt diff --git a/.woodpecker/build.yaml b/.woodpecker/build.yaml new file mode 100644 index 0000000..2ffb30e --- /dev/null +++ b/.woodpecker/build.yaml @@ -0,0 +1,20 @@ +when: + - event: pull_request + +steps: + # PR gate: build the CA-baked plugin image only, no push. buildah runs + # unprivileged in-cluster, so use the vfs storage driver + chroot isolation. + - name: build + image: quay.io/buildah/stable + commands: + - buildah build --isolation chroot --storage-driver vfs -t plugin-docker-buildx:${CI_COMMIT_SHA} . + backend_options: + kubernetes: + serviceAccountName: plugin-docker-buildx + resources: + requests: + memory: 512Mi + cpu: 1 + limits: + memory: 2Gi + cpu: 2 diff --git a/.woodpecker/release.yaml b/.woodpecker/release.yaml new file mode 100644 index 0000000..0c60e71 --- /dev/null +++ b/.woodpecker/release.yaml @@ -0,0 +1,32 @@ +when: + - event: tag + ref: refs/tags/v* + +steps: + # Build the CA-baked plugin image and push it to artifactapi's docker-internal + # registry. buildah runs unprivileged in-cluster (vfs + chroot isolation). + # + # Push is credential-less: the in-cluster runner already has push access to the + # artifactapi docker-internal registry (same pattern as autobackup-operator / + # jellyfin-ha). --tls-verify=false is a deliberate bootstrap: THIS image is what + # teaches k8s buildx to trust artifactapi's internal CA, so its own push cannot + # yet rely on that trust. + - name: release + image: quay.io/buildah/stable + environment: + IMG: artifactapi.k8s.syd1.au.unkin.net/docker-internal/plugin-docker-buildx + commands: + - buildah build --isolation chroot --storage-driver vfs -t $${IMG}:${CI_COMMIT_TAG} . + - buildah tag --storage-driver vfs $${IMG}:${CI_COMMIT_TAG} $${IMG}:latest + - buildah push --storage-driver vfs --tls-verify=false $${IMG}:${CI_COMMIT_TAG} + - buildah push --storage-driver vfs --tls-verify=false $${IMG}:latest + backend_options: + kubernetes: + serviceAccountName: plugin-docker-buildx + resources: + requests: + memory: 512Mi + cpu: 1 + limits: + memory: 2Gi + cpu: 2 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5e0c85d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,6 @@ +FROM woodpeckerci/plugin-docker-buildx:latest +# buildkit reads this to trust artifactapi's internal-CA registry on push +COPY unkin-ca.crt /etc/docker/certs.d/artifactapi.k8s.syd1.au.unkin.net/ca.crt +# fallback: system trust store (docker login / other code paths) +COPY unkin-ca.crt /usr/local/share/ca-certificates/unkin-ca.crt +RUN cat /usr/local/share/ca-certificates/unkin-ca.crt >> /etc/ssl/certs/ca-certificates.crt || true diff --git a/README.md b/README.md index a1b6372..5d29b46 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,30 @@ # plugin-docker-buildx -Woodpecker plugin-docker-buildx image with the internal Vault-PKI CA baked in (trusts artifactapi) \ No newline at end of file +A drop-in rebuild of `woodpeckerci/plugin-docker-buildx` with the internal +Vault-PKI CA baked in. + +## Why + +The stock `woodpeckerci/plugin-docker-buildx` image does not trust artifactapi's +internal CA, so k8s Woodpecker buildx jobs cannot push to +`artifactapi.k8s.syd1.au.unkin.net/docker-internal/*` — buildkit needs +`/etc/docker/certs.d//ca.crt` inside the plugin container, and the k8s +backend has no way to inject it. + +This image copies the `vault-ca-cert` bundle (root + intermediate) into that path +plus the system trust store, so pipelines can `settings.registry: +artifactapi.k8s.syd1.au.unkin.net` and push over TLS. + +## Published as + +`artifactapi.k8s.syd1.au.unkin.net/docker-internal/plugin-docker-buildx:` (and `:latest`) + +## Bootstrap + +This image is itself built and pushed by **buildah** (`.woodpecker/release.yaml`), +not by buildx, using `buildah push --tls-verify=false`. buildah is used precisely +because it sidesteps the buildx CA-trust problem that this image exists to fix — +its own push therefore cannot rely on that trust yet. + +Once published, point Woodpecker docker-buildx steps at this image instead of the +upstream one to push to the docker-internal registry. diff --git a/unkin-ca.crt b/unkin-ca.crt new file mode 100644 index 0000000..58d7a5a --- /dev/null +++ b/unkin-ca.crt @@ -0,0 +1,42 @@ +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIULZAR/QcvAnxdi04S6bXhNeazozYwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJdW5raW4ubmV0MB4XDTI0MDQyNzExMzcyMloXDTI5MDQy +NjExMzc1MlowKzEpMCcGA1UEAxMgdW5raW4ubmV0IEludGVybWVkaWF0ZSBBdXRo +b3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDq0ZU2DnuYW5s +E3lPjVe2Ns6cPu64yx1GLVqB5VbOUs71ThRjPjvEwE98YtGMza8ok0CQSqS2qX8z +vnMbnVCaWKjCnem/dtQtB+8WCu5uQuNHhwqxgw1tD/klAkVLWGgTPDEgasvjDMkc +sW8in/BhtrV9YA/lQGpge+j9/MFXhlnvaLCPybFifPRX9Yc5CcnhSzLSzFPO4PJx +VH4Qu9eByyKHMTvgcCy6p9qjjzz+8dtAlxeIsgfTEdvtfCPowsF+v2XooutTsJt0 +xUDvUDu4xV6tVCEOYRA2cZHkLRBhV289M0hocHrsGqMmA1+j0skwwt/6UkVHqlCT +mitItX+RAgMBAAGjgewwgekwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFEp/+grAdVqRSeb9xJjSeZYNW32MMB8GA1UdIwQYMBaAFBqc +v6Y+hfHt4EjgKa/uoQGEHTknMEcGCCsGAQUFBwEBBDswOTA3BggrBgEFBQcwAoYr +aHR0cHM6Ly92YXVsdC5zZXJ2dWNlLmNvbnN1bC92MS9wa2lfcm9vdC9jYTA9BgNV +HR8ENjA0MDKgMKAuhixodHRwczovL3ZhdWx0LnNlcnZpY2UuY29uc3VsL3YxL3Br +aV9yb290L2NybDANBgkqhkiG9w0BAQsFAAOCAQEAM0FS8tscZe7yly/gM7jO6lx5 +muMFusifjUIrcQGnZBkoECeuUVPNTs3e/Th+XaxjCnmSpqSNT3z9Irr6Hhxf7n03 +4+hpF3G0bf1yh4DRex/0ua3szvgo91RwyKVQM1BHIA1PwdF8csO+LT4FTMILzo4U +DdSVvDEIaxYYQCDNfAD81n+8lmFbabupfsKbkSTR+sNTS+TMnLpN8YwSXdB0e+RU +eEZRNVu0jKmbE8U/66Sc33YLe6cxbCclHA+G4giGwEP+lYZk+rFjmr6ci9bj5yyN +Sznr7xdW0ofOdACAQFFy5KTZqCDjIrvk12vUn4bSsXmWVIQEd+jPx6wuxD/rSw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDLzCCAhegAwIBAgIUIDADwsHIrQ8dfncpechBdIUCQdIwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJdW5raW4ubmV0MB4XDTI0MDQyNzExMjcwMloXDTM0MDQy +NTExMjczMlowFDESMBAGA1UEAxMJdW5raW4ubmV0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA3ENPv7R7gCUJAg8Q4hB2LEZSdvbK155YbcrguLDDnu6m +2fkJn8jYMMW3Z6/+Y04ouGwi6sKup8ggTb217sY+dC4IUZjotDPAhruxfXVQAh0v +Yr3RYoxVDrm4nRSFLo1RA4Qt+1KK299mHGQf9iAiwbsFp5mDrJT9uz15FE2uWmbK +8/onMyJC4fnkMihVN6NIgTtjpHYNm5aAJwxoWldTopgF0ucb7X3XVPNbKAmd3Avd +lsOo6m751zSZ0HvJOxgRSy7lvPzMuUfCQsOcmI4O4+Z2FL4Y7p+T9DvWkciC7L3i +tBiK30fPfGKNpWaof1ONCcPQNjMwWcEFXqSiWUOXkwIDAQABo3kwdzAOBgNVHQ8B +Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGpy/pj6F8e3gSOAp +r+6hAYQdOScwHwYDVR0jBBgwFoAUGpy/pj6F8e3gSOApr+6hAYQdOScwFAYDVR0R +BA0wC4IJdW5raW4ubmV0MA0GCSqGSIb3DQEBCwUAA4IBAQA5xocILzuvD+R2Iub1 +UnTdcVpgNcxJmESz0eX4UrkcBmddtuFINXvDTv5//XTFs78LsVVSf00xZ+2C62Xe +xRdCdluHN8VDCAKulP4XJY1BiZ7im0v+iMgPDKhq4OXb86WFYI/8J6uRm7oIAwj1 +zhhKxMimkzli+yHB8ipL15W7l68CMUgmOjFA+EG6sbfadFpQTX/h6TVj3FQPkU/p +UJEm2XjlGNAKGJrNRU47PM4vRDv5Joyowp9zv/pHFXvUJladaJupMKRJQVWQz1US +EXE67rawG79s3vm8dDolnbli/IhPHtjDRIprxAwrMs5tt9cY0xsRkFBZVcAOjrpb +4gqd +-----END CERTIFICATE----- From 7f3adc5725c075d23fccc2dd2f38347ea3cff07a Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Sat, 15 Aug 2026 16:26:38 +1000 Subject: [PATCH 2/4] woodpecker: quote buildah commands (YAML colon-space parse fix) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit woodpecker interpolates ${CI_COMMIT_TAG} into the raw pipeline text before YAML parsing; when empty, '-t $${IMG}:${CI_COMMIT_TAG} .' collapses to '... : .' and the colon-space is parsed as a map key ('cannot unmarshal map ... into a string value'). Quote every buildah command so it stays a scalar. --- .woodpecker/build.yaml | 2 +- .woodpecker/release.yaml | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.woodpecker/build.yaml b/.woodpecker/build.yaml index 2ffb30e..c92a45c 100644 --- a/.woodpecker/build.yaml +++ b/.woodpecker/build.yaml @@ -7,7 +7,7 @@ steps: - name: build image: quay.io/buildah/stable commands: - - buildah build --isolation chroot --storage-driver vfs -t plugin-docker-buildx:${CI_COMMIT_SHA} . + - "buildah build --isolation chroot --storage-driver vfs -t plugin-docker-buildx:${CI_COMMIT_SHA} ." backend_options: kubernetes: serviceAccountName: plugin-docker-buildx diff --git a/.woodpecker/release.yaml b/.woodpecker/release.yaml index 0c60e71..88f54b1 100644 --- a/.woodpecker/release.yaml +++ b/.woodpecker/release.yaml @@ -11,15 +11,19 @@ steps: # jellyfin-ha). --tls-verify=false is a deliberate bootstrap: THIS image is what # teaches k8s buildx to trust artifactapi's internal CA, so its own push cannot # yet rely on that trust. + # + # Commands are quoted: woodpecker templates ${CI_COMMIT_TAG} into the raw YAML + # before parsing, so an unquoted "-t $${IMG}:${CI_COMMIT_TAG} ." can collapse to + # "... -t $${IMG}: ." and YAML then reads the "colon-space" as a map key. - name: release image: quay.io/buildah/stable environment: IMG: artifactapi.k8s.syd1.au.unkin.net/docker-internal/plugin-docker-buildx commands: - - buildah build --isolation chroot --storage-driver vfs -t $${IMG}:${CI_COMMIT_TAG} . - - buildah tag --storage-driver vfs $${IMG}:${CI_COMMIT_TAG} $${IMG}:latest - - buildah push --storage-driver vfs --tls-verify=false $${IMG}:${CI_COMMIT_TAG} - - buildah push --storage-driver vfs --tls-verify=false $${IMG}:latest + - "buildah build --isolation chroot --storage-driver vfs -t $${IMG}:${CI_COMMIT_TAG} ." + - "buildah tag --storage-driver vfs $${IMG}:${CI_COMMIT_TAG} $${IMG}:latest" + - "buildah push --storage-driver vfs --tls-verify=false $${IMG}:${CI_COMMIT_TAG}" + - "buildah push --storage-driver vfs --tls-verify=false $${IMG}:latest" backend_options: kubernetes: serviceAccountName: plugin-docker-buildx From 6fd0c6efba6139562e57bc389a8eb7e3d6fd79cc Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Sat, 15 Aug 2026 16:31:23 +1000 Subject: [PATCH 3/4] ci: re-trigger build (plugin-docker-buildx SA now exists via argocd-apps#368) From 597752734878855a6ec2fa2a909c0a0379844528 Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Sat, 15 Aug 2026 16:34:02 +1000 Subject: [PATCH 4/4] Dockerfile: fully-qualify base image (buildah short-name TTY fix) buildah (quay.io/buildah/stable) enforces short-name resolution and cannot prompt without a TTY, so 'FROM woodpeckerci/plugin-docker-buildx:latest' errors. Qualify as docker.io/... . Keep it on docker.io (public CA) deliberately: this image is what bootstraps internal-CA trust, so pulling its own base through the internal-CA artifactapi registry would reintroduce the x509 problem in-build. --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 5e0c85d..a2ee409 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM woodpeckerci/plugin-docker-buildx:latest +FROM docker.io/woodpeckerci/plugin-docker-buildx:latest # buildkit reads this to trust artifactapi's internal-CA registry on push COPY unkin-ca.crt /etc/docker/certs.d/artifactapi.k8s.syd1.au.unkin.net/ca.crt # fallback: system trust store (docker login / other code paths)