<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alessandro (Ale) Segala</title>
    <description>The latest articles on DEV Community by Alessandro (Ale) Segala (@italypaleale).</description>
    <link>https://dev.to/italypaleale</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F277035%2Fc77629dc-6a87-4c26-8028-942bfb514eca.jpg</url>
      <title>DEV Community: Alessandro (Ale) Segala</title>
      <link>https://dev.to/italypaleale</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/italypaleale"/>
    <language>en</language>
    <item>
      <title>Essential Cryptography for JavaScript Developers</title>
      <dc:creator>Alessandro (Ale) Segala</dc:creator>
      <pubDate>Wed, 30 Mar 2022 00:19:03 +0000</pubDate>
      <link>https://dev.to/italypaleale/essential-cryptography-for-javascript-developers-4h2m</link>
      <guid>https://dev.to/italypaleale/essential-cryptography-for-javascript-developers-4h2m</guid>
      <description>&lt;p&gt;In the fall of 2020, my first book came out: &lt;a href="https://www.amazon.com/dp/1839213620/ref=cm_sw_em_r_mt_dp_PVHQQYG2TK3PRFYHGTRK"&gt;&lt;em&gt;Svelte 3 Up and Running&lt;/em&gt;&lt;/a&gt;, published by Packt. When one of their acquisition editors contacted me some months prior, I was not new to writing, having blogged for many years, but the idea of writing an entire technical book was fascinating to me—and working with a reputable publisher like Packt seemed like a fantastic opportunity to try something new.&lt;/p&gt;

&lt;p&gt;While writing about Svelte 3 was fun, shortly after the first book hit the (virtual) shelves, I had already an idea for a second one that I pitched to Packt: I wanted to write about cryptography, creating a handbook that was specifically meant for software developers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://packt.link/AcgWC"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UN-7ED7M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/agrhu7xovfeq6lcin6gs.jpg" alt="Book cover: Essential Cryptography for JavaScript Developers" width="880" height="1087"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm proud to share with you that this second book is now complete: &lt;strong&gt;Essential Cryptography for JavaScript Developers&lt;/strong&gt;. You can find it &lt;a href="https://packt.link/AcgWC"&gt;on Amazon&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the book is about
&lt;/h2&gt;

&lt;p&gt;Obviously, my second book is about cryptography. However, it takes the somewhat unique approach of being written for an audience of software developers who may not have any background in cryptography, and yet they are interested in learning how to adopt common cryptographic operations in their applications, safely.&lt;/p&gt;

&lt;p&gt;Throughout the book we focus on learning about four common cryptographic operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hashing&lt;/strong&gt;: A set of functions that allows generating a unique &lt;em&gt;hash&lt;/em&gt; (also called &lt;em&gt;digest&lt;/em&gt; or &lt;em&gt;checksum&lt;/em&gt;) that is always of a fixed length. Unlike encryption, hashing is one-way: that is, it's an operation that cannot be reversed. Its uses include verifying the integrity of messages and files, generating unique identifiers, protecting passwords stored in databases, and deriving encryption keys from passwords.
In the book, we cover algorithms such as SHA-2, scrypt, and Argon2… and we look at why outdated algorithms like MD5 and SHA-1 are not to be used anymore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Symmetric encryption&lt;/strong&gt;: This is about encrypting (and decrypting) data using a symmetric key: i.e. using the same key for both encryption and decryption. Most people are familiar with this concept, for example when they protect a ZIP file with a passphrase.
In the book we cover how to encrypt and decrypt messages and entire files using two symmetric ciphers: AES and ChaCha20-Poly1305.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asymmetric encryption&lt;/strong&gt;: This is another class of encryption algorithms in which users have a pair of keys, consisting of a private key and a public one, and those are used to encrypt and decrypt messages when they're shared with other people. While asymmetric ciphers are much lesser known (and understood), they are used by virtually every human being, daily, given that they underpin protocols like HTTPS that is used to serve web pages securely.
Within the book, we learn about asymmetric ciphers and hybrid ones (that combine an asymmetric cipher with a symmetric one), when they should be used and how. We're focusing on RSA and algorithms based on Elliptic Curve Cryptography (ECDH and ECIES).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Digital signatures&lt;/strong&gt;: With digital signature schemes, developers can build solutions that leverage public key cryptography to authenticate messages and certify their integrity. For example, those QR codes that many people are familiar with these days to prove COVID test results or vaccination status embed a message that is digitally signed, allowing everyone to verify the integrity of the certification and who issued it. Although they often operate "behind the scenes" and are not immediately visible to users, digital signatures have a multitude of uses in software development, including securing software distribution, preventing tampering with messages, etc.
In my book, you'll be able to learn when to use digital signatures and how, using RSA and schemes based on Elliptic Curve Cryptography (ECDSA and EdDSA).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As per the title of the book, it includes code samples written in JavaScript, for both Node.js (and platforms based on Node.js, like Electron) and for client-side code that runs within a web browser. I chose JavaScript because it's a very popular language and it has vast applications, from front-ends, to servers, to desktop and mobile apps.&lt;/p&gt;

