---
# SSH Mesh CA — convert from key-based to certificate-based SSH authentication.
#
# This playbook transitions the mesh from static authorized_keys to a CA trust
# model. After running, nodes authenticate each other via certificates signed
# by a single CA keypair — no more distributing individual public keys.
#
# What it does:
#   1. Generates a CA keypair on the controller (once, idempotent).
#   2. Creates a "mesh" service user on each node.
#   3. Signs each node's host key with the CA (clients verify host identity).
#   4. Generates a per-node user keypair and signs it with the CA.
#   5. Configures sshd to present host certs and trust user certs from the CA.
#   6. Configures the mesh user's ssh_config to verify hosts via the CA.
#   7. Optionally deploys an empty KRL for future certificate revocation.
#
# Usage:
#   ansible-playbook playbooks/ssh-mesh-ca.yml                      # full mesh
#   ansible-playbook playbooks/ssh-mesh-ca.yml --limit chatmail     # single group
#   ansible-playbook playbooks/ssh-mesh-ca.yml --tags verify        # verify only
#
# Adding a new node:
#   Add it to the inventory, then re-run. The CA signs its keys automatically.
#
# Revoking a node:
#   ssh-keygen -k -f revoked_keys -u <node_cert.pub>
#   Copy revoked_keys to files/ssh-ca/mesh_revoked_keys
#   Re-run the playbook (it deploys the KRL via ssh_revoked_keys_dest).
#
# Prerequisites:
#   pip install ansible
#   ansible-galaxy collection install community.crypto
#
# Defaults (override in group_vars/host_vars as needed):
#   ssh_ca_key_type: ed25519
#   ssh_host_cert_validity: +52w (1 year)
#   ssh_user_cert_validity: +52w (1 year)
#   ssh_mesh_user: mesh
#   ssh_mesh_principals: mesh
#   ssh_mesh_port: 22

- name: Deploy SSH mesh CA certificates
  hosts: wg_mesh:chatmail
  become: true
  roles:
    - role: ssh_mesh_ca
      tags: [ssh, certs]

  post_tasks:
    # ---------- Verification ----------

    - name: Verify host certificate is present
      stat:
        path: "{{ ssh_host_cert_dest | default('/etc/ssh/ssh_host_ed25519_key-cert.pub') }}"
      register: _host_cert
      failed_when: not _host_cert.stat.exists
      tags: [verify]

    - name: Verify host certificate is valid
      command: >
        ssh-keygen -L -f {{ ssh_host_cert_dest | default('/etc/ssh/ssh_host_ed25519_key-cert.pub') }}
      changed_when: false
      tags: [verify]

    - name: Verify CA public key is deployed
      stat:
        path: "{{ ssh_ca_pubkey_dest | default('/etc/ssh/mesh_ca.pub') }}"
      register: _ca_pub
      failed_when: not _ca_pub.stat.exists
      tags: [verify]

    - name: Verify sshd config references host certificate
      command: >
        grep -q 'HostCertificate' /etc/ssh/sshd_config.d/10-mesh-ca.conf
      changed_when: false
      tags: [verify]

    - name: Verify sshd config references TrustedUserCAKeys
      command: >
        grep -q 'TrustedUserCAKeys' /etc/ssh/sshd_config.d/10-mesh-ca.conf
      changed_when: false
      tags: [verify]

    - name: Verify mesh user exists
      command: id {{ ssh_mesh_user | default('mesh') }}
      changed_when: false
      tags: [verify]

    - name: Verify mesh user certificate is present
      stat:
        path: "/home/{{ ssh_mesh_user | default('mesh') }}/.ssh/id_ed25519-cert.pub"
      register: _user_cert
      failed_when: not _user_cert.stat.exists
      tags: [verify]

    - name: Verify mesh user certificate is valid
      command: >
        ssh-keygen -L -f /home/{{ ssh_mesh_user | default('mesh') }}/.ssh/id_ed25519-cert.pub
      changed_when: false
      tags: [verify]

    - name: Verify sshd is running
      command: systemctl is-active ssh
      changed_when: false
      tags: [verify]

    - name: Display certificate summary
      shell: |
        set -euo pipefail
        echo "=== Host Certificate ==="
        ssh-keygen -L -f {{ ssh_host_cert_dest | default('/etc/ssh/ssh_host_ed25519_key-cert.pub') }} 2>&1 | grep -E 'Valid|Principals|Key ID'
        echo ""
        echo "=== User Certificate ({{ ssh_mesh_user | default('mesh') }}) ==="
        ssh-keygen -L -f /home/{{ ssh_mesh_user | default('mesh') }}/.ssh/id_ed25519-cert.pub 2>&1 | grep -E 'Valid|Principals|Key ID'
      args:
        executable: /bin/bash
      changed_when: false
      register: _cert_summary
      tags: [verify]

    - name: Show certificate summary
      debug:
        msg: "{{ _cert_summary.stdout_lines }}"
      tags: [verify]
