<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>It's Pi all the way down... - luks</title><link href="https://waldorf.waveform.org.uk/" rel="alternate"></link><link href="https://waldorf.waveform.org.uk/feeds/luks.atom.xml" rel="self"></link><id>https://waldorf.waveform.org.uk/</id><updated>2023-11-06T08:37:40+00:00</updated><entry><title>Building Blocks</title><link href="https://waldorf.waveform.org.uk/2023/building-blocks.html" rel="alternate"></link><published>2023-10-24T00:00:00+01:00</published><updated>2023-11-06T08:37:40+00:00</updated><author><name>Dave Jones</name></author><id>tag:waldorf.waveform.org.uk,2023-10-24:/2023/building-blocks.html</id><summary type="html">&lt;p class="first last"&gt;In which we finally cover what a block device&amp;nbsp;is&lt;/p&gt;
</summary><content type="html">&lt;p&gt;In an earlier series of posts (Playing with Blocks &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2021/playing-with-blocks-lvm.html"&gt;1&lt;/a&gt;, &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2021/playing-with-blocks-luks.html"&gt;2&lt;/a&gt;, &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2022/playing-with-blocks-its-all-connected.html"&gt;3&lt;/a&gt;, and &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2023/playing-with-blocks-reluks.html"&gt;4&lt;/a&gt;) we had a
look at customizing Ubuntu images for the Raspberry Pi by playing around with
various block device transformations. However, we never covered &lt;em&gt;what&lt;/em&gt; a block
device actually &lt;em&gt;is&lt;/em&gt;. This is going to be a vaguely important topic in an
upcoming series of posts on &lt;abbr title="Network Block Device"&gt;&lt;span class="caps"&gt;NBD&lt;/span&gt;&lt;/abbr&gt; booting of
Ubuntu, so I figured some brief coverage of the topic is&amp;nbsp;warranted.&lt;/p&gt;
&lt;p&gt;Brief.&lt;/p&gt;
&lt;p&gt;Who am I&amp;nbsp;kidding?&lt;/p&gt;
&lt;div class="section" id="blockage"&gt;
&lt;h2&gt;Blockage&lt;/h2&gt;
&lt;p&gt;In the &lt;span class="caps"&gt;UNIX&lt;/span&gt; world a &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Device_file"&gt;block device&lt;/a&gt; is a very simple concept: it&amp;#8217;s a storage
device which provides access to its contents as an ordered sequence of
identically sized blocks. That&amp;#8217;s it. No files, no directories, no permissions,
nothing more than a numbered sequence of blocks all with the same size.
Typically, the blocks are some whole multiple of an underlying device&amp;#8217;s sector
size, which over most of computing history has been 512 bytes. However, the
user may access block devices byte-by-byte if they&amp;nbsp;wish:&lt;/p&gt;
&lt;object data="https://waldorf.waveform.org.uk/images/block-ops.svg" type="image/svg+xml"&gt;&lt;/object&gt;
&lt;p&gt;For instance, a read of a few bytes (illustrated on the left in green) may read
a full 512-byte sector, throw away the bytes outside the requested range, and
return that which was requested &lt;a class="footnote-reference" href="#cache1" id="footnote-reference-1"&gt;[5]&lt;/a&gt;. A write of a few bytes (illustrated
in the middle in red) is a bit more complex; the kernel needs to read the full
sector from the underlying device, change those bytes we requested to write in
the middle, then write the whole sector back to the underlying device
&lt;a class="footnote-reference" href="#cache2" id="footnote-reference-2"&gt;[6]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Crucially, block devices are &lt;em&gt;random&lt;/em&gt; access. We can access any block,
anywhere, at any time, without having to access all blocks prior to it. In
other words, block devices make storage look and &amp;#8220;feel&amp;#8221; like &lt;abbr title="Random Access Memory"&gt;&lt;span class="caps"&gt;RAM&lt;/span&gt;&lt;/abbr&gt;. This is as opposed to the &amp;#8220;byte-stream&amp;#8221; view of files which
owes more to the tape drives of old (&amp;#8220;seeking&amp;#8221; the head to a particular
location, then reading or writing from that&amp;nbsp;point).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="transform"&gt;
&lt;h2&gt;Transform!&lt;/h2&gt;
&lt;p&gt;The simplicity of block devices leads to them being wonderfully flexible things
that can often be converted into new block devices in useful ways. Probably the
most basic block device transformation that everyone is familiar with is
&amp;#8220;partitioning&amp;#8221;, which simply sub-divides one block device into multiple new
ones (minus some header space). This transformation effectively just re-numbers
the blocks but doesn&amp;#8217;t change their content or&amp;nbsp;ordering.&lt;/p&gt;
&lt;p&gt;More complex transformations are also&amp;nbsp;available.&lt;/p&gt;
&lt;p&gt;The &lt;abbr title="Logical Volume Manager"&gt;&lt;span class="caps"&gt;LVM&lt;/span&gt;&lt;/abbr&gt; sub-system (&lt;a class="reference external" href="https://waldorf.waveform.org.uk/2021/playing-with-blocks-lvm.html"&gt;explored previously&lt;/a&gt;) gathers multiple block devices into a &amp;#8220;volume group&amp;#8221;. The
volume group can then be used to produce other block devices called &amp;#8220;logical
volumes&amp;#8221;. These are similar to partitions, but have no need to be contiguous on
the underlying block devices, and can even span multiple underlying&amp;nbsp;devices.&lt;/p&gt;
&lt;object data="https://waldorf.waveform.org.uk/images/block-transforms.svg" type="image/svg+xml"&gt;A drive (sda) is divided into two partitions (sda1, sda2) the latter
of which is further divided into three block devices with &lt;span class="caps"&gt;LVM&lt;/span&gt; (root,
home, and swap). The home device has been expanded at some point in
its history as its storage is non-contiguous&lt;/object&gt;
&lt;p&gt;Speaking of multiple underlying devices, &lt;abbr title="Redundant Array of Inexpensive Disks"&gt;&lt;span class="caps"&gt;RAID&lt;/span&gt;&lt;/abbr&gt; systems (like &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Mdadm"&gt;mdadm&lt;/a&gt;) consume multiple block devices and
produce a single block device. The blocks in the produced device are duplicated
to the underlying block devices (in the simplest mirror case; more complex
transforms are involved in things like &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Standard_RAID_levels"&gt;&lt;span class="caps"&gt;RAID5&lt;/span&gt;&lt;/a&gt;). Corruption
or even loss of one of the underlying block devices, as in the failure of a
drive, can be entirely hidden from the consumer of the produced block&amp;nbsp;device.&lt;/p&gt;
&lt;object data="https://waldorf.waveform.org.uk/images/block-raid.svg" type="image/svg+xml"&gt;Four drives (sda, sdb, sdc, and sdd) are partitioned such that each
has a small initial partition (sda1 etc.) and a larger partition
(sda2 etc.); the small initial partitions are combined as a &lt;span class="caps"&gt;RAID1&lt;/span&gt;
mirror into a boot block device. The larger partitions are combined
as a &lt;span class="caps"&gt;RAID10&lt;/span&gt; device (a stripe of mirrors) as a root device.&lt;/object&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup"&gt;&lt;span class="caps"&gt;LUKS&lt;/span&gt;&lt;/a&gt; encryption mechanism (also explored in &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2021/playing-with-blocks-luks.html"&gt;previous posts&lt;/a&gt;) consumes one block device and produces a slightly smaller one
(minus the size of the &lt;span class="caps"&gt;LUKS&lt;/span&gt; header) that scrambles (and unscrambles) the
content of blocks as they are written (and&amp;nbsp;read).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-hierarchy"&gt;
&lt;h2&gt;The&amp;nbsp;Hierarchy&lt;/h2&gt;
&lt;p&gt;A &lt;a class="reference external" href="https://en.wikipedia.org/wiki/File_system"&gt;file-system&lt;/a&gt; is just another kind of transformation of a block device; one
which converts the flat sequence of blocks into a tree-like hierarchy of files
(optionally with attributes like ownership, groups, permissions, and all the
rest of that&amp;nbsp;gubbins).&lt;/p&gt;
&lt;p&gt;File systems can be relatively simple affairs, like the ancient but ubiquitous
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system"&gt;&lt;span class="caps"&gt;FAT&lt;/span&gt;&lt;/a&gt; which has no concept of file ownership, &lt;span class="caps"&gt;UNIX&lt;/span&gt; modes, and no symlinks.
Alternatively they can be complex, like the common &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Ext4"&gt;ext4&lt;/a&gt; file-system which
has journaling data recovery, the full suite of &lt;span class="caps"&gt;UNIX&lt;/span&gt; ownership, attributes, and
linkage, and numerous tunable&amp;nbsp;options.&lt;/p&gt;
&lt;p&gt;Ultimately, the file-systems produced from various block devices are all
grafted together (&amp;#8220;mounted&amp;#8221; in &lt;span class="caps"&gt;UNIX&lt;/span&gt; parlance) onto a &amp;#8220;virtual&amp;#8221; file-system
which is what all userland processes (and you, the user) generally consider
&amp;#8220;the file-system&amp;#8221;; the place you find all the files on your&amp;nbsp;computer.&lt;/p&gt;
&lt;object data="https://waldorf.waveform.org.uk/images/block-to-fs.svg" type="image/svg+xml"&gt;Two partitions (sda1 and sda2) are formatted as &lt;span class="caps"&gt;FAT&lt;/span&gt; and ext4
respectively. The vfat driver converts the sda1 block device into a
typical boot file-system for the Pi (containing bootcode.bin,
start4.elf, config.txt, etc). The ext4 driver converts the sda2 block
device into a typical Linux root file-system (containing bin, etc,
lib, usr, sbin directories). The virtual file-system then &amp;#8220;mounts&amp;#8221;
the ext4 hierarchy under / and the &lt;span class="caps"&gt;FAT&lt;/span&gt; hierarchy under /boot/firmware&lt;/object&gt;
&lt;p&gt;A common Linux storage layout is shown above. The drive (&lt;tt class="docutils literal"&gt;/dev/sda&lt;/tt&gt;) has two
partitions. The first partition (&lt;tt class="docutils literal"&gt;/dev/sda1&lt;/tt&gt;) is formatted as &lt;span class="caps"&gt;FAT&lt;/span&gt;, which the
kernel&amp;#8217;s vfat driver transforms into a file-system. The second partition
(&lt;tt class="docutils literal"&gt;/dev/sda2&lt;/tt&gt;) is formatted as ext4, which the ext4 driver transforms into
another file-system. The kernel has mounted the ext4 file-system as the root of
the &amp;#8220;virtual&amp;#8221; file-system, and the &lt;span class="caps"&gt;FAT&lt;/span&gt; file-system under the &lt;tt class="docutils literal"&gt;/boot/firmware&lt;/tt&gt;
mount-point.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="holy-cow"&gt;
&lt;h2&gt;Holy&amp;nbsp;CoW!&lt;/h2&gt;
&lt;p&gt;Some modern file-systems provide a copy-on-write facility (most notably
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Btrfs"&gt;btrfs&lt;/a&gt; and &lt;a class="reference external" href="https://en.wikipedia.org/wiki/ZFS"&gt;zfs&lt;/a&gt;). This allows rapid (near instantaneous) cloning of an
entire file-system hierarchy. The clone doesn&amp;#8217;t initially take any storage of
its own, and reads of the clone actually go to the original files. However,
writes to the clone allocate new storage for the changed&amp;nbsp;content.&lt;/p&gt;
&lt;p&gt;However, the facility is not limited to modern file-systems. &lt;span class="caps"&gt;LVM&lt;/span&gt; also provides
such a facility, initially intended to provide snapshots of file-systems at a
point in time (for backup, testing, or other&amp;nbsp;purposes).&lt;/p&gt;
&lt;object data="https://waldorf.waveform.org.uk/images/block-cow-snap.svg" type="image/svg+xml"&gt;The &amp;#8220;root&amp;#8221; block device contains a number of filled blocks in green,
while the &amp;#8220;snap&amp;#8221; block device has an equivalent number of &amp;#8220;empty&amp;#8221;
blocks. Two reads, indicated by arrows, are made against the &amp;#8220;snap&amp;#8221;
device but pass through to the underlying &amp;#8220;root&amp;#8221; device. Below this
an equivalent layout is show, but now one of the &amp;#8220;filled&amp;#8221; blocks is
&amp;#8220;red&amp;#8221; indicating a change in content. Above it, the equivalent block
in the &amp;#8220;snap&amp;#8221; device is green indicating it contains the original
content. A read against this block comes directly from the &amp;#8220;snap&amp;#8221;
device instead of passing through to the underlying &amp;#8220;root&amp;#8221; device.&lt;/object&gt;
&lt;p&gt;The illustration above shows a &amp;#8220;root&amp;#8221; block device, presumably containing a
root file-system. We create a snapshot of the &amp;#8220;root&amp;#8221; block device called
&amp;#8220;snap&amp;#8221;. Initially, the &amp;#8220;snap&amp;#8221; block device is empty, and reads to it pass
through to the underlying &amp;#8220;root&amp;#8221; block device. However, when a block is the
&amp;#8220;root&amp;#8221; device is written to, its original content is first copied to the &amp;#8220;snap&amp;#8221;
device. Subsequent reads of this block in the &amp;#8220;snap&amp;#8221; device will go to this
copied block instead. Further writes to the same block in the &amp;#8220;root&amp;#8221; device are
ignored because the &amp;#8220;snap&amp;#8221; device only cares about the content at the point in
time it was&amp;nbsp;created.&lt;/p&gt;
&lt;p&gt;Note that one of the beauties of this system is that &lt;em&gt;we don&amp;#8217;t care&lt;/em&gt; what
file-system is on the &amp;#8220;root&amp;#8221; device. It could be &lt;span class="caps"&gt;FAT&lt;/span&gt;, ext4, &lt;span class="caps"&gt;XFS&lt;/span&gt;, even
(redundantly) one of the more modern systems that supports this internally.
However, a limitation of this snapshot system is that we need to allocate space
for it up front &lt;a class="footnote-reference" href="#notall" id="footnote-reference-3"&gt;[8]&lt;/a&gt;. Can we come up with something in which the snapshot
allocates blocks&amp;nbsp;dynamically?&lt;/p&gt;
&lt;object data="https://waldorf.waveform.org.uk/images/block-cow-thin.svg" type="image/svg+xml"&gt;At the top, the &amp;#8220;image&amp;#8221; block device (read-only) contains a number
of filled blocks in green. Above it, a clone, &amp;#8220;clone1&amp;#8221;, exists with
the same number of blocks but all are empty. A read of two blocks in
&amp;#8220;clone1&amp;#8221;, indicated by arrows, passes through to the corresponding
blocks in &amp;#8220;image&amp;#8221;. Below, the one of the blocks in &amp;#8220;clone1&amp;#8221; is now
red indicating it has been changed from the original content in
&amp;#8220;image&amp;#8221;. Another arrow, indicating a read of that block now comes
straight from &amp;#8220;clone1&amp;#8221; and doesn&amp;#8217;t pass through. Another clone,
&amp;#8220;clone2&amp;#8221;, is below it with entirely empty blocks. A read of the same
block which is changed in &amp;#8220;clone1&amp;#8221;, passes through &amp;#8220;clone2&amp;#8221; to the
underlying &amp;#8220;image&amp;#8221; device.&lt;/object&gt;
&lt;p&gt;The illustration above shows &amp;#8220;thinly provisioned&amp;#8221; snapshots in &lt;span class="caps"&gt;LVM&lt;/span&gt;. This
operates a little like the regular snapshots in reverse. An underlying block
device called &amp;#8220;image&amp;#8221; presumably contains an &lt;span class="caps"&gt;OS&lt;/span&gt; image. We have created a
&amp;#8220;thinly provisioned&amp;#8221; snapshot of this called &amp;#8220;clone1&amp;#8221;. Reads of an unchanged
block pass through to the underlying (read-only) &amp;#8220;image&amp;#8221;. Writes to blocks in
&amp;#8220;clone1&amp;#8221; occur within its storage, with subsequent reads to that block no
longer passing through. Finally, we create another clone, &amp;#8220;clone2&amp;#8221;, which reads
the original block from the underlying&amp;nbsp;&amp;#8220;image&amp;#8221;.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s worth noting that most of the blocks in the clones are empty. Provided
they stay that way (i.e. the clones don&amp;#8217;t change too many blocks of the
underlying image), there&amp;#8217;s little sense in &lt;em&gt;actually&lt;/em&gt; allocating them. This is
the &amp;#8220;thin&amp;#8221; in &amp;#8220;thinly provisioned&amp;#8221;. The blocks of the clones are allocated on
demand so a clone initially takes up no space. This allocate-on-demand facility
can implement one form of &amp;#8220;over provisioning&amp;#8221; of storage. Each clone &lt;em&gt;thinks&lt;/em&gt;
it has all the storage allocated to the original image, but there&amp;#8217;s no need to
have all the storage available (unless the clones grow to require it,&amp;nbsp;naturally).&lt;/p&gt;
&lt;p&gt;Hopefully this gives some idea of how modern cloud systems can spin up clones
of an &lt;span class="caps"&gt;OS&lt;/span&gt; image nearly instantaneously, and how they can seemingly provide many
gigabytes of storage to containers or VMs, without necessarily having installed
all the storage they apparently&amp;nbsp;provide.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="layer-cake"&gt;
&lt;h2&gt;Layer&amp;nbsp;Cake&lt;/h2&gt;
&lt;p&gt;Finally, a brief illustration of just how silly this can get. Here&amp;#8217;s a
diagram of a storage layout I&amp;#8217;ve used on servers in the&amp;nbsp;past:&lt;/p&gt;
&lt;object data="https://waldorf.waveform.org.uk/images/block-stack.svg" type="image/svg+xml"&gt;A spiders web of storage. Four boxes represent four hard at the
bottom. Above this a larger box represents the &lt;span class="caps"&gt;RAID&lt;/span&gt; device built from
the drives. Above this a hexagonal volume group is built from the
large &lt;span class="caps"&gt;RAID&lt;/span&gt; device. From the volume group spring numerous block
devices, for &amp;#8220;tmp&amp;#8221;, &amp;#8220;root&amp;#8221;, &amp;#8220;home&amp;#8221;, and &amp;#8220;images&amp;#8221;. From the first
three spring regular file-systems, but from &amp;#8220;images&amp;#8221; spring several
more block devices named &amp;#8220;base&amp;#8221; and from that &amp;#8220;munin&amp;#8221;, &amp;#8220;docs&amp;#8221;, and
&amp;#8220;git&amp;#8221; (&lt;span class="caps"&gt;OS&lt;/span&gt; images running in containers).&lt;/object&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Four hard drives exist, each containing a small boot partition and a large
partition occupying the rest of the&amp;nbsp;capacity&lt;/li&gt;
&lt;li&gt;The four boot partitions are combined with a &lt;span class="caps"&gt;RAID1&lt;/span&gt; mirror into a boot block
device, &amp;#8220;md1&amp;#8221; &lt;a class="footnote-reference" href="#mirror" id="footnote-reference-4"&gt;[7]&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &amp;#8220;md1&amp;#8221; block device is formatted as &lt;span class="caps"&gt;FAT&lt;/span&gt; and contains the &amp;#8220;/boot&amp;#8221;&amp;nbsp;hierarchy.&lt;/li&gt;
&lt;li&gt;The four large partitions are combined with &lt;span class="caps"&gt;RAID5&lt;/span&gt; into a large block device,
&amp;#8220;md2&amp;#8221; (&lt;span class="caps"&gt;RAID5&lt;/span&gt; implies it has the capacity of n-1, i.e. three, of the
underlying devices, and can survive the loss of any one&amp;nbsp;device).&lt;/li&gt;
&lt;li&gt;The &amp;#8220;md2&amp;#8221; device is consumed by the &amp;#8220;raidvg&amp;#8221; volume group from which are
produced various block devices: the &amp;#8220;root&amp;#8221;, &amp;#8220;home&amp;#8221;, &amp;#8220;tmp&amp;#8221;, and &amp;#8220;images&amp;#8221;&amp;nbsp;volumes.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;root&amp;#8221;, &amp;#8220;home&amp;#8221;, and &amp;#8220;tmp&amp;#8221; are formatted with a mix of file-systems, ext4 and
&lt;span class="caps"&gt;XFS&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;The &amp;#8220;images&amp;#8221; volume is a &amp;#8220;thin pool&amp;#8221; from which the &amp;#8220;base&amp;#8221; volume is&amp;nbsp;derived.&lt;/li&gt;
&lt;li&gt;The &amp;#8220;munin&amp;#8221;, &amp;#8220;docs&amp;#8221;, and &amp;#8220;git&amp;#8221; volumes are all thinly provisioned snapshots
of the &amp;#8220;base&amp;#8221;&amp;nbsp;volume.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This may seem like a complicated stack of transformations, but consider that in
essence most amount to little more than re-numbering and re-ordering of blocks
(the &lt;span class="caps"&gt;RAID5&lt;/span&gt; transform is a little more involved, admittedly). Hence, for very
little performance cost, we&amp;#8217;ve got redundancy (&lt;span class="caps"&gt;RAID&lt;/span&gt;), flexible volume creation
system with snapshotting (&lt;span class="caps"&gt;LVM&lt;/span&gt;), and copy-on-write cloning for VMs or containers
launched on the server (thin&amp;nbsp;provisioning).&lt;/p&gt;
&lt;p&gt;By this point you should have a reasonable understanding of what a block device
is, and what can be accomplished with the various transforms that are available
for them under Linux. Next time we&amp;#8217;ll take a look at the issues with netbooting
from &lt;span class="caps"&gt;NFS&lt;/span&gt; and how &lt;span class="caps"&gt;NBD&lt;/span&gt; (or block devices in general) can mitigate some of these&amp;nbsp;issues.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;table class="docutils footnote" frame="void" id="cache1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[5]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;In practice it&amp;#8217;s unlikely the bytes will actually be thrown away;
the sector requested will be stored in a cache, in case a future read
requests more bytes from the same sector (very likely when reading through a
file sequentially).&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="cache2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[6]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Again, the changed block will wind up in a cache so future
modifications can skip the initial read step.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="mirror" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-4"&gt;[7]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Simple &lt;span class="caps"&gt;RAID1&lt;/span&gt; mirroring is used to ensure that the &lt;span class="caps"&gt;BIOS&lt;/span&gt; can use any
of the drives as its initial boot device without caring about the &lt;span class="caps"&gt;RAID&lt;/span&gt;
layout (which it doesn&amp;#8217;t understand). &lt;em&gt;Note&lt;/em&gt;: This carries risks as it means
the &lt;span class="caps"&gt;BIOS&lt;/span&gt; and bootloader must treat the boot partition as strictly read-only
(and that&amp;#8217;s not necessarily guaranteed).&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="notall" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-3"&gt;[8]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;The snapshot doesn&amp;#8217;t require all the space to be allocated, as the
diagram suggests. In fact, assuming the underlying device changes
infrequently, it&amp;#8217;s common to only allocate ~5% of the origin&amp;#8217;s storage.
However, you do still need to provide &lt;em&gt;some&lt;/em&gt; up front.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="misc"></category><category term="storage"></category><category term="lvm"></category><category term="luks"></category></entry><entry><title>Playing with Blocks - ReLUKS</title><link href="https://waldorf.waveform.org.uk/2023/playing-with-blocks-reluks.html" rel="alternate"></link><published>2023-04-20T00:00:00+01:00</published><updated>2023-08-01T17:02:11+01:00</updated><author><name>Dave Jones</name></author><id>tag:waldorf.waveform.org.uk,2023-04-20:/2023/playing-with-blocks-reluks.html</id><summary type="html">&lt;p class="first last"&gt;Making a Pi desktop with encrypted root storage&amp;nbsp;(again!)&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;strong&gt;See Also&lt;/strong&gt;: &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2021/playing-with-blocks-luks.html"&gt;&lt;span class="caps"&gt;LUKS&lt;/span&gt;&lt;/a&gt;,
&lt;a class="reference external" href="https://waldorf.waveform.org.uk/2022/playing-with-blocks-its-all-connected.html"&gt;&lt;span class="caps"&gt;LVM&lt;/span&gt;+&lt;span class="caps"&gt;LUKS&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ve looked at using &lt;span class="caps"&gt;LUKS&lt;/span&gt; on the Ubuntu Pi desktop images &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2021/playing-with-blocks-luks.html"&gt;before&lt;/a&gt; but it was a rather painful
process primarily as it involved shrinking the root partition. This in turn
meant that a separate machine (or at the very least a Pi booting from something
other than its &lt;span class="caps"&gt;SD&lt;/span&gt; card) was required to perform the&amp;nbsp;changes.&lt;/p&gt;
&lt;p&gt;Can we do better? In particular, can we reduce the requirements to just a
single machine (the target Raspberry Pi) with a single storage medium? Thanks
to a relatively minor change in the just-released Ubuntu Lunar (23.04) Pi
desktop image, I think we&amp;nbsp;can!&lt;/p&gt;
&lt;div class="section" id="when-you-wanna-go-do-it"&gt;
&lt;h2&gt;When you wanna go do&amp;nbsp;it&lt;/h2&gt;
&lt;p&gt;You&amp;#8217;ll need the following for any&amp;nbsp;scenario:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;a Raspberry Pi 4 or&amp;nbsp;400&lt;/li&gt;
&lt;li&gt;a micro-&lt;span class="caps"&gt;SD&lt;/span&gt; card (or &lt;span class="caps"&gt;USB&lt;/span&gt;-attached boot&amp;nbsp;drive)&lt;/li&gt;
&lt;li&gt;a&amp;nbsp;monitor&lt;/li&gt;
&lt;li&gt;a keyboard and a&amp;nbsp;mouse&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;#8217;re trying to do this on a single machine (not flashing your storage
device on a separate machine), you&amp;#8217;ll also&amp;nbsp;need:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;a relatively recent boot&amp;nbsp;firmware&lt;/li&gt;
&lt;li&gt;an Ethernet&amp;nbsp;connection&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Newly purchased Pis (as of 2023) should all have sufficiently up to date
firmwares. Older Pis may require an &lt;span class="caps"&gt;EEPROM&lt;/span&gt; update which can be accomplished
under Ubuntu (or RaspiOS) by running &lt;tt class="docutils literal"&gt;sudo &lt;span class="pre"&gt;rpi-eeprom-update&lt;/span&gt; &lt;span class="pre"&gt;-a&lt;/span&gt;&lt;/tt&gt; and
rebooting if an update is shown as&amp;nbsp;available.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="hit-me-with-those-laser-beams"&gt;
&lt;h2&gt;Hit me with those laser&amp;nbsp;beams&lt;/h2&gt;
&lt;p&gt;Start up your Raspberry Pi. The monitor should show the red and white Raspberry
Pi bootloader screen, with the prompt &amp;#8220;Press and hold &amp;lt;&lt;span class="caps"&gt;SHIFT&lt;/span&gt;&amp;gt; key to stop boot
and start net install&amp;#8221;. Follow this instruction and it should change to &amp;#8220;If not
done so already, insert ethernet cable&amp;#8221; (this capability only works over
Ethernet, not WiFi as the bootloader can only configure the&amp;nbsp;former).&lt;/p&gt;
&lt;p&gt;After a short download, you should find yourself at a full-screen version of
the &lt;a class="reference external" href="https://snapcraft.io/rpi-imager"&gt;rpi-imager&lt;/a&gt;. From here you can select Ubuntu as you normally would in the
desktop version of the&amp;nbsp;software:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Click &amp;#8220;Choose &lt;span class="caps"&gt;OS&lt;/span&gt;&amp;#8221;&lt;/li&gt;
&lt;li&gt;Select &amp;#8220;Other general-purpose &lt;span class="caps"&gt;OS&lt;/span&gt;&amp;#8221;&lt;/li&gt;
&lt;li&gt;Select&amp;nbsp;&amp;#8220;Ubuntu&amp;#8221;&lt;/li&gt;
&lt;li&gt;Select &amp;#8220;Ubuntu Desktop 23.04&amp;nbsp;(64-bit)&amp;#8221;&lt;/li&gt;
&lt;li&gt;Back at the main screen, click &amp;#8220;Choose Storage&amp;#8221; and pick your boot medium
(which should be the only drive connected to the Pi at this&amp;nbsp;point)&lt;/li&gt;
&lt;li&gt;Click&amp;nbsp;&amp;#8220;Write&amp;#8221;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The utility should prompt to ensure you want to overwrite everything and
anything on the storage device and, once confirmed, you should find it writing
to the storage&amp;nbsp;medium.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;Do not be alarmed if there is an extremely long pause in the writing
process. The Ubuntu images are heavily compressed, and the &amp;#8220;slack space&amp;#8221;
baked into the image (which &lt;a class="reference external" href="https://github.com/raspberrypi/rpi-imager/issues/480"&gt;may be excessive&lt;/a&gt;) compresses &lt;em&gt;extremely&lt;/em&gt;
well. This can lead to a potentially long pause in the progress bar while a
few bytes in the compressed image expand into gigabytes of written&amp;nbsp;data.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="make-making-it-your-intention"&gt;
&lt;h2&gt;Make making it your&amp;nbsp;intention&lt;/h2&gt;
&lt;p&gt;Once the &lt;span class="caps"&gt;OS&lt;/span&gt; is written to the boot medium (and verified), the Pi should reboot
into Ubuntu Desktop. You&amp;#8217;ll need to run through the initial setup wizard,
configuring your locale and user&amp;nbsp;details.&lt;/p&gt;
&lt;p&gt;After the initial setup wizard, login to your new user. We now need to take a
series of steps which may seem premature and in some cases a bit odd. Start a
terminal and perform the&amp;nbsp;following:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;# &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;cryptsetup-initramfs&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;# &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rootfs  &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;findmnt&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;SOURCE&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;  none  luks,discard&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/crypttab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;# &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'s,^LABEL=writable,/dev/mapper/rootfs,'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/fstab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;# &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'s,LABEL=writable,/dev/mapper/rootfs,'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/boot/firmware/cmdline.txt&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;# &lt;/span&gt;reboot
&lt;/pre&gt;
&lt;p&gt;In order, these&amp;nbsp;commands:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Switch to the root user (everything we&amp;#8217;re going to do requires root access
and I can&amp;#8217;t be bothered re-typing&amp;nbsp;sudo).&lt;/li&gt;
&lt;li&gt;Re-install &lt;tt class="docutils literal"&gt;cryptsetup&lt;/tt&gt;. I say &amp;#8220;re-&amp;#8221; because this package is actually
part of the base image, but the initial setup decides it isn&amp;#8217;t required and
removes it at the end of the setup.&amp;nbsp;Doh!&lt;/li&gt;
&lt;li&gt;Create the &lt;tt class="docutils literal"&gt;crypttab&lt;/tt&gt; entry for the&amp;nbsp;rootfs.&lt;/li&gt;
&lt;li&gt;Re-write the source of the root mount in &lt;tt class="docutils literal"&gt;fstab&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;… and the same in the kernel command&amp;nbsp;line.&lt;/li&gt;
&lt;li&gt;Reboot the&amp;nbsp;machine.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to double check things, assuming your boot device is an &lt;span class="caps"&gt;SD&lt;/span&gt; card
(&lt;tt class="docutils literal"&gt;/dev/mmcblk0&lt;/tt&gt;) your &lt;tt class="docutils literal"&gt;crypttab&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;fstab&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;cmdline.txt&lt;/tt&gt; files
should look like&amp;nbsp;this:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;root&amp;#64;miss-piggy:~# &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/etc/crypttab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;# &lt;/span&gt;&amp;lt;target&lt;span class="w"&gt; &lt;/span&gt;name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;device&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;&amp;lt;key&lt;span class="w"&gt; &lt;/span&gt;file&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;&amp;lt;options&amp;gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;rootfs  /dev/mmcblk0p2  none  luks,discard
&lt;/span&gt;&lt;span class="gp"&gt;root&amp;#64;miss-piggy:~# &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/etc/fstab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;/dev/mapper/rootfs      /       ext4    discard 0       1
LABEL=system-boot       /boot/firmware  vfat    defaults        0       1
&lt;/span&gt;&lt;span class="gp"&gt;root&amp;#64;miss-piggy:~# &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/boot/firmware/cmdline.txt&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;zswap.enabled=1 zswap.zpool=z3fold zswap.compressor=zstd dwc_otg.lpm_enable=0 console=tty1 root=/dev/mapper/rootfs rootfstype=ext4 rootwait fixrtc quiet splash&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="hit-me-hit-me"&gt;
&lt;h2&gt;Hit me, hit&amp;nbsp;me!&lt;/h2&gt;
&lt;p&gt;At this point you may notice that the boot seems to be taking rather a long
time. In fact, it&amp;#8217;s going to fail because the &lt;tt class="docutils literal"&gt;rootfs&lt;/tt&gt; device we told the
kernel to go looking for doesn&amp;#8217;t exist yet. But that&amp;#8217;s okay! Be patient and let
it fail; the initramfs still gets loaded and it&amp;#8217;s got all the tools we need to
create&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Once you find yourself at a command prompt (with a notice complaining that it
couldn&amp;#8217;t mount the root file-system), do the&amp;nbsp;following:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp-VirtualEnv"&gt;(initramfs)&lt;/span&gt; &lt;span class="go"&gt;rootdev=$(readlink -f /dev/disk/by-label/writable)
&lt;/span&gt;&lt;span class="gp-VirtualEnv"&gt;(initramfs)&lt;/span&gt; &lt;span class="go"&gt;cryptsetup reencrypt --encrypt --reduce-device-size 16M --cipher xchacha12,aes-adiantum-plain64 $rootdev
&lt;/span&gt;&lt;span class="gp-VirtualEnv"&gt;(initramfs)&lt;/span&gt; &lt;span class="go"&gt;cryptsetup open $rootdev rootfs
&lt;/span&gt;&lt;span class="gp-VirtualEnv"&gt;(initramfs)&lt;/span&gt; &lt;span class="go"&gt;exit&lt;/span&gt;
&lt;/pre&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Create the rootfs device. This will prompt you to enter &amp;#8220;&lt;span class="caps"&gt;YES&lt;/span&gt;&amp;#8221; (for
confirmation you really want to do this), and for the password to unlock the
encryption key for the device (twice); &lt;em&gt;don&amp;#8217;t forget this!&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Go make coffee; or twiddle your thumbs for an excessively long period of time
while it encrypts the &lt;em&gt;entire&lt;/em&gt; device, including all the empty space. On the
plus side, after a minute it should give you a reasonably accurate estimate
of how long it&amp;#8217;s going to take to encrypt the device, so you can set a timer
and come back when it&amp;#8217;s&amp;nbsp;done.&lt;/li&gt;
&lt;li&gt;Open the newly created rootfs device (this will prompt you once more for the
password) and &lt;tt class="docutils literal"&gt;exit&lt;/tt&gt; to continue the&amp;nbsp;boot.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="re-luks"&gt;
&lt;h2&gt;Re-&lt;span class="caps"&gt;LUKS&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Once you&amp;#8217;re logged into the desktop once more, you have one final task.
Re-generate the initramfs now that the &lt;tt class="docutils literal"&gt;rootfs&lt;/tt&gt; device&amp;nbsp;exists:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;update-initramfs&lt;span class="w"&gt; &lt;/span&gt;-u
&lt;/pre&gt;
&lt;p&gt;Done! At this point all future boots should prompt you for the password to
unlock the encrypted root&amp;nbsp;file-system.&lt;/p&gt;
&lt;p&gt;Obviously in an ideal world, this could all be accomplished from the installer,
but there&amp;#8217;s a slight wrinkle in that with the lunar release. The first time
setup application on the Pi desktop images is &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;oem-config&lt;/span&gt;&lt;/tt&gt; which is derived
from the venerable &lt;tt class="docutils literal"&gt;ubiquity&lt;/tt&gt; installer. As you may have noticed in the
&lt;a class="reference external" href="https://discourse.ubuntu.com/t/lunar-lobster-release-notes/31910"&gt;lunar release notes&lt;/a&gt; the installer is being replaced by a new one based on
&lt;tt class="docutils literal"&gt;subiquity&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;However, this only applies to those platforms which need the &amp;#8220;full fat&amp;#8221;
installer, i.e. the &lt;span class="caps"&gt;PC&lt;/span&gt; where you boot off some medium and then install to
another (the internal drive). It &lt;em&gt;doesn&amp;#8217;t&lt;/em&gt; apply to Ubuntu&amp;#8217;s pre-installed
desktop images (like the Pi ones) yet. There seemed little point in pouring
effort into adding this to &lt;tt class="docutils literal"&gt;ubiquity&lt;/tt&gt; this cycle, only to see it thrown out
during the next cycle when the &lt;tt class="docutils literal"&gt;subiquity&lt;/tt&gt; based installer comes to replace
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;oem-config&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Hopefully in a future cycle we can integrate all this and have a slightly
friendlier experience, but for now at least it&amp;#8217;s achievable without requiring a
separate&amp;nbsp;machine.&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"></category><category term="pi"></category><category term="ubuntu"></category><category term="storage"></category><category term="luks"></category><category term="lunar"></category></entry><entry><title>Playing with Blocks - It’s All Connected</title><link href="https://waldorf.waveform.org.uk/2022/playing-with-blocks-its-all-connected.html" rel="alternate"></link><published>2022-09-08T00:00:00+01:00</published><updated>2023-08-01T17:02:11+01:00</updated><author><name>Dave Jones</name></author><id>tag:waldorf.waveform.org.uk,2022-09-08:/2022/playing-with-blocks-its-all-connected.html</id><summary type="html">&lt;p class="first last"&gt;Making a Pi image with encrypted volume-managed root&amp;nbsp;storage&lt;/p&gt;
</summary><content type="html">&lt;p&gt;In the &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2021/playing-with-blocks-lvm.html"&gt;last&lt;/a&gt; &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2021/playing-with-blocks-luks.html"&gt;two&lt;/a&gt; articles we looked at &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)"&gt;&lt;span class="caps"&gt;LVM&lt;/span&gt;&lt;/a&gt; and
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup"&gt;&lt;span class="caps"&gt;LUKS&lt;/span&gt;&lt;/a&gt; for some enhancement of the basic storage of the standard Ubuntu Pi
images. This time around we&amp;#8217;ll combine both of those previous articles to make
an image in the same way that the Ubuntu Desktop for &lt;span class="caps"&gt;PC&lt;/span&gt; images install when
they&amp;#8217;re given free reign to overwrite the entire contents of the&amp;nbsp;drive.&lt;/p&gt;
&lt;p&gt;Specifically, this means we aim to wind up&amp;nbsp;with:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;A &lt;span class="caps"&gt;FAT&lt;/span&gt; boot partition (no difference there), 512 &lt;span class="caps"&gt;MB&lt;/span&gt; in&amp;nbsp;size&lt;/li&gt;
&lt;li&gt;A second partition taking up the rest of the card containing&lt;ul&gt;
&lt;li&gt;An encrypted &lt;span class="caps"&gt;LUKS&lt;/span&gt; container, containing&lt;ul&gt;
&lt;li&gt;An &lt;span class="caps"&gt;LVM&lt;/span&gt; physical volume (&lt;span class="caps"&gt;PV&lt;/span&gt;) belonging to&lt;ul&gt;
&lt;li&gt;An &lt;span class="caps"&gt;LVM&lt;/span&gt; volume group (&lt;span class="caps"&gt;VG&lt;/span&gt;) called &amp;#8220;pivg&amp;#8221; containing&lt;ul&gt;
&lt;li&gt;An &lt;span class="caps"&gt;LVM&lt;/span&gt; logical volume (&lt;span class="caps"&gt;LV&lt;/span&gt;) called &amp;#8220;root&amp;#8221; taking up some reasonable
portion of the disk space (8 &lt;span class="caps"&gt;GB&lt;/span&gt; in this&amp;nbsp;example)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;object data="https://waldorf.waveform.org.uk/images/luks-lvm-partitions.svg" type="image/svg+xml"&gt;A diagram illustrating the &lt;span class="caps"&gt;SD&lt;/span&gt; card layout showing: a large bar
representing the whole &lt;span class="caps"&gt;SD&lt;/span&gt; card /dev/mmcblk0 (N &lt;span class="caps"&gt;GB&lt;/span&gt;). Beneath
that, two bars: a small one on the left for the system-boot
partition /dev/mmcblk0p1 (512 &lt;span class="caps"&gt;MB&lt;/span&gt;), and a large one on the right
for the remaining partition /dev/mmcblk0p2 (N &lt;span class="caps"&gt;GB&lt;/span&gt; - 512 &lt;span class="caps"&gt;MB&lt;/span&gt;).
Beneath the large right-hand bar, a bar representing the &lt;span class="caps"&gt;LUKS&lt;/span&gt;
encrypted container (again, N &lt;span class="caps"&gt;GB&lt;/span&gt; - 512 &lt;span class="caps"&gt;MB&lt;/span&gt;). Beneath that, two
more bars: a tiny one on the left representing the &lt;span class="caps"&gt;LUKS&lt;/span&gt; header
(16 &lt;span class="caps"&gt;MB&lt;/span&gt;), and a much larger one on the right representing the
&lt;span class="caps"&gt;LVM&lt;/span&gt; &lt;span class="caps"&gt;PV&lt;/span&gt; /dev/mapper/rootfs within the &lt;span class="caps"&gt;LUKS&lt;/span&gt; container (N &lt;span class="caps"&gt;GB&lt;/span&gt; -
512 &lt;span class="caps"&gt;MB&lt;/span&gt; - 16 &lt;span class="caps"&gt;MB&lt;/span&gt;). Lower down, a dotted outline of the same size
representing the &lt;span class="caps"&gt;LVM&lt;/span&gt; &lt;span class="caps"&gt;VG&lt;/span&gt; /dev/pivg. Finally, beneath that, a
smaller bar representing the &lt;span class="caps"&gt;LVM&lt;/span&gt; &lt;span class="caps"&gt;LV&lt;/span&gt; /dev/mapper/pivg-root (8 &lt;span class="caps"&gt;GB&lt;/span&gt;).&lt;/object&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;One thing to note is that I&amp;#8217;ve only tested this with the Ubuntu 22.04
(jammy) server for pi image. Notably, jammy has &lt;tt class="docutils literal"&gt;cryptsetup&lt;/tt&gt; within the
default initramfs on the image. I would not necessarily be confident that
this works on earlier&amp;nbsp;releases.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="three-rowdy-layers"&gt;
&lt;h2&gt;Three (?) Rowdy&amp;nbsp;Layers&lt;/h2&gt;
&lt;p&gt;Rather than go through all the individual commands, which would result in this
post looking like a foreword followed by the dump of a shell script, I&amp;#8217;ll go
through the high level procedure because the detail is almost exactly the same
as the original articles but for a few minor differences and some deliberate&amp;nbsp;omissions.&lt;/p&gt;
&lt;p&gt;Firstly, we&amp;#8217;ll deal with the content of the &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2021/playing-with-blocks-lvm.html"&gt;first article&lt;/a&gt; and set up &lt;span class="caps"&gt;LVM&lt;/span&gt;:&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p class="first"&gt;Follow the first article instructions until it&amp;#8217;s time to create the &lt;span class="caps"&gt;PV&lt;/span&gt; (with
&lt;tt class="docutils literal"&gt;pvcreate&lt;/tt&gt;):&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Plug in the &lt;span class="caps"&gt;SD&lt;/span&gt;&amp;nbsp;card&lt;/li&gt;
&lt;li&gt;Unmount any auto-mounted&amp;nbsp;partitions&lt;/li&gt;
&lt;li&gt;Repartition with &lt;tt class="docutils literal"&gt;gdisk&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;At this point we need to create the &lt;span class="caps"&gt;PV&lt;/span&gt; with &lt;span class="caps"&gt;16MB&lt;/span&gt; &lt;em&gt;less&lt;/em&gt; space than is
available in the second partition, to leave a little room for the &lt;span class="caps"&gt;LUKS&lt;/span&gt;
header around the &lt;span class="caps"&gt;PV&lt;/span&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;From the &lt;tt class="docutils literal"&gt;gdisk&lt;/tt&gt; session, you should have a printout of the new partition
table; if you don&amp;#8217;t, run &lt;tt class="docutils literal"&gt;sudo gdisk &lt;span class="pre"&gt;-l&lt;/span&gt; /dev/mmcblk0&lt;/tt&gt; (assuming
&lt;tt class="docutils literal"&gt;/dev/mmcblk0&lt;/tt&gt; is your &lt;span class="caps"&gt;SD&lt;/span&gt;&amp;nbsp;card)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;For the second partition, calculate the number of sectors it occupies
(which is simply end sector minus start sector) and then subtract 32768
(each sector is 512 bytes, so 32768 is &lt;span class="caps"&gt;16MB&lt;/span&gt;). For example, on a &lt;span class="caps"&gt;32GB&lt;/span&gt; &lt;span class="caps"&gt;SD&lt;/span&gt;&amp;nbsp;card:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;gdisk&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="w"&gt; &lt;/span&gt;/dev/mmcblk0&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;GPT fdisk (gdisk) version 1.0.8

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.
Disk /dev/mmcblk0: 62333952 sectors, 29.7 GiB
Model: STORAGE DEVICE
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): A9BDFD97-F2A5-4419-9A83-B0160820FDBB
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 62333918
Partitions will be aligned on 2048-sector boundaries
Total free space is 4061 sectors (2.0 MiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         1048576   511.0 MiB   0700  system-boot
   2         1050624        62333918   29.2 GiB    8E00  lvm
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nv"&gt;PV_SECTORS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;62333918&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1050624&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;32768&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$PV_SECTORS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;61250526&lt;/span&gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Proceed to creating the logical volume, but explicitly specify the number
of sectors to use when creating the &lt;span class="caps"&gt;PV&lt;/span&gt; with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--setphysicalvolumesize&lt;/span&gt;&lt;/tt&gt;
and the number of sectors with the suffix&amp;nbsp;&amp;#8220;s&amp;#8221;:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pvcreate&lt;span class="w"&gt; &lt;/span&gt;--setphysicalvolumesize&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PV_SECTORS&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;s&lt;span class="w"&gt; &lt;/span&gt;/dev/mmcblk0p2&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;Physical volume &amp;quot;/dev/mmcblk0p2&amp;quot; successfully created.
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;vgcreate&lt;span class="w"&gt; &lt;/span&gt;pivg&lt;span class="w"&gt; &lt;/span&gt;/dev/mmcblk0p2&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;Volume group &amp;quot;pivg&amp;quot; successfully created
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;lvcreate&lt;span class="w"&gt; &lt;/span&gt;--size&lt;span class="w"&gt; &lt;/span&gt;8G&lt;span class="w"&gt; &lt;/span&gt;--name&lt;span class="w"&gt; &lt;/span&gt;root&lt;span class="w"&gt; &lt;/span&gt;pivg&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;Logical volume &amp;quot;root&amp;quot; created.&lt;/span&gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Finish the first article&amp;#8217;s&amp;nbsp;instructions:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Unpacking the&amp;nbsp;image&lt;/li&gt;
&lt;li&gt;Creating a loop device for the&amp;nbsp;image&lt;/li&gt;
&lt;li&gt;Transferring the content of the image partitions to the&amp;nbsp;card&lt;/li&gt;
&lt;li&gt;Updating the boot command line and fstab to point to the &amp;#8220;new&amp;#8221; root&amp;nbsp;device&lt;/li&gt;
&lt;li&gt;Unmount the root and boot partitions, and disable the &lt;span class="caps"&gt;VG&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Don&amp;#8217;t&lt;/em&gt; eject the &lt;span class="caps"&gt;SD&lt;/span&gt; card, we still need to do some&amp;nbsp;surgery!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="luks-dujour"&gt;
&lt;h2&gt;&lt;span class="caps"&gt;LUKS&lt;/span&gt;&amp;nbsp;Dujour&lt;/h2&gt;
&lt;p&gt;Now it&amp;#8217;s time to move on to the &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2021/playing-with-blocks-luks.html"&gt;second article&lt;/a&gt; and set up the encrypted &lt;span class="caps"&gt;LUKS&lt;/span&gt;
container around the physical volume (&lt;span class="caps"&gt;PV&lt;/span&gt;):&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p class="first"&gt;Skip everything up to the encryption&amp;nbsp;step:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;No need to download another&amp;nbsp;image&lt;/li&gt;
&lt;li&gt;No need to boot the image&amp;nbsp;yet&lt;/li&gt;
&lt;li&gt;No need to unmount stuff (we already did&amp;nbsp;that)&lt;/li&gt;
&lt;li&gt;No need to shrink partitions (the root partition hasn&amp;#8217;t been auto-expanded
because we haven&amp;#8217;t booted anything, and we&amp;#8217;ve pre-shrunk the &lt;span class="caps"&gt;PV&lt;/span&gt; containing
the&amp;nbsp;root)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Now it&amp;#8217;s time to encrypt the second partition containing the &lt;span class="caps"&gt;PV&lt;/span&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;First the encryption; this is exactly as in the second&amp;nbsp;article:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;cryptsetup&lt;span class="w"&gt; &lt;/span&gt;reencrypt&lt;span class="w"&gt; &lt;/span&gt;--encrypt&lt;span class="w"&gt; &lt;/span&gt;--reduce-device-size&lt;span class="w"&gt; &lt;/span&gt;16M&lt;span class="w"&gt; &lt;/span&gt;--cipher&lt;span class="w"&gt; &lt;/span&gt;xchacha12,aes-adiantum-plain64&lt;span class="w"&gt; &lt;/span&gt;/dev/mmcblk0p2&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;
WARNING!
========
This will overwrite data on LUKS2-temp-a823bd67-a632-41cb-955e-8776b8b3fb5b.new irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for LUKS2-temp-a823bd67-a632-41cb-955e-8776b8b3fb5b.new:
Verify passphrase:
Finished, time 36:53.687, 29915 MiB written, speed  13.5 MiB/s&lt;/span&gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Next we open the encrypted&amp;nbsp;container:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;cryptsetup&lt;span class="w"&gt; &lt;/span&gt;open&lt;span class="w"&gt; &lt;/span&gt;/dev/mmcblk0p2&lt;span class="w"&gt; &lt;/span&gt;rootfs&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;Enter passphrase for /dev/mmcblk0p2:&lt;/span&gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Then we re-scan for physical volumes (PVs) and re-activate the pivg volume
group (&lt;span class="caps"&gt;VG&lt;/span&gt;) we created earlier; this isn&amp;#8217;t in the original article but is
necessary as we&amp;#8217;ve altered the mapper&amp;nbsp;configuration:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pvscan&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;  PV /dev/mapper/rootfs   VG pivg            lvm2 [29.20 GiB / 21.20 GiB free]
  Total: 1 [29.20 GiB] / in use: 1 [29.20 GiB] / in no VG: 0 [0   ]
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;vgchange&lt;span class="w"&gt; &lt;/span&gt;-ay&lt;span class="w"&gt; &lt;/span&gt;pivg&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;  1 logical volume(s) in volume group &amp;quot;pivg&amp;quot; now active&lt;/span&gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;We skip over all the resizing bits because we&amp;#8217;ve already established the
size of the root volume, and just mount the root file-system (we don&amp;#8217;t
need to mount the boot file-system). This is, again, slightly different to
the original article because the root file-system is a mapper device,
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pivg-root&lt;/span&gt;&lt;/tt&gt; as in the first&amp;nbsp;article:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;/mnt/root&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;/dev/mapper/pivg-root&lt;span class="w"&gt; &lt;/span&gt;/mnt/root
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Then a bit (but only a bit) of configuration&amp;nbsp;manipulation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;Add our entry to &lt;tt class="docutils literal"&gt;/etc/crypttab&lt;/tt&gt;. Please heed the advice in the original
article regarding the source device here; this is the source device &lt;em&gt;as
seen by the Pi&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/mnt/root/etc/crypttab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;# &lt;/span&gt;&amp;lt;target&lt;span class="w"&gt; &lt;/span&gt;name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;device&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;&amp;lt;key&lt;span class="w"&gt; &lt;/span&gt;file&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;&amp;lt;options&amp;gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rootfs  /dev/mmcblk0p2  none  luks,discard&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/mnt/root/etc/crypttab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/mnt/root/etc/crypttab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;# &lt;/span&gt;&amp;lt;target&lt;span class="w"&gt; &lt;/span&gt;name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;device&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;&amp;lt;key&lt;span class="w"&gt; &lt;/span&gt;file&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;&amp;lt;options&amp;gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;rootfs  /dev/mmcblk0p2  none  luks,discard&lt;/span&gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Skip the bits about editing &lt;tt class="docutils literal"&gt;fstab&lt;/tt&gt; and the boot command line; we&amp;#8217;ve
already done everything we need to for those. Just unmount root
file-system, and close the encrypted&amp;nbsp;container:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;umount&lt;span class="w"&gt; &lt;/span&gt;/mnt/root&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;cryptsetup&lt;span class="w"&gt; &lt;/span&gt;close&lt;span class="w"&gt; &lt;/span&gt;rootfs
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Now just follow the second article to the&amp;nbsp;end:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Eject the card and boot it on your&amp;nbsp;Pi&lt;/li&gt;
&lt;li&gt;There&amp;#8217;s a &lt;em&gt;long&lt;/em&gt; delay while the initial root mount&amp;nbsp;fails&lt;/li&gt;
&lt;li&gt;In the emergency prompt that appears, open the encrypted device and exit
the&amp;nbsp;prompt&lt;/li&gt;
&lt;li&gt;Once booted, update the&amp;nbsp;initramfs&lt;/li&gt;
&lt;li&gt;Reboot to make sure everything&amp;nbsp;works!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="future-cases"&gt;
&lt;h2&gt;Future&amp;nbsp;Cases&lt;/h2&gt;
&lt;p&gt;Congratulations! At this point you should have a setup eerily similar to the
one I use on my main development Pi, albeit that one boots off a large &lt;span class="caps"&gt;SSD&lt;/span&gt;
instead of an &lt;span class="caps"&gt;SD&lt;/span&gt; card. Future things worth exploring with this&amp;nbsp;setup:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;How to get plymouth prompting nicely for the password; plymouth&amp;#8217;s always been
on the Pi server images but for some reason it doesn&amp;#8217;t work properly (unlike
the Pi desktop images where it&amp;#8217;s happy). I had a cursory look into this a
couple of cycles ago, but didn&amp;#8217;t get anywhere at that&amp;nbsp;time.&lt;/li&gt;
&lt;li&gt;How about ditching password encryption and using a key on removable storage.
For instance, if booting off &lt;span class="caps"&gt;SD&lt;/span&gt; card, how about using a &lt;span class="caps"&gt;USB&lt;/span&gt; key with the
encryption key. Or for my favoured setup where I boot off a &lt;span class="caps"&gt;USB3&lt;/span&gt; attached &lt;span class="caps"&gt;SSD&lt;/span&gt;
drive, how about using an &lt;span class="caps"&gt;SD&lt;/span&gt; card with the&amp;nbsp;key?&lt;/li&gt;
&lt;li&gt;With this configuration I usually set up &lt;span class="caps"&gt;LXD&lt;/span&gt; with an &lt;span class="caps"&gt;LVM&lt;/span&gt; thin-pool for its
default storage. This usually requires taking a crow-bar to &lt;span class="caps"&gt;LXD&lt;/span&gt; and forcing
it to use the thin-pool (with &lt;a class="reference external" href="https://linuxcontainers.org/lxd/docs/master/reference/storage_lvm/#storage-lvm-pool-config"&gt;lvm.vg.force_reuse&lt;/a&gt;; &lt;span class="caps"&gt;LXD&lt;/span&gt; doesn&amp;#8217;t like working
with a non-empty &lt;span class="caps"&gt;VG&lt;/span&gt; for reasons I&amp;#8217;ve never full understood, but at least it&amp;#8217;s
possible). Let me know in the comments if it would be useful to have another
article covering&amp;nbsp;this!&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="misc"></category><category term="pi"></category><category term="ubuntu"></category><category term="storage"></category><category term="lvm"></category><category term="luks"></category></entry><entry><title>Playing with Blocks - LUKS</title><link href="https://waldorf.waveform.org.uk/2021/playing-with-blocks-luks.html" rel="alternate"></link><published>2021-10-19T00:00:00+01:00</published><updated>2023-08-01T17:02:11+01:00</updated><author><name>Dave Jones</name></author><id>tag:waldorf.waveform.org.uk,2021-10-19:/2021/playing-with-blocks-luks.html</id><summary type="html">&lt;p class="first last"&gt;Making a Pi desktop with encrypted root&amp;nbsp;storage&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;strong&gt;See Also&lt;/strong&gt;: &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2022/playing-with-blocks-its-all-connected.html"&gt;&lt;span class="caps"&gt;LVM&lt;/span&gt;+&lt;span class="caps"&gt;LUKS&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://waldorf.waveform.org.uk/2021/playing-with-blocks-lvm.html"&gt;Last time&lt;/a&gt; we had a look at using &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)"&gt;&lt;span class="caps"&gt;LVM&lt;/span&gt;&lt;/a&gt; on our root storage. This time
around it&amp;#8217;s &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup"&gt;&lt;span class="caps"&gt;LUKS&lt;/span&gt;&lt;/a&gt;&amp;#8216; turn: we&amp;#8217;re going to make an Ubuntu Desktop for Raspberry
Pi card, with the root file-system encrypted with &lt;span class="caps"&gt;LUKS&lt;/span&gt;. Thankfully this is much
simpler affair as &lt;span class="caps"&gt;LUKS&lt;/span&gt; can encrypt, decrypt, or for that matter, re-encrypt a
block device non-destructively (even with interruptions in the&amp;nbsp;middle!).&lt;/p&gt;
&lt;div class="section" id="as-easy-as"&gt;
&lt;h2&gt;As Easy As&amp;nbsp;…&lt;/h2&gt;
&lt;p&gt;We get off to the simplest possible start. You&amp;#8217;ll need a machine running Ubuntu
and some form of Pi-compatible storage (an &lt;span class="caps"&gt;SD&lt;/span&gt; card, or some form of &lt;span class="caps"&gt;USB&lt;/span&gt; mass&amp;nbsp;storage).&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Install the &lt;a class="reference external" href="https://www.raspberrypi.com/software/"&gt;Raspberry Pi imaging utility&lt;/a&gt; (or use &lt;tt class="docutils literal"&gt;sudo snap install
&lt;span class="pre"&gt;rpi-imager&lt;/span&gt;&lt;/tt&gt; for the snap version if you&amp;#8217;re on an architecture other than&amp;nbsp;amd64)&lt;/li&gt;
&lt;li&gt;Grab an &lt;span class="caps"&gt;SD&lt;/span&gt; card or some form of &lt;span class="caps"&gt;USB&lt;/span&gt; storage (if you&amp;#8217;re intending to use the
desktop image, I&amp;#8217;d recommend something fast like an &lt;span class="caps"&gt;SSD&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;Install the Ubuntu 21.10 desktop image (substitute server if you wish) on the
storage with the imaging utility (I won&amp;#8217;t bother detailing this process
because, frankly, the pi&amp;#8217;s imaging utility is about as simple as you can
possibly&amp;nbsp;get!)&lt;/li&gt;
&lt;li&gt;Boot the installed image on your&amp;nbsp;Pi&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="wot-no-cryptsetup"&gt;
&lt;h2&gt;Wot, no&amp;nbsp;cryptsetup?&lt;/h2&gt;
&lt;p&gt;It might seem a bit odd that we&amp;#8217;re jumping straight to booting the image, but
there is a reason for this: on earlier versions of Ubuntu, the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cryptsetup-initramfs&lt;/span&gt;&lt;/tt&gt; package isn&amp;#8217;t installed by default. On Impish it &lt;em&gt;is&lt;/em&gt;
installed by default, but the initramfs that ships with the image still doesn&amp;#8217;t
incorporate the &lt;tt class="docutils literal"&gt;cryptsetup&lt;/tt&gt; binary that&amp;#8217;s actually necessary. Hence, we need
to boot it at least once and re-generate the initramfs to include&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Get to a usable terminal (if you&amp;#8217;re on the desktop image just go through the
initial setup), then install &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cryptsetup-initramfs&lt;/span&gt;&lt;/tt&gt; (as mentioned, on Impish
this shouldn&amp;#8217;t be necessary but best to make sure) and re-generate the&amp;nbsp;initramfs.&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;cryptsetup-initramfs&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;... usual apt stuff ...
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;update-initramfs&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;... lots of flash-kernel output ...&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;That last step will take several minutes; here&amp;#8217;s &lt;a class="reference external" href="https://waldorf.waveform.org.uk/2021/making-impish-impier.html"&gt;some hints&lt;/a&gt; to read first if
you want to speed things up a bit. Now shut down the Pi and plug the &lt;span class="caps"&gt;SD&lt;/span&gt; card
(or &lt;span class="caps"&gt;USB&lt;/span&gt; drive) back into your original&amp;nbsp;machine.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="setec-astronomy"&gt;
&lt;h2&gt;Setec&amp;nbsp;Astronomy&lt;/h2&gt;
&lt;p&gt;Time to perform the actual encryption. Below I&amp;#8217;m assuming that your &lt;span class="caps"&gt;SD&lt;/span&gt; card (or
whatever target storage you&amp;#8217;re using) appears as the &lt;tt class="docutils literal"&gt;/dev/mmcblk0&lt;/tt&gt; on your
machine. Adjust these instructions according to your&amp;nbsp;setup!&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re going to unmount the partitions of the &lt;span class="caps"&gt;SD&lt;/span&gt; card (or other storage) you&amp;#8217;ve
just inserted (this is only necessary if your Ubuntu machine is a desktop
machine which will auto-mount the card), force a file-system check of the root
partition, and shrink that partition to its minimal&amp;nbsp;size:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;umount&lt;span class="w"&gt; &lt;/span&gt;/dev/mmcblk0p1&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;umount&lt;span class="w"&gt; &lt;/span&gt;/dev/mmcblk0p2&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;fsck&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;/dev/mmcblk0p2&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;fsck from util-linux 2.34
e2fsck 1.45.5 (07-Jan-2020)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
writable: 154688/557520 files (0.2% non-contiguous), 1507014/2229303 blocks
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;resize2fs&lt;span class="w"&gt; &lt;/span&gt;-M&lt;span class="w"&gt; &lt;/span&gt;/dev/mmcblk0p2&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;resize2fs 1.45.5 (07-Jan-2020)
Resizing the filesystem on /dev/sda2 to 1881115 (4k) blocks.
The filesystem on /dev/sda2 is now 1881115 (4k) blocks long.&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Now for the actual encryption. First, pick a &lt;a class="reference external" href="https://xkcd.com/936/"&gt;decent passphrase&lt;/a&gt;, then pick a
decent encryption cipher. Below I&amp;#8217;m going to use the &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Adiantum_(cipher)"&gt;Adiantum cipher&lt;/a&gt; as this
performs reasonably well on the Pi. It&amp;#8217;s well above the speed of most &lt;span class="caps"&gt;SD&lt;/span&gt; cards,
but be aware it will probably hurt the performance of SSDs. Use &lt;tt class="docutils literal"&gt;cryptsetup
benchmark &lt;span class="pre"&gt;--cipher&lt;/span&gt; &lt;span class="pre"&gt;xchacha12,aes-adiantum&lt;/span&gt;&lt;/tt&gt; if you want an idea of its
performance; compare this to the output of &lt;tt class="docutils literal"&gt;cryptsetup benchmark&lt;/tt&gt; which runs
through several of the more common&amp;nbsp;algorithms.&lt;/p&gt;
&lt;p&gt;At any rate, expect this next bit to take some considerable&amp;nbsp;time!&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;cryptsetup&lt;span class="w"&gt; &lt;/span&gt;reencrypt&lt;span class="w"&gt; &lt;/span&gt;--encrypt&lt;span class="w"&gt; &lt;/span&gt;--reduce-device-size&lt;span class="w"&gt; &lt;/span&gt;16M&lt;span class="w"&gt; &lt;/span&gt;--cipher&lt;span class="w"&gt; &lt;/span&gt;xchacha12,aes-adiantum-plain64&lt;span class="w"&gt; &lt;/span&gt;/dev/mmcblk0p2&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;
WARNING!
========
This will overwrite data on LUKS2-temp-dd54103b-d96c-4d1d-9e23-e3c375c81ecb.new irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase for LUKS2-temp-dd54103b-d96c-4d1d-9e23-e3c375c81ecb.new:
Verify passphrase:
Progress:   1.8%, ETA 09:51,  160 MiB written, speed  14.4 MiB/s
...
Progress:  17.7%, ETA 08:05, 1544 MiB written, speed  14.8 MiB/s
...
Finished, time 09:45.528, 8700 MiB written, speed  14.8 MiB/s
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;cryptsetup&lt;span class="w"&gt; &lt;/span&gt;open&lt;span class="w"&gt; &lt;/span&gt;/dev/mmcblk0p2&lt;span class="w"&gt; &lt;/span&gt;rootfs&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;Enter passphrase for /dev/mmcblk0p2:&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="rooting-around"&gt;
&lt;h2&gt;Rooting&amp;nbsp;Around&lt;/h2&gt;
&lt;p&gt;At this point our encrypted container on &lt;tt class="docutils literal"&gt;/dev/mmcblk0p2&lt;/tt&gt; is open as a
decrypted device called &lt;tt class="docutils literal"&gt;/dev/mapper/rootfs&lt;/tt&gt;. We can now expand the partition
back to its &amp;#8220;normal&amp;#8221; size (minus the 16M we shrunk it for metadata), and mount
it (and the boot partition) at some appropriate&amp;nbsp;location.&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;resize2fs&lt;span class="w"&gt; &lt;/span&gt;/dev/mapper/rootfs&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;resize2fs 1.45.5 (07-Jan-2020)
Resizing the filesystem on /dev/mapper/rootfs to 2227255 (4k) blocks.
The filesystem on /dev/mapper/rootfs is now 2227255 (4k) blocks long.
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;/mnt/boot&lt;span class="w"&gt; &lt;/span&gt;/mnt/root&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;/dev/mmcblk0p1&lt;span class="w"&gt; &lt;/span&gt;/mnt/boot&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;/dev/mapper/rootfs&lt;span class="w"&gt; &lt;/span&gt;/mnt/root
&lt;/pre&gt;
&lt;p&gt;Now we need to perform some surgery on the file-system tables. Firstly, we need
to tell the system how to set up the &amp;#8220;rootfs&amp;#8221; node we just opened. This is the
job of the &lt;tt class="docutils literal"&gt;/etc/crypttab&lt;/tt&gt; file. This should look relatively familiar to
anyone used to messing with &lt;tt class="docutils literal"&gt;/etc/fstab&lt;/tt&gt;, but bear in mind that the target
and source devices are &amp;#8220;backwards&amp;#8221; (target first, then&amp;nbsp;source).&lt;/p&gt;
&lt;p&gt;Another &lt;strong&gt;important&lt;/strong&gt; thing to remember here is that in this file,
&lt;tt class="docutils literal"&gt;/dev/mmcblk0p2&lt;/tt&gt; is the device for the encrypted partition &lt;em&gt;from the Pi&amp;#8217;s
perspective&lt;/em&gt;. In other words, if your &lt;span class="caps"&gt;SD&lt;/span&gt; card appears as &lt;tt class="docutils literal"&gt;/dev/sdf&lt;/tt&gt; on your
&lt;span class="caps"&gt;PC&lt;/span&gt; and you&amp;#8217;ve been using &lt;tt class="docutils literal"&gt;/dev/sdf2&lt;/tt&gt; as the card&amp;#8217;s root partition in the
instructions above you should &lt;em&gt;not&lt;/em&gt; do that here: just use &lt;tt class="docutils literal"&gt;/dev/mmcblk0p2&lt;/tt&gt;.
However, if you&amp;#8217;re using an &lt;span class="caps"&gt;SSD&lt;/span&gt; via a &lt;span class="caps"&gt;USB&lt;/span&gt; adapter as your storage, you may need
to adjust the line below to use &lt;tt class="docutils literal"&gt;/dev/sda2&lt;/tt&gt; as that&amp;#8217;s how the Pi will be
referring to this partition at boot&amp;nbsp;time.&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/mnt/root/etc/crypttab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;# &lt;/span&gt;&amp;lt;target&lt;span class="w"&gt; &lt;/span&gt;name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;device&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;&amp;lt;key&lt;span class="w"&gt; &lt;/span&gt;file&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;&amp;lt;options&amp;gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rootfs  /dev/mmcblk0p2  none  luks,discard&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/mnt/root/etc/crypttab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/mnt/root/etc/crypttab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;# &lt;/span&gt;&amp;lt;target&lt;span class="w"&gt; &lt;/span&gt;name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;device&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;&amp;lt;key&lt;span class="w"&gt; &lt;/span&gt;file&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;&amp;lt;options&amp;gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;rootfs  /dev/mmcblk0p2  none  luks,discard&lt;/span&gt;
&lt;/pre&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;You may or may not wish to include the &amp;#8220;discard&amp;#8221; option above. It&amp;#8217;s the
default in Debian and Ubuntu for encrypted partitions but may carry
security risks. See &lt;tt class="docutils literal"&gt;man crypttab&lt;/tt&gt; for full&amp;nbsp;details.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;With the &lt;tt class="docutils literal"&gt;/dev/mapper/rootfs&lt;/tt&gt; device configured, all that remains is to tell
the kernel and systemd to look there for its root device via the &lt;tt class="docutils literal"&gt;/etc/fstab&lt;/tt&gt;
table, and the &lt;tt class="docutils literal"&gt;cmdline.txt&lt;/tt&gt; file on the boot&amp;nbsp;partition:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/mnt/root/etc/fstab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;# &lt;/span&gt;UNCONFIGURED&lt;span class="w"&gt; &lt;/span&gt;FSTAB&lt;span class="w"&gt; &lt;/span&gt;FOR&lt;span class="w"&gt; &lt;/span&gt;BASE&lt;span class="w"&gt; &lt;/span&gt;SYSTEM&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;LABEL=writable    /     ext4    defaults,x-systemd.growfs    0 0
/swapfile         none  swap    sw    0 0
LABEL=system-boot       /boot/firmware  vfat    defaults        0       1
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'s,^LABEL=writable,/dev/mapper/rootfs,'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/mnt/root/etc/fstab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/mnt/root/etc/fstab&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;# &lt;/span&gt;UNCONFIGURED&lt;span class="w"&gt; &lt;/span&gt;FSTAB&lt;span class="w"&gt; &lt;/span&gt;FOR&lt;span class="w"&gt; &lt;/span&gt;BASE&lt;span class="w"&gt; &lt;/span&gt;SYSTEM&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;/dev/mapper/rootfs    /     ext4    defaults,x-systemd.growfs    0 0
/swapfile         none  swap    sw    0 0
LABEL=system-boot       /boot/firmware  vfat    defaults        0       1
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/mnt/boot/cmdline.txt&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;dwc_otg.lpm_enable=0 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline rootwait fixrtc quiet splash
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'s,LABEL=writable,/dev/mapper/rootfs,'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/mnt/boot/cmdline.txt&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/mnt/boot/cmdline.txt&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;dwc_otg.lpm_enable=0 console=tty1 root=/dev/mapper/rootfs rootfstype=ext4 elevator=deadline rootwait fixrtc quiet splash&lt;/span&gt;
&lt;/pre&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;Again, feel free to use an editor here instead of messing around with
&lt;tt class="docutils literal"&gt;sed&lt;/tt&gt;; I&amp;#8217;ve illustrated the changes necessary by showing the before and
after states of the file&amp;nbsp;affected.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="fail-and-then-succeed"&gt;
&lt;h2&gt;Fail! (and then&amp;nbsp;succeed)&lt;/h2&gt;
&lt;p&gt;Time to clean up and test our&amp;nbsp;card.&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;umount&lt;span class="w"&gt; &lt;/span&gt;/mnt/root&lt;span class="w"&gt; &lt;/span&gt;/mnt/boot&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;cryptsetup&lt;span class="w"&gt; &lt;/span&gt;close&lt;span class="w"&gt; &lt;/span&gt;rootfs
&lt;/pre&gt;
&lt;p&gt;Eject the card (or mass storage) properly, shove it in your Pi and start it
booting. This first boot will appear to take a &lt;em&gt;very&lt;/em&gt; long time (several
minutes, while it times out waiting for the root device to appear) and will
then fail, dropping to the initramfs prompt. The reason for this is that, even
though we re-generated the initramfs to include the &lt;tt class="docutils literal"&gt;cryptsetup&lt;/tt&gt; tool, it
still isn&amp;#8217;t configured to actually unlock the correct partition. We&amp;#8217;ll need to
re-generate it again to do that, but first we need to get the system&amp;nbsp;booted.&lt;/p&gt;
&lt;p&gt;At the &lt;tt class="docutils literal"&gt;(initramfs)&lt;/tt&gt; prompt run the following to get the system booting
(if you&amp;#8217;re booting an &lt;span class="caps"&gt;SSD&lt;/span&gt; drive, adjust &lt;tt class="docutils literal"&gt;/dev/mmcblk0p2&lt;/tt&gt; below to
&lt;tt class="docutils literal"&gt;/dev/sda2&lt;/tt&gt;):&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp-VirtualEnv"&gt;(initramfs)&lt;/span&gt; &lt;span class="go"&gt;cryptsetup open /dev/mmcblk0p2 rootfs
Enter passphrase for /dev/mmcblk0p2:
&lt;/span&gt;&lt;span class="gp-VirtualEnv"&gt;(initramfs)&lt;/span&gt; &lt;span class="go"&gt;exit&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Once the system has booted successfully, login and re-generate the initramfs
one last time before rebooting to test your new&amp;nbsp;setup:&lt;/p&gt;
&lt;pre class="code console literal-block"&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;update-initramfs&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;reboot
&lt;/pre&gt;
&lt;p&gt;This time the initramfs should prompt you nicely to unlock your device before
proceeding with the rest of the&amp;nbsp;boot.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s all for this time. Let me know below if you run into any issues with&amp;nbsp;this!&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"></category><category term="pi"></category><category term="ubuntu"></category><category term="storage"></category><category term="luks"></category></entry></feed>