---
#
# We have some tasks here in case this is a bare metal machine
# and we are provisioning it for the first time. 
# virtual machines are handled in tasks/virt-instance-create
#

- name: make sure there is no old ssh host key for the host still around
  local_action: known_hosts path={{item}} host={{ inventory_hostname }} state=absent
  ignore_errors: True
  with_items:
  - /root/.ssh/known_hosts
  when: birthday is defined

- name: gather ssh host key from new instance
  local_action: command ssh-keyscan -t rsa {{ inventory_hostname }}
  ignore_errors: True
  register: hostkey
  when: birthday is defined

- name: add new ssh host key (until we can sign it)
  local_action: known_hosts path={{item}} key="{{ hostkey.stdout }}" host={{ inventory_hostname }} state=present
  ignore_errors: True
  with_items:
  - /root/.ssh/known_hosts
  when: birthday is defined

- name: make sure libselinux-python is installed
  package: name=libselinux-python state=present
  tags:
  - basessh
  - sshd_config
  - config
  - sshd
  - selinux
  when: ansible_distribution == 'RedHat' and ansible_distribution_major_version|int < 8 

- name: make sure python3-libselinux is installed
  package: name=python3-libselinux state=present
  tags:
  - basessh
  - sshd_config
  - config
  - sshd
  - selinux
  when: ( ansible_distribution == 'Fedora' and ansible_distribution_major_version|int >= 30 ) or ( ansible_distribution == 'RedHat' and ansible_distribution_major_version|int >= 8 )

- name: check if sshd port is already known by selinux
  shell: semanage port -l | grep ssh
  register: sshd_selinux_port
  check_mode: no
  changed_when: false
  failed_when: false
  tags:
  - basessh
  - sshd_config
  - config
  - sshd
  - selinux
  - base

- name: allow alternate sshd port
  command: semanage port -a -t ssh_port_t -p tcp {{ sshd_port }}
  when: sshd_port in sshd_selinux_port
  failed_when: false
  tags:
  - basessh
  - sshd_config
  - config
  - sshd
  - selinux
  - base

- name: sshd_config
  template: src=sshd_config dest=/etc/ssh/sshd_config mode=0600
  notify:
  - restart sshd
  tags:
  - basessh
  - sshd_config
  - config
  - sshd
  - base

- name: Determine SSH keys generated by this machine
  find: paths=/etc/ssh
        file_type=file
      patterns="ssh_host_*_key"
  register: ssh_key_files
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

- name: Determine SSH keys never signed
  stat: path="{{item.path}}-cert.pub"
  with_items: "{{ssh_key_files.files}}"
  register: ssh_cert_files
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

- name: Set lists of certs to sign to empty
  set_fact:
    certs_to_sign: []
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

- name: Set list of certs to sign
  set_fact:
    certs_to_sign: "{{ certs_to_sign + [item.item.path] }}"
  with_items: "{{ssh_cert_files.results}}"
  when: not item.stat.exists
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

# Renew if last mod was more than 10 months ago
- name: Get soon-to-expire certificates to sign
  set_fact:
    certs_to_sign: "{{ certs_to_sign + [item.item.path] }}"
  with_items: "{{ssh_cert_files.results}}"
  when: "item.stat.exists and item.stat.mtime|int < (lookup('pipe', 'date +%s')|int - 25920000)"
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

- set_fact:
    pubkeydir: "/tmp/sshkeysign/{{inventory_hostname}}"
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

- name: Create directory for storing pubkeys
  file: path="{{pubkeydir}}"
        owner=root
        group=root
        mode=0600
        state=directory
  delegate_to: localhost
  run_once: true
  changed_when: False
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

- name: Get public keys for certs to sign
  fetch: src="{{item}}.pub"
         dest="{{pubkeydir}}"
         fail_on_missing=false
  with_items: "{{certs_to_sign}}"
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

- name: Set some extra signing facts
  set_fact:
    sign_hostnames: "{{ssh_hostnames + [inventory_hostname]}}"
    sign_validity: "-1h:+52w"
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

# Currently, we use the epoch as serial. That's unique enough for now
- name: Sign the certificates
  shell: "ssh-keygen -s {{private}}/files/ssh/{{env}}_ca_host_key -t rsa-sha2-256 -I {{inventory_hostname}} -h -n {{ sign_hostnames|join(',') }} -V {{sign_validity}} -z `date +%s` {{pubkeydir}}/{{inventory_hostname}}{{item}}.pub"
  delegate_to: localhost
  with_items: "{{certs_to_sign}}"
  check_mode: no
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

- name: Copy the certificates
  copy: src="{{pubkeydir}}/{{inventory_hostname}}{{item}}-cert.pub"
        dest="{{item}}-cert.pub"
  with_items: "{{certs_to_sign}}"
  register: certcopy
  notify:
  - restart sshd
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

- name: Remove the generated certificates
  local_action: file path="{{pubkeydir}}/{{inventory_hostname}}" state=absent
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

- name: Restart sshd in case we just signed a new certificate so it gets applied
  service: name=sshd state=restarted
  when: certcopy.changed
  tags:
  - basessh
  - sshd_cert
  - sshd_config
  - config
  - sshd
  - base

- name: make sure there is no old ssh host key for the host still around
  local_action: known_hosts path={{item}} host={{ inventory_hostname }} state=absent
  ignore_errors: True
  with_items:
  - /root/.ssh/known_hosts
