diff --git a/README.md b/README.md index a6e428b..6abcd41 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ You need to have the Python library `cryptography` in version `>1.2.3` available * `ca_logstash`: Create Logstash compatible certificate as well. Needs `ca_server_cert` to be set. (default: `false`) * `ca_etcd`: Create additional etcd compatible certificates. Requires `ca_etcd_group` to be defined. (default: `false`) * `ca_etcd_group`: Needs to be set to the group name of etcd nodes and will add the default IPv4 address of each node to the certificates. 127.0.0.1 will also be added by the role to the SAN for loopback purposes.(default: `undefined`) +* `ca_san_extra`: Extra subject alternative names for the client and server certificates of a host, for example `["IP:192.0.2.10", "DNS:lb.example.com"]`. (default: `[]`) * `ca_keypassphrase`: Password for the client key, default not defined * `ca_openssl_cipher`: Cipher to use for key creation, default not defined * `ca_client_ca_dir`: Directory to place CA and certificates on the clients (default: `/opt/ca`) diff --git a/defaults/main.yml b/defaults/main.yml index f00a5c0..9084b68 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -15,6 +15,8 @@ ca_server_cert: true ca_logstash: false ca_etcd: false +ca_san_extra: [] + ca_country: EX ca_state: EX ca_locality: EX diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index 0410f09..303d4c4 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -27,5 +27,11 @@ provisioner: config_options: defaults: roles_path: "$MOLECULE_PROJECT_DIRECTORY/.." + inventory: + host_vars: + ca_default_client: + ca_san_extra: + - IP:192.0.2.10 + - DNS:lb.example.com verifier: name: ansible diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index 789fab0..873b0f4 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -116,3 +116,34 @@ - hostvars['ca_default_client']['ansible_default_ipv4']['address'] not in etcd_san_server_stat.stdout - '"127.0.0.1" not in etcd_san_server_stat.stdout' + + - name: Register SAN of client and server certificate + command: > + openssl x509 -noout -ext subjectAltName + -in {{ ca_client_ca_dir }}/{{ inventory_hostname }}{{ item }}.crt + loop: + - "" + - "-server" + register: san_stat + changed_when: false + + # openssl prints an IP entry as "IP Address:192.0.2.10" + - name: Fail if an entry of ca_san_extra is missing + fail: + msg: >- + {{ item.1 }} is missing in + {{ inventory_hostname }}{{ item.0.item }}.crt + loop: "{{ san_stat.results | product(san_extra) | list }}" + vars: + san_extra: "{{ ca_san_extra | default([]) }}" + when: item.1 | regex_replace('^IP:', 'IP Address:') not in item.0.stdout + + - name: Fail if a host without ca_san_extra got the extra names + fail: + msg: >- + {{ inventory_hostname }}{{ item.item }}.crt + contains names of ca_san_extra + loop: "{{ san_stat.results }}" + when: + - ca_san_extra is not defined + - "'192.0.2.10' in item.stdout or 'lb.example.com' in item.stdout" diff --git a/tasks/main.yml b/tasks/main.yml index f7e5435..8e25a2a 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -44,6 +44,11 @@ DNS:{{ ansible_fqdn }}, DNS:{{ inventory_hostname }} +- name: Add ca_san_extra to ca_san + ansible.builtin.set_fact: + ca_san: "{{ ([ca_san] + ca_san_extra) | join(', ') }}" + when: ca_san_extra | length > 0 + ### client certificate ### - name: Create key