Dotfiles/setup/modules/FreeipaAnsible/ansible/collect-luks-keys.yml

131 lines
4.6 KiB
YAML

---
# collect-luks-keys.yml — fetch LUKS backup keys from enrolled clients and store them
# on the ansipa-luks-keys SMB share (accessible only to KeyAdmin group members).
#
# Flow per host:
# 1. Fetch /_LUKS_BACKUP_KEY from the client to a local staging directory.
# 2. Upload the staged file to //IPA_SERVER/ansipa-luks-keys/ via smbclient.
# 3. Delete the local staging copy.
#
# The ansipa-luks-keys SMB share is write-only for 'luks-upload' and read-only
# for members of the 'KeyAdmin' group. Add a Samba user to KeyAdmin on the IPA
# container to grant read access:
# useradd -r -G KeyAdmin <user> && smbpasswd -a <user>
#
# Usage:
# ansible-playbook -i inventory collect-luks-keys.yml \
# -e luks_smb_server=ipa.corp.example.com \
# -e luks_upload_password=<LUKS_KEY_UPLOAD_PASSWORD>
#
# Or set defaults in group_vars / ansible-vault. The smb_server can also be
# auto-detected from /etc/ipa/default.conf on the clients.
- name: Collect and archive LUKS backup keys
hosts: all
become: yes
vars:
luks_key_path: /_LUKS_BACKUP_KEY
# Local staging dir — files are deleted after a successful SMB upload.
luks_keys_stage: "{{ playbook_dir }}/luks-keys-stage"
luks_smb_server: "{{ luks_smb_server | mandatory('luks_smb_server is required — use -e luks_smb_server=<IPA host>') }}"
luks_smb_share: ansipa-luks-keys
luks_upload_user: luks-upload
luks_upload_password: "{{ luks_upload_password | mandatory('luks_upload_password is required — use -e luks_upload_password=... or ansible-vault') }}"
# Temp credentials file on the controller — removed at the end of the play.
_smb_creds_file: "/tmp/.ansipa-luks-upload-{{ ansible_date_time.epoch }}.creds"
tasks:
- name: Ensure local staging directory exists
file:
path: "{{ luks_keys_stage }}"
state: directory
mode: '0700'
delegate_to: localhost
run_once: true
become: false
- name: Write temporary SMB credentials file on controller
copy:
dest: "{{ _smb_creds_file }}"
mode: '0600'
content: |
username = {{ luks_upload_user }}
password = {{ luks_upload_password }}
domain = WORKGROUP
delegate_to: localhost
run_once: true
become: false
no_log: true
- name: Check for LUKS backup key on client
stat:
path: "{{ luks_key_path }}"
register: luks_key_stat
- name: Fetch LUKS backup key to local staging area
fetch:
src: "{{ luks_key_path }}"
dest: "{{ luks_keys_stage }}/{{ inventory_hostname }}_LUKS_BACKUP_KEY"
flat: yes
when: luks_key_stat.stat.exists
register: luks_key_fetch
- name: Secure staged key permissions
file:
path: "{{ luks_keys_stage }}/{{ inventory_hostname }}_LUKS_BACKUP_KEY"
mode: '0400'
delegate_to: localhost
become: false
when:
- luks_key_stat.stat.exists
- luks_key_fetch is changed
- name: Upload key to ansipa-luks-keys SMB share
shell: >
smbclient "//{{ luks_smb_server }}/{{ luks_smb_share }}"
-A "{{ _smb_creds_file }}"
-c "put {{ luks_keys_stage }}/{{ inventory_hostname }}_LUKS_BACKUP_KEY {{ inventory_hostname }}_LUKS_BACKUP_KEY"
delegate_to: localhost
become: false
when:
- luks_key_stat.stat.exists
- luks_key_fetch is changed
register: smb_upload
no_log: true
- name: Remove local staging copy after successful upload
file:
path: "{{ luks_keys_stage }}/{{ inventory_hostname }}_LUKS_BACKUP_KEY"
state: absent
delegate_to: localhost
become: false
when:
- luks_key_stat.stat.exists
- luks_key_fetch is changed
- smb_upload is succeeded
- name: Report key status
debug:
msg: >-
{{ inventory_hostname }}:
{% if not luks_key_stat.stat.exists %}
no /_LUKS_BACKUP_KEY present (unencrypted install or key already removed)
{% elif luks_key_fetch is changed and smb_upload is succeeded %}
key uploaded to //{{ luks_smb_server }}/{{ luks_smb_share }}/{{ inventory_hostname }}_LUKS_BACKUP_KEY
{% elif luks_key_fetch is not changed %}
key unchanged since last collection — skipped upload
{% else %}
WARNING: key fetched but SMB upload failed — check smbclient output
{% endif %}
post_tasks:
- name: Remove temporary SMB credentials file
file:
path: "{{ _smb_creds_file }}"
state: absent
delegate_to: localhost
run_once: true
become: false