feat(ssh): add bootstrap-ssh-ca role for OpenBao SSH user CA trust

Deploy TrustedUserCAKeys, auth_principals from ssh_principals.yaml, and
Makefile targets bootstrap-ssh-ca / bootstrap-ssh-ca-host (NET-WP-0020 T5).
This commit is contained in:
2026-06-18 01:06:43 +02:00
parent be81d49a7b
commit c31d70b53f
5 changed files with 139 additions and 0 deletions

View File

@@ -143,6 +143,17 @@ provision-custodian-agent-host: ## Deploy custodian agent key to one host: make
cd ansible && ansible-playbook playbooks/custodian-agent.yaml -u $(SSH_USER) \
--limit "$(HOST)"
bootstrap-ssh-ca: ## Deploy OpenBao SSH CA trust + auth_principals: make bootstrap-ssh-ca SSH_CA_PUBKEY=/path/to/ca_user.pub
@test -n "$(SSH_CA_PUBKEY)" || (echo "Usage: make bootstrap-ssh-ca SSH_CA_PUBKEY=/path/to/ca_user.pub [HOST=Railiance01]"; exit 1)
cd ansible && ansible-playbook playbooks/bootstrap-ssh-ca.yaml -u $(SSH_USER) \
-e ssh_ca_pubkey_path="$(SSH_CA_PUBKEY)" \
$(if $(HOST),--limit "$(HOST)",)
bootstrap-ssh-ca-host: ## Deploy SSH CA trust to one host: make bootstrap-ssh-ca-host HOST=Railiance01 SSH_CA_PUBKEY=...
@test -n "$(HOST)" && test -n "$(SSH_CA_PUBKEY)" || \
(echo "Usage: make bootstrap-ssh-ca-host HOST=Railiance01 SSH_CA_PUBKEY=/path/to/ca_user.pub"; exit 1)
$(MAKE) bootstrap-ssh-ca SSH_CA_PUBKEY="$(SSH_CA_PUBKEY)" HOST="$(HOST)"
# ---- Orchestration ----
apply: tf-fmt tf-apply ansible-bootstrap ## Provision via Terraform then converge via Ansible

View File

@@ -0,0 +1,19 @@
# Central SSH certificate principals inventory — synced with ops-warden actor
# principals (wiki/ActorInventoryPatterns.md). Public data only.
ssh_principals:
CoulombCore:
users:
tegwick:
- agt-task-bridge
- agt-interhub-bootstrap
- adm-full
- atm-backup-daily
Railiance01:
users:
tegwick:
- agt-task-bridge
- agt-interhub-bootstrap
- adm-full
- atm-backup-daily

View File

@@ -0,0 +1,19 @@
---
# Deploy OpenBao SSH user CA trust and per-user auth_principals.
#
# Prerequisite: railiance-platform openbao-configure-ssh (exports CA pubkey).
#
# cd ~/railiance-platform
# OPENBAO_TOKEN_FILE=~/.local/openbao/platform-admin.token \
# OPENBAO_SSH_CA_PUBKEY_OUT=/tmp/openbao-ssh-ca.pub \
# make openbao-configure-ssh
#
# cd ~/railiance-infra
# make bootstrap-ssh-ca SSH_CA_PUBKEY=/tmp/openbao-ssh-ca.pub
- hosts: all
become: true
vars_files:
- ../inventory/ssh_principals.yaml
roles:
- role: ssh_ca_host

View File

@@ -0,0 +1,5 @@
---
- name: Restart sshd
ansible.builtin.service:
name: ssh
state: restarted

View File

@@ -0,0 +1,85 @@
---
- name: Require SSH CA public key path
ansible.builtin.assert:
that:
- ssh_ca_pubkey_path is defined
- ssh_ca_pubkey_path | length > 0
fail_msg: >-
Set ssh_ca_pubkey_path to the OpenBao SSH CA public key file
(from railiance-platform openbao-configure-ssh).
- name: Stat SSH CA public key source
ansible.builtin.stat:
path: "{{ ssh_ca_pubkey_path }}"
delegate_to: localhost
become: false
register: ssh_ca_pubkey_stat
- name: Fail when SSH CA public key is missing
ansible.builtin.fail:
msg: "SSH CA public key not found on controller: {{ ssh_ca_pubkey_path }}"
when: not ssh_ca_pubkey_stat.stat.exists
- name: Ensure SSH CA directory exists
ansible.builtin.file:
path: /etc/ssh/ca
state: directory
owner: root
group: root
mode: "0755"
- name: Install SSH user CA public key
ansible.builtin.copy:
src: "{{ ssh_ca_pubkey_path }}"
dest: /etc/ssh/ca/ca_user.pub
owner: root
group: root
mode: "0644"
notify: Restart sshd
- name: Configure SSH certificate trust
ansible.builtin.copy:
dest: /etc/ssh/sshd_config.d/20-ssh-ca.conf
owner: root
group: root
mode: "0644"
content: |
TrustedUserCAKeys /etc/ssh/ca/ca_user.pub
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
notify: Restart sshd
- name: Ensure auth_principals directory exists
ansible.builtin.file:
path: /etc/ssh/auth_principals
state: directory
owner: root
group: root
mode: "0755"
- name: Resolve principals for this host
ansible.builtin.set_fact:
ssh_ca_host_principals: >-
{{
(ssh_principals[inventory_hostname].users
if ssh_principals is defined
and inventory_hostname in ssh_principals
else {})
}}
- name: Deploy auth_principals files per user
ansible.builtin.copy:
dest: "/etc/ssh/auth_principals/{{ item.key }}"
owner: root
group: root
mode: "0644"
content: "{{ item.value | join('\n') }}\n"
loop: "{{ ssh_ca_host_principals | dict2items }}"
when: ssh_ca_host_principals | length > 0
notify: Restart sshd
- name: Warn when no principals configured for host
ansible.builtin.debug:
msg: >-
No principals in ssh_principals.yaml for {{ inventory_hostname }} —
CA trust installed; add users under hosts.<name>.users to enable cert login.
when: ssh_ca_host_principals | length == 0