&lt;p&gt;However, if you primarily work with another programming language or framework, you will still be able to learn principles and techniques that can be ported to your preferred stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I wrote this book
&lt;/h2&gt;

&lt;p&gt;I believe that having at least some knowledge of cryptography is an important skill for every software developer, and it's becoming even more important every day.&lt;/p&gt;

&lt;p&gt;Us developers are facing increased pressure to build apps that are safe against more widespread and more sophisticated attacks. We are also being asked to design solutions that comply with more stringent privacy requirements, either due to external regulation (like GDPR) or simply because of business requirements—more commonly, privacy is a selling point for apps, and more customers are demanding that. For both these reasons and more, cryptography is an immensely powerful tool that we can leverage to accomplish those goals—not sufficient, but almost always necessary.&lt;/p&gt;

&lt;p&gt;Yet, as a software developer, learning about cryptography is not always easy. To start, cryptography is a vast topic, has many confusing things, and mistakes are not always immediately clear.&lt;/p&gt;

&lt;p&gt;There are of course lots of resources to learn cryptography, including many books that have already been written. However, a large part of those tutorials, videos, articles and lectures, and perhaps almost all books, seem to have a focus on cryptography as a science, and are generally written for an audience of aspiring cryptographers. As such, they spend a good chunk of time on the formal descriptions of the algorithms, with lots and lots of (complex) math.&lt;/p&gt;

&lt;p&gt;While resources like those are incredibly valuable for people who want to learn the science and art of cryptography, as a software developer myself I was always more interested in the &lt;strong&gt;practical applications&lt;/strong&gt; and found the math distracting—if not outright confusing at times.&lt;/p&gt;

&lt;p&gt;With &lt;em&gt;Essential Cryptography for JavaScript Developers&lt;/em&gt; I've attempted to collect all my learnings from over a decade of using cryptographic operations to develop many different apps and share them with other developers so they can avoid the same mistakes I've made.&lt;/p&gt;

&lt;p&gt;It's a book written for other software developers who want to know which are the most common cryptographic operations, what they're used for, and how they can use them in their code, safely, relying on proven implementations such as those built-into JavaScript and Node.js.&lt;/p&gt;

&lt;p&gt;This book took quite a lot of time to put together, but I'm very excited about the end result and I can't wait for other developers to read it and then see what they build with that! And please do share any feedback you have about the book with me—including showcasing the projects you've written!&lt;/p&gt;

&lt;p&gt;You can order &lt;em&gt;Essential Cryptography for JavaScript Developers&lt;/em&gt; &lt;a href="https://packt.link/AcgWC"&gt;on Amazon&lt;/a&gt; in any country, or directly from &lt;a href="https://www.packtpub.com/product/essential-cryptography-for-javascript-developers/9781801075336"&gt;Packt&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>cryptography</category>
      <category>crypto</category>
      <category>book</category>
      <category>learning</category>
    </item>
    <item>
      <title>Watch: JavaScript apps going Inter-Planetary</title>
      <dc:creator>Alessandro (Ale) Segala</dc:creator>
      <pubDate>Thu, 23 Jan 2020 01:41:06 +0000</pubDate>
      <link>https://dev.to/italypaleale/watch-javascript-apps-going-inter-planetary-1l6d</link>
      <guid>https://dev.to/italypaleale/watch-javascript-apps-going-inter-planetary-1l6d</guid>
      <description>&lt;p&gt;Last December, I gave a talk at Node+JS Interactive in Montreal, with the title &lt;strong&gt;&lt;em&gt;JavaScript apps going Inter-Planetary&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I was very excited to have the opportunity to speak for the first time at a large tech event, and I got to explain and demo something I'm very passionate about: building static web apps for the Distributed Web, and making them "production ready".&lt;/p&gt;

&lt;p&gt;After briefly explaining &lt;strong&gt;what is the Inter-Planetary File System&lt;/strong&gt; (IPFS) and how to interact with it, I showed how to &lt;strong&gt;run a static JavaScript app&lt;/strong&gt; (&lt;a href="https://withblue.ink/2019/11/16/your-next-app-may-not-have-a-backend.html"&gt;JAMstack&lt;/a&gt;) deployed through IPFS.&lt;/p&gt;

&lt;p&gt;To make that app accessible to anyone in an easy manner, I then introduced using public &lt;strong&gt;IPFS gateways&lt;/strong&gt; with Cloudflare, and &lt;strong&gt;simpler URLs&lt;/strong&gt; thanks to the IPNS, or Inter-Planetary Name Service.&lt;/p&gt;

&lt;p&gt;Lastly, I demoed how you can enable a full DevOps pipeline with &lt;strong&gt;Continuous Integration and Continuous Delivery&lt;/strong&gt;, to automatically publish apps on the IPFS network.&lt;/p&gt;

&lt;p&gt;📺 The full talk has been recorded and is now on YouTube:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/OY-YnkVHJcc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;🖥 You can also find all the &lt;a href="https://static.sched.com/hosted_files/njsi2019/0f/JavaScript%20Apps%20Going%20Inter-Planetary.pdf"&gt;slides in PDF here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;🧑‍💻 The code used for the demo, as well as all the instructions to replicate it yourself, are published on GitHub at &lt;strong&gt;&lt;a href="https://github.com/ItalyPaleAle/calendar-next-demo"&gt;ItalyPaleAle/calendar-next-demo&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;📖 Lastly, if you're interested in reading more, check out my other articles about IPFS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://withblue.ink/2018/11/14/distributed-web-host-your-website-with-ipfs-clusters-cloudflare-and-devops.html"&gt;Distributed Web: host your website with IPFS clusters, Cloudflare, and DevOps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://withblue.ink/2019/03/20/hugo-and-ipfs-how-this-blog-works-and-scales.html"&gt;Hugo and IPFS: how this blog works (and scales to serve 5,000% spikes instantly!)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope you enjoy the content, and let me know if you have any feedback!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>distributedweb</category>
      <category>ipfs</category>
    </item>
    <item>
      <title>Auto-mounting encrypted drives with a remote key on Linux</title>
      <dc:creator>Alessandro (Ale) Segala</dc:creator>
      <pubDate>Mon, 20 Jan 2020 06:06:07 +0000</pubDate>
      <link>https://dev.to/italypaleale/auto-mounting-encrypted-drives-with-a-remote-key-on-linux-l2g</link>
      <guid>https://dev.to/italypaleale/auto-mounting-encrypted-drives-with-a-remote-key-on-linux-l2g</guid>
      <description>&lt;p&gt;I've been building a simple NAS for my home, and I wanted to store the data on a secondary disk, encrypted with dm-crypt/LUKS. There are plenty of articles on how to do that, but when it comes to automatically mounting the disk at boot, all of them recommend writing the encryption key in a keyfile and store it on the local filesystem.&lt;/p&gt;

&lt;p&gt;This approach wasn't acceptable to me: while the data would be encrypted at rest, the key to open the encrypted partition would also be sitting in the same place. If someone were to steal the physical server (imagine this were a small Raspberry Pi!), they would have access to the data without any issue.&lt;/p&gt;

&lt;p&gt;How could I have the LUKS encryption key stored in a secure, remote place, while at the same time being able to have the encrypted disk automatically mounted without manual intervention (e.g. in case of a reboot after a power outage)? In other words, how to have your cake and eat it too.&lt;/p&gt;

