Use Network Bound Disk Encryption on Oracle Linux

2
0
Send lab feedback

Use Network Bound Disk Encryption on Oracle Linux

Introduction

This tutorial demonstrates how to configure an Oracle Linux system with Linux Unified Key Setup (LUKS) disk encryption that is dependent on a network-based key service consisting of Tang and Clevis . You will create an encrypted XFS file system that is automatically unlocked at boot when on the same network as your key server.

Objectives

In this tutorial, you'll learn how to:

  • Set up LUKS using cryptsetup , which provides the tooling for disk-based encryption and includes support for LUKS.
  • Configure Tang as a network service that provides cryptographic services over HTTP.
  • Use Clevis for the network encryption framework. Clevis can use keys provided by Tang as a passphrase to unlock LUKS volumes.

Prerequisites

  • Minimum of two Oracle Linux systems

  • Each system should have Oracle Linux installed and configured with:

    • A non-root user account with sudo access
    • Access to the Internet
    • A disk or block device attached to the system to use for encrypted storage

Deploy Oracle Linux

Note: If running in your own tenancy, read the linux-virt-labs GitHub project README.md and complete the prerequisites before deploying the lab environment.

  1. Open a terminal on the Luna Desktop.

  2. Clone the linux-virt-labs GitHub project.

    git clone https://github.com/oracle-devrel/linux-virt-labs.git
  3. Change into the working directory.

    cd linux-virt-labs/ol
  4. Install the required collections.

    ansible-galaxy collection install -r requirements.yml
  5. Update the Oracle Linux instance configuration.

    cat << EOF | tee instances.yml > /dev/null
    compute_instances:
      1:
        instance_name: "ol-node-01"
        type: "server"
      2:
        instance_name: "ol-node-02"
        type: "server"
    use_nginx: true
    passwordless_ssh: true
    EOF
    
  6. Deploy the lab environment.

    ansible-playbook create_instance.yml -e localhost_python_interpreter="/usr/bin/python3.6" -e "@instances.yml" -e add_block_storage=true -e block_count=1

    The free lab environment requires the extra variable local_python_interpreter, which sets ansible_python_interpreter for plays running on localhost. This variable is needed because the environment installs the RPM package for the Oracle Cloud Infrastructure SDK for Python, located under the python3.6 modules.

    The default deployment shape uses the AMD CPU and Oracle Linux 8. To use an Intel CPU or Oracle Linux 9, add -e instance_shape="VM.Standard3.Flex" or -e os_version="9" to the deployment command.

    Important: Wait for the playbook to run successfully and reach the pause task. At this stage of the playbook, the installation of Oracle Linux is complete, and the instances are ready. Take note of the previous play, which prints the public and private IP addresses of the nodes it deploys and any other deployment information needed while running the lab.

Install and Configure Tang on the Server Instance

  1. Open a terminal and connect via SSH to the ol-node-01 instance.

    ssh oracle@<ip_address_of_instance>
  2. Install the Tang package.

    sudo dnf install -y tang
  3. Note the IP address of the server instance in the local network.

    hostname -I | awk '{print $1}'
  4. Add a trusted zone for the network and allow the required port through the firewall for systems in the trusted zone.

    sudo firewall-cmd --zone=trusted --add-source=10.0.0.0/24
    sudo firewall-cmd --zone=trusted --add-service=http
    sudo firewall-cmd --runtime-to-permanent
  5. Enable the service.

    sudo systemctl enable --now tangd.socket

