Contents

Ansible LUKS: Automated Full-Disk Encryption with Ansible

Ansible LUKS: Automated Full-Disk Encryption with Ansible

ansible.luks automates LUKS (Linux Unified Key Setup) disk encryption operations across Linux hosts using Ansible. It covers creating encrypted volumes, managing keys, and automating unlock at boot.

What is LUKS?

LUKS is the standard Linux disk encryption layer. It provides full-disk or partition-level encryption with support for multiple key slots, making it suitable for both workstations and servers.

Playbook: Encrypting a New Volume

---
- name: Setup LUKS encrypted volume
  hosts: storage_nodes
  become: true
  vars:
    luks_device: /dev/sdb
    luks_name: data_encrypted
    luks_mount: /mnt/data
    luks_fs: ext4

  tasks:
    - name: Install cryptsetup
      package:
        name: cryptsetup
        state: present

    - name: Check if device is already LUKS-formatted
      command: cryptsetup isLuks {{ luks_device }}
      register: is_luks
      failed_when: false
      changed_when: false

    - name: Format device with LUKS
      expect:
        command: cryptsetup luksFormat {{ luks_device }}
        responses:
          "Are you sure.*": "YES"
          "Enter passphrase.*": "{{ luks_passphrase }}"
          "Verify passphrase.*": "{{ luks_passphrase }}"
      when: is_luks.rc != 0
      no_log: true

    - name: Open LUKS device
      expect:
        command: cryptsetup open {{ luks_device }} {{ luks_name }}
        responses:
          "Enter passphrase.*": "{{ luks_passphrase }}"
      when: is_luks.rc != 0
      no_log: true

    - name: Create filesystem
      filesystem:
        fstype: "{{ luks_fs }}"
        dev: "/dev/mapper/{{ luks_name }}"
      when: is_luks.rc != 0

    - name: Create mount point
      file:
        path: "{{ luks_mount }}"
        state: directory
        mode: "0755"

    - name: Mount encrypted volume
      mount:
        path: "{{ luks_mount }}"
        src: "/dev/mapper/{{ luks_name }}"
        fstype: "{{ luks_fs }}"
        state: mounted

Key Management Role

# roles/luks_keys/tasks/main.yml
---
- name: Add a new LUKS key slot
  command: >
    cryptsetup luksAddKey {{ luks_device }}
    --key-file <(echo -n "{{ existing_passphrase }}")    
  args:
    stdin: "{{ new_passphrase }}"
  no_log: true

- name: Remove a LUKS key slot
  command: >
    cryptsetup luksRemoveKey {{ luks_device }}    
  args:
    stdin: "{{ passphrase_to_remove }}"
  no_log: true

- name: Check key slots usage
  command: cryptsetup luksDump {{ luks_device }}
  register: luks_dump
  changed_when: false

- name: Show key slots
  debug:
    msg: "{{ luks_dump.stdout | regex_findall('Key Slot \\d+: ENABLED') }}"

Auto-unlock with a Keyfile (Server Use)

- name: Create keyfile for auto-unlock
  copy:
    content: "{{ luks_keyfile_content }}"
    dest: /etc/luks-keys/data.key
    mode: "0400"
    owner: root
  no_log: true

- name: Add keyfile as LUKS key slot
  command: >
    cryptsetup luksAddKey {{ luks_device }} /etc/luks-keys/data.key    
  args:
    stdin: "{{ luks_passphrase }}"
  no_log: true

- name: Configure crypttab for auto-unlock
  lineinfile:
    path: /etc/crypttab
    line: "{{ luks_name }} {{ luks_device }} /etc/luks-keys/data.key luks"
    create: true

Inventory Example

[storage_nodes]
node1 ansible_host=192.168.1.10
node2 ansible_host=192.168.1.11
node3 ansible_host=192.168.1.12
# group_vars/storage_nodes/vault.yml (ansible-vault encrypted)
luks_passphrase: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  ...

Running the Playbook

# Encrypt a new volume (passphrase from vault)
ansible-playbook -i inventory setup-luks.yml --ask-vault-pass

# Rotate keys
ansible-playbook -i inventory rotate-keys.yml --ask-vault-pass

Conclusion

Automating LUKS with Ansible makes full-disk encryption manageable at scale. Combined with ansible-vault for secret management, this playbook provides a repeatable, auditable approach to securing data at rest across Linux infrastructure.

Source: GitHub