Sebastian Frankowski
Santander Bank Polska
Sebastian FrankowskiDev Engineer @ Santander Bank Polska

Raspberry Pi a zabezpieczenie systemu plików

Sprawdź, jak rozwiązać problem zabezpieczeń systemu plików przy pracy z Raspberry Pi.
11.01.20216 min
Raspberry Pi a zabezpieczenie systemu plików

Raspberry Pi oraz platformy mu podobne często korzystają z kart pamięci jako głównego nośnika dla systemu operacyjnego. Jest to rozwiązanie, które posiada wiele zalet, jak chociażby niski koszt, dopasowanie nośnika do potrzeb (prędkość/pojemność) czy też możliwość łatwej podmiany karty w celu uruchomienia innego systemu na tym samym urządzeniu. 

Nie jest to rozwiązanie pozbawione wad, a jedną z bardziej dokuczliwych, z którą przyszło mi się zetknąć już niejednokrotnie, jest wysoka podatność na uszkodzenie systemu plików np. podczas utraty zasilania przez urządzenie w trakcie dokonywania operacji zapisu.

Jako iż problem wystąpił kilkakrotnie na przestrzeni dłuższego czasu, postanowiłem poszukać na to jakiegoś remedium. Pierwszą opcją było cykliczne robienie dumpa karty na PC, tak, aby w razie wystąpienia problemu, móc szybko przywrócić malinkę do życia, jednak regularne robienie takiego zrzutu, poza oczywistą upierdliwością, powodowała, iż taka "odbudowa" systemu była obarczona utratą zmian z okresu od ostatniego dumpa.

Szukając innego rozwiązania, wpadłem na pomysł, aby rozwiązać problem na warstwie sprzętu. Najpierw pomyślałem o bootowaniu z dysku na USB, jednak w tamtym okresie, aby tego dokonać, nadal trzeba było mieć kartę SD, która służyła jako starter. Zatem szukając dalej, zwróciłem się o pomoc do pamięci RAM :)

Podstawowym problemem był fakt dokonywania operacji zapisu na systemie plików podczas gdy zanikało zasilanie. Najprościej więc będzie pozbyć się lub ograniczyć operacje zapisu na karcie SD (co też wydłuży jej życie z uwagi na limity zapisu związane z technologią, w jakiej karty SD są tworzone).

Sposobów na to jest kilka. Tutaj opiszę jeden z nich i powiem parę słów o dostępnych alternatywach. Pragnę też podkreślić, iż całość tego poradnika jest tak naprawdę moim opracowaniem, które powstało na bazie doświadczenia wynikającego z kilku wpisów o podobnej tematyce na przestrzeni czasu, podczas którego starałem się dostosować ich treść do mojego przypadku.

 Koncept

Na początek koncept. Możemy co prawda całkowicie wyeliminować zapis na kartę SD, jednak w zależności od zastosowania naszego urządzenia, możemy czasem potrzebować dokonania jakichś zmian na systemie, dlatego też postanowiłem:

  • Montować system plików w trybie read-only 
  • Mniej istotne elementy, w których dokonywany jest zapis, zmapować do tempa (RAM) 
  • Przy bardziej istotnych operacjach przemontowywać system plików w tryb write, dokonać operacji i ponownie przemontować na read-only 


Takie podejście znacząco zniweluje prawdopodobieństwo wystąpienia awarii systemu plików, gdyż operacje zapisu będą zdarzać się niezmiernie rzadko.

 Konfiguracja

Przejdźmy do mięska na przykładzie raspbiana na RPi.

1. W pierwszej kolejności najlepiej zrobić update wszystkich dostępnych pakietów (a nawet i kernela, ale to już pomijam. Każdy, kto będzie chciał tego dokonać, zapewne znajdzie potrzebne materiały w sieci). 

apt-get update; apt-get upgrade 
reboot


2. Teraz pozbądźmy się niechcianych pakietów, mogących stwarzać problem poprzez jakieś regularne akcje zapisu, które trzeba by osobno jeszcze dokonfigurować i obudować, by nie stwarzały problemu. Trzeba mieć na uwadze, iż w jakimś konkretnym zastosowaniu mogą być potrzebne, dlatego też jeśli trzeba by je zostawić, to należy je dokładniej przeanalizować i spróbować uodpornić na system plików tylko do odczytu. 

apt-get remove --purge wolfram-engine triggerhappy dphys-swapfile dbus 
apt-get autoremove --purge


3. Przyszła pora na wyłączenie SWAP-a, aktywację fastboota i poinformowanie systemu podczas wstawaniu o pracy w ReadOnly. 


W /boot/cmdline.txt dodajemy na końcu

fastboot noswap ro


4. Kolejnym krokiem będzie zmiana pliku fstab tak, by system plików był read-only oraz ustawienie tymczasowego systemu plików na pamięć RAM. W /etc/fstab:

proc            /proc           proc    defaults          0       0
PARTUUID=6cebe3ce-01  /boot           vfat    defaults,ro          0       2
PARTUUID=6cebe3ce-02  /               ext4    defaults,noatime,ro  0       1
tmpfs           /tmp            tmpfs   nosuid,nodev         0       0
tmpfs           /var/log        tmpfs   nosuid,nodev         0       0
tmpfs           /var/tmp        tmpfs   nosuid,nodev         0       0 


5. Skoro mamy już przygotowany system plików, warto teraz poprzepinać istotne foldery, aby pracowały na pamięci RAM. 