&lt;p&gt;Turns out, there's a relatively simple solution, which requires just two systemd units.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: this approach can not be used with encrypted root volumes, but only with secondary disks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1: Generate and store the keyfile
&lt;/h2&gt;

&lt;p&gt;The first thing we need to do is to generate a keyfile. This should be 256-bytes long, and can be generated with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;256 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/random | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; keyfile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I'm piping the encryption key through base64 so we don't have to deal with binary files, making things more manageable.&lt;/p&gt;

&lt;p&gt;You will then need to store the keyfile somewhere safe. You can pick and choose any place you'd like; some ideas include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A key vault like &lt;a href="https://docs.microsoft.com/en-us/azure/key-vault/key-vault-overview"&gt;Azure Key Vault&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;HTTPS servers, including object storage services such as AWS S3 or Azure Blob Storage; make sure you're using TLS to protect the data while in transit, rather than basic HTTP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a simple (but effective enough) solution, you can store the keyfile in Azure Blob Storage. You can see an example of doing this in the &lt;em&gt;Appendix&lt;/em&gt; below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Create a script returning the keyfile
&lt;/h2&gt;

&lt;p&gt;You will need to create a script that can return the keyfile when invoked, stored as &lt;code&gt;/etc/luks/key.sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The content of the script completely depends on how and where you stored your keyfile. Following up on the example in the &lt;em&gt;Appendix&lt;/em&gt;, with a keyfile stored on Azure Blob Storage, the script would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c"&gt;# Request the file from Azure Blob Storage using the URL with the SAS token, then pipe it through `base64 -d` to decode it from base64&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://ln5bxfzbl0tlf5z.blob.core.windows.net/keyfiles/keyfile?se=2022-01-19T23%3A02Z&amp;amp;sp=r&amp;amp;spr=https&amp;amp;sv=2018-11-09&amp;amp;sr=b&amp;amp;sig=gkaN2OSzN2zj1WSAPiLJMgtkcXLi2Y8EOVdBUmZQh88%3D"&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Whatever the content of your script (which could be a shell script or written in any other language), it's important then to make it executable and readable by the &lt;code&gt;root&lt;/code&gt; user only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Ensure the owner of this file is "root"&lt;/span&gt;
&lt;span class="nb"&gt;chown &lt;/span&gt;root:root /etc/luks/key.sh
&lt;span class="c"&gt;# Allow only the owner (root) to read and execute the script&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;0500 /etc/luks/key.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Encrypt the disk using LUKS
&lt;/h2&gt;

&lt;p&gt;We're now ready to get to the fun part, and encrypt the disk or partition.&lt;/p&gt;

&lt;p&gt;To start, check the name of the disk you want to use, using &lt;code&gt;lsblk&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;lsblk
NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda       8:0    0   30G  0 disk
├─sda1    8:1    0 29.9G  0 part /
├─sda14   8:14   0    4M  0 part
└─sda15   8:15   0  106M  0 part /boot/efi
sdb       8:16   0    4G  0 disk
└─sdb1    8:17   0    4G  0 part /mnt
sdc       8:32   0   32G  0 disk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example, I'm going to use the &lt;strong&gt;&lt;code&gt;sdc&lt;/code&gt;&lt;/strong&gt; disk. This is likely going to be different for you, so make sure you replace the disk name in all the commands below.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Watch out! The commands below will &lt;strong&gt;delete all files&lt;/strong&gt; on the drive you select.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before we start, install the &lt;code&gt;cryptsetup&lt;/code&gt; utility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Debian, Ubuntu, Raspbian…&lt;/span&gt;
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; cryptsetup

