From 56b505cf94b900a4de0099d21d7992f8173b0738 Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Wed, 16 Sep 2020 14:19:19 +0200 Subject: [PATCH] init --- README.adoc | 110 ++++++++++++++++++++++++++++++++++ defaults/main.yml | 2 + files/ssh-cert-renew | 6 ++ files/ssh-cert-renew@.service | 8 +++ files/ssh-cert-renew@.timer | 8 +++ handlers/main.yml | 2 + meta/main.yml | 53 ++++++++++++++++ tasks/main.yml | 102 +++++++++++++++++++++++++++++++ tests/inventory | 2 + tests/test.yml | 5 ++ vars/main.yml | 9 +++ 11 files changed, 307 insertions(+) create mode 100644 README.adoc create mode 100644 defaults/main.yml create mode 100755 files/ssh-cert-renew create mode 100644 files/ssh-cert-renew@.service create mode 100644 files/ssh-cert-renew@.timer create mode 100644 handlers/main.yml create mode 100644 meta/main.yml create mode 100644 tasks/main.yml create mode 100644 tests/inventory create mode 100644 tests/test.yml create mode 100644 vars/main.yml diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..908509d --- /dev/null +++ b/README.adoc @@ -0,0 +1,110 @@ +ssh_cert +======== + +Implements SSH-Certificate-renewal on hosts. +The renewal-process connects to ssh-ca-host and fetches a new certificate, if needed. + +These renewal can be used for host-certificates and user-certificates. + +Prepares `sshd_config` to use the CA and the host-certificate. + +Requirements +------------ + +systemd is required, so it would not work on alpine or openwrt, yet. + +Role Variables +-------------- + +ssh_ca_host:: +Hostmachine for CA. +This is not host-specific, so you should change it for all hosts or neither. +Must match with `ssh_ca`-role. + +ssh_ca_user:: +Hostmachine for CA. +This is not host-specific, so you should change it for all hosts or neither. +Must match with `ssh_ca`-role. +Default: `sshca` + +ssh_ca_base_dir:: +Path to CA base on ssh-ca-host. +This is not host-specific, so you should change it for all hosts or neither. +Must match with `ssh_ca`-role. +Default: `~/.ssh-ca` + +ssh_cert_mail_to:: +If you want to be informed on renewal or errors, provide a mailto-address. +Mandatory, yet. + +ssh_cert_mail_from:: +If you want to be informed on renewal or errors, provide an address of sender. +Mandatory, yet. + +ssh_cert_sign_host:: +Default: `{{ssh_ca_user}}@{{ssh_ca_host}}` + +ssh_cert_host_pub_path:: +Path to host-key-pub on host-machine. +Would be used like a CSR. +Default: `/etc/ssh/ssh_host_ed25519_key.pub` + +ssh_cert_host_cert_path:: +Where to place the host-certificate on host-machine? +Default: `/etc/ssh/ssh_host_ed25519_key-cert.pub` + +ssh_cert_host_capub_path:: +Where to place the CA on host-machine? +Default: `/etc/ssh/ca.pub` + +ssh_cert_user_pub_path:: +Path to user-key-pub on host-machine. +Would be used like a CSR. +Default: `~/.ssh/id_ed25519.pub` + +ssh_cert_user_cert_path:: +Where to place the user-certificate on host-machine? +Default: `~/.ssh/id_ed25519-cert.pub` + +ssh_cert_host_addition_ids:: +Additional IDs (as list) placed in certificate. +For host-keys, additional hostnames like `git.example.net`. +Default is empty. + +Dependencies +------------ + +* ssh-ca + +Example Playbook +---------------- + +Optional, use ssh-ca-role before: + +---- +- name: SSH-CA + hosts: ssh_ca_server + roles: + - role: ssh-ca +---- + +This you need only on one machine. + +Then use the regular role: + +---- +- name: SSH-Cert + hosts: hosts + roles: + - role: ssh-cert +---- + +License +------- + +AGPLv3 + +Author Information +------------------ + +Denis Knauf - https://git.denkn.at/deac/ansible-role-ssh-cert diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..5746bf8 --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for ssh-ca \ No newline at end of file diff --git a/files/ssh-cert-renew b/files/ssh-cert-renew new file mode 100755 index 0000000..6a06001 --- /dev/null +++ b/files/ssh-cert-renew @@ -0,0 +1,6 @@ +#!/usr/bin/env sh +set -e +ssh_ca_host="$1" +filepf="$2" +>"${filepf}-cert.pub.tmp" ssh -o BatchMode=true -i "${filepf}" "${ssh_ca_host}" renew show +mv "${filepf}-cert.pub.tmp" "${filepf}-cert.pub" diff --git a/files/ssh-cert-renew@.service b/files/ssh-cert-renew@.service new file mode 100644 index 0000000..aba5eb9 --- /dev/null +++ b/files/ssh-cert-renew@.service @@ -0,0 +1,8 @@ +[Unit] +Description=Renewal ssh host certificate %i + +[Service] +EnvironmentFile=/etc/default/ssh-cert-renew +Type=oneshot +ExecStart=/usr/local/bin/timer-mail -t ${ssh_ca_mail_to} -f ${ssh_ca_mail_from} -s "ssh certificate renewal %i" -ve \ + /etc/systemd/ssh-cert-renew ${ssh_ca_sign_host} /etc/ssh/%i diff --git a/files/ssh-cert-renew@.timer b/files/ssh-cert-renew@.timer new file mode 100644 index 0000000..d3c54e3 --- /dev/null +++ b/files/ssh-cert-renew@.timer @@ -0,0 +1,8 @@ +[Unit] +Description=Renewal ssh host certificate %i + +[Install] +WantedBy=timers.target + +[Timer] +OnCalendar=4:00 diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..d4e2697 --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for ssh-ca \ No newline at end of file diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 0000000..227ad9c --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,53 @@ +galaxy_info: + author: your name + description: your role description + company: your company (optional) + + # If the issue tracker for your role is not on github, uncomment the + # next line and provide a value + # issue_tracker_url: http://example.com/issue/tracker + + # Choose a valid license ID from https://spdx.org - some suggested licenses: + # - BSD-3-Clause (default) + # - MIT + # - GPL-2.0-or-later + # - GPL-3.0-only + # - Apache-2.0 + # - CC-BY-4.0 + license: license (GPL-2.0-or-later, MIT, etc) + + min_ansible_version: 2.9 + + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + # + # Provide a list of supported platforms, and for each platform a list of versions. + # If you don't wish to enumerate all versions for a particular platform, use 'all'. + # To view available platforms and versions (or releases), visit: + # https://galaxy.ansible.com/api/v1/platforms/ + # + # platforms: + # - name: Fedora + # versions: + # - all + # - 25 + # - name: SomePlatform + # versions: + # - all + # - 1.0 + # - 7 + # - 99.99 + + galaxy_tags: [] + # List tags for your role here, one per line. A tag is a keyword that describes + # and categorizes the role. Users find roles by searching for tags. Be sure to + # remove the '[]' above, if you add tags to this list. + # + # NOTE: A tag is limited to a single word comprised of alphanumeric characters. + # Maximum 20 tags per role. + +dependencies: [] + # List your role dependencies here, one per line. Be sure to remove the '[]' above, + # if you add dependencies to this list. + \ No newline at end of file diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..388d98f --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,102 @@ +--- +# vim: set expandtab tabstop=2 shiftwidth=2: + +- name: Pull host pub + register: host_pub + slurp: + src: '{{ssh_cert_host_pub_path}}' + #dest: '{{ssh_cert_base_dir}}/host-{{inventory_hostname}}.pub' + #flat: true +- set_fact: + host_pub_type: '{{(host_pub.content | b64decode).split(" ")[0]}}' + host_pub_hash: '{{(host_pub.content | b64decode).split(" ")[1]}}' + principals: "{{lookup( 'flattened', + [inventory_hostname, inventory_hostname+'.'+domain, inventory_hostname+'.local'] + + lookup ('dig', inventory_hostname, 'qtype=A', wantlist=True)|difference('NXDOMAIN') + + lookup ('dig', inventory_hostname, 'qtype=AAAA', wantlist=True)|difference('NXDOMAIN') + + (ssh_cert_host_addition_ids | default ([])) + )}}" +- name: Register host pub for sshca + remote_user: root + delegate_to: '{{ssh_ca_host}}' + authorized_key: + user: '{{ssh_ca_user}}' + state: present + key: '{{host_pub_type}} {{host_pub_hash}} {{inventory_hostname}}' + key_options: 'restrict,command="/var/lib/sshca/ssh-ca host {{inventory_hostname|quote}} {{principals|quote}}"' + +- name: Push ca pub + copy: + src: '{{ssh_cert_host_capub_path}}' + dest: '{{ssh_cert_host_capub_path}}' + mode: 0644 + owner: root + group: root +- name: sshd_config - HostCertificate + lineinfile: + path: /etc/ssh/sshd_config + insertbefore: '^# HostKeys for protocol' + regexp: '^\s*HostCertificate\s+' + line: 'HostCertificate {{ssh_cert_host_cert_path}}' +- name: known_hosts ca-cert + known_hosts: + hash_host: false + path: /etc/ssh/ssh_known_hosts + name: denkn.at + key: "@cert-authority * {{lookup('file', ssh_cert_host_capub_path)}}" + +- name: install ssh-cert-renew + copy: + dest: '{{item.value}}' + src: '{{item.key}}' + mode: 0644 + owner: root + group: root + with_dict: + ssh-cert-renew@.timer: /etc/systemd/system/ssh-cert-renew@.timer + ssh-cert-renew@.service: /etc/systemd/system/ssh-cert-renew@.service +- name: install ssh-cert-renew + copy: + dest: '{{item.value}}' + src: '{{item.key}}' + mode: 0755 + owner: root + group: root + with_dict: + ssh-cert-renew: /etc/systemd/ssh-cert-renew + +- name: config ssh-cert-renew + lineinfile: + create: true + path: '/etc/default/ssh-cert-renew' + regexp: '^\s*{{item.key}}=' + line: '{{item.key}}={{item.value}}' + with_dict: + ssh_cert_mail_to: '{{ssh_cert_mail_to |mandatory}}' + ssh_cert_mail_from: '{{ssh_cert_mail_from|mandatory}}' + ssh_cert_sign_host: '{{ssh_cert_sign_host|mandatory}}' + +- name: renew ssh-cert + systemd: + daemon_reload: true + name: "ssh-cert-renew@ssh_host_ed25519_key.service" + state: started +- name: enable services + systemd: + name: '{{item}}' + enabled: true + state: started + with_items: + - "ssh-cert-renew@ssh_host_ed25519_key.timer" + - ssh.service + +- name: reload ssh + service: + name: ssh + state: reloaded + +- name: remove from local known_hosts + known_hosts: + state: absent + host: '{{item}}' + with_items: '{{principals.split(",")}}' diff --git a/tests/inventory b/tests/inventory new file mode 100644 index 0000000..878877b --- /dev/null +++ b/tests/inventory @@ -0,0 +1,2 @@ +localhost + diff --git a/tests/test.yml b/tests/test.yml new file mode 100644 index 0000000..2a3735e --- /dev/null +++ b/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - ssh-ca \ No newline at end of file diff --git a/vars/main.yml b/vars/main.yml new file mode 100644 index 0000000..67baa8e --- /dev/null +++ b/vars/main.yml @@ -0,0 +1,9 @@ +ssh_ca_user: sshca +ssh_ca_base_dir: ~/.ssh-ca +ssh_cert_sign_host: '{{ssh_ca_host}}' +ssh_cert_host_pub_path: /etc/ssh/ssh_host_ed25519_key.pub +ssh_cert_host_cert_path: /etc/ssh/ssh_host_ed25519_key-cert.pub +ssh_cert_host_capub_path: /etc/ssh/ca.pub +ssh_cert_user_pub_path: ~/.ssh/id_ed25519.pub +ssh_cert_user_cert_path: ~/.ssh/id_ed25519-cert.pub +#ssh_cert_host_addition_ids: []