diff --git a/roles/sed_configure/README.md b/roles/sed_configure/README.md new file mode 100644 index 00000000..5260478c --- /dev/null +++ b/roles/sed_configure/README.md @@ -0,0 +1,35 @@ +Role Definition +------------------------------- +- Role name: sed +- Definition: + - The self-encrypting drives (SED) support protects data at rest on IBM Storage Scale System drives. + - TPM is a specialized hardware security chip that provides secure cryptographic functions. + - mmvdisk tpm , esstpm and esstpmkey provides options to setup the tpm ,generate keys, enroll drives with the generated keys in the IBM Storage Scale cluster. + - These operations are performed on the I/O nodes and the keys generated are also backed up on the utility node. + + +Prerequisite +---------------------------- +- Red Hat Enterprise Linux 9.x is supported. +- OpenSSL version 3+ is supported. +- TPM version 2.0 is required to use this support +- A password file with appropriate permissions (600) must exist for taking TPM ownership. + +Design +--------------------------- +- Directory Structure: + - Path: /ibm-spectrum-scale-install-infra/roles/sed_configure + - Inside the sed role, there are sub-tasks to setup the TPM stepwise + - `check_prereq`: This task checks that all the prerequisites are satisfied before proceeding with the TPM setup. It checks the following things: + - RHEL 9.x is present. + - OpenSSL 3+ version present. + - Check whether TPM is enabled from BIOS. + - Check tpm2-tools rpms. If not installed already, install it. + - `tpm_ownership`: This task sets up the TPM to be used. + - check if tpm ownership already taken, if yes skip the entire process after validating the ownership + - if not taken, we proceed to take the ownership + - if 'change_pasword' flag is set, we skip the setup and jump to the password change + - `create_nv_slots`: This task create NV slots which will be used for key generation. + - `generate_tpm_key`: This task generated a tpm key in the mentioned nv slot. + - `enroll_sed`: This task enrolls an sed using the tpm key + - `manage_key`: This task handles the backup and restore of the tpm key. diff --git a/roles/sed_configure/defaults/main.yml b/roles/sed_configure/defaults/main.yml new file mode 100644 index 00000000..28789e10 --- /dev/null +++ b/roles/sed_configure/defaults/main.yml @@ -0,0 +1,21 @@ +scale_sed_config: + tpm_password_file: "/path/to/password.txt" + new_tpm_password_file: "/path/to/newpassword.txt" + disable_clear: true + change_password: false + nv_slot_id: "0x01500000" + nv_slot_count: 4 + recovery_group: "RecoveryGroupName" + enroll_drive: false + rekey_drive: false + generate: false + migrate: false + backup_key: false + restore_key: false + io_nodes: + - ionode1 + - ionode2 + utility_nodes: + - utilitynode + emsvm: + - emsvmnode \ No newline at end of file diff --git a/roles/sed_configure/meta/main.yml b/roles/sed_configure/meta/main.yml new file mode 100644 index 00000000..e48de9b9 --- /dev/null +++ b/roles/sed_configure/meta/main.yml @@ -0,0 +1,18 @@ +--- +galaxy_info: + author: IBM Corporation + description: Highly-customizable Ansible role for installing and configuring IBM Spectrum Scale (GPFS) + company: IBM + + license: Apache-2.0 + + min_ansible_version: 2.9 + + platforms: + - name: EL + versions: + - 9 + + galaxy_tags: [] + +dependencies: [] \ No newline at end of file diff --git a/roles/sed_configure/tasks/check_prereq.yml b/roles/sed_configure/tasks/check_prereq.yml new file mode 100644 index 00000000..e400fe10 --- /dev/null +++ b/roles/sed_configure/tasks/check_prereq.yml @@ -0,0 +1,50 @@ +--- +- block: + # Check the OpenSSL version and fail if the version is < 3 + - name: Check OpenSSL version + command: openssl version + register: openssl_version_output + changed_when: false + failed_when: openssl_version_output.stdout | regex_search('OpenSSL\s([0-2]\\.[0-9]+)') + + - debug: + msg: "{{(openssl_version_output.rc == 0) | ternary(openssl_version_output.stdout.split('\n'), openssl_version_output.stderr.split('\n')) }}" + + # Check the OS version and fail if the version is < RHEL 9 + - name: Check OS version + command: cat /etc/redhat-release + register: os_version_output + changed_when: false + failed_when: os_version_output.stdout | regex_search('release\s([0-8])') + + - debug: + msg: "{{(os_version_output.rc == 0) | ternary(os_version_output.stdout.split('\n'), os_version_output.stderr.split('\n')) }}" + delegate_to: "{{ item }}" + +- block: + - name: Check TPM presence + stat: + path: /dev/tpm0 + register: tpm_device + + - debug: + msg: "TPM device present" + when: tpm_device.stat.exists + + - fail: + msg: "TPM is not enabled in BIOS. Please enable it manually before proceeding." + when: not tpm_device.stat.exists + + - name: Check if tpm2-tools is installed + command: rpm -q tpm2-tools + register: tpm2_tools_check + ignore_errors: true + changed_when: false + + - name: Install tpm2-tools if not present + yum: + name: tpm2-tools + state: present + when: tpm2_tools_check.rc != 0 + delegate_to: "{{ item }}" + when: item in scale_sed_config.io_nodes \ No newline at end of file diff --git a/roles/sed_configure/tasks/create_nv_slot.yml b/roles/sed_configure/tasks/create_nv_slot.yml new file mode 100644 index 00000000..be771b6d --- /dev/null +++ b/roles/sed_configure/tasks/create_nv_slot.yml @@ -0,0 +1,24 @@ +--- +- block: + # Creation of NV slots on IO nodes + - name: Create NV slots + command: mmvdisk tpm createSlots --number-of-slots {{ scale_sed_config.nv_slot_count }} --nv-slot-id {{ scale_sed_config.nv_slot_id }} --password-file {{ scale_sed_config.tpm_password_file }} + register: nv_slot_creation_io + failed_when: nv_slot_creation_io.rc != 0 + + - debug: + msg: "{{(nv_slot_creation_io.rc == 0) | ternary(nv_slot_creation_io.stdout.split('\n'), nv_slot_creation_io.stderr.split('\n')) }}" + delegate_to: "{{ item }}" + when: item in scale_sed_config.io_nodes + +- block: + # Creation of NV slots on utility nodes + - name: Create NV slots on utility node + command: /opt/ibm/ess/tools/bin/.TPM/./esstpm createslot --nv-slot-id {{scale_sed_config.nv_slot_id}} --password-file {{ scale_sed_config.tpm_password_file }} + register: nv_slot_creation_utility + failed_when: nv_slot_creation_utility.rc != 0 + + - debug: + msg: "{{(nv_slot_creation_utility.rc == 0) | ternary(nv_slot_creation_utility.stdout.split('\n'), nv_slot_creation_utility.stderr.split('\n')) }}" + delegate_to: "{{ item }}" + when: item in scale_sed_config.utility_nodes \ No newline at end of file diff --git a/roles/sed_configure/tasks/enroll_sed_drive.yml b/roles/sed_configure/tasks/enroll_sed_drive.yml new file mode 100644 index 00000000..a671dd9d --- /dev/null +++ b/roles/sed_configure/tasks/enroll_sed_drive.yml @@ -0,0 +1,26 @@ +--- +- block: + # Enrolling the SED with the generated TPM key + - name: Enroll drives with TPM key + command: mmvdisk sed enroll --recovery-group {{ scale_sed_config.recovery_group }} --tpm-slot-id {{ scale_sed_config.nv_slot_id }} --confirm + register: drive_enrollment + + - debug: + msg: "{{(drive_enrollment.rc == 0) | ternary(drive_enrollment.stdout.split('\n'), drive_enrollment.stderr.split('\n')) }}" + failed_when: drive_enrollment.rc != 0 + delegate_to: "{{ item }}" + run_once: true + when: scale_sed_config.enroll_drive + +- block: + # Rekeying the SED with the a new TPM key + - name: Rekey drives with new TPM key + command: mmvdisk sed rekey --recovery-group {{ scale_sed_config.recovery_group }} --tpm-slot-id {{ scale_sed_config.nv_slot_id }} --confirm + register: drive_rekey + + - debug: + msg: "{{(drive_rekey.rc == 0) | ternary(drive_rekey.stdout.split('\n'), drive_rekey.stderr.split('\n')) }}" + failed_when: drive_rekey.rc != 0 + delegate_to: "{{ item }}" + run_once: true + when: scale_sed_config.rekey_drive \ No newline at end of file diff --git a/roles/sed_configure/tasks/generate_tpm_key.yml b/roles/sed_configure/tasks/generate_tpm_key.yml new file mode 100644 index 00000000..5e0414e0 --- /dev/null +++ b/roles/sed_configure/tasks/generate_tpm_key.yml @@ -0,0 +1,28 @@ +--- +- block: + # Generate a TPM key + - name: Generate TPM key + command: mmvdisk tpm genkey --nv-slot-id {{ scale_sed_config.nv_slot_id }} --password-file {{ scale_sed_config.tpm_password_file }} + register: tpm_key_generate + + - debug: + msg: "{{(tpm_key_generate.rc == 0) | ternary(tpm_key_generate.stdout.split('\n'), tpm_key_generate.stderr.split('\n')) }}" + failed_when: tpm_key_generate.rc != 0 + delegate_to: "{{ item }}" + when: scale_sed_config.generate + run_once: true + +- block: + # Migrate the generated TPM key to other io nodes + - name: Migrate TPM key to other nodes + command: mmvdisk tpm migratekey --nv-slot-id {{ scale_sed_config.nv_slot_id }} -s {{ scale_sed_config.io_nodes.0 }} -N {{ target_nodes | join(',') }} + vars: + target_nodes: "{{ scale_sed_config.io_nodes[1:] }}" + register: tpm_key_migrate + + - debug: + msg: "{{ (tpm_key_migrate.rc == 0) | ternary(tpm_key_migrate.stdout.split('\n'),tpm_key_migrate.stderr.split('\n')) }}" + failed_when: tpm_key_migrate.rc != 0 + delegate_to: "{{ io_nodes.0 }}" + when: scale_sed_config.migrate + run_once: true \ No newline at end of file diff --git a/roles/sed_configure/tasks/main.yml b/roles/sed_configure/tasks/main.yml new file mode 100644 index 00000000..682cb55e --- /dev/null +++ b/roles/sed_configure/tasks/main.yml @@ -0,0 +1,22 @@ +--- +- include_tasks: check_prereq.yml + tags: check prerequisites + loop: "{{ io_nodes + utility_nodes }}" + +- include_tasks: tpm_ownership.yml + tags: tpm ownership + loop: "{{ io_nodes + utility_nodes }}" + +- include_tasks: create_nv_slot.yml + tags: create nv slot + loop: "{{ io_nodes + utility_nodes }}" + +- include_tasks: generate_tpm_key.yml + tags: generate tpm key + +- include_tasks: enroll_sed_drive.yml + tags: enroll sed drive + +- include_tasks: manage_key.yml + tags: restore and backup key + loop: "{{ emsvm }}" \ No newline at end of file diff --git a/roles/sed_configure/tasks/manage_key.yml b/roles/sed_configure/tasks/manage_key.yml new file mode 100644 index 00000000..9aef5310 --- /dev/null +++ b/roles/sed_configure/tasks/manage_key.yml @@ -0,0 +1,27 @@ +--- +- block: + - name: Backup TPM key + command: /opt/ibm/ess/tools/bin/.TPM/./esstpmkey backup --source-node {{ source_node }} --destination-node {{ dest_node }} --tpm-slot-id {{ scale_sed_config.nv_slot_id }} --destination-node-password-file {{ scale_sed_config.tpm_password_file}} + vars: + source_node: "{{ scale_sed_config.io_nodes[0]}}" + dest_node: "{{ scale_sed_config.utility_nodes[0] }}" + register: backup_key + when: scale_sed_config.backup + + - debug: + msg: "{{(backup_key.rc == 0) | ternary(backup_key.stdout.split('\n'), backup_key.stderr.split('\n')) }}" + when: scale_sed_config.backup + + - name: Restore TPM key from backup + command: /opt/ibm/ess/tools/bin/.TPM/./esstpmkey restore --source-node {{ source_node }} --destination-node {{ dest_node }} --tpm-slot-id {{ scale_sed_config.nv_slot_id }} --source-node-password-file {{ scale_sed_config.tpm_password_file}} + vars: + source_node: "{{ scale_sed_config.utility_nodes[0] }}" + dest_node: "{{ scale_sed_config.io_nodes[0] }}" + register: restore_key + when: scale_sed_config.restore + + - debug: + msg: "{{(restore_key.rc == 0) | ternary(restore_key.stdout.split('\n'), restore_key.stderr.split('\n')) }}" + when: scale_sed_config.restore + delegate_to: "{{ item }}" + run_once: true \ No newline at end of file diff --git a/roles/sed_configure/tasks/tpm_ownership.yml b/roles/sed_configure/tasks/tpm_ownership.yml new file mode 100644 index 00000000..d1dac589 --- /dev/null +++ b/roles/sed_configure/tasks/tpm_ownership.yml @@ -0,0 +1,112 @@ +--- +- name: Check if ownership already taken on IO nodes + shell: | + tpm2_getcap properties-variable | awk -F': *' '/ownerAuthSet:/ { v=tolower($2); print (v ~ /(^1$|set|true)/) ? 1 : 0; exit }' + register: ownership_taken_io + changed_when: false + delegate_to: "{{ item }}" + when: item in scale_sed_config.io_nodes + +- name: Check if ownership already taken on utility node + shell: | + tpm2_getcap properties-variable | awk -F': *' '/ownerAuthSet:/ { v=tolower($2); print (v ~ /(^1$|set|true)/) ? 1 : 0; exit }' + register: ownership_taken_utility + changed_when: false + delegate_to: "{{ item }}" + when: item in scale_sed_config.utility_nodes + +# skip the setup -> if ownership taken. We mention that ownership is taken, validate it. And continue to nv slot creation. +- block: + - name: Validate ownership password + debug: + msg: Ownership already taken. Skipping the tpm ownership setup. + + - name: Check the password + command: mmvdisk tpm chpasswd --old-password-file {{ scale_sed_config.tpm_password_file }} --new-password-file {{ scale_sed_config.tpm_password_file }} + register: pwd_validation_io + + - debug: + msg: "Validated the Ownership successfully" + when: pwd_validation_io.rc == 0 + + - fail: + msg: "Ownership password did not match. Please verify" + when: pwd_validation_io.rc != 0 + delegate_to: "{{ item }}" + when: item in scale_sed_config.io_nodes and ownership_taken_io.stdout == '1' and not scale_sed_config.change_password + +- block: + - name: Validate ownership password + debug: + msg: Ownership already taken. Skipping the tpm ownership setup. + + - name: Check the password + command: /opt/ibm/ess/tools/bin/.TPM/./esstpm chpasswd --old-password-file {{ scale_sed_config.tpm_password_file }} --new-password-file {{ scale_sed_config.tpm_password_file }} + register: pwd_validation_utility + + - debug: + msg: "Validated the Ownership successfully" + when: pwd_validation_utility.rc == 0 + + - fail: + msg: "Ownership password did not match. Please verify" + when: pwd_validation_utility.rc != 0 + delegate_to: "{{ item }}" + when: item in scale_sed_config.utility_nodes and ownership_taken_utility.stdout == '1' and not scale_sed_config.change_password + +# if tpm ownership not taken already, proceed to take it on io nodes +- block: + - name: Disable TPM clear + command: tpm2_clearcontrol -C l s + register: disable_operation + when: disable_clear + + - name: Take TPM ownership # ensure file permission is 600 + command: mmvdisk tpm setup --password-file {{ scale_sed_config.tpm_password_file }} + register: take_ownership_io + + - debug: + msg: "{{(take_ownership_io.rc == 0) | ternary(take_ownership_io.stdout.split('\n'),take_ownership_io.stderr.split('\n')) }}" + delegate_to: "{{ item }}" + when: item in scale_sed_config.io_nodes and ownership_taken_io.stdout == '0' and not scale_sed_config.change_password + +# if tpm ownership not taken already, proceed to take it on utility node +- block: + - name: Disable TPM clear + command: tpm2_clearcontrol -C l s + register: disable_operation + when: disable_clear + + - name: Take TPM ownership on utility node + command: /opt/ibm/ess/tools/bin/.TPM/./esstpm setup --password-file {{ scale_sed_config.tpm_password_file }} + register: take_ownership_utility + + - debug: + msg: "{{(take_ownership_utility.rc == 0) | ternary(take_ownership_utility.stdout.split('\n'), take_ownership_utility.stderr.split('\n')) }}" + delegate_to: "{{ item }}" + when: item in scale_sed_config.utility_nodes and ownership_taken_utility.stdout == '0' and not scale_sed_config.change_password + +# execute only when change password is set to true. +- block: + # Change password on IO nodes + - name: Change TPM Ownership password + command: mmvdisk tpm chpasswd --old-password-file {{ scale_sed_config.tpm_password_file }} --new-password-file {{ scale_sed_config.new_tpm_password_file }} + register: change_pw_io + failed_when: change_pw_io.rc != 0 + + - debug: + msg: "{{(change_pw_io.rc == 0) | ternary(change_pw_io.stdout.split('\n'), change_pw_io.stderr.split('\n')) }}" + delegate_to: "{{ item }}" + when: item in scale_sed_config.io_nodes and scale_sed_config.change_password + +- block: + # Change password on Utility node + - name: Change TPM Ownership password + command: /opt/ibm/ess/tools/bin/.TPM/./esstpm chpasswd --old-password-file {{ scale_sed_config.tpm_password_file }} --new-password-file {{ scale_sed_config.new_tpm_password_file }} + register: change_pw_utility + failed_when: change_pw_utility.rc != 0 + + - debug: + msg: "{{(change_pw_utility.rc == 0) | ternary(change_pw_utility.stdout.split('\n'), change_pw_utility.stderr.split('\n')) }}" + delegate_to: "{{ item }}" + when: item in scale_sed_config.utility_nodes and scale_sed_config.change_password \ No newline at end of file diff --git a/samples/playbook_sed_tpm.yml b/samples/playbook_sed_tpm.yml new file mode 100644 index 00000000..0c43013c --- /dev/null +++ b/samples/playbook_sed_tpm.yml @@ -0,0 +1,7 @@ +--- +- hosts: all + become: no + pre_tasks: + - include_vars: sed_tpm_vars.yml + roles: + - sed_configure \ No newline at end of file diff --git a/samples/vars/sed_tpm_vars.yml b/samples/vars/sed_tpm_vars.yml new file mode 100644 index 00000000..4128365f --- /dev/null +++ b/samples/vars/sed_tpm_vars.yml @@ -0,0 +1,20 @@ +scale_sed_config: + tpm_password_file: "/root/tpm_pwd" + new_tpm_password_file: "/path/to/newpassword.txt" + disable_clear: true + nv_slot_count: 4 + nv_slot_id: "0x1500000" + generate: true + migrate: true + enroll_drive: true + rekey_drive: false + backup_key: true + restore_key: false + recovery_group: "recoverygroup" + io_nodes: + - ionode1 + - ionode2 + utility_nodes: + - utilitynode + emsvm: + - emsvmnode \ No newline at end of file