&lt;span class="c"&gt;# CentOS, Fedora, RedHat&lt;/span&gt;
yum &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; cryptsetup-luks
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;First, if your disk doesn't have a partition yet (like mine), create a GPT partition table and a partition (without formatting it):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Replace sdc with the drive you want to use&lt;/span&gt;
parted /dev/sdc mklabel gpt
parted &lt;span class="nt"&gt;-a&lt;/span&gt; opt /dev/sdc mkpart datadisk ext4 0% 100%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Encrypt the &lt;code&gt;sdc1&lt;/code&gt; partition using LUKS, create an ext4 volume in that partition, and then close the encrypted volume. In all commands that require a keyfile, we're invoking the &lt;code&gt;/etc/luks/key.sh&lt;/code&gt; script that we created before, and telling &lt;code&gt;cryptsetup&lt;/code&gt; to read the keyfile from stdin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Encrypt the disk&lt;/span&gt;
&lt;span class="c"&gt;# Replace sdc1 with the correct partition!&lt;/span&gt;
/etc/luks/key.sh | cryptsetup &lt;span class="nt"&gt;-d&lt;/span&gt; - &lt;span class="nt"&gt;-v&lt;/span&gt; luksFormat /dev/sdc1

&lt;span class="c"&gt;# Open the encrypted volume, with the name "data"&lt;/span&gt;
&lt;span class="c"&gt;# Replace sdc1 with the correct partition!&lt;/span&gt;
/etc/luks/key.sh | cryptsetup &lt;span class="nt"&gt;-d&lt;/span&gt; - &lt;span class="nt"&gt;-v&lt;/span&gt; luksOpen /dev/sdc1 data

&lt;span class="c"&gt;# Create a filesystem on the encrypted volume&lt;/span&gt;
mkfs.ext4 &lt;span class="nt"&gt;-F&lt;/span&gt; /dev/mapper/data

&lt;span class="c"&gt;# Close the encrypted volume&lt;/span&gt;
cryptsetup &lt;span class="nt"&gt;-v&lt;/span&gt; luksClose data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Enable auto-mounting the encrypted disk
&lt;/h2&gt;

&lt;p&gt;We're almost done: ready to enable auto-mounting of the encrypted disk.&lt;/p&gt;

&lt;p&gt;We'll do that with two systemd units: one unlocking the encrypted device, and the other one actually mounting the disk.&lt;/p&gt;

&lt;p&gt;To start, get the UUID of the &lt;code&gt;/dev/sdc1&lt;/code&gt; partition, using &lt;code&gt;lsblk --fs&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;lsblk &lt;span class="nt"&gt;--fs&lt;/span&gt;
NAME    FSTYPE      LABEL           UUID                                 MOUNTPOINT
&lt;span class="o"&gt;[&lt;/span&gt;...]
sdc
└─sdc1  crypto_LUKS                 a17db19d-5037-4cbb-b50b-c85e3e074864
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In my example, that is &lt;code&gt;a17db19d-5037-4cbb-b50b-c85e3e074864&lt;/code&gt;; it will be different for you.&lt;/p&gt;

&lt;p&gt;Create a systemd unit for unlocking the encrypted device and save it as &lt;strong&gt;&lt;code&gt;/etc/systemd/system/unlock-data.service&lt;/code&gt;&lt;/strong&gt;. Make sure you replace the UUID in the command below!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Unit]
Description=Open encrypted data volume
After=network-online.target local-fs.target
StopWhenUnneeded=true

[Service]
Type=oneshot
ExecStart=/bin/sh -c '/etc/luks/key.sh | /sbin/cryptsetup -d - -v luksOpen /dev/disk/by-uuid/a17db19d-5037-4cbb-b50b-c85e3e074864 data'
RemainAfterExit=true
ExecStop=/sbin/cryptsetup -d - -v luksClose data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note the &lt;code&gt;StopWhenUnneeded=true&lt;/code&gt; line: this will make systemd stop the unit (including running the &lt;code&gt;luksClose&lt;/code&gt; operation) automatically when the disk is unmounted.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create another systemd unit with the mountpoint for &lt;code&gt;/mnt/data&lt;/code&gt;, and save it as &lt;strong&gt;&lt;code&gt;/etc/systemd/system/mnt-data.mount&lt;/code&gt;&lt;/strong&gt;. Note that the unit's name must match the path of the mountpoint!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Unit]
Requires=unlock-data.service
After=unlock-data.service

