Skip to content

Give CI an SSH key the nodes authorise - #319

Merged
anuveyatsu merged 1 commit into
mainfrom
bead/ci-can-ssh-to-deploy
Sep 13, 2026
Merged

anuveyatsu merged 1 commit into
mainfrom
bead/ci-can-ssh-to-deploy

Conversation

@anuveyatsu

Copy link
Copy Markdown
Member

Third and last auth gate for CI deploy. The run got through the tunnel, Access, and host-key verification, then failed at SSH: Permission denied (publickey). The nodes authorise only the operator's key (injected by Hetzner at provision); CI has none.

The ssh role now installs a dedicated CI deploy key into root's authorized_keys -- appended, so the operator's key is untouched -- gated on ci_deploy_ssh_public_key (committed public half). A separate key means CI can be revoked by deleting the line and redeploying, without touching anyone's laptop. The private half is the Actions secret WG_CI_SSH_KEY; deploy.yml writes it 0600 and sets ANSIBLE_PRIVATE_KEY_FILE, and the guard refuses to start without it.

Already installed on both nodes (verified CHANGED on both); the role keeps it idempotently.

One more secret to set: gh secret set WG_CI_SSH_KEY -R datopian/openbases < <the ci-ssh private key>.

🤖 Generated with Claude Code

The CI deploy got through the tunnel, Access and host-key verification
and then failed at the SSH layer: "Permission denied (publickey)". The
nodes authorise one key -- the operator's, injected by Hetzner at
provision -- and CI has no laptop and no such key.

The ssh role now installs a dedicated CI deploy key into root's
authorized_keys, appended so the operator's injected key is untouched,
and gated on ci_deploy_ssh_public_key (defaulted to the committed
public half). A separate key means CI can be revoked by deleting the
line and redeploying, without disturbing anyone's laptop access. The
public key is committed; the private half is the GitHub Actions secret
WG_CI_SSH_KEY, and deploy.yml writes it to a 0600 file and points
ANSIBLE_PRIVATE_KEY_FILE at it. The auth guard now refuses to start
without it.

The key is already installed on both staging nodes (ansible lineinfile,
CHANGED on both); the role task keeps it there idempotently on every
run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 45 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: daa67d59-105b-485c-9014-747d455c227d

📥 Commits

Reviewing files that changed from the base of the PR and between 320b660 and d7f716a.

📒 Files selected for processing (3)
  • .github/workflows/deploy.yml
  • infra/ansible/roles/ssh/defaults/main.yml
  • infra/ansible/roles/ssh/tasks/main.yml

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@anuveyatsu
anuveyatsu merged commit de8e77d into main Sep 13, 2026
7 checks passed
@anuveyatsu
anuveyatsu deleted the bead/ci-can-ssh-to-deploy branch September 13, 2026 18:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant