Skip to content

Instantly share code, notes, and snippets.

@jakelee8
Created December 5, 2016 04:41
Show Gist options
  • Save jakelee8/a7eac29c54ea0ddebf0d3855db5ad55a to your computer and use it in GitHub Desktop.
Save jakelee8/a7eac29c54ea0ddebf0d3855db5ad55a to your computer and use it in GitHub Desktop.
#!/usr/bin/python
import errno
import os
import os.path
import sys
import uuid
from subprocess import call
def mkdir_p(path):
""" mkdir -p
http://stackoverflow.com/a/600612
"""
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
def install_dependencies():
call(['apt', 'install', '-y', 'cryptsetup', 'zfs'])
def generate_key(path):
with open(path, 'wb') as fh:
call(['head', '-c', '256', '/dev/urandom'], stdout=fh)
os.chmod(path, 0600)
class CryptBlockDevice(object):
N_KEY_SLOTS = 3
def __init__(self, block_device_path, device_uuid=None,
keyfiles_dir='keyfiles'):
if device_uuid is None:
device_uuid = str(uuid.uuid4())
keyfiles_dir = os.path.realpath(keyfiles_dir)
self.block_device_path = block_device_path
self.device_uuid = device_uuid
self.keyfiles_dir = os.path.realpath(keyfiles_dir)
self.keyfile_path = os.path.join(keyfiles_dir, device_uuid)
@property
def device_path(self):
return os.path.join('/dev/mapper', self.device_uuid)
def create(self):
self.init()
self.open()
def init(self):
self.create_keyfile_directory()
self.create_keyfiles_if_not_exist()
self.format_block_device()
self.set_rescue_keys()
def open(self):
keyfile_path = '%s.slot-0.key' % self.keyfile_path
call([
'cryptsetup', 'open',
'--type', 'luks',
'--key-file=%s' % keyfile_path,
self.block_device_path,
self.device_uuid])
def close(self):
call(['cryptsetup', 'close', self.device_path])
def create_keyfile_directory(self):
mkdir_p(self.keyfiles_dir)
os.chmod(self.keyfiles_dir, 0600)
def create_keyfiles_if_not_exist(self):
for i in range(self.N_KEY_SLOTS):
keyfile_path = '%s.slot-%d.key' % (self.keyfile_path, i)
if not os.path.exists(keyfile_path):
generate_key(keyfile_path)
def format_block_device(self):
keyfile_path = '%s.slot-0.key' % self.keyfile_path
call([
'cryptsetup', 'luksFormat',
'--uuid=%s' % self.device_uuid,
'--key-file=%s' % keyfile_path,
self.block_device_path])
def set_rescue_keys(self):
keyfile_path = '%s.slot-0.key' % self.keyfile_path
for i in range(1, self.N_KEY_SLOTS):
rescue_keyfile_path = '%s.slot-%d.key' % (self.keyfile_path, i)
call([
'cryptsetup', 'luksAddKey',
'--key-file=%s' % keyfile_path,
'UUID=%s' % self.device_uuid,
rescue_keyfile_path])
def save_crypttab(self, options=None):
if options is None:
options = []
if not isinstance(options, (list, tuple)):
options = [options]
else:
options = list(options)
options.insert(0, 'luks')
options = ','.join(options)
crypttab_file = '%s.crypttab' % self.keyfile_path
with open(crypttab_file, 'wb') as fh:
fh.write('%s UUID=%s %s %s\n' % (
self.device_uuid, self.device_uuid,
self.device_path, options))
class Zpool(object):
"""
https://www.jamescoyle.net/how-to/478-create-a-zfs-volume-on-ubuntu
https://help.ubuntu.com/community/encryptedZfs
"""
def __init__(self, name, block_devices):
self.name = name
self.block_devices = list(block_devices)
def create(self):
call([
'zpool', 'create',
'-O', 'mountpoint=none',
self.name, 'raidz',
] + self.block_devices)
def destroy(self):
call(['zpool', 'destroy', self.name])
# def save_fstab(device_path, output_path):
# print('UUID=%s %s btrfs '
# 'defaults,noauto,nofail,autodefrag,'
# 'compress=lzo,degraded,recovery,nossd 0 0')
# def save_autofs(device_path, output_path):
# print('%s -fstype=btrfs,autodefrag,compress=lzo,degraded,recovery,nossd '
# ':%s')
def main(block_device_paths, keyfiles_dir='keyfiles'):
crypt_block_devices = []
for block_device_path in block_device_paths:
cbd = CryptBlockDevice(block_device_path, keyfiles_dir=keyfiles_dir)
cbd.init()
cbd.set_rescue_keys()
cbd.save_crypttab()
crypt_block_devices.append(cbd)
del cbd
for cbd in crypt_block_devices:
cbd.open()
crypt_block_device_paths = [cbd.device_path for cbd in crypt_block_devices]
datapool = Zpool('datapool', crypt_block_device_paths)
datapool.create()
# zfs create -o mountpoint=/data -o compression=lz4 datapool/data
if __name__ == '__main__':
install_dependencies()
main(list(sys.argv[1:]))
#!/usr/bin/bash
python luks_zfs.py /dev/disk/by-id/ata-*
zfs create -o mountpoint=/data -o compression=lz4 datapool/data
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment