Merge pull request 'fix: docs: rent-a-human instructions for Caddy host SSH key setup (#748)' (#756) from fix/issue-748 into main
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
This commit is contained in:
commit
b95e2da645
1 changed files with 167 additions and 0 deletions
167
formulas/rent-a-human-caddy-ssh.toml
Normal file
167
formulas/rent-a-human-caddy-ssh.toml
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
# formulas/rent-a-human-caddy-ssh.toml — Provision SSH key for Caddy log collection
|
||||
#
|
||||
# "Rent a Human" — walk the operator through provisioning a purpose-limited
|
||||
# SSH keypair so collect-engagement.sh can fetch Caddy access logs remotely.
|
||||
#
|
||||
# The key uses a `command=` restriction so it can ONLY cat the access log.
|
||||
# No interactive shell, no port forwarding, no agent forwarding.
|
||||
#
|
||||
# Parent vision issue: #426
|
||||
# Sprint: website-observability-wire-up (ops PR #10)
|
||||
# Consumed by: site/collect-engagement.sh (issue #745)
|
||||
|
||||
name = "rent-a-human-caddy-ssh"
|
||||
description = "Provision a purpose-limited SSH keypair for remote Caddy log collection"
|
||||
version = 1
|
||||
|
||||
# ── Step 1: Generate keypair ─────────────────────────────────────────────────
|
||||
|
||||
[[steps]]
|
||||
id = "generate-keypair"
|
||||
title = "Generate a dedicated ed25519 keypair"
|
||||
description = """
|
||||
Generate a purpose-limited SSH keypair for Caddy log collection.
|
||||
|
||||
Run on your local machine (NOT the Caddy host):
|
||||
|
||||
```
|
||||
ssh-keygen -t ed25519 -f caddy-collect -N '' -C 'disinto-collect-engagement'
|
||||
```
|
||||
|
||||
This produces two files:
|
||||
- caddy-collect (private key — goes into the vault)
|
||||
- caddy-collect.pub (public key — goes onto the Caddy host)
|
||||
|
||||
Do NOT set a passphrase (-N '') — the factory runs unattended.
|
||||
"""
|
||||
|
||||
# ── Step 2: Install public key on Caddy host ─────────────────────────────────
|
||||
|
||||
[[steps]]
|
||||
id = "install-public-key"
|
||||
title = "Install the public key on the Caddy host with command= restriction"
|
||||
needs = ["generate-keypair"]
|
||||
description = """
|
||||
Install the public key on the Caddy host with a strict command= restriction
|
||||
so this key can ONLY read the access log.
|
||||
|
||||
1. SSH into the Caddy host as the user who owns /var/log/caddy/access.log.
|
||||
|
||||
2. Open (or create) ~/.ssh/authorized_keys:
|
||||
mkdir -p ~/.ssh && chmod 700 ~/.ssh
|
||||
nano ~/.ssh/authorized_keys
|
||||
|
||||
3. Add this line (all on ONE line — do not wrap):
|
||||
|
||||
command="cat /var/log/caddy/access.log",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA... disinto-collect-engagement
|
||||
|
||||
Replace "AAAA..." with the contents of caddy-collect.pub.
|
||||
|
||||
To build the line automatically:
|
||||
echo "command=\"cat /var/log/caddy/access.log\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding $(cat caddy-collect.pub)"
|
||||
|
||||
4. Set permissions:
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
|
||||
What the restrictions do:
|
||||
- command="cat /var/log/caddy/access.log"
|
||||
Forces this key to only execute `cat /var/log/caddy/access.log`,
|
||||
regardless of what the client requests.
|
||||
- no-port-forwarding — blocks SSH tunnels
|
||||
- no-X11-forwarding — blocks X11
|
||||
- no-agent-forwarding — blocks agent forwarding
|
||||
|
||||
If the access log is at a different path, update the command= restriction
|
||||
AND set CADDY_ACCESS_LOG in the factory environment to match.
|
||||
"""
|
||||
|
||||
# ── Step 3: Add private key to vault secrets ─────────────────────────────────
|
||||
|
||||
[[steps]]
|
||||
id = "store-private-key"
|
||||
title = "Add the private key to .env.vault.enc as CADDY_SSH_KEY"
|
||||
needs = ["generate-keypair"]
|
||||
description = """
|
||||
Store the private key in the factory's encrypted vault secrets.
|
||||
|
||||
1. Read the private key:
|
||||
cat caddy-collect
|
||||
|
||||
2. Add it to .env.vault.enc (or .env.vault for plaintext fallback) as
|
||||
CADDY_SSH_KEY. The key is multi-line, so use the base64-encoded form:
|
||||
|
||||
echo "CADDY_SSH_KEY=$(base64 -w0 caddy-collect)" >> .env.vault.enc
|
||||
|
||||
Or, if using SOPS-encrypted vault, decrypt first, add the variable,
|
||||
then re-encrypt.
|
||||
|
||||
3. IMPORTANT: After storing, securely delete the local private key file:
|
||||
shred -u caddy-collect 2>/dev/null || rm -f caddy-collect
|
||||
rm -f caddy-collect.pub
|
||||
|
||||
The public key is already installed on the Caddy host; the private key
|
||||
now lives only in the vault.
|
||||
|
||||
Never commit the private key to any git repository.
|
||||
"""
|
||||
|
||||
# ── Step 4: Configure Caddy host address ─────────────────────────────────────
|
||||
|
||||
[[steps]]
|
||||
id = "store-caddy-host"
|
||||
title = "Add the Caddy host address to .env.vault.enc as CADDY_HOST"
|
||||
needs = ["install-public-key"]
|
||||
description = """
|
||||
Store the Caddy host connection string so collect-engagement.sh knows
|
||||
where to SSH.
|
||||
|
||||
1. Add to .env.vault.enc (or .env.vault for plaintext fallback):
|
||||
|
||||
echo "CADDY_HOST=user@caddy-host-ip-or-domain" >> .env.vault.enc
|
||||
|
||||
Replace user@caddy-host-ip-or-domain with the actual SSH user and host
|
||||
(e.g. debian@203.0.113.42 or deploy@caddy.disinto.ai).
|
||||
|
||||
2. If using SOPS, decrypt/add/re-encrypt as above.
|
||||
"""
|
||||
|
||||
# ── Step 5: Test the connection ──────────────────────────────────────────────
|
||||
|
||||
[[steps]]
|
||||
id = "test-connection"
|
||||
title = "Verify the SSH key works and returns the access log"
|
||||
needs = ["install-public-key", "store-private-key", "store-caddy-host"]
|
||||
description = """
|
||||
Test the end-to-end connection before the factory tries to use it.
|
||||
|
||||
1. From the factory host (or anywhere with the private key), run:
|
||||
|
||||
ssh -i caddy-collect -o StrictHostKeyChecking=accept-new user@caddy-host
|
||||
|
||||
Expected behavior:
|
||||
- Outputs the contents of /var/log/caddy/access.log
|
||||
- Disconnects immediately (command= restriction forces this)
|
||||
|
||||
If you already shredded the local key, decode it from the vault:
|
||||
echo "$CADDY_SSH_KEY" | base64 -d > /tmp/caddy-collect-test
|
||||
chmod 600 /tmp/caddy-collect-test
|
||||
ssh -i /tmp/caddy-collect-test -o StrictHostKeyChecking=accept-new user@caddy-host
|
||||
rm -f /tmp/caddy-collect-test
|
||||
|
||||
2. Verify the output is Caddy structured JSON (one JSON object per line):
|
||||
ssh -i /tmp/caddy-collect-test user@caddy-host | head -1 | jq .
|
||||
|
||||
You should see fields like: ts, request, status, duration.
|
||||
|
||||
3. If the connection fails:
|
||||
- Permission denied → check authorized_keys format (must be one line)
|
||||
- Connection refused → check sshd is running on the Caddy host
|
||||
- Empty output → check /var/log/caddy/access.log exists and is readable
|
||||
by the SSH user
|
||||
- "jq: error" → Caddy may be using Combined Log Format instead of
|
||||
structured JSON; check Caddy's log configuration
|
||||
|
||||
4. Once verified, the factory's collect-engagement.sh can use this key
|
||||
to fetch logs remotely via:
|
||||
ssh -i <decoded-key-path> $CADDY_HOST
|
||||
"""
|
||||
Loading…
Add table
Add a link
Reference in a new issue