Playbook: BMS Server Root SSH Lockout Recovery (OVH Kimsufi console)
Trigger: ssh root@<bms-ip> fails with Permission denied (publickey,password) and a
jump host (e.g. via bms-1) also fails — i.e. the developer workstation key
(C:\Users\konar\.ssh\id_ed25519) is not present in /root/.ssh/authorized_keys on the
target BMS host.
Why this recurs: the SSH key rotation flow (ssh-key-rotation.md) and
per-host provisioning add the workstation key to the ubuntu account on bms-2/bms-3/bms-4 (see
that playbook’s server table and step 2), but not to root. When a host is later switched to
root-key access without first seeding /root/.ssh/authorized_keys, root login fails. This already
happened on bms-4 (fixed 2026-06-16) and recurred on bms-2 (#1905).
Check the documented access path FIRST — root may be the wrong account. Per
CLAUDE.md, the documented human SSH path for bms-2 isubuntu@145.239.133.104(withclaude-admin@…for Claude), notroot. bms-4 is the host documented forrootlogin. If you only need to run a command, tryubuntu@<host>+sudobefore assuming a root lockout — the workstation key is normally present onubuntu. Only proceed with console recovery below if root access is genuinely required andubuntu/claude-adminaccess is also confirmed broken.
Affected hosts
| Server | IP | Provider console |
|---|---|---|
| bms-1 | 94.23.26.113 | OVH Kimsufi IPMI / KVM |
| bms-2 | 145.239.133.104 | OVH Kimsufi IPMI / KVM |
| bms-3 | 51.68.155.224 | OVH Kimsufi IPMI / KVM |
| bms-4 | 54.36.123.110 | OVH Kimsufi IPMI / KVM |
1. Confirm the lockout (do NOT print key values)
# Exit code only — never use -v (leaks key negotiation), never cat authorized_keys
ssh -o BatchMode=yes -o ConnectTimeout=8 root@145.239.133.104 "echo ok" ; echo "exit=$?"
# Try the documented ubuntu / claude-admin path too — if either works, no console needed:
ssh -o BatchMode=yes -o ConnectTimeout=8 ubuntu@145.239.133.104 "echo ok" ; echo "exit=$?"
ssh -o BatchMode=yes -o ConnectTimeout=8 claude-admin@145.239.133.104 "echo ok" ; echo "exit=$?"A non-zero exit on all accounts confirms a full key lockout → use the console (step 3).
If ubuntu/claude-admin succeed, skip the console — use that account with sudo instead (step 4).
2. Get the public key to add (this is NOT a secret — public keys are safe to read)
On the developer workstation (PowerShell):
Get-Content C:\Users\konar\.ssh\id_ed25519.pubCopy the single ssh-ed25519 AAAA… radieu@… line. (The matching private key never leaves the
workstation.)
3. Add the key via OVH Kimsufi console (human action — requires OVH account)
-
Log in to the OVH Manager → Bare Metal Cloud → select the server (bms-2 =
ns3087638) → KVM / IPMI → open the console. -
Log in at the console as
root(orubuntuthensudo -i). Console uses the local password, not the SSH key, so it works while SSH is locked out. -
Seed root’s authorized_keys idempotently (paste the public key from step 2 in place of
KEY):install -d -m 700 -o root -g root /root/.ssh grep -qxF 'KEY' /root/.ssh/authorized_keys 2>/dev/null \ || echo 'KEY' >> /root/.ssh/authorized_keys chmod 600 /root/.ssh/authorized_keys chown root:root /root/.ssh/authorized_keys -
Confirm sshd permits root key login (default for these hosts is
prohibit-password, which allows keys):sshd -T 2>/dev/null | grep -i permitrootlogin # expect: prohibit-password (or yes)If it shows
no, root key login is intentionally disabled on this host — use theubuntuaccount path (step 4) instead of re-enabling root.
4. Alternative — use the ubuntu account + sudo (no console needed)
If ubuntu@<host> still accepts the workstation key (it usually does — rotation seeds it there):
ssh ubuntu@145.239.133.104 "sudo grep -c '' /root/.ssh/authorized_keys" # check, no values printed
# Add the workstation key to root from inside the ubuntu session:
ssh ubuntu@145.239.133.104 \
"sudo bash -c \"install -d -m700 /root/.ssh; grep -qxF 'KEY' /root/.ssh/authorized_keys || echo 'KEY' >> /root/.ssh/authorized_keys; chmod 600 /root/.ssh/authorized_keys\""5. Verify recovery
ssh -o BatchMode=yes root@145.239.133.104 "hostname" # expect: ns30876386. Prevention
- When rotating the workstation key, add it to both
ubuntuandrooton every BMS host — updatessh-key-rotation.mdloops if a host needs root access. - When provisioning or onboarding a new BMS host, seed
/root/.ssh/authorized_keyswith the workstation key during the initial console session, before SSH-only access is assumed. - The Ansible
commonrole only pre-checks that/root/.ssh/authorized_keysis non-empty (a lockout guard) — it does not push keys. Seeding root keys remains a manual/console step.
Escalation
If the OVH console itself is unavailable or root has no working password:
- Open an OVH support ticket for IPMI/KVM access to the affected
ns…server. - Send a Discord alert via
P24_DISCORD_INFRA_SCRIPTS_ERRORS_WEBHOOK_URL(red) and keep the tracking GitHub issue open with labelhuman-actionuntil root SSH is restored.
Recovery log
| Date | Host | Actor | Notes |
|---|---|---|---|
| 2026-06-16 | bms-4 | radieu | root authorized_keys seeded (first occurrence) |
| 2026-06-28 | bms-2 | pending | #1905 — OVH console action required |
Audit Log — Log to infra_operations
After this operation completes, log it to the infra_operations audit table.
Python (Linux server — bms-4, vps-i1, vps-h1, or similar):
import sys
sys.path.insert(0, '/opt/p24-infra')
from scripts.lib.log_op import log_op
log_op(
actor="radieu", # "radieu" for manual human ops, "claude" for agent
op_type="config_change",
resource="bms-root-ssh",
result="success", # "success" | "failed" | "skipped"
detail="BMS server root SSH lockout recovery — authorized_keys restored via IPMI/KVM",
env="bms-1",
gh_issue=2730,
)PowerShell (Windows dev machine):
$env:SUPABASE_URL = (Get-Content "C:\code_2026\p24-infra\.env.local" | Select-String "^SUPABASE_URL=").ToString().Split("=",2)[1].Trim()
$env:SUPABASE_SERVICE_KEY = (Get-Content "C:\code_2026\p24-infra\.env.local" | Select-String "^SUPABASE_SERVICE_KEY=").ToString().Split("=",2)[1].Trim()
python -c "
import os, sys
sys.path.insert(0, 'C:/code_2026/p24-infra')
from scripts.lib.log_op import log_op
log_op('radieu', 'config_change', 'bms-root-ssh', 'success', 'BMS server root SSH lockout recovery — authorized_keys restored via IPMI/KVM', 'bms-1')
"
$env:SUPABASE_URL = ''; $env:SUPABASE_SERVICE_KEY = ''