From b4eaaeb9ccc4910dc2505cacf33d0026b22de3e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Douglas=20Mendiz=C3=A1bal?= Date: Mon, 13 Jul 2020 15:41:50 -0500 Subject: [PATCH] Add support for High Availability This patch adds the ability to configure the Luna Network HSM client to use more than one HSM for high availability (HA) mode. Change-Id: If0eb393ca970206cc95c7453641f33781eb698b2 --- README.rst | 27 ++++++++----- defaults/main.yaml | 12 +----- tasks/main.yaml | 63 +++++++++++++++++++++++++------ tasks/register_client.yaml | 77 ++++++++++++++++++++++++++++++++++++++ tasks/register_hsm.yaml | 56 --------------------------- 5 files changed, 148 insertions(+), 87 deletions(-) create mode 100644 tasks/register_client.yaml delete mode 100644 tasks/register_hsm.yaml diff --git a/README.rst b/README.rst index 8359007..15bec95 100644 --- a/README.rst +++ b/README.rst @@ -1,11 +1,14 @@ lunasa-hsm ========== -A role to manage Safenet Lunasa Hardware Security Module (HSM) client software. +A role to manage Thales Luna Network Hardware Security Module (HSM) clients. Role Variables -------------- +This ansible role automates the configuration of a new client for the +Thales Luna Network HSM. + .. list-table:: :widths: auto :header-rows: 1 @@ -25,18 +28,22 @@ Role Variables * - lunasa_client_installer_path - None - Path to the instal.sh script inside the tarball. - * - lunasa_hsm_server_hostname + * - lunasa_client_pin - None - - Hostnme for the Lunasa HSM. - * - lunasa_hsm_server_admin_password - - None - - Password for the admin user for the Lunasa HSM. - * - lunasa_hsm_partition - - None - - HSM Partition to assign the client. + - The HSM Partition Password (PKCS#11 PIN) to be used by the client. * - lunasa_client_ip - None - - IP to use when registering the client. + - (Optional) When set, this role will use the given IP to register + the client instead of the client's fqdn. + * - lunasa_client_rotate_cert + - False + - When set to True, the role will generate a new client certificate + to replace the previous one. + * - lunasa_hsms + - None + - List of dictionaries, each of which describes a single HSM + `see vars.sample.yaml` for details. When more than one HSM is + listed here, the client will be configured in HA mode. Requirements ------------ diff --git a/defaults/main.yaml b/defaults/main.yaml index 2038406..b28987c 100644 --- a/defaults/main.yaml +++ b/defaults/main.yaml @@ -1,12 +1,4 @@ --- -# TODO: maybe use random tmpdir here lunasa_client_working_dir: /tmp/lunasa_client_install - -# non-defaults -#lunasa_client_tarball_location: http://download-node-02.eng.bos.redhat.com/qa/rhts/lookaside/IdM/rhcs/lunasa_software/610-012382-014_SW_Client_HSM_6.2_RevA.tar.zip -#lunasa_client_tarball_name: 610-012382-014_SW_Client_HSM_6.2_RevA.tar.zip -#lunasa_client_installer_path: 610-012382-014_SW_Client_HSM_6.2_RevA/linux/64/install.sh -#lunasa_hsm_server_hostname: os-luna-hsm-1.perf.lab.eng.rdu2.redhat.com -#lunasa_hsm_server_admin_password: ABC123!!! -#lunasa_hsm_partition: secdfgPartition1 -#lunasa_client_ip: 10.0.79.37 +lunasa_client_rotate_cert: false +lunasa_ha_label: myHAgroup diff --git a/tasks/main.yaml b/tasks/main.yaml index 8b97462..20f93c1 100644 --- a/tasks/main.yaml +++ b/tasks/main.yaml @@ -1,9 +1,9 @@ --- - name: Create working directory file: - path: "{{ lunasa_client_working_dir }}" - state: directory - mode: 0755 + path: "{{ lunasa_client_working_dir }}" + state: directory + mode: 0755 - name: Download Lunasa client tarball get_url: @@ -26,22 +26,59 @@ creates: /usr/lib/libCryptoki2_64.so become: true -- name: register the client to the HSMs - include_tasks: register_hsm.yaml - loop: "{{ lunasa_hsms }}" +- name: set client facts for fqdn + set_fact: + client_name: "{{ ansible_fqdn }}" + client_reg_opt: "-hostname" + client_host: "{{ ansible_fqdn }}" + client_cert_cn: "{{ inventory_hostname }}" + when: lunasa_client_ip is undefined + +- name: set client facts for IP override + set_fact: + client_name: "{{ ansible_fqdn }}" + client_reg_opt: "-ip" + client_host: "{{ lunasa_client_ip }}" + client_cert_cn: "{{ lunasa_client_ip }}" + when: lunasa_client_ip is defined + +- name: Check for existing client cert + stat: + path: "/usr/safenet/lunaclient/cert/client/{{ client_host }}.pem" + register: client_cert + +- name: Generate a new client cert for NTL + command: /usr/safenet/lunaclient/bin/vtl createCert -n "{{ client_cert_cn }}" + become: true + register: created_cert + when: not client_cert.stat.exists or lunasa_client_rotate_cert + +- name: Note when a new cert is created + set_fact: + client_new_cert: "{{ created_cert.changed }}" + +- name: register the client on each HSM + include_tasks: register_client.yaml vars: - hsm_name: "{{ item.name }}" hsm_hostname: "{{ item.hostname }}" hsm_admin_password: "{{ item.admin_password }}" - client_ip: "{{ item.client_ip }}" hsm_partition: "{{ item.partition }}" + loop: "{{ lunasa_hsms }}" - name: verify the NTL connection command: /usr/safenet/lunaclient/bin/vtl verify become: true + register: vtl_verify + +- name: Fail if NTL connection doesn't verify + fail: + msg: > + ERROR: 'vtl verify' failed. This is commonly due to network NAT between + the client and the HSM. Try disabling client IP checking in the HSM + when: "'Error: Unable to find any Luna SA slots/partitions' in vtl_verify.stdout" - name: create hsm ha partition - when: lunasa_ha_label is defined + when: lunasa_hsms | length > 1 become: true block: - name: create ha partition @@ -49,7 +86,7 @@ echo 'copy' | /usr/safenet/lunaclient/bin/lunacm -c hagroup createGroup \ -label {{ lunasa_ha_label }} \ -serialNumber {{ lunasa_hsms[0].partition_serial }} \ - -password {{ lunasa_partition_password }} + -password {{ lunasa_client_pin }} register: result failed_when: - "'Command Result : No Error' not in result.stdout" @@ -60,7 +97,7 @@ echo 'copy' | /usr/safenet/lunaclient/bin/lunacm -c hagroup addMember \ -group {{ lunasa_ha_label }} \ -serialNumber {{ item.partition_serial }} \ - -password {{ lunasa_partition_password }} + -password {{ lunasa_client_pin }} loop: "{{ lunasa_hsms }}" loop_control: extended: yes @@ -86,3 +123,7 @@ - name: Set HA Slot fact for use by the playbook calling this role set_fact: lunasa_ha_slot: "{{ slot_result.stdout }}" + + - name: Log the HA Slot ID used + debug: + var: lunasa_ha_slot diff --git a/tasks/register_client.yaml b/tasks/register_client.yaml new file mode 100644 index 0000000..401fccc --- /dev/null +++ b/tasks/register_client.yaml @@ -0,0 +1,77 @@ +--- +- name: Log when client is being registered to HSM + debug: + msg: "Registering client: {{ client_name }} [{{ client_host }}] with HSM: {{ hsm_hostname }}" + +- name: Get the hsm server cert from the hsm_server + shell: > + sshpass -p '{{ hsm_admin_password }}' + scp -o StrictHostKeyChecking=false -c aes256-cbc + admin@{{ hsm_hostname }}:server.pem + /usr/safenet/lunaclient/bin/{{ hsm_hostname }}.pem + args: + creates: /usr/safenet/lunaclient/bin/{{ hsm_hostname }}.pem + become: true + +- name: Register the HSM server cert with the client + shell: > + /usr/safenet/lunaclient/bin/vtl addServer -n {{ hsm_hostname }} + -c /usr/safenet/lunaclient/bin/{{ hsm_hostname }}.pem + register: add_server + become: true + failed_when: + - add_server.rc != 0 + - '"This server is already registered" not in add_server.stdout' + +- name: Check for existing clients + shell: > + sshpass -p '{{ hsm_admin_password }}' + ssh -o StrictHostKeyChecking=false -c aes256-cbc admin@{{ hsm_hostname }} + -C client list + register: client_list + +- name: Fail if client is already registered, but we don't have that cert + fail: + msg: "Client: {{ client_name }} is already registered, but the client cert is missing!" + when: + - client_name in client_list.stdout + - client_new_cert + - not lunasa_client_rotate_cert + +- name: Delete existing client when rotating certs + shell: > + sshpass -p '{{ hsm_admin_password }}' ssh -c aes256-cbc admin@{{ hsm_hostname }} + -C "client delete -f -c {{ client_name }}" + when: + - client_name in client_list.stdout + - lunasa_client_rotate_cert + +- name: Register the client certificate on the hsm_server + block: + - name: Copy the NTL client cert to the HSM + shell: > + sshpass -p '{{ hsm_admin_password }}' scp -c aes256-cbc + /usr/safenet/lunaclient/cert/client/{{ client_host }}.pem + admin@{{ hsm_hostname }}:{{ client_host }}.pem + + - name: Register the client + shell: > + sshpass -p '{{ hsm_admin_password }}' ssh -c aes256-cbc admin@{{ hsm_hostname }} + -C "client register -c {{ client_name }} {{ client_reg_opt }} {{ client_host }}" + register: client_register + failed_when: + - client_register.rc != 0 + - "'client with the same IP address has already been registered' not in client_register.stdout" + become: true + when: client_name not in client_list.stdout or lunasa_client_rotate_cert + +- name: Assign client to an HSM partition + shell: | + sshpass -p '{{ hsm_admin_password }}' ssh -c aes256-cbc admin@{{ hsm_hostname }} \ + -C "client assignPartition -c {{ client_name }} -p {{ hsm_partition }}" + register: assign_partition + failed_when: + - assign_partition.rc != 0 + - "'client already has access' not in assign_partition.stdout" + become: true + diff --git a/tasks/register_hsm.yaml b/tasks/register_hsm.yaml deleted file mode 100644 index ab893dd..0000000 --- a/tasks/register_hsm.yaml +++ /dev/null @@ -1,56 +0,0 @@ ---- -- debug: - msg: "Registering the following HSM: {{ hsm_name }}" - -- name: Get the hsm server cert from the hsm_server - shell: | - sshpass -p '{{ hsm_admin_password }}' \ - scp -o StrictHostKeyChecking=false admin@{{ hsm_hostname }}:server.pem /usr/safenet/lunaclient/bin/{{ hsm_hostname }}.pem - become: true - -- name: Register the HSM server cert with the client - shell: | - /usr/safenet/lunaclient/bin/vtl addServer -n {{ hsm_hostname }} \ - -c /usr/safenet/lunaclient/bin/{{ hsm_hostname }}.pem - register: add_server - become: true - failed_when: - - add_server.rc != 0 - - '"This server is already registered" not in add_server.stdout' - -- name: Set the cert file name - set_fact: - client_name: "{{ inventory_hostname }}" - -- name: Create a client cert for NTL - command: /usr/safenet/lunaclient/bin/vtl createCert -n "{{ client_ip }}" - args: - creates: "/usr/safenet/lunaclient/cert/client/{{ client_ip }}.pem" - become: true - -- name: Copy the NTL client cert to the HSM - shell: | - sshpass -p '{{ hsm_admin_password }}' scp /usr/safenet/lunaclient/cert/client/{{ client_ip }}.pem \ - admin@{{ hsm_hostname }}:{{ client_ip }}.pem - become: true - -# A client with the same hostname has already been registered -- name: Register the client certificate on the hsm_server - shell: | - sshpass -p '{{ hsm_admin_password }}' ssh admin@{{ hsm_hostname }} \ - -C "client register -c {{ client_name }} -ip {{ client_ip }}" - register: client_register - failed_when: - - client_register.rc != 0 - - "'client with the same IP address has already been registered' not in client_register.stdout" - become: true - -- name: Assign client to an HSM partition - shell: | - sshpass -p '{{ hsm_admin_password }}' ssh admin@{{ hsm_hostname }} \ - -C "client assignPartition -c {{ client_name }} -p {{ hsm_partition }}" - register: assign_partition - failed_when: - - assign_partition.rc != 0 - - "'client already has access' not in assign_partition.stdout" - become: true