Disk Encryption¶
Introduction¶
The OpenSVC agent can manage encrypted block devices.
This section describes how to deploy a simple filesystem over encrypted block device stack.
Prerequisites¶
This feature requires:
OpenSVC agent version 2.1-1405 minimum
cryptsetup binary (LUKS implementation)
Configuration¶
Loopback device¶
Service configuration¶
We can use a loop device to demonstrate the encrypted datas.
First, we build the service template file:
# cat > /tmp/loopback.conf <<-EOF
[DEFAULT]
id = e60306f6-e429-4a02-bd8f-a537a918a217
[disk#0]
type = loop
file = /opt/{fqdn}.img
size = 1G
[disk#1]
type = crypt
dev = {disk#0.exposed_devs[0]}
name = {fqdn}-crypt
[fs#0]
type = ext4
dev = {disk#1.exposed_devs[0]}
mnt = /srv/{svcname}
EOF
Service creation¶
Then, we can deploy the loopcrypt
service, in the demo
namespace:
# om demo/svc/loopcrypt create --config=/tmp/loopback.conf
create demo/svc/loopcrypt
The service is created, but not provisioned:
# om demo/svc/loopcrypt print status -r
demo/svc/loopcrypt down
`- instances
`- demo1 down not provisioned, idle
|- disk#0 .....P.. down loop /opt/loopcrypt.demo.svc.default.img
|- disk#1 .....P.. down crypt /dev/mapper/loopcrypt.demo.svc.default-crypt
`- fs#0 .....P.. down ext4 /dev/mapper/loopcrypt.demo.svc.default-crypt@/srv/loopcrypt
Service start¶
We first have to provision the service, which will build and start ressources:
# om demo/svc/loopcrypt provision --wait
@ n:demo1 o:demo/svc/loopcrypt sc:n
demo/svc/loopcrypt defer target state set to provisioned
The new service state is now provisioned, and all resources are up:
# om demo/svc/loopcrypt print status -r
demo/svc/loopcrypt up
`- instances
`- demo1 up idle, started
|- disk#0 ........ up loop /opt/loopcrypt.demo.svc.default.img
|- disk#1 ........ up crypt /dev/mapper/loopcrypt.demo.svc.default-crypt
`- fs#0 ........ up ext4 /dev/mapper/loopcrypt.demo.svc.default-crypt@/srv/loopcrypt
# om demo/svc/loopcrypt print devs
demo/svc/loopcrypt
|- disk#0 (disk.loop)
| |- base
| | `- /dev/sda
| `- exposed
| `- /dev/loop1
`- disk#1 (disk.crypt)
|- base
| `- /dev/sda
|- sub
| `- /dev/loop1
`- exposed
`- /dev/mapper/loopcrypt.demo.svc.default-crypt
# losetup
NAME SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE DIO LOG-SEC
/dev/loop1 0 0 0 0 /opt/loopcrypt.demo.svc.default.img 0 512
# df -h /srv/loopcrypt
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/loopcrypt.demo.svc.default-crypt 977M 2.5M 908M 1% /srv/loopcrypt
Note
LUKS encryption requires space to store metadatas (16kB) and keyslots (16MB), that’s why the usable space in the df
is less than the 1GB
size requested initially.
While running provision actions, the agent did the following tasks in the background:
create the
/opt/loopcrypt.demo.svc.default.img
file with a 1GB sizeconfigure a loop device
/dev/loop1
over/opt/loopcrypt.demo.svc.default.img
filecreate an opensvc secret object
demo/sec/loopcrypt
to store the passphrase (if it did not exist yet)generate a random passphrase and store it in the
demo/sec/loopcrypt
object, associated with keydisk_1_crypt_passphrase
(change the passphrase if it already existed, see themanage_passphrase
keyword documentation for more information about this policy)run a
cryptsetup luksFormat
command to encrypt the loop device contentsrun a
cryptsetup luksOpen
command to expose/dev/mapper/loopcrypt.demo.svc.default-crypt
which is the unencrypted block device to store datacreate a
/srv/loopcrypt
mountpointrun a mkfs.ext4 on the
/dev/mapper/loopcrypt.demo.svc.default-crypt
block devicemount the
/dev/mapper/loopcrypt.demo.svc.default-crypt
block device on the/srv/loopcrypt
mountpoint
We can see that the secret object has been created by the agent:
# om demo/sec/loopcrypt keys
disk_1_crypt_passphrase
# om demo/sec/loopcrypt decode --key disk_1_crypt_passphrase
<Cev~1nU38Mlt&b55)pn>>#pQ$R)|n%PBORIXhU]A;pM[4q|{o1H!z|Z;fk<eyDTp)HGn,CWw,nV||X,R.o"6REKtr?x{vc&-GxP-#K?T1sbr.OrBEYA"#,8h71y}jQ!?WFT~Ym5XiU~^U/e%h2tQfOdjy[(Ba?7YR{4)bE@83V98S@M$*VSSu|d$vp{UKTxcvar1_"I@ee7%</^]I,,j~f*?UkTk>rvP[(;xueG[qs(g%_p^cn>TP!W/C<O]ZT&
The orchestrated start
service action produces the following entries in the service log file /var/log/opensvc/namespaces/demo/svc/loopcrypt.log
:
2022-01-14 14:15:27,005 INFO sid:4580f356-999e-49bf-ab80-97202d8aa91b n:demo1 o:demo/svc/loopcrypt sc:n | do start --local (daemon origin)
2022-01-14 14:15:27,061 INFO sid:4580f356-999e-49bf-ab80-97202d8aa91b n:demo1 o:demo/svc/loopcrypt r:disk#0 sc:n | /sbin/losetup -f /opt/loopcrypt.demo.svc.default.img
2022-01-14 14:15:29,098 INFO sid:4580f356-999e-49bf-ab80-97202d8aa91b n:demo1 o:demo/svc/loopcrypt r:disk#0 sc:n | /dev/loop1 now loops to /opt/loopcrypt.demo.svc.default.img
2022-01-14 14:15:29,211 INFO sid:4580f356-999e-49bf-ab80-97202d8aa91b n:demo1 o:demo/svc/loopcrypt r:disk#1 sc:n | cryptsetup luksOpen /dev/loop5 loopcrypt.demo.svc.default-crypt -
2022-01-14 14:15:31,357 INFO sid:4580f356-999e-49bf-ab80-97202d8aa91b n:demo1 o:demo/svc/loopcrypt r:fs#0 sc:n | e2fsck -p /dev/mapper/loopcrypt.demo.svc.default-crypt
2022-01-14 14:15:31,364 INFO sid:4580f356-999e-49bf-ab80-97202d8aa91b n:demo1 o:demo/svc/loopcrypt r:fs#0 sc:n | | /dev/mapper/loopcrypt.demo.svc.default-crypt: clean, 12/64512 files, 8786/258048 blocks
2022-01-14 14:15:31,365 INFO sid:4580f356-999e-49bf-ab80-97202d8aa91b n:demo1 o:demo/svc/loopcrypt r:fs#0 sc:n | mount -t ext4 /dev/mapper/loopcrypt.demo.svc.default-crypt /srv/loopcrypt
Service stop¶
When the service is stopped, are ressources are brought down:
# om demo/svc/loopcrypt print status
demo/svc/loopcrypt up
`- instances
`- demo1 up idle, started
|- disk#0 ........ up loop /opt/loopcrypt.demo.svc.default.img
|- disk#1 ........ up crypt /dev/mapper/loopcrypt.demo.svc.default-crypt
`- fs#0 ........ up ext4 /dev/mapper/loopcrypt.demo.svc.default-crypt@/srv/loopcrypt
# om demo/svc/loopcrypt stop
@ n:demo1 o:demo/svc/loopcrypt sc:n
demo/svc/loopcrypt defer target state set to stopped
# om demo/svc/loopcrypt print status
demo/svc/loopcrypt down
`- instances
`- demo1 down frozen, idle
|- disk#0 ........ down loop /opt/loopcrypt.demo.svc.default.img
|- disk#1 ........ down crypt /dev/mapper/loopcrypt.demo.svc.default-crypt
`- fs#0 ........ down ext4 /dev/mapper/loopcrypt.demo.svc.default-crypt@/srv/loopcrypt
During the stop
action, the steps below are executed:
unmount the
/srv/loopcrypt
filesystemrun a
cryptsetup luksClose
command to stop the exposure of unencrypted blockdevice/dev/mapper/loopcrypt.demo.svc.default-crypt
unconfigure the loop device
/dev/loop1
The orchestrated stop
service action produces the following entries in the service log file /var/log/opensvc/namespaces/demo/svc/loopcrypt.log
:
2022-01-14 14:19:22,165 INFO sid:364cb3df-a8f8-4068-8d8c-3fe7fcabaf9e n:demo1 o:demo/svc/loopcrypt sc:n | do stop --local (daemon origin)
2022-01-14 14:19:22,446 INFO sid:364cb3df-a8f8-4068-8d8c-3fe7fcabaf9e n:demo1 o:demo/svc/loopcrypt r:fs#0 sc:n | umount /srv/loopcrypt
2022-01-14 14:19:22,498 INFO sid:364cb3df-a8f8-4068-8d8c-3fe7fcabaf9e n:demo1 o:demo/svc/loopcrypt r:disk#1 sc:n | cryptsetup luksClose /dev/mapper/loopcrypt.demo.svc.default-crypt
2022-01-14 14:19:22,615 INFO sid:364cb3df-a8f8-4068-8d8c-3fe7fcabaf9e n:demo1 o:demo/svc/loopcrypt r:disk#0 sc:n | /sbin/losetup -d /dev/loop1
SAN device¶
For production use, using real block devices is strongly recommended
In the example, we use the multipathed disk below:
# multipath -l 36589cfc000000b4f42b70859f9e9dbee
36589cfc000000b4f42b70859f9e9dbee dm-12 FreeNAS,iSCSI Disk
size=1.0G features='0' hwhandler='1 alua' wp=rw
|-+- policy='service-time 0' prio=0 status=active
| `- 3:0:0:10 sdk 8:160 active undef running
`-+- policy='service-time 0' prio=0 status=enabled
`- 4:0:0:10 sdx 65:112 active undef running
Service configuration¶
First, we build the service template file:
# cat > /tmp/sancrypt.conf <<-EOF
[DEFAULT]
id = 2d683ea4-5006-4e82-aae1-169d10d1f34a
[disk#1]
type = crypt
dev = /dev/mapper/36589cfc000000b4f42b70859f9e9dbee
name = {fqdn}-crypt
[fs#0]
type = ext4
dev = {disk#1.exposed_devs[0]}
mnt = /srv/{svcname}
EOF
Service creation¶
Then, we can deploy the sancrypt
service, in the demo
namespace:
# om demo/svc/sancrypt create --config=/tmp/sancrypt.conf
create demo/svc/sancrypt
Service start¶
We first have to provision the service, which will build and start ressources:
# om demo/svc/sancrypt provision --wait
@ n:demo1 o:demo/svc/sancrypt sc:n
demo/svc/sancrypt defer target state set to provisioned
The new service state is now provisioned, and all resources are up:
# om demo/svc/sancrypt print status -r
demo/svc/sancrypt up
`- instances
`- demo1 up idle, started
|- disk#1 ........ up crypt /dev/mapper/sancrypt.demo.svc.default-crypt
`- fs#0 ........ up ext4 /dev/mapper/sancrypt.demo.svc.default-crypt@/srv/sancrypt
# om demo/svc/sancrypt print devs
demo/svc/sancrypt
|- fs#0 (fs)
| |- base
| | |- /dev/dm-12
| | `- /dev/sdx
| `- sub
| |- /dev/sdk
| `- /dev/sdx
`- disk#1 (disk.crypt)
|- base
| `- /dev/dm-12
|- sub
| `- /dev/mapper/36589cfc000000b4f42b70859f9e9dbee
`- exposed
`- /dev/mapper/sancrypt.demo.svc.default-crypt
# df -h /srv/sancrypt
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/sancrypt.demo.svc.default-crypt 977M 2.5M 908M 1% /srv/sancrypt
We can see that the secret object has been created by the agent:
# om demo/sec/sancrypt keys
disk_1_crypt_passphrase
# om demo/sec/sancrypt decode --key disk_1_crypt_passphrase
Rc)ovE#k|tw?E,6Y@L}f+Vg,KGzi*]{EU,YNot5rJRbN^2hln`~-]~7LPAKb8;4zAM,g7:X?[fLXa,lCQN[yF<E~^k(&x6nnspM;PNlO6B(YyC}J"f%AF8xmfe:F,-]N]K$mUH3RLG#^AJc<rip=RB:Q(nT.V+68&A-}/^][s5X5<9l2Zvhp:ASt:EH(CA-a)G)CQ5:LqR|7Och(HKm+1+gbT>%zz8jocb@7^-Z~[WR^5fA<RDPI.{y*PS<Qum9A
Note
More complex setups can be configured (encrypted drbd device, encrypted mdadm device, …).
Passphrase¶
LUKS needs a random passphrase to format the encrypted block device.
By default, the opensvc agent deals with the passphrase creation and store it encrypted in a secret object, replicated across cluster nodes.
The generated passphrase is made of 256 characters randomly choosen from uppercase, lowercase, punctuation (except '
and \
)
It is possible to disable the automatic passphrase management from opensvc agent, using the parameter manage_passphrase = false
. You will have to create the secret object, and associated key by yourself.
Note
Whatever the value of manage_passphrase
, the secret object is always replicated accross cluster nodes
Loss protection¶
In case the passphrase is manually deleted from the opensvc secret object, the agent won’t accept to stop the encrypted disk ressource, to have a last chance to backup the filesystem for example (or restore the passphrase)
An orchestrated stop
service action will end in stop failed
status, while a CRM stop
action will propose the --force
cli option to bypass the security:
First we simulate the passphrase loss by deleting the key containing the passphrase:
# om demo/sec/loopcrypt keys
disk_1_crypt_passphrase
# om demo/sec/loopcrypt remove --key disk_1_crypt_passphrase
# om demo/sec/loopcrypt keys
#
The service is still operational without the passphrase, because the unencrypted blockdevice is still opened:
# om demo/svc/loopcrypt print status -r
demo/svc/loopcrypt up
`- instances
`- demo1 up frozen, idle, started
|- disk#0 ........ up loop /opt/loopcrypt.demo.svc.default.img
|- disk#1 ........ up crypt /dev/mapper/loopcrypt.demo.svc.default-crypt
`- fs#0 ........ up ext4 /dev/mapper/loopcrypt.demo.svc.default-crypt@/srv/loopcrypt
# om demo/svc/loopcrypt mon
demo/svc/loo... demo1 demo2
demo/svc/loopcrypt up 1/1 | O^
The orchestrated stop
action fails (root cause explained in the service logfile):
# om demo/svc/loopcrypt stop
@ n:demo1 o:demo/svc/loopcrypt sc:n
demo/svc/loopcrypt defer target state set to stopped
# om demo/svc/loopcrypt mon
demo/svc/loo... demo1 demo2
demo/svc/loopcrypt warn! 0/1 | !!* stop failed
The CRM stop
action display on stdout why the disk#1
ressource can not be stopped:
# om demo/svc/loopcrypt stop --local
@ n:demo1 o:demo/svc/loopcrypt r:fs#0 sc:n
ext4 /dev/mapper/loopcrypt.demo.svc.default-crypt@/srv/loopcrypt is already umounted
@ n:demo1 o:demo/svc/loopcrypt r:disk#1 sc:n
E abort crypt deactivate, so you can backup the device that we won't be able to activate again: demo/sec/loopcrypt has no disk_1_crypt_passphrase key. restore the key or use --force to skip this safeguard
Supposing that the filesystem has been saved somewhere, we can force the agent to close the unencrypted block device:
# om demo/svc/loopcrypt stop --local --force
@ n:demo1 o:demo/svc/loopcrypt r:fs#0 sc:n
ext4 /dev/mapper/loopcrypt.demo.svc.default-crypt@/srv/loopcrypt is already umounted
@ n:demo1 o:demo/svc/loopcrypt r:disk#1 sc:n
cryptsetup luksClose /dev/mapper/loopcrypt.demo.svc.default-crypt
@ n:demo1 o:demo/svc/loopcrypt r:disk#0 sc:n
/sbin/losetup -d /dev/loop1
@ n:demo1 o:demo/svc/loopcrypt sc:n
/bin/echo 1 >/sys/fs/cgroup/freezer/opensvc.slice/demo.slice/loopcrypt.slice/cgroup.clone_children
no task to kill
The cryptsetup luksClose
definitely close the unencrypted block device. To reopen it, the sysadmin would have to restore the passphrase in the secret object key, and start the service.
Unprovision/Purge¶
Warning
Be aware that running unprovision
or purge
service actions will lead to data loss