Skip to content

Instantly share code, notes, and snippets.

@zoredache
Last active October 5, 2021 08:22
Show Gist options
  • Save zoredache/88ae53edf7fce081ef5912199614332e to your computer and use it in GitHub Desktop.
Save zoredache/88ae53edf7fce081ef5912199614332e to your computer and use it in GitHub Desktop.
sign_ssh_host_keys.yml
---
# signing key generated with
#
# ssh-keygen -t ed25519 -f 20200624_ca_ed25519 -C 20200624_ca_ed25519 -N ""
#
# encrypted with ansible-vault
#
# ansible-vault encrypt 20200624_ca_ed25519
- hosts: localhost:linux_systems
gather_facts: no
vars:
ansible_ssh_extra_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o HostKeyAlias={{ inventory_hostname }}"
ca_name: 20200624_ca_ed25519
tasks:
- name: localhost must be included when using limit
assert:
that:
- "'localhost' in ansible_play_hosts_all"
- "ansible_limit is undefined or 'localhost' in ansible_limit"
fail_msg: play must be include localhost
- gather_facts:
# Curently buggy.
# https://github.com/ansible/ansible/issues/70339
# I fixed locally with a patch, but you might want to just handle this with lineinfile
- name: deploy ca public key to ssh_known_hosts
known_hosts:
name: '@cert-authority *.example.org'
path: /etc/ssh/ssh_known_hosts
key: "{{ lookup('file', 'sshca/'~ca_name~'.known_host') }}"
- name: create temporary directory
when: inventory_hostname == 'localhost'
changed_when: no
tempfile:
state: directory
prefix: ansible_hostkeys
register: tempdir
- name: copy+decrypt the ssh ca
when: inventory_hostname == 'localhost'
copy:
mode: '0600'
src: sshca/{{ ca_name }}
dest: "{{ hostvars['localhost']['tempdir']['path'] }}/{{ ca_name }}"
- name: fetch the host keys
when: ansible_ssh_host_key_ed25519_public is defined and inventory_hostname !='localhost'
fetch:
fail_on_missing: no
src: "{{ item.src }}"
dest: "{{ hostvars['localhost']['tempdir']['path'] }}"
loop:
- src: /etc/ssh/ssh_host_ed25519_key.pub
- src: /etc/ssh/ssh_host_ed25519_key-cert.pub
changed_when: no
- name: Sign host key
when: ansible_ssh_host_key_ed25519_public is defined and inventory_hostname !='localhost'
delegate_to: localhost
shell: >
ssh-keygen -s "{{ hostvars['localhost']['tempdir']['path'] }}/{{ ca_name }}"
-I {{ inventory_hostname }} -h -n "{{ ','.join(cert_principals | sort | unique | reject('eq','') | list) }}"
-V -1d:forever "{{ hostvars['localhost']['tempdir']['path'] }}/{{ inventory_hostname }}/etc/ssh/ssh_host_ed25519_key.pub"
args:
creates: "{{ hostvars['localhost']['tempdir']['path'] }}/{{ inventory_hostname }}/etc/ssh/ssh_host_ed25519_key-cert.pub"
vars:
cert_principals:
- "{{ inventory_hostname }}"
- "{{ inventory_hostname_short }}"
- "{{ hostvars[inventory_hostname]['ansible_host']|default('')
if hostvars[inventory_hostname]['ansible_host'] is defined and
not hostvars[inventory_hostname]['ansible_host']|ipaddr
else '' }}"
- name: Upload the signed certificates
when: ansible_ssh_host_key_ed25519_public is defined and inventory_hostname !='localhost'
copy:
dest: /etc/ssh/ssh_host_ed25519_key-cert.pub
src: "{{ hostvars['localhost']['tempdir']['path'] }}/{{ inventory_hostname }}/etc/ssh/ssh_host_ed25519_key-cert.pub"
- name: Remove temporary directory
delegate_to: localhost
run_once: yes
changed_when: no
file:
state: absent
path: "{{ tempdir.path }}"
- name: Add certificates to SSH configuration file.
when: ansible_ssh_host_key_ed25519_public is defined and inventory_hostname !='localhost'
register: sshd_config
lineinfile:
dest: /etc/ssh/sshd_config
line: HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
state: present
insertafter: ^#?HostKey .*$
validate: /usr/sbin/sshd -t -f %s
- name: restart sshd
when: sshd_config is changed
service:
name: ssh
state: restarted
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment