Disklessová pracovní stanice

Z DCEwiki
Skočit na navigaci Skočit na vyhledávání

Výsledný operační systém disklessové pracovní stanice je výsledkem sloučení několika vrstev do jednoho sendviče.

Specifika sendviče překrytého overlayem

Sendvič, sestavený z několika vrstev a překrytý zapisovatelnou vrstvou v RAM má svá specifika. Především si musíme si uvědomit, že je velmi důležité pořadí, v jakém se vrstvy sestaví do sendviče – poslední vítězí. Tzn. že pokud budete mít v nižší vrstvě adresář, který bude o vrstvu výše nahrazen symlinkem, bude pro sendvič rozhodující ten symlink a soubor na který bude odkazovat.

Tohle je velice důležité především z toho důvodu, že se ve stále větší míře linuxové distribuce přizpůsobují diktátu systemd, jehož cílem je odstranit původní unixovou hierarchii a splácat všechny knihovny a binární soubory do jednoho chlíva[1]. Z praktického hlediska to znamená, že původní adresáře pro binární soubory /bin, /sbin byly nahrazeny symlinky na své protějšky v adresáři /usr a adresáře knihoven /lib, /lib32, /lib64 a /libx32 stejně tak.

systemd

Rovněž spouštění systémových služeb již neprobíhá postupně (jak to dělal sysv-init), nýbrž paralelně na základě závislostí definovaných v unitách. Z praktického hlediska to znamená především fakt, že pokud zůstane systemd během zavádění "viset" na nějaké službě, tak to vůbec nemusí souviset s tím, co se vypsalo těsně předtím ať již v syslogu, nebo na monitoru.

U systemd se zapisují logy do žurnálu, k jehož prohlížení se používá samostatný nástroj journalctl.

overlay.service

Jak už bylo naznačeno výše, u disklessového sendviče má vždy prioritu vyšší vrstva. U sendviče překrytého overlayem ale můžeme narazit na další problémy. Některé mohly být důsledkem chyb, které již mouhou být u novějších verzí jádra opraveny (jako např. probublávání souborů do nejvyšší vrstvy). Jiné ve skutečnosti ani chybami nejsou.

Kupř. u laboratorního disklessu určitě nechcete…

  • aby se uživatelé hrabali v historii shellu,
  • aby kolaboval apt-get jen proto, že v některé nižší vrstvě zůstal zapomenutý zámek,
  • nebo aby se po síti honila zbytečná data, jako například staré logy.

Navíc může každá kombinace vrstev vyžadovat specifické zásahy, proto jsem si vytvořil overlay.service. Službu, která při startu prohledá obsah adresáře /etc/overlay.d, do kterého se u sestaveného sendviče zpropagují konfigurační soubory všech použitých vrstev, a na jejich základě potřebné operace zrealizuje.

Obsah unity overlay.service vypadá takto:

[Unit]
Description=Overlay touch
After=network.target auditd.service
Before=graphical.target lightdm.service

[Service]
Type=notify
ExecStart=/etc/systemd/scripts/overlay
Nice=5

[Install]
WantedBy=multi-user.target

Její aktivaci během spouštění systému zajistí symlink v adresáři /etc/systemd/system/multi-user.target.wants/overlay.service, který na ni bude odkazovat.

Obsah volaného skriptu /etc/systemd/scripts/overlay vypadá takto:

#!/bin/bash

OVERLAYDIR=${OVERLAY-/etc/overlay.d}

[ -d ${OVERLAYDIR} ] && \
  for i in $(ls -1 ${OVERLAYDIR})
    do
      cat "${OVERLAYDIR}/${i}" | while read line
        do
          AKCE=${line%% *}
          VZOREC=${line#* }
          PATTERN=${VZOREC##*/}
          case $AKCE in
            touch) find ${VZOREC%/*} \
              \( -type f -o -type l \) \
              -name "${PATTERN}" \
              -exec touch '{}' \;
              ;;
            notouch) find ${VZOREC%/*} \
              -type f ! -name "${PATTERN}" \
              -exec touch '{}' \;
              ;;
            remove) find ${VZOREC%/*} \
              \( -type f -o -type l \) \
              -name "${PATTERN}" -exec rm '{}' \;
              ;;
            noremove) find ${VZOREC%/*} \
              -type f ! -name "${PATTERN}" \
              -exec rm '{}' \;
              ;;
            truncate) find ${VZOREC%/*} \
              -type f -name "${PATTERN}" \
              -exec truncate --size=0 '{}' \;
              ;;
          esac
      done
  done

Adresář /etc/overlay.d v rámci jednotlivých vrstev pak obsahuje soubory s příponou .conf, ve kterých jsou řádky s pevně danou syntaxí.

Každá začíná názvem akce co se má realizovat, za kterou následuje absolutní cesta k souboru či adresáři, které se týká:

touch
Aplikuje na všechny soubory (nikoliv symlinky!) příkaz touch, čímž ho vytáhne ze sendviče do nejvyšší vrstvy, ve které s ním lze dále pracovat.
notouch
Aplikuje na předané cestě u všech souborů, které svým názvem nebudou odpovídat vzoru (poslední položka předané cesty) příkaz touch – tzn. že všechny budou vytaženy do nejvyšší (zapisovatelné) vrstvy sendviče.
remove
Podobně jako při akci touch, pouze s tím rozdílem, že budou soubory odstraněny.
noremove
Podobně jako při akci notouch, pouze s tím rozdílem, že soubory nebudou vytaženy do nejvyšší vrstvy, ale rovnou odstraněny.
truncate
Aplikuje na všechny soubory, které svým názvem odpovídají vzoru (poslední položka předané cesty) příkaz truncate – tzn. že budou vyprázdněny, a zároveň vytaženy do nejvyšší (zapisovatelné) vrstvy sendviče.
merge
Je relativně nová operace. Používá se, pokud potřebujeme obsah odkazovaného souboru/ů integrovat do jednoho souboru na nejvyšší úrovni.

rc-local.service

Jsou také situace, kde byste měli rádi, před zobrazením přihlašovacího dialogu měli poslední slovo. U systémů, které používaly sysv-init byl pro tento účel v adresáři /etc spustitelný(!) skript rc.local. Jehož obsah mohl vypadat kupř. takto:

#!/bin/sh -e
ntpdate ntp.felk.cvut.cz
mount /local
exit 0
Poznámka Ve výchozím stavu, v něm existoval pouze poslední řádek s příkazem exit 0 – v takovém případě po sputštění skript neudělá nic a jeho návratový kód 0 jenom oznámil, že jeho spuštění bylo úspěšné.

Pokud chcete tento skript používat i u disklessu, kde se služby spouští přes systemd, pak si musíte v adresáři /lib/systemd/system vytvořit unitu rc-local.service s následujícím obsahem:

[Unit]
Description=/etc/rc.local
ConditionPathExists=/etc/rc.local

[Service]
Type=forking
ExecStart=/etc/rc.local start
TimeoutSec=10
StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99

[Install]
WantedBy=multi-user.target

Pokud v adresáři /lib/systemd/system/ bude existovat adresář rc-local.service.d, může obsahovat další soubory s příponou .conf, ve kterých mohou být další konfigurační parametry. Např. soubor debian.conf s následujícím obsahem ovlivňuje kam se má posílat výstup ze spuštěno skriptu rc.local:

[Unit]
After=network-online.target

[Service]
StandardOutput=journal+console
StandardError=journal+console

Aktivaci unity při spouštění zajistí, podobně u té předchozí, symlink v adresáři /etc/systemd/system/multi-user.target.wants, který bude odkazovat na tuhle unitu. Např. /etc/systemd/system/rc-local.service, bude-li uložena zrovna tam.

Místo ní totiž může být v adresáři /etc symlink, který bude odkazovat na soubor v adresáři /lib/systemd/system/, kam se obvykle instalují pouze unity dodávané s instalačními balíky.

Lokální kešování

Pokud použijete u disklessu také lokální kešování, musíte počítat také s tím, že kromě výhod sebou přináší i jisté nevýhody.

/etc/fstab

Soubor /etc/fstab nemá žádný obsah, protože full-diskless ke své existenci lokální blokové zařízení nepotřebuje a připojení tmpfs na adresář /tmp je zbytečné, protože stejně všechno překrývá overlay, který už v paměti je.

Připojení tmpfs

U disklessového stroje který nemá overlay, se pracuje přímo s obsahem adresáře nasdíleného z NFS serveru – např. disklessové servery. V takovém případě je naopak vysoce žádoucí tmpfs na adresář /tmp připojit – bez toho by se dočasně vytvořené soubory zbytečně honily po síti sem a tam a zatěžovaly NFS server (zamykání, odemykání, rušení, …). V takovém případě se hodí do souboru /etc/fstab přidat následující řádek:

tmpfs           /tmp            tmpfs   nodev,nosuid    0       0

Do adresáře /tmp může zapisovat každý. Parametry nosuid a nodev zabra%nují jeho případnému zneužití. Pokud by do něj někdo nakopíroval upravenou aplikaci, která má nastaven tzv. suid bit, tak byl získal práva uživatele root. Parametr nodev pro změnu zabraňuje v tom, aby by si zde někdo vytvořil internetový soket, nebo jiné zařízení, přes které by mohl škodit. Bylo by možné použít ještě parametr noexec, který by způsobil, že by soubor nakopírovaný do tohoto adresáře nešel spustit, ale to už je možná v prostředí laboratorního disklessu příliš restriktivní, protože se stejně veškerý obsah RAM při restartu zahazuje.

Připojení lokálního diskového oddílu

Nicméně se za určitých okolností je připojení lokálního blokového zařízení potřeba. Kupř. u half-disklessových serverů, co startují kompletně z NFS, bez komunikace s DHCP je na virtuálním blokovém zařízení umístěn GRUB s linuxovým jádrem včetně ramdisku a pokud chceme, nebo potřebujeme udělat jeho aktualizaci, potřebujeme, aby byl jeho obsah dostupný.

Jsou to virtuály, do kterých se propaguje virtuální disk jako blokové zařízení /dev/sda. Protože firmware QEMU při zavádění nepočítá s UEFI, je zbytečné aby na něm byla GPT tabulka a víc než jeden diskový oddíl. Navíc jde o velmi malý virtuální disk, bohatě stačí max. velikost kolem 200MB, proto je na něm MS-DOS tabulka, s jedním primárním diskovým oddílem, formátovaným na ext4. GRUB se instaluje do MBR sektoru, a na jeho přečtení diskového oddílu mu stačí relativně malé moduly part_msdos a ext2.

LABEL=boot      /boot   ext4    noauto  0       0

Parametr noauto v tomto případě preventivně brání neúmyslnému poškození ramdisku. Pokud chceme hrabat na konfigurační soubor grub.cfg, nebo aktualizovat ramdisk, musíme si tento virtuální disk na adresář /boot připojit.

Poznámka Je lepší mountovat zařízení přes návěští souborového systému (LABEL) než přes cestu k blokovému zařízení, protože tím pádem nemusíme řešit další bloková zařízení ani jiné diskové oddíly.

V laboratořích Katedry kybernetiky se – na rozdíl od laboratoří Katedry řídící techniky – lokálně instalované MS Windows nepoužívají. Ale diskless SSD disky s nimiž byly stroje dodány využívá automaticky, pokud na nich najde swapovací oddíl.

Kromě toho se ale využívají také jako lokální úložiště pro velké soubory virtuálních strojů, s nimiž se pracuje přes VMWare. Proto /etc/fstab u laboratorního disklessu Katedry kybernetiky obsahuje následující záznam:

LABEL=local /local ext4 defaults,noauto,users 0 2

Pokud diskless, na lokálním disku stroje kde byl spuštěn, nalezne diskový oddíl formátovaný na ext4 s názvem 'local', tak ho má přihlášený uživatel možnost připojit. Aby se o to nesnažil automaticky je uvedena volba noauto – bez ní by totiž zůstal při zavádění systém viset v ramdisku, pokud by takový diskový oddíl na stroji při startu nenašel.

A bez volby users, by to mohl pro změnu udělat pouze uživatel root.

Přihlašování uživatelů

Základní rozdíl mezi disklessovými pracovními stanicemi katedry DCE (Katedra řídící techniky) a DC (Katedra kybernetiky) je ve způsobu ověřování uživatelů. Zatím co stroje DCE jsou opřené o ČVUT AD (které spravuje VIC), laboratorní stroje DC jsou opřeny o laboratorní LDAP server.

Ověřovací proces sestává z několika fází:

Získání UID

Během první fáze se systém pokusí na základě uživatelského jména získat UID uživatele.

Stará se o to nslcd démon, který při tom postupuje podle nastavení v souboru /etc/nsswitch.conf:

passwd: compat ldap systemd
group: compat ldap systemd

To říká, že nejprve se má podívat do lokálního souboru /etc/passwd (resp. /etc/groups), a teprve pokud v něm uživatelské jméno (skupinu) nenajde, má zkusit ldap.

Poznámka Pokud za řetězcem ldap následuje řetězec systemd, pak to znamená, že kdyby se náhodou uživatel nenašel ani v databázi LDAPu, tak se má použít modul nss-systemd, který ho – pokud to má některá unita přes parametr DynamicUser= nastaveno – dynamicky vytvoří. Řetězec systemd tedy není nezbytně nutný (proto je uveden kurzívou) a pokud je uveden, tak by měl být vždy jako poslední možnost na konci řádku.

Lokální uživatelé

U disklessových strojů s overlayem je doporučeno mít k dispozici minimálně dva lokální uživatele:

root
Lokální administrátor. Změny v jeho domovském adresáři /root se ukládají pouze na tmpfs v RAM, tzn. že se při restartu zahodí. Zůstane jen to co je v podkladové vrstvě – ssh klíče a soubor authorized_keys s naimportovaným veřejným klíčem, aby bylo možné mezi stanicemi procházet přes SSH. Pozor na sudo! I když je to pouze lokální administrátor, jehož UID je na NFS serveru squashovaný, není žádoucí, aby se na něj mohl dostat každý uživatel.
guest
Je lokální uživatel, s jednoduchým heslem a zcela prázdným domovským adresářem, který je mimo standardní adresář /home. Používá se pouze k dočasnému přihlášení a veškeré změny jsou uloženy pouze v paměti a tudíž se po restartu zahodí.
guest00 – guest??
Kromě výše uvedených uživatelů lze použít také lokální uživatelé guest00 až guest?? (otazníky zastupují čísla, záleží totiž na tom, kolik je potřeba účtů). Od uživatele guest se tyto účty liší tím, že se jejich domovský adresář mountuje z NFS serveru – stejně jako domovské adresáře uživatelů ověřených přes LDAP či AD.
Využívají se pouze při různých vícedenních kurzech, pro uživatele co nemají řádný účet ČVUT a potřebují aby jim vytvořené soubory zůstaly zachovány i po restartu pro další dny. Tyto uživatelské účty jsou nevhodné, pokud potřebujete zpracovávat citlivá data – např. přistupovat na svůj účet v bance atp. – v takovém případě použijte raději uživatele guest, u kterého je jistota, že se veškerá data při restartu zahodí.
Tyto adresáře se také čas od času z NFS serveru odstraňují.

Uživatelé z LDAPu (AD)

Jednoduché ověření, zda-li je uživatel znám, lze při nakonfigurovaném LDAPu provést pomocí příkazu id:

# id neznamy
id: 'neznamy': no such user
# id guest
uid=1000(guest) gid=1000(guest) groups=1000(guest)
# id znamyuser
uid=32911(znamyuser) gid=32911(znamyuser) groups=1000(guest),1003(stud),32911(znamyuser)

Pokud se při ověření uživatele 'znamyuser' objeví stejná chybová z práva jako v případě id 'neznamy', pak to znamená, že:

  • buď není v LDAPu
  • nebo není LDAP správně nakonfigurován
  • nebo z nějakého důvodu přístup na LDAP nefunguje

Nastavení LDAPu na DC

Je třeba nainstalovat instalační balík nslcd a buď v dialogu při instalaci, nebo následně v souboru /etc/nslcd.conf nastavit výchozí URL k LDAP serveru:

uri ldap://<ldap>.felk.cvut.cz

a výchozí bázi, aby se UID vyhledávalo ve správném kontextu:

base dc=<ldap>,dc=felk,dc=cvut,dc=c

Všechny ostatní volby lze zakomentovat. S výjimkou jediné:

tls_reqcert never
Poznámka Místo řetězce <ldap> se uvádí hostname LDAP serveru, vůči kterému je stroj opřený

Nastavení ČVUT AD na DCE

Active Directory (AD) je implementace LDAP serveru od fy. Microsoft. Nastavuje se tudíž obdobně jako LDAP na DC. Zásadní rozdíl je ale v použitém schématu.

Zatím co LDAP server na DC používá jednoduché schéma, které nabízí UID uživatele prakticky hned na první úrovni (jako hodnotu atributu … ). Je schéma ČVUT AD komplikované. Proto je komplikovaný i konfigurační soubor /etc/nslcd.conf (místo názvu domény AD je uveden řetězec <ad>):

uid nslcd
gid nslcd
uri ldaps://<ad>.cvut.cz
base ou=IDM,dc=<ad>,dc=cvut,dc=cz
binddn <agent>@cvut.cz
bindpw <heslo>
filter passwd (&(objectClass=user)(uidNumber=*))
map passwd gidNumber "10000"
map passwd homeDirectory "${homeDirectory:-/home/$uid}"
map passwd loginShell "${loginShell:-/bin/bash}"
# SSL options
ssl on
tls_reqcert never
tls_cacertfile /etc/ssl/certs/ca-certificates.crt
scope sub

Je to dáno tím, že ČVUT AD (které spravuje VIC) zahrnuje veškeré uživatele a organizační složky ČVUT a navíc bylo primárně vytvořeno k ověřování strojů s OS MS Windows. Proto je připojení na server ms.cvut.cz šifrované přes SSL (Volba ssl on a ldaps:// v uri), a vyhrazené pouze pro agenta, jehož uživatelské jméno <agent>@cvut.cz a heslo <heslo> musí být součástí tohoto konfiguračního souboru.

Kromě toho se využívá pro ověření komunikace ještě řetězec certifikátů v souboru /etc/ssl/certs/ca-certificates.crt

Ověření uživatele

Upozornění U disklessového linuxu trvá nejdéle získat uživatelský UID – obzvláště při ověřování přes AD, kdy se pokaždé načítá a prohledává plný seznam uživatelský jmen, což znamená několik tisíc položek. Bohužel použité schéma nedovoluje použít efektivní dotaz, který by vracel pouze jednu položku.

Samotné ověření už proběhne relativně rychle.

Po úspěšném ověření se postupně volají PAM moduly, na základě konfiguračních souborů v adresáři /etc/pam.d. Ty by se nikdy neměly editovat přímo, protože se generují na základě konfiguračních souborů v adresáři /usr/share/pam-configs pomocí utility pam-auth-update.

Tyhle konfigurační soubory se instalují zároveň s příslušnými PAM moduly a v podstatě až na pár výjimek je můžeme nechat na pokoji.

ČVUT AD i laboratorní LDAP DC používá k ověření uživatelského hesla kerberos (Konfigurační soubor pro PAM krb5 nainstaluje balík libpam-krb5). Tomu se přes konfigurační soubor /etc/krb5.conf nastavuje, koho a s jakými parametry se má zeptat, zda-li je udané heslo pro příslušné UID platné.

Pozn.: Místo doménového jména LDAP serveru je v konfiguraci uveden řetězec <ldap>:

[libdefaults]
        default_realm = <LDAP>.FELK.CVUT.CZ
        dns_lookup_realm = false
        dns_lookup_kdc = false
        forwardable = true
        proxiable = true
        allow_weak_crypto = true
        rdns = false

[realms]
        <LDAP>.FELK.CVUT.CZ = {
                kdc = <ldap>.felk.cvut.cz
                admin_server = <ldap>.felk.cvut.cz
                default_domain = felk.cvut.cz
        }

[domain_realm]
        <ldap>.felk.cvut.cz = <LDAP>.FELK.CVUT.CZ

[login]
        krb4_convert = true
        krb4_get_tickets = false

Pro AD vypadá takto (místo názvu domény AD je uveden řetězec <ad> a místo <server.ad> patří doménové jméno serveru, který dělá ověření):

[libdefaults]
        default_realm = <AD>.CVUT.CZ
        dns_lookup_realm = false
        dns_lookup_kdc = false
        forwardable = true
        proxiable = true
        allow_weak_crypto = true
        rdns = false

[realms]
        <AD>.CVUT.CZ = {
                default_domain = <ad>.cvut.cz
                kdc = <ad>.cvut.cz
                admin_server = <server.ad>.cvut.cz
                kpasswd_server = <server.ad>.cvut.cz
        }

[domain_realm]
        <ad>.cvut.cz = <AD>.CVUT.CZ

[login]
        krb4_convert = true
        krb4_get_tickets = false

Session

Klíčovou výjimkou je konfigurační soubor pam_script.

Původní obsah souboru:

Name: Support for authentication by external scripts
Default: yes
Priority: 257
Auth-Type: Primary
Auth:
       sufficient                      pam_script.so
Account-Type: Primary
Account:
       sufficient                      pam_script.so
Password-Type: Primary
Password:
       sufficient                      pam_script.so
Session-Type: Additional
Session:
       optional                        pam_script.so

Nahradíme tímto:

Name: Support for authentication by external scripts
Default: yes
Priority: 10
Session-Interactive-Only: yes
Session-Type: Additional
Session:
       optional                        pam_script.so dir=/etc/pam-scripts

Prakticky vše, s výjimkou posledních třech řádků můžeme s klidnou duší vyhodit, protože chceme skripty z adresáře /etc/pam-scripts volat pouze při zahájení a ukončení interaktivní session. Důležitá je také priorita. Volané skripty totiž provádějí operace, které musí proběhnout ihned poté, co dojde k úspěšnému ověření uživatele.

Menu

Upozornění Položky menu by měly být vždy součástí vrstvy, ve které se nachází aplikace, která se přes ně má spouštět!
/usr/local/share/application
/usr/share/applications
/usr/share/icons

Adresář /usr/share/menu

~/.config/menus/xfce-applications.menu

Odkud se berou položky v menu?

$ env | grep XDG_CONFIG_DIRS

Soubor /usr/local/share/applications/mimeinfo.cache obsahuje…

[MIME Cache]
application/mathematica=wolfram-mathematica8.desktop;
…

Vytvořit nějaký skript, který by sloučil existující soubory mimeinfo.cache do jednoho. Viz ten modul pro systemd?

Kontejnerová virtualizace

  1. Původně se na kořenové úrovni nacházely pouze systémové aplikace, nezbytné k řešení problémů, co mohly nastat během mountování dalších adresářů.
    Vyžadovaly to především tehdejší technologické možnosti. Disky byly drahé a měly relativně malou kapacitu. Pro vytvoření dostatečně velkého datového úložiště bylo nutné kombinovat další technologie a pokud došlo k fyzickému selhání disku, bylo nutné situaci vyřešit ještě před startem do multiuživatelského módu.
    Rizkové bylo také zaplnění souborového systému. Z toho důvodu se systémový disk rozděloval na vícero samostatně mountovaných diskových oddílů, aby se tak předešlo kolapsu celého systému a takový problém bylo možné vyřešit vzdáleně.
    S rostoucí diskovou kapacitou a přechodem na moderní souborové systémy jako je např. Btrfs, které umožňuje omezit kapacitu subvolume pomocí nastavené kvóty, se stalo rozdělování systému na vícero samostatně mountovaných diskových oddílů přežitkem.
    Navíc za tu dobu vzrostla i dostupná kapacita RAM, takže bylo možné nástroje nezbytné k řešení krizové situace přesunout do ramdisku.