Add the host bootstrap: deploy user, key, docker access, stack root
bootstrap.yml prepares a host as an admin via -u; new-deploy-key.sh makes the key pair and refuses to write inside the repo. CI deploys refuse the bootstrap playbook, since the dispatch API ignores the dropdown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
78b227f32d
commit
792f7cde48
10 files changed
+443
-9
No files matched your search
Executable
+97
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Generate the Ansible deploy key pair.
|
||||
#
|
||||
# scripts/new-deploy-key.sh # ~/.ssh/deploy_key
|
||||
# scripts/new-deploy-key.sh ~/.ssh/other # somewhere else
|
||||
# scripts/new-deploy-key.sh --force # replace an existing key
|
||||
# scripts/new-deploy-key.sh --print-secret # also print the value for CI
|
||||
#
|
||||
# Prints the paths and the public key. It does not print the private key unless
|
||||
# you ask for it: load-ssh-key.sh keeps key material off stdout and out of logs
|
||||
# and the process list, and this script holds the same line.
|
||||
#
|
||||
# The public key belongs in the deploy user's authorized_keys, which
|
||||
# ansible/playbooks/bootstrap.yml does for you. The private key belongs in the
|
||||
# CI secret SSH_PRIVATE_KEY_B64. See docs/bootstrap.md and docs/secrets.md.
|
||||
set -euo pipefail
|
||||
umask 077
|
||||
|
||||
log() { printf 'new-deploy-key: %s\n' "$*" >&2; }
|
||||
die() { log "$*"; exit 1; }
|
||||
|
||||
force=0
|
||||
print_secret=0
|
||||
key_path=""
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--force) force=1 ;;
|
||||
--print-secret) print_secret=1 ;;
|
||||
-h|--help) sed -n '3,9p' "$0" | sed 's/^#[[:space:]]\{0,1\}//'; exit 0 ;;
|
||||
-*) die "unknown option: $1" ;;
|
||||
*)
|
||||
[ -z "$key_path" ] || die "only one key path may be given"
|
||||
key_path="$1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
key_path="${key_path:-$HOME/.ssh/deploy_key}"
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
key_dir="$(dirname "$key_path")"
|
||||
[ -d "$key_dir" ] || die "no such directory: $key_dir"
|
||||
key_dir="$(cd "$key_dir" && pwd)"
|
||||
|
||||
# gitleaks scans the working tree *and* the full history, and a key committed
|
||||
# once stays leaked after the file is deleted. Refuse before that can happen.
|
||||
case "$key_dir/" in
|
||||
"$repo_root"/*) die "refusing to write a private key inside the repository: $repo_root" ;;
|
||||
esac
|
||||
|
||||
if [ -e "$key_path" ] && [ "$force" -ne 1 ]; then
|
||||
die "$key_path already exists. Replacing it locks out every host that still
|
||||
trusts the old key, so pass --force if that is what you want."
|
||||
fi
|
||||
# An `if`, not `[ ... ] && rm ...`: an AND-list whose test fails returns
|
||||
# non-zero, which under `set -e` is a trap this repository has been bitten by
|
||||
# before -- see the same note in .gitea/workflows/deploy.yml.
|
||||
if [ "$force" -eq 1 ]; then
|
||||
rm -f "$key_path" "$key_path.pub"
|
||||
fi
|
||||
|
||||
# ed25519, and no passphrase: nothing in CI or in a playbook run can type one,
|
||||
# and an encrypted key fails later with an authentication error that says
|
||||
# nothing about the passphrase.
|
||||
ssh-keygen -t ed25519 -f "$key_path" -N "" -C "ansible-deploy@$(basename "$repo_root")" >/dev/null
|
||||
|
||||
printf 'private key %s\n' "$key_path"
|
||||
printf 'public key %s\n\n' "$key_path.pub"
|
||||
cat "$key_path.pub"
|
||||
|
||||
cat <<INSTRUCTIONS
|
||||
|
||||
Next:
|
||||
|
||||
1. Put it on the host, and create everything else it needs:
|
||||
|
||||
cd ansible
|
||||
ansible-playbook playbooks/bootstrap.yml -u <admin-user> -k -K \\
|
||||
-e deploy_pubkey_file=$key_path.pub
|
||||
|
||||
2. Store the private key as the CI secret SSH_PRIVATE_KEY_B64 (where, per
|
||||
platform, is in docs/secrets.md):
|
||||
|
||||
base64 -w0 < $key_path
|
||||
|
||||
3. Confirm it works before any deploy: the connectivity workflow on GitHub
|
||||
or Gitea, the ansible:ping job on GitLab.
|
||||
INSTRUCTIONS
|
||||
|
||||
if [ "$print_secret" -eq 1 ]; then
|
||||
printf '\nSSH_PRIVATE_KEY_B64:\n'
|
||||
base64 -w0 < "$key_path"
|
||||
printf '\n'
|
||||
fi
|
||||
Reference in new issue
Block a user