#!/bin/bash ################################################################################ # create-secrets.sh — Docker Swarm secret provisioning helper # # Usage: # source deploy/create-secrets.sh # create_or_update_secret "secret_name" "secret_value" # # What it does: # - Creates a Docker secret if it does not already exist # - Detects value changes via a SHA256 checksum stored as a secret label # - If the value has changed: removes the old secret and recreates it # - If the value is unchanged: skips silently (no service disruption) # # Important notes: # - Docker Swarm has no native "update secret" API. Changing a secret # requires removing and recreating it, then redeploying all services # that reference it. This script handles removal + recreation, but the # stack redeploy still happens via the normal deploy step. # - Secrets are stored encrypted in Swarm's Raft consensus database and # automatically replicated across all nodes. # - The checksum label is NOT the secret value — it is a SHA256 hash used # only to detect whether the value has changed, avoiding unnecessary # secret rotation. ################################################################################ create_or_update_secret() { local NAME="$1" local VALUE="$2" if [ -z "$NAME" ]; then echo " [ERROR] create_or_update_secret: NAME is required" return 1 fi if [ -z "$VALUE" ]; then echo " [WARN] $NAME: value is empty, skipping" return 0 fi # Compute SHA256 of the new value (no trailing newline to keep hash stable) local NEW_HASH NEW_HASH=$(printf '%s' "$VALUE" | sha256sum | cut -d' ' -f1) if docker secret inspect "$NAME" >/dev/null 2>&1; then # Secret exists — check if value has changed via stored checksum label local OLD_HASH OLD_HASH=$(docker secret inspect "$NAME" \ --format '{{index .Spec.Labels "checksum"}}' 2>/dev/null || echo "") if [ "$NEW_HASH" = "$OLD_HASH" ]; then echo " [SKIP] $NAME (unchanged)" return 0 fi # Value changed — must remove and recreate (Docker limitation) echo " [UPDATE] $NAME (value changed, rotating)" docker secret rm "$NAME" >/dev/null 2>&1 || { echo " [ERROR] $NAME: failed to remove existing secret" echo " Secret may be in use by a running service." echo " Scale down the service first, then re-run." return 1 } else echo " [CREATE] $NAME" fi # Create the secret with checksum label for future change detection printf '%s' "$VALUE" | docker secret create \ --label "checksum=${NEW_HASH}" \ --label "managed-by=woodpecker" \ "$NAME" - >/dev/null && echo " [OK] $NAME" || { echo " [ERROR] $NAME: failed to create secret" return 1 } }