diff --git a/.woodpecker/deploy.yaml b/.woodpecker/deploy.yaml index 4aeddad..99263ff 100644 --- a/.woodpecker/deploy.yaml +++ b/.woodpecker/deploy.yaml @@ -27,53 +27,8 @@ steps: - test -f "hosts/$TARGET" || (echo "ERROR - unknown host alias $TARGET" && exit 1) - . "hosts/$TARGET" - 'echo "Resolved host alias $TARGET -> $SSH_USER@$SSH_HOST"' - # Tooling: oras (artifact retrieval) and sops (secret decryption). - - apk add --no-cache curl openssh-client - - curl -sL "https://github.com/oras-project/oras/releases/download/v1.3.4/oras_1.3.4_linux_amd64.tar.gz" -o /tmp/oras.tar.gz - - mkdir -p /tmp/oras-install && tar -xzf /tmp/oras.tar.gz -C /tmp/oras-install - - install /tmp/oras-install/oras /usr/local/bin/oras - - curl -sL "https://github.com/getsops/sops/releases/download/v3.13.3/sops-v3.13.3.linux.amd64" -o /usr/local/bin/sops - - chmod +x /usr/local/bin/sops - # Retrieve the exact deployment artifact by digest/tag reference. - - mkdir -p /tmp/deploy-bundle && cd /tmp/deploy-bundle - - oras login "registry.ci.poc.mehl.mx" -u "$ZOT_USERNAME" -p "$ZOT_PASSWORD" - - oras pull "$ARTIFACT" - - test -f compose.yaml || (echo "ERROR - compose.yaml missing from artifact" && exit 1) - - test -f secrets.prod.env || (echo "ERROR - secrets.prod.env missing from artifact" && exit 1) - - test -f release.env || (echo "ERROR - release.env missing from artifact" && exit 1) - # Decrypt the service's secrets transiently, using the deployment age key. - - sops --decrypt secrets.prod.env > /tmp/deploy-bundle/secrets.decrypted.env - - chmod 600 /tmp/deploy-bundle/secrets.decrypted.env - # Set up the SSH key used to reach the target host. - - mkdir -p -m 700 /tmp/ssh - - echo "$DEPLOY_SSH_KEY" > /tmp/ssh/id_deploy - - chmod 600 /tmp/ssh/id_deploy - # Ensure the remote working directory exists, then transfer - # compose.yaml, release.env, the decrypted secrets and the generic - # bin/deploy-compose script to the target host, run the deployment, - # and remove the plaintext secrets. Kept as a single commands: item - # (one shell script) rather than several, since separate ssh/scp - # list items have intermittently triggered a Woodpecker command - # parsing bug (log-streaming artifact, not a real shell syntax - # error - confirmed by direct SSH inspection of target1's state - # after affected runs). - - | - set -e - ssh -i /tmp/ssh/id_deploy -o StrictHostKeyChecking=accept-new \ - $SSH_USER@$SSH_HOST mkdir -p /tmp/poc-deploy - scp -i /tmp/ssh/id_deploy -o StrictHostKeyChecking=accept-new \ - compose.yaml release.env secrets.decrypted.env \ - $SSH_USER@$SSH_HOST:/tmp/poc-deploy/ - scp -i /tmp/ssh/id_deploy -o StrictHostKeyChecking=accept-new \ - $CI_WORKSPACE/bin/deploy-compose \ - $SSH_USER@$SSH_HOST:/tmp/poc-deploy/ - ssh -i /tmp/ssh/id_deploy -o StrictHostKeyChecking=accept-new \ - $SSH_USER@$SSH_HOST chmod +x /tmp/poc-deploy/deploy-compose - ssh -i /tmp/ssh/id_deploy -o StrictHostKeyChecking=accept-new \ - $SSH_USER@$SSH_HOST /tmp/poc-deploy/deploy-compose registry.ci.poc.mehl.mx $ZOT_USERNAME $ZOT_PASSWORD - ssh -i /tmp/ssh/id_deploy -o StrictHostKeyChecking=accept-new \ - $SSH_USER@$SSH_HOST rm -f /tmp/poc-deploy/secrets.decrypted.env - - echo "Deployment finished." + - chmod +x bin/run-deployment + - ./bin/run-deployment "$ARTIFACT" "$SSH_HOST" "$SSH_USER" registry.ci.poc.mehl.mx "$ZOT_USERNAME" "$ZOT_PASSWORD" "$SOPS_AGE_KEY" "$DEPLOY_SSH_KEY" when: event: [deployment, manual] diff --git a/bin/run-deployment b/bin/run-deployment new file mode 100755 index 0000000..c34b132 --- /dev/null +++ b/bin/run-deployment @@ -0,0 +1,70 @@ +#!/bin/sh +# Runs a full deployment: retrieves the deployment artifact by reference, +# decrypts its secrets, transfers everything to the target host, and +# invokes bin/deploy-compose there. +# +# Usage: run-deployment \ +# +# +# Must be run from the deployments.git workspace root (so bin/deploy-compose +# and hosts/ are reachable as relative paths). +set -e + +ARTIFACT="$1" +SSH_HOST="$2" +SSH_USER="$3" +REGISTRY="$4" +ZOT_USERNAME="$5" +ZOT_PASSWORD="$6" +SOPS_AGE_KEY="$7" +DEPLOY_SSH_KEY="$8" + +export SOPS_AGE_KEY + +WORKSPACE="$(pwd)" + +# Tooling: oras (artifact retrieval) and sops (secret decryption). +apk add --no-cache curl openssh-client +curl -sL "https://github.com/oras-project/oras/releases/download/v1.3.4/oras_1.3.4_linux_amd64.tar.gz" -o /tmp/oras.tar.gz +mkdir -p /tmp/oras-install && tar -xzf /tmp/oras.tar.gz -C /tmp/oras-install +install /tmp/oras-install/oras /usr/local/bin/oras +curl -sL "https://github.com/getsops/sops/releases/download/v3.13.3/sops-v3.13.3.linux.amd64" -o /usr/local/bin/sops +chmod +x /usr/local/bin/sops + +# Retrieve the exact deployment artifact by digest/tag reference. +mkdir -p /tmp/deploy-bundle +cd /tmp/deploy-bundle +oras login "$REGISTRY" -u "$ZOT_USERNAME" -p "$ZOT_PASSWORD" +oras pull "$ARTIFACT" +test -f compose.yaml || (echo "ERROR - compose.yaml missing from artifact" && exit 1) +test -f secrets.prod.env || (echo "ERROR - secrets.prod.env missing from artifact" && exit 1) +test -f release.env || (echo "ERROR - release.env missing from artifact" && exit 1) + +# Decrypt the service's secrets transiently, using the deployment age key. +sops --decrypt secrets.prod.env > secrets.decrypted.env +chmod 600 secrets.decrypted.env + +# Set up the SSH key used to reach the target host. +mkdir -p -m 700 /tmp/ssh +echo "$DEPLOY_SSH_KEY" > /tmp/ssh/id_deploy +chmod 600 /tmp/ssh/id_deploy + +# Transfer compose.yaml, release.env, the decrypted secrets and the +# generic bin/deploy-compose script to the target host, run the +# deployment, then remove the plaintext secrets. +ssh -i /tmp/ssh/id_deploy -o StrictHostKeyChecking=accept-new \ + $SSH_USER@$SSH_HOST mkdir -p /tmp/poc-deploy +scp -i /tmp/ssh/id_deploy -o StrictHostKeyChecking=accept-new \ + compose.yaml release.env secrets.decrypted.env \ + $SSH_USER@$SSH_HOST:/tmp/poc-deploy/ +scp -i /tmp/ssh/id_deploy -o StrictHostKeyChecking=accept-new \ + $WORKSPACE/bin/deploy-compose \ + $SSH_USER@$SSH_HOST:/tmp/poc-deploy/ +ssh -i /tmp/ssh/id_deploy -o StrictHostKeyChecking=accept-new \ + $SSH_USER@$SSH_HOST chmod +x /tmp/poc-deploy/deploy-compose +ssh -i /tmp/ssh/id_deploy -o StrictHostKeyChecking=accept-new \ + $SSH_USER@$SSH_HOST /tmp/poc-deploy/deploy-compose "$REGISTRY" "$ZOT_USERNAME" "$ZOT_PASSWORD" +ssh -i /tmp/ssh/id_deploy -o StrictHostKeyChecking=accept-new \ + $SSH_USER@$SSH_HOST rm -f /tmp/poc-deploy/secrets.decrypted.env + +echo "Deployment finished."