<?xml version="1.0" encoding="utf-8"?><rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:media="http://search.yahoo.com/mrss/"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
>
<channel>
  <title>Srijan Choudhary, all posts tagged: security</title>
  <link>https://srijan.ch/feed/all/tag:security</link>
  <lastBuildDate>Wed, 22 Feb 2023 19:45:00 +0000</lastBuildDate>
  <image>
    <url>https://srijan.ch/assets/favicon/favicon-32x32.png</url>
    <title>Srijan Choudhary, all posts tagged: security</title>
    <link>https://srijan.ch/feed/all/tag:security</link>
  </image>
  <sy:updatePeriod>daily</sy:updatePeriod>
  <sy:updateFrequency>1</sy:updateFrequency>
  <generator>Kirby</generator>
  <atom:link href="https://srijan.ch/feed/all.xml/tag:security" rel="self" type="application/rss+xml" />
  <description>Srijan Choudhary&#039;s Articles and Notes Feed for tag: security</description>
  <item>
    <title>Encrypting an existing Linux system&#039;s root partition</title>
    <description><![CDATA[Encrypt an unencrypted root partition on an Arch Linux system]]></description>
    <link>https://srijan.ch/encrypting-an-existing-linux-systems-root-partition</link>
    <guid isPermaLink="false">63f61c905e8d350001eda64a</guid>
    <category><![CDATA[linux]]></category>
    <category><![CDATA[security]]></category>
    <dc:creator>Srijan Choudhary</dc:creator>
    <pubDate>Wed, 22 Feb 2023 19:45:00 +0000</pubDate>
    <media:content url="https://srijan.ch/media/pages/blog/encrypting-an-existing-linux-systems-root-partition/27f278c9de-1699621096/partitions-summary.excalidraw.png" medium="image" />
    <content:encoded><![CDATA[<h2>Introduction</h2>
<p>I have an Arch Linux 
system with an unencrypted root partition that I wanted to encrypt. I've
 documented the steps I followed to achieve this here.</p> <p>I selected the "LUKS on a partition" option <a href="https://wiki.archlinux.org/title/dm-crypt/Encrypting_an_entire_system" rel="noreferrer">from here</a>. I don't have an LVM setup on this system and didn't need to encrypt the boot partition.</p><figure data-ratio="auto">
    <img src="https://srijan.ch/media/pages/blog/encrypting-an-existing-linux-systems-root-partition/27f278c9de-1699621096/partitions-summary.excalidraw.png" alt="">
  
  </figure>
<p>The
 first step was to have a backup so that if something failed, I could at
 least recover my critical files. I don't have filesystem-level backups 
configured, so I used <a href="https://github.com/kopia/kopia" rel="noreferrer">kopia</a> to back up my home folder. Details on this might be in a future blog post.</p><h2>Process</h2>
<p>1. To begin, I set up a <a href="https://wiki.archlinux.org/title/USB_flash_installation_medium" rel="noreferrer">USB flash installation medium</a>
 so that I could boot into a live environment to perform the actual 
actions. Since I needed to encrypt the root partition, this could not be
 performed from inside the system running off that partition.</p> <p>2. 
After booting into the live environment using the above USB medium, I 
first shrank the existing filesystem by 32MiB to make space for the LUKS
 encryption header, which is always stored at the beginning of the 
device. My filesystem size is exactly 500GiB, so I set the new size to <code>511968M</code>.</p><figure>
  <pre><code class="language-shellsession"># echo &quot;Check the filesystem&quot;
# e2fsck -f /dev/nvme0n1p7

# echo &quot;Resize&quot;
# resize2fs -p /dev/nvme0n1p7 511968M</code></pre>
  </figure>
<p>3. Now, I encrypted it using the default cipher. This took 37 minutes on my 500GiB partition, which was about 55% full.</p><figure>
  <pre><code class="language-shellsession"># cryptsetup reencrypt --encrypt --reduce-device-size 16M /dev/nvme0n1p7

WARNING!

========

This will overwrite data on LUKS2-temp-12345678-9012-3456-7890-123456789012.new irrevocably.

Are you sure? (Type &#039;yes&#039; in capital letters): YES
Enter passphrase for LUKS2-temp-12345678-9012-3456-7890-123456789012.new: 
Verify passphrase:</code></pre>
  </figure>
<p>4. Next, I extended the original ext4 file system to occupy all available space again on the now encrypted partition:</p><figure>
  <pre><code class="language-shellsession"># cryptsetup open /dev/nvme0n1p7 root
Enter passphrase for /dev/nvme0n1p7: 

# resize2fs /dev/mapper/root</code></pre>
  </figure>
<p>5. Now, I mounted the filesystem and chrooted into it:</p><figure>
  <pre><code class="language-shellsession"># mount /dev/mapper/root /mnt
# mount /dev/nvme0n1p1 /mnt/boot
# arch-chroot /mnt</code></pre>
  </figure>
<p>6. Since I have a systemd-based initramfs, I added <code>keyboard</code>, <code>sd-vconsole</code>, and <code>sd-encrypt</code> hooks in the <code>HOOKS</code> section of <code>/etc/mkinitcpio.conf</code>:</p><figure>
  <pre><code class="language-ini">HOOKS=(base systemd autodetect modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)</code></pre>
    <figcaption class="text-center">/etc/mkinitcpio.conf</figcaption>
  </figure>
<p>7. Next, I regenerated the initramfs ( <code>-P</code> regenerates it for all presets ):</p><figure>
  <pre><code class="language-shellsession"># mkinitcpio -P</code></pre>
  </figure>
<p>8. Next, I configured the boot loader by adding to kernel parameters:</p><figure>
  <pre><code class="language-ini">rd.luks.name=&lt;device-UUID&gt;=root root=/dev/mapper/root</code></pre>
  </figure>
<p>I found the device UUID using: <code>sudo blkid -s UUID -o value /dev/nvme0n1p7</code>. Surprisingly (for me), the UUID had changed after encrypting the partition.</p> <p>My final bootloader conf file looked like this:</p><figure>
  <pre><code class="language-text">title    Arch Linux
linux    /vmlinuz-linux
initrd   /amd-ucode.img
initrd   /initramfs-linux.img
options  rd.luks.name=1df8ea89-4274-4ef9-a670-76c13e612901=root root=/dev/mapper/root rw</code></pre>
    <figcaption class="text-center">/boot/loader/entries/arch.conf</figcaption>
  </figure>
<p>9. Lastly, I updated <code>/etc/fstab</code>:</p><figure>
  <pre><code class="language-text">/dev/mapper/root  /  ext4  rw,relatime  0 1</code></pre>
    <figcaption class="text-center">/etc/fstab</figcaption>
  </figure>
<p>10. All done. To test it out, I logged out of the chroot environment and rebooted the system.</p><p>It asked me for the disk encryption password. After entering the password selected in step 3, the system booted up as usual, and everything looked to be working.</p><h2>Final Thoughts</h2>
<p>This was surprisingly easy to do and did not take much time. The <a href="https://wiki.archlinux.org/" rel="noreferrer">ArchWiki</a> was helpful, even if the information was spread over multiple pages/sections. Taking a backup before starting also made me feel safe about the process.</p><p>I did not like the design of the decryption password prompt at bootup. Maybe there's a way to customize it to look better. Update: I found a way. <a href="https://srijan.ch/graphical-password-prompt-for-disk-decryption" rel="noreferrer">Details here</a>.</p>]]></content:encoded>
    <comments>https://srijan.ch/encrypting-an-existing-linux-systems-root-partition#comments</comments>
    <slash:comments>1</slash:comments>
  </item><item>
    <title>Download a file securely from GCS on an untrusted system</title>
    <description><![CDATA[Download files from google cloud storage using temporary credentials or time-limited access URLs]]></description>
    <link>https://srijan.ch/secure-gcs-download</link>
    <guid isPermaLink="false">632920ea8948d20001269e4e</guid>
    <category><![CDATA[cloud]]></category>
    <category><![CDATA[security]]></category>
    <category><![CDATA[devops]]></category>
    <dc:creator>Srijan Choudhary</dc:creator>
    <pubDate>Sun, 27 Nov 2022 19:30:00 +0000</pubDate>
    <content:encoded><![CDATA[<h2>The Problem</h2>
<p>We publish some of our build artifacts to <a href="https://cloud.google.com/storage" rel="noreferrer">Google Cloud Storage</a>,
 and users need to download these to the target installation system. 
But, this target system is not always trusted and can have shared local 
users, so we don't want to store long-lived credentials.</p> <p>As a 
user, I can download the artifact on my (secure) laptop and transfer it 
to the target system. But, the artifact can be large (several GBs). So, 
downloading and uploading again makes it cumbersome and slow.</p><h2>Option 1: use <a href="https://cloud.google.com/sdk/docs/install" rel="noreferrer">gcloud CLI</a> on the target system</h2>
<p>Log in to the target system, install gcloud CLI, authenticate, and then download the file:</p><figure>
  <pre><code class="language-shellsession">$ gcloud storage cp gs://$BUCKET/$FILE ./</code></pre>
  </figure>
<p>This has two problems:</p><ol><li>The user must install (and maybe update) gcloud CLI on the target system.</li><li>The
 user needs to store their credentials on the target system. These 
credentials have full access to whatever resources the user has. So, 
it's a huge security risk, especially if we don't trust the target 
system.</li></ol><p>To mitigate (2), the user can log out of gcloud CLI after downloading. But, this is a manual step they might miss.</p><h2>Option 2: use gcloud CLI with a service account</h2>
<p>This
 is a variation of the above solution - we log in using a service 
account instead of the user account. This service account can have 
restricted access to only the resources needed.</p><figure>
  <pre><code class="language-shellsession">$ gcloud iam service-accounts create $SA_NAME \
    --description=&quot;Service Account for downloading artifacts&quot;
$ gsutil iam ch \
    serviceAccount:$SA_NAME@$PROJECT_ID.iam.gserviceaccount.com:roles/storage.objectViewer \
    gs://$BUCKET</code></pre>
  </figure>
<p>This partially mitigates problem (2) above. If 
the user forgets to log out of gcloud CLI, the damage will be restricted
 to the resources accessible by the service account.</p><h2>Option 3: Short-lived access token</h2>
<p>Gcloud CLI supports creating short-lived credentials for the end-user account or <a href="https://cloud.google.com/iam/docs/create-short-lived-credentials-direct" rel="noreferrer">any service account</a>.</p> <p>This credential can be used to download the artifact using wget with an authorization header - no need to install gcloud CLI.</p> <p>Here's
 a small script that asks for the auth token as input, parses various 
GCS bucket URL formats, and downloads the requested artifact directly 
using wget:</p><figure>
  <pre><code class="language-bash">#!/bin/bash
# Download artifact from GCS bucket

set -e

echo -e &quot;====&gt; Run \`gcloud auth print-access-token\` on a system where you&#039;ve setup gcloud to get access token\n&quot;
read -r -p &quot;Enter access token: &quot; StorageAccessToken
read -r -p &quot;Enter GCS artifact URL: &quot; ArtifactURL

if [[ &quot;${ArtifactURL:0:33}&quot; == &quot;https://console.cloud.google.com/&quot; ]]; then
    BucketAndFile=&quot;${ArtifactURL#*https://console.cloud.google.com/storage/browser/_details/}&quot;
elif [[ &quot;${ArtifactURL:0:33}&quot; == &quot;https://storage.cloud.google.com/&quot; ]]; then
    BucketAndFile=&quot;${ArtifactURL#*https://storage.cloud.google.com/}&quot;
elif [[ &quot;${ArtifactURL:0:5}&quot; == &quot;gs://&quot; ]]; then
    BucketAndFile=&quot;${ArtifactURL#*gs://}&quot;
else
    echo &quot;Invalid GCS artifact URL&quot;
    exit 1
fi

StorageBucket=&quot;${BucketAndFile%%/*}&quot;
StorageFile=&quot;${BucketAndFile#*/}&quot;
StorageFileEscaped=$(echo &quot;${StorageFile}&quot; | sed &#039;s/\//%2F/g&#039;)
OutputFileName=&quot;${StorageFile##*/}&quot;

echo -e &quot;\n====&gt; Downloading gs://${StorageBucket}/${StorageFile} to ${OutputFileName}\n&quot;

wget -O &quot;${OutputFileName}&quot; --header=&quot;Authorization: Bearer ${StorageAccessToken}&quot; \
    &quot;https://storage.googleapis.com/storage/v1/b/${StorageBucket}/o/${StorageFileEscaped}?alt=media&quot;</code></pre>
  </figure>
<h2>Option 4: Signed URLs</h2>
<p>Google Cloud Storage also supports <a href="https://cloud.google.com/storage/docs/access-control/signed-urls" rel="noreferrer">signed URLs</a>
 - which give time-limited access to a specific Cloud Storage resource. 
Anyone possessing the signed URL can use it while it's active without 
any further credentials. This fits our use case brilliantly.</p> <p>To do this, first we need to give ourselves the <code>iam.serviceAccountTokenCreator</code> role so that we can impersonate a service account.</p><figure>
  <pre><code class="language-shellsession">$ gcloud iam service-accounts add-iam-policy-binding \
	$SA_NAME@$PROJECT_ID.iam.gserviceaccount.com \
    --member=$MY_EMAIL \
    --role=roles/iam.serviceAccountTokenCreator</code></pre>
  </figure>
<p>Then, we can generate a signed URL:</p><figure>
  <pre><code class="language-shellsession">$ gcloud config set auth/impersonate_service_account \
    $SA_NAME@$PROJECT_ID.iam.gserviceaccount.com

$ gsutil signurl -u -r $REGION -d 10m gs://$BUCKET/$FILE

$ gcloud config unset auth/impersonate_service_account</code></pre>
  </figure>
<p>And we can use wget to download the artifact from this URL without any further authentication.</p>]]></content:encoded>
    <comments>https://srijan.ch/secure-gcs-download#comments</comments>
    <slash:comments>0</slash:comments>
  </item></channel>
</rss>
