Public Access
The Site workflow's last step, and the release workflow after publishing, ask the web server over SSH to rebuild the site. The key CI holds is tied on the server to one forced command (restrict,command=...), so CI sends no command and a leaked key can only refresh the site. The server, the user, the key and the server's host key are Gitea secrets; with none of them set the step does nothing. scripts/site_refresh.sh is what both workflows run; scripts/site_deploy_keygen.sh makes the key and prints where each half goes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
53 lines
2.5 KiB
Bash
Executable File
53 lines
2.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Creates the key CI uses to ask the web server for a site refresh, once (issue #79,
|
|
# docs/milestones/W1.md), and says where each half goes. The private key stays in
|
|
# ~/.config/roro9stack/ until it is pasted into the Gitea secret; it is never committed and this
|
|
# script doesn't print it.
|
|
#
|
|
# scripts/site_deploy_keygen.sh [/full/path/to/rororefresh.sh] [the runner's address]
|
|
set -euo pipefail
|
|
KEY="${RORO_SITE_DEPLOY_KEY:-$HOME/.config/roro9stack/site-deploy-key}"
|
|
COMMAND="${1:-/full/path/to/rororefresh.sh}"
|
|
FROM="${2:-}"
|
|
|
|
if [ -e "$KEY" ]; then
|
|
echo "A site deploy key already exists at $KEY; not overwriting it." >&2
|
|
else
|
|
mkdir -p "$(dirname "$KEY")"
|
|
( umask 077; ssh-keygen -q -t ed25519 -N "" -C roro9stack-ci-site-refresh -f "$KEY" )
|
|
fi
|
|
|
|
options="restrict,command=\"$COMMAND\""
|
|
[ -z "$FROM" ] || options="from=\"$FROM\",$options"
|
|
|
|
cat <<TEXT
|
|
|
|
1. On the web server, as the user that runs the refresh, add this one line to ~/.ssh/authorized_keys:
|
|
|
|
$options $(cat "$KEY.pub")
|
|
|
|
restrict: no terminal, no forwarding of any kind. command=: whatever the client asks for, this
|
|
runs instead.$([ -n "$FROM" ] || printf '\n Give the runner'"'"'s address as the second argument to add from="...": the key then works from there only.')
|
|
|
|
2. In Gitea, the repository's Settings > Actions > Secrets:
|
|
|
|
SITE_DEPLOY_KEY the whole of $KEY (the private key, with its BEGIN and END lines)
|
|
SITE_DEPLOY_HOST the server's address as the runner reaches it, or address:port
|
|
SITE_DEPLOY_USER that user's name
|
|
SITE_DEPLOY_KNOWN_HOSTS the server's host key, one line, from a machine you trust the network of:
|
|
ssh-keyscan -t ed25519 <address> (or: -p <port> <address>)
|
|
and compare it with the server's own:
|
|
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub (on the server)
|
|
ssh-keyscan -t ed25519 <address> | ssh-keygen -lf - (here)
|
|
|
|
3. Try it, from here, with the same four values in the environment:
|
|
|
|
SITE_DEPLOY_KEY="\$(cat $KEY)" SITE_DEPLOY_HOST=... SITE_DEPLOY_USER=... \\
|
|
SITE_DEPLOY_KNOWN_HOSTS="\$(ssh-keyscan -t ed25519 ... 2>/dev/null)" scripts/site_refresh.sh
|
|
|
|
(with from= set, this works from the runner's address only.) Then, to see that the key can do
|
|
nothing else: ssh -i $KEY <user>@<address> id must run the refresh, not \`id\`.
|
|
|
|
Once the secret is in Gitea, the copy at $KEY can be deleted.
|
|
TEXT
|