[Mount]
What=/dev/mapper/data
Where=/mnt/data
Type=ext4
Options=defaults,noatime

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We're now ready, let's enable the &lt;code&gt;mnt-data.mount&lt;/code&gt; unit so it's activated at boot, and then mount it right away:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;mnt-data.mount
systemctl start mnt-data.mount
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can now check with &lt;code&gt;lsblk&lt;/code&gt; to see the encrypted disk mounted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;lsblk
NAME     MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
&lt;span class="o"&gt;[&lt;/span&gt;...]
sdc        8:32   0   32G  0 disk
└─sdc1     8:33   0   32G  0 part
  └─data 253:0    0   32G  0 crypt /mnt/data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Try rebooting the system, and you'll see the partition being mounted automatically.&lt;/p&gt;

&lt;p&gt;We're done! However, keep in mind a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To mount and un-mount the encrypted disk you must use &lt;code&gt;systemctl&lt;/code&gt; rather than the usual &lt;code&gt;mount&lt;/code&gt; and &lt;code&gt;umount&lt;/code&gt; commands. Mount the disk with &lt;strong&gt;&lt;code&gt;systemctl start mnt-data.mount&lt;/code&gt;&lt;/strong&gt;, and un-mount with &lt;strong&gt;&lt;code&gt;systemctl stop mnt-data.mount&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The systemd units are executed only after the network and the other "normal" filesystems are mounted. If you have another service depending on the data disk's availability, you need to explicitly make its systemd unit depending on the &lt;code&gt;mnt-data.mount&lt;/code&gt; unit (with &lt;code&gt;Requires=mnt-data.mount&lt;/code&gt; and &lt;code&gt;After=mnt-data.mount&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;As mentioned at the beginning, this solution can't be used with the root filesystem, but only with secondary data disks.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Appendix: Keyfiles on Azure Blob Storage
&lt;/h2&gt;

&lt;p&gt;In this example, I'm storing the keyfile in Azure Blob Storage. While this doesn't offer the same protection as a key vault, it can be enough for most people, depending on your threat model. I'm guaranteeing some level of security by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configuring the Storage Account to accept only secure connections that use HTTPS&lt;/li&gt;
&lt;li&gt;Allowing connections only from the IP of my home (I have a "quasi-static" IP, that changes less than once per year)&lt;/li&gt;
&lt;li&gt;Requiring clients to use a SAS token to download the file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My threat model involves people stealing the disk and/or the server. The attacker wouldn't be able to download the keyfile if they're not in my network. By having the keyfile on a remote server, I can delete it right away if I need to, e.g. if the physical disk is stolen. This protection is enough for me, but depending on your threat model, you might want to look into more complex solutions, for example involving key vaults.&lt;/p&gt;

&lt;p&gt;If you're starting from scratch, you can create an Azure Storage Account, configure it per the requirements above, and upload your keyfile with the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest"&gt;Azure CLI&lt;/a&gt;. You will need an &lt;a href="https://azure.com/free"&gt;Azure subscription&lt;/a&gt;, which is free and with this kind of usage you'll be comfortably within their free tier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This example assumes that you've generated a base64-encoded keyfile available in the &lt;code&gt;keyfile&lt;/code&gt; file, in the current working directory, just as per &lt;em&gt;Step 1&lt;/em&gt; above.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Login to Azure if you need to&lt;/span&gt;
az login

&lt;span class="c"&gt;# Location where to store the keyfile; choose an Azure region close to you&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"eastus2"&lt;/span&gt;

&lt;span class="c"&gt;# If you have a fixed (or almost) IP address, you can restrict access to the storage account from that IP.&lt;/span&gt;
&lt;span class="c"&gt;# You can also use an IP range in the CIDR format.&lt;/span&gt;
&lt;span class="c"&gt;# Otherwise, leave this variable as an empty string&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ALLOW_IP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1.2.3.4"&lt;/span&gt;

&lt;span class="c"&gt;# Generate a random name for the Storage Account&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;STORAGE_ACCOUNT_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /dev/random | &lt;span class="nb"&gt;base64&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-dc&lt;/span&gt; &lt;span class="s1"&gt;'a-zA-Z0-9'&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;'[:upper:]'&lt;/span&gt; &lt;span class="s1"&gt;'[:lower:]'&lt;/span&gt; | &lt;span class="nb"&gt;fold&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; 15 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Create a Resource Group and a Storage Account&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RG_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Keyfiles"&lt;/span&gt;
az group create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$RG_NAME&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nv"&gt;$LOCATION&lt;/span&gt;
az storage account create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$STORAGE_ACCOUNT_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RG_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nv"&gt;$LOCATION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--sku&lt;/span&gt; Standard_LRS &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--kind&lt;/span&gt; StorageV2

&lt;span class="c"&gt;# Require using TLS/HTTPS only&lt;/span&gt;
az storage account update &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$STORAGE_ACCOUNT_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--https-only&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# Allow from a specific IP only, if the variable ALLOW_IP isn't empty&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ALLOW_IP&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="c"&gt;# Disallow access from anywhere by default&lt;/span&gt;
  az storage account update &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RG_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$STORAGE_ACCOUNT_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--default-action&lt;/span&gt; Deny
  &lt;span class="c"&gt;# Allow the IP or IP range&lt;/span&gt;
  az storage account network-rule add &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RG_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--account-name&lt;/span&gt; &lt;span class="nv"&gt;$STORAGE_ACCOUNT_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--ip-address&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ALLOW_IP&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="c"&gt;# Disallow "Trusted Microsoft Services"&lt;/span&gt;
  az storage account update &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RG_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$STORAGE_ACCOUNT_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--bypass&lt;/span&gt; None
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Create a blob container&lt;/span&gt;
az storage container create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"keyfiles"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--public-access&lt;/span&gt; off &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--account-name&lt;/span&gt; &lt;span class="nv"&gt;$STORAGE_ACCOUNT_NAME&lt;/span&gt;

&lt;span class="c"&gt;# Upload the key&lt;/span&gt;
az storage blob upload &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--account-name&lt;/span&gt; &lt;span class="nv"&gt;$STORAGE_ACCOUNT_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--container-name&lt;/span&gt; &lt;span class="s2"&gt;"keyfiles"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--file&lt;/span&gt; &lt;span class="s2"&gt;"./keyfile"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"keyfile"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that the file has been uploaded, we can get a link to it. Since the file is in a "private" container, it requires a special authentication token (&lt;a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview?toc=%2fazure%2fstorage%2fblobs%2ftoc.json"&gt;SAS token&lt;/a&gt;) to be retrieved. SAS tokens add some extra protection thanks to having an expiration date and being tied to an account key, which can be revoked at any time. You can also add additional requirements on the SAS tokens, such as restrictions on IPs; this is a (less ideal) alternative to setting IP restrictions on the Storage Account as shown above.&lt;/p&gt;

&lt;p&gt;You can generate a URL with a SAS token for the blob with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create an expiration date 2 years in the future&lt;/span&gt;
&lt;span class="c"&gt;# On Linux:&lt;/span&gt;
&lt;span class="nv"&gt;SAS_EXPIRY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"2 years"&lt;/span&gt; &lt;span class="s1"&gt;'+%Y-%m-%dT%H:%MZ'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# On macOS:&lt;/span&gt;
&lt;span class="nv"&gt;SAS_EXPIRY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;+2y &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s1"&gt;'+%Y-%m-%dT%H:%MZ'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Generate the URL with the SAS token&lt;/span&gt;
az storage blob generate-sas &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--account-name&lt;/span&gt; &lt;span class="nv"&gt;$STORAGE_ACCOUNT_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--container-name&lt;/span&gt; &lt;span class="s2"&gt;"keyfiles"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"keyfile"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--https-only&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--permissions&lt;/span&gt; r &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--expiry&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SAS_EXPIRY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--full-uri&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Result will be similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://ln5bxfzbl0tlf5z.blob.core.windows.net/keyfiles/keyfile?se=2022-01-19T23%3A02Z&amp;amp;sp=r&amp;amp;spr=https&amp;amp;sv=2018-11-09&amp;amp;sr=b&amp;amp;sig=gkaN2OSzN2zj1WSAPiLJMgtkcXLi2Y8EOVdBUmZQh88%3D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can use the URL above in the &lt;code&gt;/etc/luks/key.sh&lt;/code&gt; script, as per &lt;em&gt;Step 2&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>cryptography</category>
      <category>encryption</category>
    </item>
  </channel>
</rss>
