Encryption (fix #3)

This commit is contained in:
Roey Darwish Dror 2018-12-02 16:01:23 +02:00
parent db9fdb29c6
commit 8c41b390a3
5 changed files with 184 additions and 22 deletions

View File

@ -17,6 +17,7 @@ This tool should be ran from an exiting Arch Linux installations. It depends on
* Arch install scripts * Arch install scripts
* mkfs.fat * mkfs.fat
* mkfs.btrfs * mkfs.btrfs
* *Optional*: cryptsetup
Dependencies will be handled for you if you install alma from AUR. Dependencies will be handled for you if you install alma from AUR.
@ -42,6 +43,7 @@ sudo alma chroot /dev/disk/by-id/usb-Generic_USB_Flash_Disk-0:0
### Flags ### Flags
* `-p / --extra-packages` - Specify extra packages to install. For example: `-p htop tmux` * `-p / --extra-packages` - Specify extra packages to install. For example: `-p htop tmux`
* `-i / --interactive` - Drop you into interactive chroot to perform further customization * `-i / --interactive` - Drop you into interactive chroot to perform further customization
* `-e / --encrypted-root` - Encrypt the root filesystem.
## What exactly does it do? ## What exactly does it do?

View File

@ -1,31 +1,39 @@
use super::block::BlockDevice; use super::block::BlockDevice;
use super::cryptsetup::EncryptedDevice;
use super::error::{Error, ErrorKind}; use super::error::{Error, ErrorKind};
use super::mountstack::{Filesystem, MountStack}; use super::mountstack::{Filesystem, MountStack};
use failure::ResultExt; use failure::ResultExt;
use log::info; use log::{debug, info};
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
pub struct ALMA { pub struct ALMA<'a> {
block: BlockDevice, block: BlockDevice,
encrypted_root: Option<EncryptedDevice<'a>>,
} }
impl ALMA { impl<'a> ALMA<'a> {
pub fn new(block: BlockDevice) -> Self { pub fn new(block: BlockDevice, encrypted_root: Option<EncryptedDevice<'a>>) -> Self {
Self { block } Self {
block,
encrypted_root,
}
} }
pub fn mount<'a>(&self, path: &'a Path) -> Result<MountStack<'a>, Error> { pub fn mount<'b>(&self, path: &'b Path) -> Result<MountStack<'b>, Error> {
let mut mount_stack = MountStack::new(); let mut mount_stack = MountStack::new();
let root_device = if let Some(encrypted_root) = &self.encrypted_root {
PathBuf::from(encrypted_root.path())
} else {
self.block.partition_device_path(3)?
};
debug!("Root partition: {}", root_device.display());
info!("Mounting filesystems to {}", path.display()); info!("Mounting filesystems to {}", path.display());
mount_stack mount_stack
.mount( .mount(&root_device, path, Filesystem::Btrfs, None)
&PathBuf::from(&self.block.partition_device_path(3)?), .context(ErrorKind::Mounting)?;
path,
Filesystem::Btrfs,
None,
).context(ErrorKind::Mounting)?;
let boot_point = path.join("boot"); let boot_point = path.join("boot");
if !boot_point.exists() { if !boot_point.exists() {

68
src/cryptsetup.rs Normal file
View File

@ -0,0 +1,68 @@
use super::error::{Error, ErrorKind};
use super::process::CommandExt;
use super::tool::Tool;
use log::{debug, warn};
use std::path::{Path, PathBuf};
pub struct EncryptedDevice<'a> {
cryptsetup: &'a Tool,
name: &'a str,
path: PathBuf,
}
impl<'a> EncryptedDevice<'a> {
pub fn prepare(cryptsetup: &Tool, device: &Path) -> Result<(), Error> {
debug!("Preparing encrypted device in {}", device.display());
cryptsetup
.execute()
.arg("luksFormat")
.arg("-q")
.arg(device)
.run(ErrorKind::LuksSetup)?;
Ok(())
}
pub fn open(
cryptsetup: &'a Tool,
device: &Path,
name: &'a str,
) -> Result<EncryptedDevice<'a>, Error> {
debug!("Opening encrypted device {} as {}", device.display(), name);
cryptsetup
.execute()
.arg("open")
.arg(device)
.arg(name)
.run(ErrorKind::LuksOpen)?;
Ok(Self {
cryptsetup,
name,
path: PathBuf::from("/dev/mapper").join(name),
})
}
fn _close(&mut self) -> Result<(), Error> {
debug!("Closing encrypted device {}", self.name);
self.cryptsetup
.execute()
.arg("close")
.arg(self.name)
.run(ErrorKind::LuksClose)?;
Ok(())
}
pub fn path(&self) -> &Path {
&self.path
}
}
impl<'a> Drop for EncryptedDevice<'a> {
fn drop(&mut self) {
if self._close().is_err() {
warn!("Error closing {}", self.name);
}
}
}

View File

@ -58,6 +58,15 @@ pub enum ErrorKind {
#[fail(display = "Failed umounting filesystems")] #[fail(display = "Failed umounting filesystems")]
UmountFailure, UmountFailure,
#[fail(display = "Error setting up an encrypted device")]
LuksSetup,
#[fail(display = "Error opening the encrypted device")]
LuksOpen,
#[fail(display = "Error closing the encrypted device")]
LuksClose,
} }
impl Fail for Error { impl Fail for Error {

View File

@ -9,18 +9,21 @@ use nix::sys::signal;
mod alma; mod alma;
mod block; mod block;
mod cryptsetup;
mod error; mod error;
mod mountstack; mod mountstack;
mod process; mod process;
mod tool; mod tool;
use alma::ALMA; use alma::ALMA;
use cryptsetup::EncryptedDevice;
use error::*; use error::*;
use failure::{Fail, ResultExt}; use failure::{Fail, ResultExt};
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use process::CommandExt; use process::CommandExt;
use simplelog::*; use simplelog::*;
use std::fs; use std::fs;
use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::exit; use std::process::exit;
use std::thread; use std::thread;
@ -32,7 +35,7 @@ use tool::Tool;
static MKINITCPIO: &'static str = "MODULES=() static MKINITCPIO: &'static str = "MODULES=()
BINARIES=() BINARIES=()
FILES=() FILES=()
HOOKS=(base udev block filesystems keyboard fsck)"; HOOKS=(base udev keyboard consolefont block encrypt filesystems keyboard fsck)";
static JOURNALD_CONF: &'static str = " static JOURNALD_CONF: &'static str = "
[Journal] [Journal]
@ -43,7 +46,8 @@ SystemMaxUse=16M
#[derive(StructOpt)] #[derive(StructOpt)]
#[structopt(name = "alma", about = "Arch Linux Mobile Appliance")] #[structopt(name = "alma", about = "Arch Linux Mobile Appliance")]
struct App { struct App {
#[structopt(short = "v", long = "verbose", help = "Verbose output")] /// Verbose output
#[structopt(short = "v", long = "verbose")]
verbose: bool, verbose: bool,
#[structopt(subcommand)] #[structopt(subcommand)]
@ -72,6 +76,10 @@ struct CreateCommand {
/// Enter interactive chroot before unmounting the drive /// Enter interactive chroot before unmounting the drive
#[structopt(short = "i", long = "interactive")] #[structopt(short = "i", long = "interactive")]
interactive: bool, interactive: bool,
/// Encrypt the root partition
#[structopt(short = "e", long = "encrypted-root")]
encrypted_root: bool,
} }
#[derive(StructOpt)] #[derive(StructOpt)]
@ -79,6 +87,10 @@ struct ChrootCommand {
/// Path starting with /dev/disk/by-id for the USB drive /// Path starting with /dev/disk/by-id for the USB drive
#[structopt(parse(from_os_str),)] #[structopt(parse(from_os_str),)]
block_device: PathBuf, block_device: PathBuf,
/// Open an encrypted root partition
#[structopt(short = "e", long = "encrypted-root")]
encrypted_root: bool,
} }
fn fix_fstab(fstab: &str) -> String { fn fix_fstab(fstab: &str) -> String {
@ -96,6 +108,16 @@ fn create(command: CreateCommand) -> Result<(), Error> {
let genfstab = Tool::find("genfstab")?; let genfstab = Tool::find("genfstab")?;
let mkfat = Tool::find("mkfs.fat")?; let mkfat = Tool::find("mkfs.fat")?;
let mkbtrfs = Tool::find("mkfs.btrfs")?; let mkbtrfs = Tool::find("mkfs.btrfs")?;
let cryptsetup = if command.encrypted_root {
Some(Tool::find("cryptsetup")?)
} else {
None
};
let blkid = if command.encrypted_root {
Some(Tool::find("blkid")?)
} else {
None
};
let block_device = block::BlockDevice::from_path(command.block_device)?; let block_device = block::BlockDevice::from_path(command.block_device)?;
@ -130,14 +152,28 @@ fn create(command: CreateCommand) -> Result<(), Error> {
.run(ErrorKind::Formatting)?; .run(ErrorKind::Formatting)?;
let root_partition = block_device.partition_device_path(3)?; let root_partition = block_device.partition_device_path(3)?;
let encrypted_root = if let Some(cryptsetup) = &cryptsetup {
EncryptedDevice::prepare(&cryptsetup, &root_partition)?;
Some(EncryptedDevice::open(
cryptsetup,
&root_partition,
"alma_root",
)?)
} else {
None
};
mkbtrfs mkbtrfs
.execute() .execute()
.arg("-f") .arg("-f")
.arg(&root_partition) .arg(if let Some(device) = &encrypted_root {
.run(ErrorKind::Formatting)?; device.path()
} else {
&root_partition
}).run(ErrorKind::Formatting)?;
let alma = ALMA::new(block_device); let alma = ALMA::new(block_device, encrypted_root);
let mut mount_stack = alma.mount(mount_point.path())?; let mount_stack = alma.mount(mount_point.path())?;
info!("Bootstrapping system"); info!("Bootstrapping system");
pacstrap pacstrap
@ -186,6 +222,30 @@ fn create(command: CreateCommand) -> Result<(), Error> {
.args(&["mkinitcpio", "-p", "linux"]) .args(&["mkinitcpio", "-p", "linux"])
.run(ErrorKind::Initramfs)?; .run(ErrorKind::Initramfs)?;
if cryptsetup.is_some() {
debug!("Setting up GRUB for an encrypted root partition");
let uuid = blkid
.unwrap()
.execute()
.arg(root_partition)
.args(&["-o", "value", "-s", "UUID"])
.run_text_output(ErrorKind::Partitioning)?;
let trimmed = uuid.trim();
debug!("Root partition UUID: {}", trimmed);
let mut grub_file = fs::OpenOptions::new()
.append(true)
.open(mount_point.path().join("etc/default/grub"))
.context(ErrorKind::Bootloader)?;
write!(
&mut grub_file,
"GRUB_CMDLINE_LINUX=\"cryptdevice=UUID={}:luks_root\"",
trimmed
).context(ErrorKind::Bootloader)?;
}
info!("Installing the Bootloader"); info!("Installing the Bootloader");
arch_chroot arch_chroot
.execute() .execute()
@ -205,18 +265,33 @@ fn create(command: CreateCommand) -> Result<(), Error> {
info!("Unmounting filesystems"); info!("Unmounting filesystems");
mount_stack.umount()?; mount_stack.umount()?;
info!("Installation succeeded. It is now safe to unplug your device.");
Ok(()) Ok(())
} }
fn chroot(command: ChrootCommand) -> Result<(), Error> { fn chroot(command: ChrootCommand) -> Result<(), Error> {
let arch_chroot = Tool::find("arch-chroot")?; let arch_chroot = Tool::find("arch-chroot")?;
let cryptsetup = if command.encrypted_root {
Some(Tool::find("cryptsetup")?)
} else {
None
};
let block_device = block::BlockDevice::from_path(command.block_device)?; let block_device = block::BlockDevice::from_path(command.block_device)?;
let mount_point = tempdir().context(ErrorKind::TmpDirError)?; let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
let alma = ALMA::new(block_device); let root_partition = block_device.partition_device_path(3)?;
let mut mount_stack = alma.mount(mount_point.path())?; let encrypted_root = if let Some(cryptsetup) = &cryptsetup {
Some(EncryptedDevice::open(
cryptsetup,
&root_partition,
"alma_root",
)?)
} else {
None
};
let alma = ALMA::new(block_device, encrypted_root);
let mount_stack = alma.mount(mount_point.path())?;
arch_chroot arch_chroot
.execute() .execute()