--- # TPM2 enrollment via systemd-cryptenroll. # Works with dracut and mkinitcpio (sd-encrypt). The user-set passphrase # remains as a backup unlock method — no auto-generated keyfiles. - name: Enroll TPM2 for LUKS block: - name: Create temporary passphrase file for TPM2 enrollment ansible.builtin.tempfile: path: /mnt/root prefix: luks-passphrase- state: file register: _tpm2_passphrase_tempfile - name: Write passphrase into temporary file ansible.builtin.copy: dest: "{{ _tpm2_passphrase_tempfile.path }}" content: "{{ configuration_luks_passphrase }}" owner: root group: root mode: "0600" no_log: true - name: Ensure TPM device is accessible in chroot ansible.builtin.shell: >- ls /mnt/dev/tpmrm0 2>/dev/null || (ls /dev/tpmrm0 && cp -a /dev/tpmrm0 /mnt/dev/tpmrm0) changed_when: false failed_when: false - name: Enroll TPM2 token via systemd-cryptenroll vars: _enroll_args: >- {{ [ '/usr/bin/systemd-cryptenroll', '--tpm2-device=' + configuration_luks_tpm2_device, '--tpm2-with-pin=false', '--wipe-slot=tpm2', '--unlock-key-file=' + ( _tpm2_passphrase_tempfile.path | regex_replace('^/mnt', '') ) ] + (['--tpm2-pcrs=' + configuration_luks_tpm2_pcrs] if configuration_luks_tpm2_pcrs | length > 0 else []) + [configuration_luks_device] }} ansible.builtin.command: "{{ chroot_command }} {{ _enroll_args | join(' ') }}" register: _tpm2_enroll_result changed_when: _tpm2_enroll_result.rc == 0 rescue: - name: TPM2 enrollment failed ansible.builtin.debug: msg: >- TPM2 enrollment failed: {{ _tpm2_enroll_result.stderr | default('unknown') }}. The system will require the passphrase for LUKS unlock on boot. TPM2 can be enrolled post-deployment via: systemd-cryptenroll --tpm2-device=auto {{ configuration_luks_device }} always: - name: Remove temporary passphrase file when: _tpm2_passphrase_tempfile.path is defined ansible.builtin.file: path: "{{ _tpm2_passphrase_tempfile.path }}" state: absent