Create an Encrypted File System on the Client Instance

  1. Open a terminal and connect via SSH to the ol-node-02 instance.

    ssh oracle@<ip_address_of_instance>
  2. Install the cryptsetup package.

    sudo dnf install -y cryptsetup
  3. Check the available block devices to make sure that an empty disk is available to host the encrypted file system.

    lsblk

    Example Output:

    NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
    sda                  8:0    0 46.6G  0 disk 
    ├─sda1               8:1    0  100M  0 part /boot/efi
    ├─sda2               8:2    0    1G  0 part /boot
    └─sda3               8:3    0 45.5G  0 part 
      ├─ocivolume-root 252:0    0 35.5G  0 lvm  /
        └─ocivolume-oled 252:1    0   10G  0 lvm  /var/oled
    sdb                  8:16   0   50G  0 disk

    Note that sdb is listed as an empty disk. This block device is preconfigured and attached to the client compute instance for this tutorial.

  4. Encrypt the disk by using LUKS.

    sudo cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 \
    --key-size 512 --hash sha256 --use-random --force-password /dev/sdb

    The following warning is displayed and you must confirm that you wish to continue by entering YES in uppercase. You must also specify a LUKS passphrase that you can use to decrypt the disk. Make sure you note down this passphrase for future use.

    Example Output:

    WARNING!
    ========
    This will overwrite data on /dev/sdb irrevocably.
    
    Are you sure? (Type 'yes' in capital letters): YES
    Enter passphrase for /dev/sdb: 
    Verify passphrase: 

    The options presented in this example are demonstrative, and you may need to alter the cipher, hash, and key size to fit your environment on a production system. Note that we used the --force-password option in this tutorial to allow you to specify a low-quality passphrase for the LUKS key. LUKS uses the pwquality.so module to enforce passphrase complexity if this option is not specified.

  5. Unlock the block device using the passphrase that you created in the previous step.

    sudo cryptsetup --verbose luksOpen /dev/sdb demodisk

    Provide a passphrase when prompted.

    Example Output:

    Enter passphrase for /dev/sdb:
    Key slot 0 unlocked.
    Command successful.
  6. A device named demodisk is available under /dev/mapper.

    ls -la /dev/mapper/demodisk

    Example Output:

    lrwxrwxrwx. 1 root root 7 Jun  7 10:20 /dev/mapper/demodisk -> ../dm-2
  7. Create a file system on the encrypted disk.

    sudo mkfs.xfs /dev/mapper/demodisk
  8. Identify the UUID of the new filesystem.

    blkid -s UUID  /dev/mapper/demodisk

    Example Output:

    /dev/mapper/demodisk: UUID="4057664e-122f-421d-bcb6-2cb5a068a4d8"
  9. Note the UUID for the next step. The easiest way to do this is to store the value in an environment variable we can reuse in subsequent steps.

    DEMODISK_ID=$(sudo blkid -s UUID /dev/mapper/demodisk |grep -oP 'UUID="\K[^"]+')
  10. Create a fstab entry for the file system using the UUID for the newly created file system.

    echo "UUID=$DEMODISK_ID /encrypted xfs defaults 0 0" | sudo tee -a /etc/fstab
  11. Reload systemd to pick up the change to fstab.

    sudo systemctl daemon-reload
  12. Mount the file system.

    sudo mkdir /encrypted
    sudo mount /encrypted

Add a Remote Key to the Encrypted Device

Use Clevis to add an additional passphrase to open the encrypted device.

  1. Install the required Clevis packages.

    sudo dnf install -y clevis-systemd clevis-luks
  2. View the keys.

    Note there is one keyslot in use, keyslot 0. In the next step, you use an additional keyslot.

    sudo cryptsetup luksDump /dev/sdb

    Example Output:

    LUKS header information
    Version:       	2
    Epoch:         	3
    Metadata area: 	16384 [bytes]
    Keyslots area: 	16744448 [bytes]
    UUID:          	61ff409e-6e38-4172-8756-e9f6fadf58c1
    Label:         	(no label)
    Subsystem:     	(no subsystem)
    Flags:       	(no flags)
    
    Data segments:
      0: crypt
    	 offset: 16777216 [bytes]
    	 length: (whole device)
    	 cipher: aes-xts-plain64
      sector: 512 [bytes]
     
    Keyslots:
      0: luks2
      Key:        512 bits
      Priority:   normal
      Cipher:     aes-xts-plain64
      Cipher key: 512 bits
      PBKDF:      argon2i
      Time cost:  4
      Memory:     609527
      Threads:    2
      Salt:       b4 3c b8 ac 9a ff 50 c1 5a 4d 3b 61 23 6f 0b 12
                 bf 63 1f c5 7b db 17 2f d1 a4 63 98 02 80 8c e7
      AF stripes: 4000
      AF hash:    sha256
      Area offset:32768 [bytes]
      Area length:258048 [bytes]
      Digest ID:  0
    Tokens:
    Digests:
      0: pbkdf2
      Hash:       sha256
      Iterations: 81209
      Salt:       8f 67 0e e1 4f 4f 25 c6 6e 9a 4c 39 17 8a 7d 72
                  d3 6e 60 fd e6 19 81 69 d5 0b 92 9f 8a 5c f5 80
      Digest:     8c 1d c2 13 cf a6 91 9c 01 37 9c 42 a9 7e 4d e1
                  22 94 7d 63 44 8b e2 5a 5c b7 a0 ab dc 4a 32 99
  3. Bind the remote tang key to a LUKS slot using Clevis.

    sudo clevis luks bind -d /dev/sdb tang '{"url":"http://ol-node-01"}'

    A prompt appears asking you to confirm you trust the key the Tang server provides. Note that you connect to the Tang server using a trusted network IP address. If you bind the LUKS slot to the Tang server on a public IP address, you can unlock the disk from anywhere on the Internet, which is more than likely undesirable.

    Example Output:

    The advertisement contains the following signing keys.
    
    9PZH7moczWcBukwc8esiW-dMAJs
    
    Do you wish to trust these keys? [ynYN] y
    Enter existing LUKS password:

    Since the keyserver and the host with the encrypted disk do not exchange private keys, you may not require TLS in your environment. However, using TLS is recommended. Therefore, you can use a reverse proxy to terminate Tang's SSL/TLS, as Clevis supports HTTPS.

    If you choose to use HTTPS, your host with the encrypted disk must trust the Certificate Authority used to sign the reverse proxy. See the update-ca-trust(8) manual page for more details.

  4. Show that Clevis is using a new keyslot in slot 1.

    sudo cryptsetup luksDump /dev/sdb

    Example Output:

    LUKS header information
    Version:       	2
    Epoch:         	5
    Metadata area: 	16384 [bytes]
    Keyslots area: 	16744448 [bytes]
    UUID:          	61ff409e-6e38-4172-8756-e9f6fadf58c1
    Label:         	(no label)
    Subsystem:     	(no subsystem)
    Flags:       	(no flags)
    
    Data segments:
      0: crypt
      offset: 16777216 [bytes]
      length: (whole device)
      cipher: aes-xts-plain64
      sector: 512 [bytes]
    
    Keyslots:
      0: luks2
      Key:        512 bits
      Priority:   normal
      Cipher:     aes-xts-plain64
      Cipher key: 512 bits
      PBKDF:      argon2i
      Time cost:  4
      Memory:     609527
      Threads:    2
      Salt:       b4 3c b8 ac 9a ff 50 c1 5a 4d 3b 61 23 6f 0b 12
                   bf 63 1f c5 7b db 17 2f d1 a4 63 98 02 80 8c e7
      AF stripes: 4000
      AF hash:    sha256
      Area offset:32768 [bytes]
      Area length:258048 [bytes]
      Digest ID:  0
      1: luks2
      Key:        512 bits
      Priority:   normal
      Cipher:     aes-xts-plain64
      Cipher key: 512 bits
      PBKDF:      argon2i
      Time cost:  4
      Memory:     475561
      Threads:    2
      Salt:       d8 fb 40 68 9c ed fa 65 c5 53 a3 3a f6 25 75 98
     	           c9 39 9d e2 b8 78 56 6a 02 24 60 55 96 8d 68 18
      AF stripes: 4000
      AF hash:    sha256
      Area offset:290816 [bytes]
      Area length:258048 [bytes]
     Digest ID:  0
    Tokens:
      0: clevis
      Keyslot:  1
    Digests:
      0: pbkdf2
      Hash:       sha256
      Iterations: 81209
      Salt:       8f 67 0e e1 4f 4f 25 c6 6e 9a 4c 39 17 8a 7d 72
     	           d3 6e 60 fd e6 19 81 69 d5 0b 92 9f 8a 5c f5 80
      Digest:     8c 1d c2 13 cf a6 91 9c 01 37 9c 42 a9 7e 4d e1
     	           22 94 7d 63 44 8b e2 5a 5c b7 a0 ab dc 4a 32 99