rm -rf /var/lib/dhcp/ /var/lib/dhcpcd5 /var/run /var/spool /var/lock /etc/resolv.conf
ln -s /tmp /var/lib/dhcp
ln -s /tmp /var/lib/dhcpcd5
ln -s /tmp /var/run
ln -s /tmp /var/spool
ln -s /tmp /var/lock
rm -rf /var/lib/systemd/timesync 
ln -s /tmp /var/lib/systemd/timesync
rm -rf /var/lib/ntp
ln -s /tmp /var/lib/ntp
touch /tmp/dhcpcd.resolv.conf; ln -s /tmp/dhcpcd.resolv.conf /etc/resolv.conf


6. Do tego dochodzi kilka zmian, które są zależne od dystrybucji Raspbiana.

I. Zmiana lokacji pliku PID DHCP


W /etc/systemd/system/dhcpcd konieczna jest zmiana z:

PIDFile=/run/dhcpcd.pid


Na:

PIDFile=/var/run/dhcpcd.pid


II. Przeniesienie random-seeda do lokacji z zapisem 

rm /var/lib/systemd/random-seed 
ln -s /tmp/random-seed /var/lib/systemd/random-seed 

W pliku /lib/systemd/system/systemd-random-seed.service dodanie wpisu w sekcji [Service]

ExecStartPre=/bin/echo "" > /tmp/random-seed 
systemctl daemon-reload


7. Następnym etapem będzie dokonanie zmian mających na celu utrzymanie poprawnej daty i godziny w systemie

apt-get install ntp ntpdate 


W pliku /etc/cron.hourly/fake-hwclock:

#!/bin/sh 
#
# Simple cron script - save the current clock periodically in case of
# a power failure or other crash
if (command -v fake-hwclock >/dev/null 2>&1) ; then
    mount -o remount,rw /
    fake-hwclock save
    mount -o remount,ro /
fi


W pliku /etc/ntp.conf konieczna jest zmiana z

driftfile /var/lib/ntp/ntp.drift


Na

driftfile /var/tmp/ntp.drift


8. Na koniec pozostało już tylko dokonać rebootu maszyny i mieć nadzieję, iż wszystko poszło po naszej myśli :) 

reboot 


Na tym można by skończyć, jeśli chodzi o podstawową konfigurację, ale oczywiście trzeba sobie usprawniać życie, dlatego poniżej dorzucam jeszcze tipsy.

Tips

1. Ręczna zmiana trybu pracy z read-only na write i vice-versa. 

W /etc/bash.bashrc:

set_bash_prompt() {
    fs_mode=$(mount | sed -n -e "s/^\/dev\/.* on \/ .*(\(r[w|o]\).*/\1/p")
    PS1='\[\033[01;32m\]\u@\h${fs_mode:+($fs_mode)}\[\033[00m\]:\[\033[01;34m\]\w\ 
    [\033[00m\]\$ '
}
alias ro='sudo mount -o remount,ro / ; sudo mount -o remount,ro /boot'
alias rw='sudo mount -o remount,rw / ; sudo mount -o remount,rw /boot'
PROMPT_COMMAND=set_bash_prompt


2. Automatyczne zapisywanie historii basha podczas wylogowania. 

W /etc/bash.bash_logout:

mount -o remount,ro / 
mount -o remount,ro /boot


3. W przypadku problemów z datą proponuję najpierw spróbować zaktualizować ntp przy użyciu polecenia: 

ntpdate -u pool.ntp.org


Jeśli to nie pomoże, to zapoznać się z wpisem na StackExchange, który to opisuje, jak można sobie z tym poradzić poprzez wykorzystanie prywatnego tempa.

4. Problem ze startem DHCP, który można zaobserwować w logach startowych systemu, da się rozwiązać poprzez zmianę lokalizacji pliku PID DHCP. 

sudo ln -s /tmp /run-dhcpcd 


A w pliku /etc/systemd/system/dhcpcd5.service zamiana linijki z PIDFile na:

PIDFile=/run-dhcpcd/dhcpcd.pid 


Teraz tak naprawdę nasz Raspbian bardzo się uodpornił na zaniki prądu. Dzięki powyższym zabiegom nasz system plików od niemalże startu urządzenia do jego wyłączenia jest bezpieczny. A jeśli zechcemy dokonać w nim jakichś zmian, wystarczy przełączyć się w tryb zapisu, a po ich dokonaniu z powrotem w tryb bezpieczny.

Alternatywy

Na koniec chciałbym wspomnieć o kilku alternatywach. Log2Ram - aplikacja/skrypt umożliwiająca w szybki i prosty sposób ustawić folder logów, aby działał w pamięci operacyjnej. Zainteresowanych odsyłam do GitHuba. 

HDD/SSD na USB - RPi 4 pozwala już na pracę z dyskami poprzez USB bez konieczności posiadania karty SD. Natomiast w starszych modelach potrzebna jest karta, aby zainicjować sam mechanizm rozruchu, który potem będzie przekierowany na dysk z USB.

RamDisk - zamiast przestawiać kartę SD w tryb odczytu, możemy pokusić się o "zasłonięcie" faktycznych części systemu ramdyskiem, gdzie podczas startu skopiujemy oryginalne dane na ramdysk, a następnie zasłonimy nim oryginalną lokalizację. Rozwiązanie to możemy stosować punktowo albo przy odpowiedniej ilości pamięci, możemy tak zasłonić znacznie większe obszary systemu. 

Jednak trzeba liczyć się z tym, iż stosowanie takiego rozwiązania może wpłynąć na czas startowania systemu przez kopiowanie danych z karty do pamięci oraz wykorzysta pamięć RAM, która w tego typu urządzeniach często jest dosyć ograniczona.

Rozruch z sieci - tutaj nie mam doświadczenia, zatem nie będę się wymądrzał. Wiem, że się da przy wykorzystaniu PXE na RPi 3+ (wcześniejsze nie mają wsparcia na SoC).

<p>Loading...</p>