Özet
- Tam disk şifreli (full disk encryption) bir cihazın sahip olduğu saldırı vektörleri (attack vector).
- Bu saldırı vektörlerine dayanıklı bir Arch Linux kurulumu.
- Secure Boot, trusted platform module (TPM), unified kernel image (UKI), initramfs mevzularının temel açıklamaları.
- Sistem disk bölümünü şifreleme ve boot süreci doğrulanıyor ise TPM ile otomatik olarak kilidini açma.
- Her sistem kullanıcısına ayrı, çıkış yaptığında kilitlenen ve giriş yaptığında açılan kullanıcı parolasıyla şifrelenmiş ev dizini vermek.
/etc/fstab
ve/etc/crypttab
dosyalarına dokunmadan disk bölümlerinin boot esnasında otomatik algılanması.
Sorun
Linux, MacOS ve Windows’a kıyasla disk şifrelemesi konusunda henüz yeterli noktada değil. Yani evet, LUKS ile disk şifrelemek mümkün ve birçok dağıtımın sistem yükleyicisi bunu tek tıkla yapabiliyor. Ancak şifreli bir disk tek başına sanıldığı kadar güvenli ve kullanışlı olmayabilir.
Her şeyden önce her önyüklemede şifreli diskin parolasının girilmesi gerekiyor. Bu hem uğraştırıcı, hem de bundan dolayı sistemi tamamen kapatmak yerine uyku moduna almaya itiyor.
Uyku modundaki cihazın içindeki verilerle saldırganın bir kabuk erişimi elde etmesi arasında duran şey -eğer mevcut ise- ekran kilidi programıdır. Bu programlar çökmesi ya da zorlanması durumunda ekranı kullanılamaz hale getirecek şekilde yapılsalar da her programda hatalar olabilir. Sırtımızı sadece buna yaslayamayız.
Diski şifreli bir sistem uyku modundayken şifreleme anahtarını RAM’de tutmaya devam eder. Bu anahtar RAM’lerin fiziksel olarak çıkartılıp üzerindeki verileri okumak üzere başka bir cihaza takılması suretiyle ya da cold boot saldırısı metoduyla ele geçirilebilir.
Kapalı ya da derin uyku (hibernation) durumdaki bir cihaz üstteki
saldırı vektörlerine karşı güvende olsa da, önyükleyici (bootloader) ve
initramfs imajı gibi parçaların durdukları şifresiz /boot/
bölümünde
değiştirilip disk parolası girilirken tuş vuruşlarının kaydedilmesinin,
hatta internet üzerinden -şifreli diskinizin bir imajını da almış olan-
saldırgana göndermesine karşı koyamayabilir.
Çözüm
Kullanıcıdan parola girişi almak yerine şifreli sistem diski TPM ile
otomatik olarak açılmalı. Şifresiz /boot/
(aslında artık /efi/
)
bölümünde tutulan unified kernel image’larımızı şifreli disk alanımızda
tuttuğumuz kendi Secure Boot anahtarlarımızla imzalamalıyız. Yalnızca
bu imzalar doğrulanabilirse boot edilmeli.
Sistem (/
) ve ev (/home/
) bölümlerini ayrı olarak şifrelenmeli.
Kullanıcı çıkış yaptığında ev dizininin şifreleme anahtarı bellekten
silinmeli, ancak sistem çalışmaya devam etmeli ve kullanıcının
tekrardan giriş yaparak ev dizininin kilidini açabilmesi sağlanmalı.
UEFI firmware’ı için bir yönetici parolası ayarlanmalı ve ayarlara müdahale edilmesi engellenmeli.
Arch Linux kurulumu
Hazırlık
Secure Boot’u setup moduna almak
Bu adım cihazdan cihaza değişiyor. UEFI (BIOS olarak da biliniyor ancak BIOS secure boot desteklemez) ayarlarının “Secure Boot” kısmından “setup” modunu aktifleştirmek gerekiyor. Bu, kendi Secure Boot anahtarlarımızı kaydedebilmemizi sağlayacak.
Arch Linux kurulumuna başlamadan önce de bunu doğrulayalım.
root@archiso ~ # bootctl
Secure Boot: disabled (setup)
TPM2 Support: yes
Disk bölümlendirme
lsblk
komutu ile üzerinde işlem yapacağımız diskin ismini
(/dev/sda
, /dev/nvme0n1
vs.) öğreniyoruz. fdisk
ya da benzer bir
program ile bu diski bölümlendirelim.
root@archiso ~ # fdisk /dev/nvme0n1
Welcome to fdisk (util-linux 2.39.3).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
g
komutu ile yeni bir GPT bölümlendirme tablosu oluşturuyoruz.
Command (m for help): __g__
Created a new GPT disklabel (GUID: 7451D5A8-2DAE-453E-B3F5-D780A4957E8B).
n
komutu yeni bir bölüm (partition) oluşturmaya yarıyor. İlk
bölümümüz boot için kullanılacak. 512 MiB alan yeterli olacaktır.
Command (m for help): __n__
Partition number (1-128, default 1): __1__
First sector (2048-500118158, default 2048): __<enter>__
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-500118158, default 500117503): __+512M__
Created a new partition 1 of type 'Linux filesystem' and of size 512 MiB.
Önceki işletim sistemi kurulumundan vs. kalmış bölümler varsa şöyle bir soru sorabilir. Evet deyip geçiyoruz.
Partition #1 contains a vfat signature.
Do you want to remove the signature? [Y]es/[N]o: __y__
The signature will be removed by a write command.
Sistem dosyalarının barınacağı root (/
) bölümü için kullanılacak
ikinci bölümü oluşturuyoruz. Disk alanının %15’i gibi bir miktar
yeterli olacaktır.
Command (m for help): __n__
Partition number (2-128, default 2): __2__
First sector (1050624-500118158, default 1050624): __<enter>__
Last sector, +/-sectors or +/-size{K,M,G,T,P} (1050624-500118158, default 500117503): __+35G__
Created a new partition 2 of type 'Linux filesystem' and of size 35 GiB.
Partition #2 contains a crypto_LUKS signature.
Do you want to remove the signature? [Y]es/[N]o: __y__
The signature will be removed by a write command.
systemd-homed
ile kullanmak üzere ev (/home/
) dizinimiz olacak 3.
bölümümüzü oluşturuyoruz. Kalan tüm alan burada kullanılacak. Bu bölüm
root dizininden ayrı olacak ki systemd-homed
‘nin şifreli ev dizinleri
ile kullanacağımızdan üst üste iki defa şifreleme yapmasın.
Command (m for help): __n__
Partition number (3-128, default 3): __3__
First sector (74450944-500118158, default 74450944): __<enter>__
Last sector, +/-sectors or +/-size{K,M,G,T,P} (74450944-500118158, default 500117503): __<enter>__
Created a new partition 3 of type 'Linux filesystem' and of size 203 GiB.
Bölümlerimizi oluşturduk. Ancak hepsi “Linux filesystem” dosya sistemi
türüne
sahip. Bölümlerimize The Discoverable Partitions Specification
‘a uygun tür değerleri vererek systemd-gpt-auto-generator
‘un bu bölümleri sistemi boot ederken otomatik olarak keşfetmesini ve
mount etmesini sağlayabiliriz. Böylelikle /etc/fstab
ve
/etc/crypttab
entry’leri oluşturmamıza gerek kalmaz.
Command (m for help): __t__
Partition number (1-3, default 3): __1__
Partition type or alias (type L to list all): __1__
Changed type of partition 'Linux filesystem' to 'EFI System'.
Command (m for help): __t__
Partition number (1-3, default 3): __2__
Partition type or alias (type L to list all): __23__
Changed type of partition 'Linux filesystem' to 'Linux root (x86-64)'.
Command (m for help): __t__
Partition number (1-3, default 3): __3__
Partition type or alias (type L to list all): __42__
Changed type of partition 'Linux filesystem' to 'Linux home'.
p
komutu ile diskin son haline bir bakalım.
Command (m for help): __p__
Disk /dev/nvme0n1: 238.47 GiB, 256060514304 bytes, 500118192 sectors
Disk model: KINGSTON OM8SEP4256Q-AA
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 7451D5A8-2DAE-453E-B3F5-D780A4957E8B
Device Start End Sectors Size Type
/dev/nvme0n1p1 2048 1050623 1048576 512M EFI System
/dev/nvme0n1p2 1050624 74450943 73400320 35G Linux root (x86-64)
/dev/nvme0n1p3 74450944 500117503 425666560 203G Linux home
Filesystem/RAID signature on partition 1 will be wiped.
Filesystem/RAID signature on partition 2 will be wiped.
İyi görünüyor. Yaptığımız tüm işlemleri diske kaydetme zamanı.
Command (m for help): __w__
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
Disk şifreleme
Bölümlendirdiğimiz Linux root (x86-64)
partition’ını LUKS ile
şifreleyeceğiz.
TPM ile bu bölümü otomatik olarak açtıracağız ama hem geçici olarak, hem de Secure Boot’ta bir sorun olması durumunda diski açabilmek için bir parolaya ihtiyacımız var. Bu parolayı sürekli elle girmeyeceğimiz için rastgele bir tane oluşturup parola yöneticisinde saklamak iyi bir pratik olacaktır.
root@archiso ~ # cryptsetup luksFormat /dev/nvme0n1p2
WARNING!
========
This will overwrite data on /dev/nvme0n1p2 irrevocably.
Are you sure? (Type 'yes' in capital letters): __YES__
Enter passphrase for /dev/nvme0n1p2: __<parola>__
Verify passphrase: __<tekrar_parola>__
cryptsetup luksFormat /dev/nvme0n1p2 21.92s user 0.58s system 148% cpu 15.199 total
Şifrelediğimiz bölümü unlock eyliyoruz. cryptroot
yerine istediğiniz
ismi yazabilirsiniz.
root@archiso ~ # cryptsetup open /dev/nvme0n1p2 cryptroot
Enter passphrase for /dev/nvme0n1p2: __<parola>__
cryptsetup open /dev/nvme0n1p2 cryptroot 6.33s user 0.14s system 106% cpu 6.072 total
Disk biçimlendirme
EFI sistem bölümünün FAT32 formatında olması gerekiyor. Diğer bölümler Ext4, BTRFS ya da tercih ettiğiniz biçim neyse o olabilir.
Uyarı: BTRFS, henüz kullanacağımız systemd-homed programı ile çok iyi çalışmıyor.
root@archiso ~ # mkfs.fat -F 32 /dev/nvme0n1p1
root@archiso ~ # mkfs.btrfs /dev/mapper/cryptroot
root@archiso ~ # mkfs.btrfs /dev/nvme0n1p3
Dosya sistemlerini sırtlanıyoruz.
root@archiso ~ # mount /dev/mapper/cryptroot /mnt
root@archiso ~ # mkdir /mnt/efi
root@archiso ~ # mount /dev/nvme0n1p1 /mnt/efi
BTRFS için subvolume’ları oluşturuyoruz.
root@archiso ~ # btrfs subvolume create /mnt/home
Create subvolume '/mnt/home'
root@archiso ~ # btrfs subvolume create /mnt/var
Create subvolume '/mnt/var'
root@archiso ~ # btrfs subvolume create /mnt/swap
Create subvolume '/mnt/swap'
root@archiso ~ # btrfs subvolume create /mnt/.snapshots
Create subvolume '/mnt/.snapshots'
Kurulum
pacstrap
ile yeni kurulumumuza gerekli paketleri kuracağız. Ben
kullandığım tüm paketleri bu adımda yüklemeyi tercih ediyorum. Ama en
azından şu paketlerin kurulması gerekli:
# pacstrap /mnt linux base mkinitcpio btrfs-progs dosfstools tpm2-tss sbctl efibootmgr intel-ucode neovim
==> Creating install root at /mnt
==> Installing packages to /mnt
...
- linux: Çekirdek. linux-lts, linux-zen vs. de tercih edilebilir. Gerekliyse -ki muhtemelen öyledir- linux-firmware da kurun.
- base: systemd, glibc, bash gibi temel paketler.
- mkinitcpio: initramfs oluşturmamız için gerekli. dracut vs. de biraz ekstra uğraşla kullanılabiliyor ama ben mkinitcpio’yu genel olarak daha iyi buldum.
- btrfs-progs: bölümleri BTRFS olarak biçimlendirdiyseniz kurun. BTRFS disk bölümlerini yönetmeye yarıyor.
- dosfstools: FAT dosya sistemi biçimi için araçlar.
- tpm2-tss: Şifreli disk bölümümüzü otomatik olarak açmak için kullanacağımız systemd-cryptenroll için gerekli.
- sbctl: Secure Boot anahtarlarımızı oluşturmak ve UEFI’ye kaydetmek için kullanacağız.
- efibootmgr: UEFI sistemler GRUB ya da systemd-boot gibi bir bootloader’a ihtiyaç duymadan işletim sistemlerini yükleyebilirler. efibootmgr ile UEFI firmware’ımıza boot entry’leri ekleyeceğiz. Eğer bilgisayar kullanan maymunlar tarafından yazılmış bir UEFI firmware’ınız mevcutsa bu düzgün çalışmayabiliyor. Bu durumda systemd-boot kullanılabilir.
- intel-ucode: İşlemci için microcode güncellemeleri. AMD
işlemciniz varsa
amd-ucode
kurun. - neovim: Ayar dosyalarını düzenleyebilmek için favori metin editörünüz.
Yapılandırma
Yeni kurulmuş sistemimize chroot ile dalıyoruz.
root@archiso ~ # arch-chroot /mnt
[root@archiso /]#
[root@archiso /]# sed -i -e '/^#en_US.UTF-8/s/^#//' /etc/locale.gen
[root@archiso /]# locale-gen
Generating locales...
en_US.UTF-8... done
Generation complete.
[root@archiso /]# ln -sf /usr/share/zoneinfo/Turkey /etc/localtime
[root@archiso /]# echo 'LANG=en_US.UTF-8' > /etc/locale.conf
[root@archiso /]# echo 'KEYMAP=us' > /etc/vconsole.conf
[root@archiso /]# echo 'recreationalnuke' > /etc/hostname
Kurulumdan sonra ihtiyacınız olacak servisleri etkinleştirin.
systemd-homed
servisine ihtiyacımız olacak.
[root@archiso /]# systemctl enable systemd-homed systemd-timesyncd systemd-networkd systemd-resolved iwd bluetooth tor
root
kullanıcısı için bir parola belirlenmeli ki kapının önünde
kalmayalım.
[root@archiso /]# passwd
New password: __<parola>__
Retype new password: __<tekrar_parola>__
passwd: password updated successfully
Initramfs
Initramfs oluşturmak için Arch Linux geliştiricileri tarafından
geliştirilen mkinitcpio
programını kullanacağız.
Ben bir süre dracut
da kullanmıştım ancak daha karmaşık geldi ve
kernel güncellemelerinden sonra otomatik olarak initramfs ve unified
kernel image oluşturması için pacman hook’ları ayarlamak gerekiyorken
mkinitcpio
buna varsayılan olarak sahip.
/etc/mkinitcpio.conf
dosyasından initramfs imajımızda nelerin
bulunacağını ayarlayacağız. Bu dosyada sadece HOOKS
dizinini
düzenleyeceğiz. Hangi hook’un ne işe yaradığına
Arch Wiki’den
bakabilirsiniz.
[root@archiso /]# nvim /etc/mkinitcpio.conf
HOOKS=(systemd autodetect microcode modconf block keyboard sd-vconsole sd-encrypt filesystems)
Diskinizi Ext4 olarak biçimlendirdiyseniz dizinin sonuna fsck
hook’unu da ekleyin. BTRFS için bu gerekli değil. Nedenini öğrenmek
isterseniz cat $(which fsck.btrfs)
komutunun çıktısını okuyun.
Unified kernel image (UKI)
Initramfs preset dosyasını unified kernel image (UKI) oluşturmaya ayarlıyoruz. Unified kernel image, basitçe Linux çekirdeği, initramfs ve birkaç başka zımbırtının bir araya getirilmesiyle oluşturulan tek bir çalıştırılabilir (executable) dosyadır. Doğrudan UEFI firmware’ı aracılığıyla boot edilebilirler.
[root@archiso /]# nvim /etc/mkinitcpio.d/linux.preset
# mkinitcpio preset file for the 'linux' package
#ALL_config="/etc/mkinitcpio.conf"
ALL_kver="/boot/vmlinuz-linux"
PRESETS=('default' 'fallback')
#default_config="/etc/mkinitcpio.conf"
#default_image="/boot/initramfs-linux.img"
default_uki="efi/EFI/Linux/arch-linux.efi"
default_options="--splash=/usr/share/systemd/bootctl/splash-arch.bmp"
#fallback_config="/etc/mkinitcpio.conf"
#fallback_image="/boot/initramfs-linux-fallback.img"
fallback_uki="efi/EFI/Linux/arch-linux-fallback.efi"
fallback_options="-S autodetect"
Benim kullandığım preset bu şekilde. *_image
satırlarını fazladan
initramfs oluşmaması için yorum satırına çevirdim ve *_uki
satırlarını unified kernel image oluşturması için yorumdan çıkardım.
Şimdi unified kernel image’larımızı oluşturacağız. Yeniden unified
kernel image oluşturulması gereken durumlarda (çekirdeğin, sürücülerin
vs. sürüm güncellenmesi) mkinitcpio’nun pacman hook’ları bunu otomatik
yapıyor. Ayar dosyasını henüz güncellediğimiz için şu an bunu elle
yapacağız ya da pacman -S linux
komutunu çalıştırıp yine pacman’e
yaptıracağız. Mkinitcpio dosya oluşturamadığından /efi/EFI/Linux
yolunu da biz açacağız.
[root@archiso /]# mkdir --parents /efi/EFI/Linux
[root@archiso /]# mkinitcpio --allpresets
Unified kernel image’larımız oluştu, şimdi UEFI firmware’ından bunları boot etmesini rica edeceğiz. Bunu efibootmgr programı ile yapıyoruz.
UEFI boot entry’leri
Öncelikle mevcut boot entry’lerini listelemek için programı doğrudan çalıştıralım.
[root@archiso /]# efibootmgr
Muhtemelen Arch Linux canlı ISO imajı ve eski kurulumlardan kalma boot
entry’lerini göreceksiniz. Eski entry’leri efibootmgr --bootnum XXXX --delete-bootnum
komutu ile silebilirsiniz ama silmeyince de bir sorun
çıkmadı ve kendiliğinden silindi.
Şimdi de yeni boot entry’leri ekleyeceğiz. Burada dikkat etmeniz
gereken nokta --disk
flag’inin disk bölümüne değil diskin kendisine
işaret etmesi. Yani /dev/sda1
değil /dev/sda
olacak. --part
da
EFI system partition’ının bu diskin kaçıncı bölümünde olduğunu
belirtiyor. Bir diğer şey ise --loader
konumlarını belirtirken eğik
çizgi (/
) yerine DOS stili ters eğik çizgi (\
) kullanmak.
[root@archiso /]# efibootmgr --create --disk /dev/nvme0n1 --part 1 --label "ARCHLINUX" --loader '\EFI\Linux\arch-linux.efi' --unicode
[root@archiso /]# efibootmgr --create --disk /dev/nvme0n1 --part 1 --label "ARCHLINUX-FALLBACK" --loader '\EFI\Linux\arch-linux-fallback.efi' --unicode
Şu aşamada işimiz kalmadı. Yeni kurulumumuza boot edebiliriz.
[root@archiso /]# exit
# poweroff
Henüz TPM ile otomatik kilidini açmayı ayarlamadığımız için disk parolası isteyecektir. Sırada bunu ayarlamak var.
Secure Boot
sbctl ile anahtarlarımızı oluşturacağız ve bunları UEFI firmware’ına yükleyeceğiz. Sonrasında bu anahtarla unified kernel image’larımızı imzalayarak makinemizde boot edilmelerine izin vereceğiz.
Anahtarlarımızı oluşturalım.
# sbctl create-keys
Oluşan anahtarlarımızı yükleyelim. --microsoft
flag’i Microsoft’a ait
platform anahtarlarını (PK) silmeden kendi anahtarlarımızı yükler.
Cihazı tuğlaya çevirme riski olmaz ve cihazda Windows da
çalıştırabilirsiniz.
--microsoft
flag’i kullanılmadığında sbctl, TPM event log’una bakıp
cihazda option ROM‘un var
olup olmadığını anlamaya çalışır.
Eğer option ROM olmadığına kanaat getirirse UEFI firmware’ındaki tüm mevcut anahtarları silip yerine kendi anahtarlarımızı koyar. 2 farklı cihazda Microsoft anahtarlarını sildim ve bir sorun çıkmadı. Yine de risk size ait.
Eğer option ROM tespit eder ya da herhangi bir TPM event log’u
bulamayıp emin olamazsa uyarı verir. Microsoft’un anahtarlarını
cihazınızda tutarak glowie’lere arka kapı açmak istemiyorsanız ve
çatınızda da kırık kiremitler varsa --yes-this-might-brick-my-machine
flag’i ile kullanarak bunu görmezden gelebilirsiniz.
# sbctl enroll-keys --microsoft
Şimdi unified kernel image’larımızı kendi anahtarlarımızla
imzalayacağız. --save
flag’i yeni oluşacak UKI’ları otomatik olarak
imzalamaya yarıyor.
# sbctl sign --save /efi/EFI/Linux/arch-linux.efi
# sbctl sign --save /efi/EFI/Linux/arch-linux-fallback.efi
Bir sorun var mı doğrulayalım.
# sbctl verify
Bir sonraki adıma geçmeden önce sistemi yeniden başlatıyoruz ki PK, KEK ve db içeriklerini tutan PCR7 (Secure Boot State) register’ı güncellensin.
# reboot
LUKS anahtarını TPM’e kaydetme
Tekrardan parolamızı girerek diski açıyoruz ve bundan sonra eğer cihaza
dışarıdan bir müdahalede bulunulmadıysa root (/
) bölümümüzün TPM ile
otomatik olarak açılması için PCR7’ye atıyoruz.
# systemd-cryptenroll /dev/gpt-auto-root-luks --tpm2-device=auto
Yeniden başlatıp test edelim.
# reboot
Kullanıcı hesabı oluşturma
Son olarak bir kullanıcı hesabı oluşturacağız. Hatırlarsanız ev dizini
“Linux home” için türünde bir disk bölümü oluşturmuştuk ancak daha
buraya hiç dokunmadık. systemd, bu bölümü otomatik olarak algılayıp
/home/
dizinine mount etmeli. lsblk
ile bunu doğrulayabiliriz.
Ayrıca şunu da görüyoruz ki bu disk bölümü şifreli değil. Verilerimizi
asıl sakladığımız bölümün şifreli olmamasının nedeni
systemd-homed
‘nin kullanıcıların ev dizinlerini LUKS ile
her kullanıcı için ayrı şekilde kendi giriş parolalarıyla
şifreleyebilmesi.
Bu sayede bir kullanıcı ekrandan uzaklaşacağı ya da cihazı uyku moduna alacağı zaman ev dizininin şifreleme anahtarını geçici bellekten tamamen silebilir ve bir ekran kilidini devreye alabilir. Sonrasında ekran kilidi üzerinden parolasını girerek ya da parmak izini okutarak ev dizininin kilidini tekrardan açabilir.
# homectl create _username_ --storage=luks --fs-type=btrfs --member-of=wheel --disk-size=max
Uyarı
Yazıyı yazdığım tarihte systemd-homed, BTRFS ile pek iyi çalışmıyor.
Eğer giriş yaparken Operation on home failed: Not enough disk space for home
hatası alıyorsanız ve giriş yapamıyorsanız, LUKS için
discard’ı etkinleştirmeniz gerekiyor.
# homectl update _username_ --luks-discard=true
homectl
‘in manual sayfasında bunu etkinleştirmenin bazı sorunlara yol
açabileceği yazıyor ancak şu anda BTRFS ile yalnızca bu şekilde
çalışıyor. Ben şu ana kadar bir sorun yaşamadım.
UEFI yönetici parolası
Şu anda cihazdaki tüm veriler ya şifreli, ya da kendi anahtarlarımızla doğrulanıyor. Ancak UEFI için bir parola koyulmazsa bir saldırgan UEFI’a firmware ayarlarımıza erişip Secure Boot’u devre dışı bırakabilir, sonrasında da istediği sistemi boot ettirebilir. Bu parola genellikle 16 karakteri aşamıyor. Rastgele bir tane oluşturup parola yöneticisinde saklamak mantıklı olacaktır.