Technical Note: Disk Encryption using Cryptsetup with Vault as Key Management Service
In Linux Operating system, full disk encryption could be achieved by various solutions: encryptfs, dm-crypt… While a step-by-step setup of disk/partition encryption can be referred from official documentation, integration disk encryption with Key Management solution like Hashicorp Vault is unobvious. Fortunately, there are a package named vaultlocker in Ubuntu Universe repository that ease this integration. I decided to spend my free time to make cryptsetup work with Vault.
Notes: A similar request has been made to Cryptsetup but it goes outside of cryptsetup so it was closed.
1. Install Vault
As JuJu charm store has working Vault/MySQL charms, Vault deployment is as simple and easy as following commands
$ juju deploy percona-cluster
$ juju deploy vault
$ juju relate vault:shared-db percona-cluster
Vault needs to be initialized and unsealed before it can provide its secure services. I followed below steps to initialize Vault
$ juju ssh vault/0
$ export VAULT_ADDR=http://127.0.0.1:8200
$ vault operator init -key-shares=3 -key-threshold=2
Unseal Key 1: hALty7n4UHvYQAN89xy3SE7yb2SUYM+9DR/tEpPGIQDB
Unseal Key 2: b+OcCcpjHQ+eG/dZ1bcGuwbL9LM1p2xR0yEha5XnsvO4
Unseal Key 3: DGo4UAsb894lXw4musCeUp30jJqoi5Qiyg5YQDpSRRqT
Initial Root Token: s.k5awSEin8LFTHQXy3qXM8GFv
...
This gives me 3 keys. I need to use 2 keys to unseal Vault in case it is locked. As we are initiating Vault, I use 2 keys to unseal vault.
$ vault operator unseal hALty7n4UHvYQAN89xy3SE7yb2SUYM+9DR/tEpPGIQDB
$ vault operator unseal b+OcCcpjHQ+eG/dZ1bcGuwbL9LM1p2xR0yEha5XnsvO4
Now Vault should be unsealed and its result can be confirmed by vault status
$ vault status
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 3
Threshold 2
Version 1.1.1
Cluster Name vault-cluster-44e9a806 Cluster ID 1087afa0-c7f1-01e4-abce-187b7b5f63a3
HA Enabled false
Authorize Juju against Vault to allow JuJu actions to run.
$ export VAULT_TOKEN=s.k5awSEin8LFTHQXy3qXM8GFv
$ vault token create -ttl=10m
Value
--- -----
token s.7jChN3pD8cbLLVUSYrXqsBig
token_accessor gj76tBhiygYh1WsK1vamP20e
token_duration 10m
token_renewable true
token_policies ["root"]
identity_policies []
policies ["root"]
$ juju status
Model Controller Cloud/Region Version SLA Timestamp
default nucctr nuc/default 2.7.1 unsupported 14:24:12+09:00
App Version Status Scale Charm Store Rev OS Notes
percona-cluster 5.7.20 active 1 percona-cluster jujucharms 282 ubuntu
vault 1.1.1 active 1 vault jujucharms 32 ubuntu
Unit Workload Agent Machine Public address Ports Message
percona-cluster/0* active idle 0 10.23.23.65 3306/tcp Unit is
ready vault/0* active idle 1 10.23.23.66 8200/tcp Unit is ready (active: true, mlock: enabled)
Machine State DNS Inst id Series AZ Message
0 started 10.23.23.65 needed-guinea bionic default Deployed
1 started 10.23.23.66 first-wahoo bionic default Deployed
Reference: https://docs.openstack.org/project-deploy-guide/charm-deployment-guide/latest/app-vault.html
2. Install VaultLocker and Setting Vault
On the test machine, install vaultlocker.
$ sudo apt update
$ sudo apt install vaultlocker
Vaultlocker will need information of Vault in order to talk to Vault. The information includes app role and proper policy to create information in Vault. So in order for vaultlocker to function, we need to create an approle and assign it a policy.
Create AppRole
I will create a approle named vaultluks
with no timeout for secret-id
$ vault auth enable approle
$ vault write auth/approle/role/vaultluks
$ vault read auth/approle/role/vaultluks/role-id
Key Value
--- -----
role_id 7cbb1c1c-2270-6120-04f6-c3b1c753191d
$ vault write -f auth/approle/role/vaultluks/secret-id
Key Value
--- -----
secret_id f657f357-4748-dd09-733c-58ff994bd985
secret_id_accessor 5eb5f63f-478b-4f41-a1c9-63f151991cf6
Create Secret Backend and Policy
In order for vaultlocker to write secret to Vault, a secret backend and a policy that allows vaultlocker to access that secret backend
$ vault secrets enable -path=luks kv
Path Type Accessor Description
---- ---- -------- -----------
charm-pki-local/ pki pki_c7e293a2 Charm created PKI backend
cubbyhole/ cubbyhole cubbyhole_ffd5c863 per-token private secret storage
identity/ identity identity_70188f48 identity store
luks/ kv kv_0ad49111 n/a
secret/ kv kv_7b586ad0 n/a
sys/ system system_0cc7f9f9 system endpoints used for control, policy and debugging
$ vim vaultluks.hcl
path "luks/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
$ vault policy write vault luks vaultluks.hcl
Configure Vaultlocker and Encrypt Disk
The url, approle
and secret_id
should be modified accordingly.
$ sudo vim /etc/vaultlocker/vaultlocker.conf
[vault]
url = http://10.23.23.66:8200
approle = 7cbb1c1c-2270-6120-04f6-c3b1c753191d
secret_id = f657f357-4748-dd09-733c-58ff994bd985
backend = luks
$ sudo vaultlocker encrypt /dev/vdb2
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 10.23.23.66
DEBUG:urllib3.connectionpool:http://10.23.23.66:8200 "POST /v1/auth/approle/login HTTP/1.1" 200 484
INFO:vaultlocker.dmcrypt:LUKS formatting /dev/vdb2 using UUID:bed01f5f-6766-4a3d-aa22-05703568da74
INFO:vaultlocker.dmcrypt:udevadm trigger block/add for /dev/vdb2 INFO:vaultlocker.dmcrypt:udevadm settle /dev/disk/by-uuid/bed01f5f-6766-4a3d-aa22-05703568da74
DEBUG:urllib3.connectionpool:http://10.23.23.66:8200 "PUT /v1/luks/vault/bed01f5f-6766-4a3d-aa22-05703568da74 HTTP/1.1" 204 0
DEBUG:urllib3.connectionpool:http://10.23.23.66:8200 "GET /v1/luks/vault/bed01f5f-6766-4a3d-aa22-05703568da74 HTTP/1.1" 200 866
INFO:vaultlocker.dmcrypt:LUKS opening bed01f5f-6766-4a3d-aa22-05703568da74
INFO:root:Enabling systemd unit for [email protected] Created symlink /etc/systemd/system/multi-user.target.wants/[email protected] → /lib/systemd/system/[email protected].
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda 252:0 0 7.5G 0 disk
└─vda1 252:1 0 7.5G 0 part /
vdb 252:16 0 5G 0 disk
├─vdb1 252:17 0 1.9G 0 part
└─vdb2 252:18 0 3.1G 0 part
└─crypt-bed01f5f-6766-4a3d-aa22-05703568da74 253:0 0 3.1G 0 crypt
Now vdb2
is encrypted and its key is stored in vaults under /luks
path. Here bed01f5f-6766-4a3d-aa22-05703568da74
is the UUID of the disk and it is also the key that vaultlocker uses to retrieve the encryption key.
In vault server, you can confirm the key file stored in Vault. There should be a key with the same uuid as the device and value is the encryption key.
$ vault kv list luks/
Keys
----
vault/
ubuntu@first-wahoo:~$ vault kv list luks/vault
Keys
----
0690f876-f297-4b09-a86c-d80f4a3c2ba1
Bed01f5f-6766-4a3d-aa22-05703568da74
$ vault kv get luks/vault/bed01f5f-6766-4a3d-aa22-05703568da74
======= Data =======
Key Value
--- -----
dmcrypt_key LONGLONGKEY
How to use
Everytime you want to open the partition you could use
$ sudo vaultlocker decrypt ${UUID}
Or
$ echo -n $KEY | sudo cryptsetup --batch-mode --key-file - open \
UUID=bed01f5f-6766-4a3d-aa22-05703568da74 \
crypt-bed01f5f-6766-4a3d-aa22-05703568da74 --type luks
Where $KEY
is the variable with value got from vault