Mount the Encrypted File System on Boot

Configure the system to unlock the encrypted device and mount the file system on boot.

  1. Identify the block device UUID.

    sudo blkid -s UUID  /dev/sdb

    Example Output:

    /dev/sdb: UUID="74f0faf1-9cb9-45f9-a3d8-ef276263d729"
  2. Store the UUID value in an environment variable.

    SDB_ID=$(sudo blkid -s UUID /dev/sdb |grep -oP 'UUID="\K[^"]+')
  3. Enable the clevis-luks-askpass systemd service.

    sudo systemctl enable clevis-luks-askpass.path
  4. Have the block device unlocked during boot.

    The file /etc/crypttab defines how the boot process handles encrypted devices.

    echo "encrypteddisk UUID=$SDB_ID - _netdev" | sudo tee -a /etc/crypttab > /dev/null
  5. Mount the file system to ensure the disk is unlocked before the file system is mounted.

    sudo sed -i '/\/encrypted/d' /etc/fstab
    echo '/dev/mapper/encrypteddisk /encrypted xfs _netdev 0 0'|sudo tee -a /etc/fstab > /dev/null
  6. Restart the client instance to verify the file system mounts at boot.

    sudo reboot

    Wait until the instance has restarted, and you can reconnect before proceeding.

  7. Confirm that the encrypted file system is mounted correctly.

    df -h /encrypted/

    Example Output:

    Filesystem               Size  Used Avail Use% Mounted on
    /dev/mapper/demodisk   50G  389M   50G   1% /encrypted

Appendix: Unlock Encrypted Root During Boot

If you have a system with an encrypted root disk, you can register a key using the clevis luks bind command described above. To allow an early unlocking, you must install an RPM and rebuild the initramfs image as described in the following step.

Note: The Oracle Linux Cloud Infrastructure instances used in this tutorial do not have an encrypted root disk, so it is impossible to demonstrate this functionality.

  1. Install the clevis-dracut package.

    sudo dnf install -y clevis-dracut
  2. Rebuild boot files.

    sudo dracut -fv

If your system does not use DHCP, then you must also pass network configuration information to initramfs so it can access your Tang server before the root filesystem is mounted. For more information, see the Network section of the dracut.cmdline(7) manual page.

Next Steps

You should now be able to configure and use an Oracle Linux system with disk encryption on a network-based key service. Check out our other storage management content on the Oracle Linux Training Station.

Other resources specific to this tutorial:

SSR