Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions .github/workflows/deploy_k8s.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -239,12 +239,22 @@ jobs:
# the chain for back-compat with older platform pushes.
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD || secrets.GITHUB_READ_PACKAGES_TOKEN || secrets.GITHUB_TOKEN }}
run: |
# 🛑 --server-side is REQUIRED here, do not "simplify" it back to a plain
# `kubectl apply -f -`. Client-side apply stamps the ENTIRE object into a
# `kubectl.kubernetes.io/last-applied-configuration` annotation — for a Secret
# that means a second, cleartext-base64 copy of the registry credential in the
# object's METADATA, where it leaks through `-o yaml` dumps, Velero snapshots
# and any tool that redacts `data:` but renders annotations verbatim.
# Found across 109 secrets on ever-k8s, 2026-08-07. Server-side apply records
# ownership in `.metadata.managedFields` instead and writes no annotation.
# `replace --force` also avoids the annotation but deletes and recreates the
# object, leaving a window where a starting pod finds no pull secret.
kubectl create secret docker-registry "${WORK_SLUG}-pull" \
--docker-server="$REGISTRY_HOST" \
--docker-username="$REGISTRY_USERNAME" \
--docker-password="$REGISTRY_PASSWORD" \
-n "$NAMESPACE" \
--dry-run=client -o yaml | kubectl apply -f -
--dry-run=client -o yaml | kubectl apply --server-side --force-conflicts -f -

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Legacy secret annotation remains

When these fixed-name Secrets already exist from a client-side apply, server-side apply updates them without removing the legacy kubectl.kubernetes.io/last-applied-configuration annotation, causing registry and application credentials to remain exposed through metadata-rendering dumps, snapshots, and tools. How this was verified: Both Secrets are updated in place, while no workflow command removes the pre-existing annotation.


- name: Provision runtime-env secret
# Materialize every repo secret as a Kubernetes Secret that the
Expand Down Expand Up @@ -304,8 +314,13 @@ jobs:
ARGS+=(--from-literal=COOKIE_DOMAIN="${INGRESS_HOST}")
fi
if [[ ${#ARGS[@]} -gt 0 ]]; then
# 🛑 --server-side is REQUIRED here — see the note on the image-pull secret
# above. This one matters even more: this Secret carries EVERY forwarded repo
# secret (DATABASE_URL, AUTH_SECRET, COOKIE_SECRET, …), so a client-side
# `apply` would duplicate the app's entire secret set in cleartext-base64 in
# the object's metadata annotation, not just a registry credential.
kubectl create secret generic "${WORK_SLUG}-runtime-env" -n "$NAMESPACE" \
"${ARGS[@]}" --dry-run=client -o yaml | kubectl apply -f -
"${ARGS[@]}" --dry-run=client -o yaml | kubectl apply --server-side --force-conflicts -f -
# Log keys (not values) so we have a paper trail of what
# was forwarded on this deploy.
printf 'Provisioned %s-runtime-env (%d keys): %s\n' \
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ You can also view a full list of our [contributors tracked by Github](https://gi

## ⭐ Star History

[![Star History Chart](https://api.star-history.com/svg?repos=ever-co/directory-web-template&type=Date)](https://star-history.com/#ever-co/directory-web-template&Date)
[![Star History Chart](https://stats-github.ever.works/svg?repos=ever-works/directory-web-template&type=Date)](https://stats-github.ever.works/#ever-works/directory-web-template&Date)

## ❤️ Powered By

Expand Down
Loading