Phase 1 of the central SSH CA. The ssh-client-signer mount and its ed25519 CA were created by hand with the root token; this PR records the role definitions and the claude-bot signing policy (house pattern: reference files, NOT applied by Flux).
Changes
openbao/ssh-ca/role-owner.json: principal k.renner, TTL 4380h (6 months). The mount was enabled with -max-lease-ttl=4380h; the 768h system default would silently cap it.
openbao/ssh-ca/role-claude.json: principal claude-bot, TTL 1h, permit-pty only.
openbao/policies/ssh-sign-claude.hcl: update on ssh-client-signer/sign/claude, with the commands to attach it to userpass claude-bot next to its existing claude-bot-write (checked live: the only policy it has today).
Verified
YubiKey sk-ssh-ed25519 key signed via OIDC login on role owner → sk-ssh-ed25519-cert-v01@openssh.com, principal k.renner, valid 2026-10-27 → 2027-04-27.
CA public key served unauthenticated at /v1/ssh-client-signer/public_key, fingerprint SHA256:xEhuqxqFVZ/ig6KpAtHOhLbwsIhyWpzXhvDcjIfM/Js (matches the cert's signing CA).
After merge (manual, root token)
bao write ssh-client-signer/roles/claude @kubernetes/infrastructure/openbao/ssh-ca/role-claude.json
bao policy write ssh-sign-claude kubernetes/infrastructure/openbao/policies/ssh-sign-claude.hcl
bao write auth/userpass/users/claude-bot token_policies=claude-bot-write,ssh-sign-claude
Phase 1 of the central SSH CA. The `ssh-client-signer` mount and its ed25519 CA were created by hand with the root token; this PR records the role definitions and the claude-bot signing policy (house pattern: reference files, NOT applied by Flux).
## Changes
- `openbao/ssh-ca/role-owner.json`: principal `k.renner`, TTL 4380h (6 months). The mount was enabled with `-max-lease-ttl=4380h`; the 768h system default would silently cap it.
- `openbao/ssh-ca/role-claude.json`: principal `claude-bot`, TTL 1h, `permit-pty` only.
- `openbao/policies/ssh-sign-claude.hcl`: `update` on `ssh-client-signer/sign/claude`, with the commands to attach it to userpass `claude-bot` next to its existing `claude-bot-write` (checked live: the only policy it has today).
## Verified
- YubiKey `sk-ssh-ed25519` key signed via OIDC login on role `owner` → `sk-ssh-ed25519-cert-v01@openssh.com`, principal `k.renner`, valid 2026-10-27 → 2027-04-27.
- CA public key served unauthenticated at `/v1/ssh-client-signer/public_key`, fingerprint `SHA256:xEhuqxqFVZ/ig6KpAtHOhLbwsIhyWpzXhvDcjIfM/Js` (matches the cert's signing CA).
## After merge (manual, root token)
```
bao write ssh-client-signer/roles/claude @kubernetes/infrastructure/openbao/ssh-ca/role-claude.json
bao policy write ssh-sign-claude kubernetes/infrastructure/openbao/policies/ssh-sign-claude.hcl
bao write auth/userpass/users/claude-bot token_policies=claude-bot-write,ssh-sign-claude
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Phase 1 of the SSH CA. The ssh-client-signer mount and its ed25519 CA
were set up by hand (root token); this records the roles and the
claude-bot signing policy.
- role owner: principal k.renner, 6-month certs. The mount was enabled
with -max-lease-ttl=4380h; the 768h system default would cap it.
- role claude: principal claude-bot, 1h certs, pty only.
- policy ssh-sign-claude for the claude-bot userpass user, next to its
existing claude-bot-write.
Verified: a YubiKey sk-ssh-ed25519 key signed on role owner yields a
sk-ssh-ed25519-cert-v01 cert, principal k.renner, valid to 2027-04-27.
CA fingerprint SHA256:xEhuqxqFVZ/ig6KpAtHOhLbwsIhyWpzXhvDcjIfM/Js,
served unauthenticated at /v1/ssh-client-signer/public_key.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🤖Automated review — model claude-opus-5-5, commit 2e412e6448f7cbbd1817fb059eb2aa04ad029201.
Automated review by the review-bot: it approves only when it found nothing red or yellow, and a human still merges. Push new commits to get a fresh review.
Summary
This PR adds three reference files that Flux does not apply. Two are SSH secrets-engine role definitions under kubernetes/infrastructure/openbao/ssh-ca/, one for owner (principal k.renner, 4380h) and one for claude (principal claude-bot, 1h, pty only). The third is policy ssh-sign-claude, which grants update on the claude sign path. The PR is mergeable and is based on the current main tip (7f61ad0c). None of the three files exist on main, no other PR covers them, and the PR links no issues. Only phase 0 (#1463, which added ssh-sign-owner.hcl) came before it. I found nothing blocking.
🟡 Suggestions
The owner role and the mount/CA setup are not written down anywhere (kubernetes/infrastructure/openbao/ssh-ca/role-owner.json). Every other policy file in policies/ keeps the exact bao commands that apply it in its header. ssh-sign-claude.hcl:4-6 does this for the claude role. Nothing in the repo does it for role-owner.json: ssh-sign-owner.hcl names sign/owner but has no bao write ssh-client-signer/roles/owner @…. The same goes for the hand-run mount and CA setup that role-owner.json depends on: secrets enable -path=ssh-client-signer -max-lease-ttl=4380h ssh and config/ca … key_type=ed25519. The PR body itself says the 4380h TTL only works because of that mount tuning. JSON can't hold comments, so add the commands either to the header of ssh-sign-owner.hcl or to a short ssh-ca/README.md. Without them, someone rebuilding the mount (instead of restoring a snapshot) would hit the 768h cap without being told why.
🟢 Nits
role-owner.json:6: permit-agent-forwarding is allowed but left out of default_extensions, so the owner has to ask for it per signing. That looks deliberate; a one-line note in the README suggested above would make that clear.
Owner certs last 6 months and the CA cannot revoke a single cert. The hardware-backed sk- key limits the damage if one leaks. Plan host-side RevokedKeys when hosts start trusting the CA (phase 2).
Tests
The repo has no automated tests for these reference files. The PR reports a manual check that matters: an owner signing produced an sk-ssh-ed25519-cert-v01 cert with the expected principal and validity, and the CA fingerprint matched. After merge, run the same check for the claude role: log in as userpass claude-bot, sign on ssh-client-signer/sign/claude, and confirm that the cert expires after 1h and carries only permit-pty.
Recommendation
Looks reasonable — no blocking issues; comments above are optional.
🤖 **Automated review** — model `claude-opus-5-5`, commit `2e412e6448f7cbbd1817fb059eb2aa04ad029201`.
> Automated review by the `review-bot`: it approves only when it found nothing red or yellow, and a human still merges. Push new commits to get a fresh review.
---
## Summary
This PR adds three reference files that Flux does not apply. Two are SSH secrets-engine role definitions under `kubernetes/infrastructure/openbao/ssh-ca/`, one for `owner` (principal `k.renner`, 4380h) and one for `claude` (principal `claude-bot`, 1h, pty only). The third is policy `ssh-sign-claude`, which grants `update` on the claude sign path. The PR is mergeable and is based on the current `main` tip (`7f61ad0c`). None of the three files exist on `main`, no other PR covers them, and the PR links no issues. Only phase 0 (#1463, which added `ssh-sign-owner.hcl`) came before it. I found nothing blocking.
## 🟡 Suggestions
- **The owner role and the mount/CA setup are not written down anywhere** (`kubernetes/infrastructure/openbao/ssh-ca/role-owner.json`). Every other policy file in `policies/` keeps the exact `bao` commands that apply it in its header. `ssh-sign-claude.hcl:4-6` does this for the claude role. Nothing in the repo does it for `role-owner.json`: `ssh-sign-owner.hcl` names `sign/owner` but has no `bao write ssh-client-signer/roles/owner @…`. The same goes for the hand-run mount and CA setup that `role-owner.json` depends on: `secrets enable -path=ssh-client-signer -max-lease-ttl=4380h ssh` and `config/ca … key_type=ed25519`. The PR body itself says the 4380h TTL only works because of that mount tuning. JSON can't hold comments, so add the commands either to the header of `ssh-sign-owner.hcl` or to a short `ssh-ca/README.md`. Without them, someone rebuilding the mount (instead of restoring a snapshot) would hit the 768h cap without being told why.
## 🟢 Nits
- `role-owner.json:6`: `permit-agent-forwarding` is allowed but left out of `default_extensions`, so the owner has to ask for it per signing. That looks deliberate; a one-line note in the README suggested above would make that clear.
- Owner certs last 6 months and the CA cannot revoke a single cert. The hardware-backed `sk-` key limits the damage if one leaks. Plan host-side `RevokedKeys` when hosts start trusting the CA (phase 2).
## Tests
The repo has no automated tests for these reference files. The PR reports a manual check that matters: an `owner` signing produced an `sk-ssh-ed25519-cert-v01` cert with the expected principal and validity, and the CA fingerprint matched. After merge, run the same check for the `claude` role: log in as userpass `claude-bot`, sign on `ssh-client-signer/sign/claude`, and confirm that the cert expires after 1h and carries only `permit-pty`.
## Recommendation
Looks reasonable — no blocking issues; comments above are optional.
<!-- pr-review:sha=2e412e6448f7cbbd1817fb059eb2aa04ad029201 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Phase 1 of the central SSH CA. The
ssh-client-signermount and its ed25519 CA were created by hand with the root token; this PR records the role definitions and the claude-bot signing policy (house pattern: reference files, NOT applied by Flux).Changes
openbao/ssh-ca/role-owner.json: principalk.renner, TTL 4380h (6 months). The mount was enabled with-max-lease-ttl=4380h; the 768h system default would silently cap it.openbao/ssh-ca/role-claude.json: principalclaude-bot, TTL 1h,permit-ptyonly.openbao/policies/ssh-sign-claude.hcl:updateonssh-client-signer/sign/claude, with the commands to attach it to userpassclaude-botnext to its existingclaude-bot-write(checked live: the only policy it has today).Verified
sk-ssh-ed25519key signed via OIDC login on roleowner→sk-ssh-ed25519-cert-v01@openssh.com, principalk.renner, valid 2026-10-27 → 2027-04-27./v1/ssh-client-signer/public_key, fingerprintSHA256:xEhuqxqFVZ/ig6KpAtHOhLbwsIhyWpzXhvDcjIfM/Js(matches the cert's signing CA).After merge (manual, root token)
🤖 Generated with Claude Code
🤖 Automated review — model
claude-opus-5-5, commit2e412e6448f7cbbd1817fb059eb2aa04ad029201.Summary
This PR adds three reference files that Flux does not apply. Two are SSH secrets-engine role definitions under
kubernetes/infrastructure/openbao/ssh-ca/, one forowner(principalk.renner, 4380h) and one forclaude(principalclaude-bot, 1h, pty only). The third is policyssh-sign-claude, which grantsupdateon the claude sign path. The PR is mergeable and is based on the currentmaintip (7f61ad0c). None of the three files exist onmain, no other PR covers them, and the PR links no issues. Only phase 0 (#1463, which addedssh-sign-owner.hcl) came before it. I found nothing blocking.🟡 Suggestions
kubernetes/infrastructure/openbao/ssh-ca/role-owner.json). Every other policy file inpolicies/keeps the exactbaocommands that apply it in its header.ssh-sign-claude.hcl:4-6does this for the claude role. Nothing in the repo does it forrole-owner.json:ssh-sign-owner.hclnamessign/ownerbut has nobao write ssh-client-signer/roles/owner @…. The same goes for the hand-run mount and CA setup thatrole-owner.jsondepends on:secrets enable -path=ssh-client-signer -max-lease-ttl=4380h sshandconfig/ca … key_type=ed25519. The PR body itself says the 4380h TTL only works because of that mount tuning. JSON can't hold comments, so add the commands either to the header ofssh-sign-owner.hclor to a shortssh-ca/README.md. Without them, someone rebuilding the mount (instead of restoring a snapshot) would hit the 768h cap without being told why.🟢 Nits
role-owner.json:6:permit-agent-forwardingis allowed but left out ofdefault_extensions, so the owner has to ask for it per signing. That looks deliberate; a one-line note in the README suggested above would make that clear.sk-key limits the damage if one leaks. Plan host-sideRevokedKeyswhen hosts start trusting the CA (phase 2).Tests
The repo has no automated tests for these reference files. The PR reports a manual check that matters: an
ownersigning produced ansk-ssh-ed25519-cert-v01cert with the expected principal and validity, and the CA fingerprint matched. After merge, run the same check for theclauderole: log in as userpassclaude-bot, sign onssh-client-signer/sign/claude, and confirm that the cert expires after 1h and carries onlypermit-pty.Recommendation
Looks reasonable — no blocking issues; comments above are optional.