Mountování uživatelských adresářů v prostředí diskless overlay

From DCEwiki
Jump to: navigation, search

Původně bylo připojení uživatelských adresářů realizováno tím nejjednodušším možným způsobem - připojením celého adresáře s domovskými adresáři. To sebou ovšem přinášelo rizika a problémy:

  • zdlouhavé vylistování adresáře /home na klientské stanici
  • potencionální možnost vykradení domovského adresáře jiným uživatelem

Nyní to funguje takto:

  1. Uživatel se na klientské stanici ověří a PAM spustí skript, který založí domovský adresář uživatele jako tzv. mountpoint a pak se do něj pokusí namountovat vzdálený domovský adresář uživatele.
  2. Pokud se mu to nepodaří, tak s největší pravděpodobností proto, že tento domovský adresář na vzdáleném NFS serveru zatím neexistuje. Proto se skript k tomuto NFS serveru přihlásí přes ssh na uživatele nfshomecreator. Proces login ovšem u tohoto uživatele nespouští shell, jako by tomu bylo obvyklé u běžných uživatelů, ale skript. Ten zpracuje parametry předané přes ssh klienta a na jejich základě ve sdíleném adresáři příslušný domovský adresář založí.
  3. Skript na bezdiskové stanici se potom pokusí zopakovat připojení domovského adresáře.
  4. Pokud se mu to ani potom nepodaří, přihlášení normálně pokračuje, pouze s tím rozdílem, že je domovský adresář uživatele součástí překrytého disku, který je pouze v paměti klientské stanice. Tudíž po restartu zase nenávratně zmizí! Z tohoto důvodu PAM skript v takovém případě vygeneruje soubor s upozorněním, že jde pouze o dočasný adresář.

Ačkoliv jde v zásadě o velmi jednoduché řešení, vyžaduje koordinaci skriptu a konfigurace bezdiskové stanice s nastavením na NFS serveru. Z tohoto hlediska je velmi výhodné, jsou-li obě strany spravovány přes Puppet

Založení uživatele nfshomecreator na straně NFS serveru[edit]

Pokud postupujeme manuálně, tak uživatele nfshomecreator založíme následující sekvencí příkazů:

Poznámka
NFS (DATASERVER) :~# adduser --system --home /etc/pam-scripts --shell /etc/pam-scripts/createhome.sh --ingroup nogroup nfshomecreator
NFS (DATASERVER) :~# addgroup nfshomecreator users
NFS (DATASERVER) :~# passwd nfshomecreator
...

Založení uživatele nfshomecreator přes puppet

Poznámka
	user { 'nfshomecreator':
		ensure => present,
		uid => 90,
		gid => 'nogroup',
		groups => 'users',
		home => '/etc/pam-scripts',
		managehome => true,
		shell => '/etc/pam-scripts/createhome.sh',
		password => '$7$MxShiP62$tWawoL7u39iwUi9fEQWe5JDgGW9eBHp2T94QR4dmHCckQpeAxD4SilExyZ2v1jfYa9qbtLo/ztW8KvnAzTxC./',
		}
	}

Poznámky

  • Pokud je kód pro založení uživatele nfshomecreator součástí univerzálního modulu pro zakládání uživatelů, je vhodné ho umístit do podmínky, tak aby se vytvořil pouze na stroji k tomu určeném
  • Ač by se nastavení hesla (v kódu puppetu parametr password) z hlediska fungování mohl jevit zbytečný, protože se klient vůči serveru autorizuje klíčem, ssh server ho vyžaduje. Pokud může jako NFS server fungovat více strojů, tak nezáleží jaké heslo tento uživatel na nich má, ale musí ho mít.

Skript createhome.sh uživatele nfshomecreator[edit]

V parametrem atributu shell je místo obvyklého shellu cesta k shellovému skriptu, který se stará o vlastní vytvoření adresáře. Tento skript je umístěn v domovském adresáři uživatele nfshomecreator a má následující obsah:

Poznámka
#!/bin/bash

TEMPORARY="$2"
NFSUSER="${TEMPORARY%%\ *}"
NFSDIR="${TEMPORARY#$NFSUSER\ }"

if [ -d "$NFSDIR" ]; then
    if [ "$(grep "^$NFSDIR[[:blank:]]" /etc/exports)" != "" ]; then
        if [ ! -d "$NFSDIR/$NFSUSER" ]; then
            mkdir "$NFSDIR/$NFSUSER"
            chmod -c 775 "$NFSDIR/$NFSUSER"
            chgrp -c users "$NFSDIR/$NFSUSER"
        fi
    fi
fi

Jeho volání z disklessové stanice pak vypadá takto:

Poznámka
stroj (diskless) :~# ssh nfshomecreator@NFS newusername /path_to_directory_with_homes

Skript převezme parametry od ssh klienta:

newusername 
Uživatelské jméno pro příslušný domovský adresář
/path_to_directory_with_homes 
Cesta do adresáře s domovskými adresáři

Aby to fungovalo, musí být adresář /path_to_directory_with_homes nasdílený přes NFS, patřit uživateli root a být ve skupině nogroup (stejné jakou má uživatel nfshomecreator). Pro každého jiného uživatele musí mít nastaveno pouze právo spouštění - bez toho by se totiž, po namountování adresáře na disklessové stanici, do něj uživatel nedostal.

Poznámka
NFS (DATASERVER) :~# chown root.nogroup /path_to_directory_with_homes
NFS (DATASERVER) :~# chmod 731 /path_to_directory_with_homes

Puppet - modul nfs[edit]

V případě tohoto skriptu je opět vhodné využít puppet, a vytvořit pro NFS modul, tak aby nebylo nutné skript, ani soubor /etc/exports kopírovat a příslušná práva řešit ručně. Oceníte to obzvláště v situaci, kdy jako NFS server může fungovat více strojů.

Poznámka
class nfs (
    $type = client,
    )   {
    case $type {
        'server': {
            package {'nfs-kernel-server':
                ensure => present,
            }
            case $hostname {
                'nfs1', 'nfs2', 'nfs3' : {
                    exec {"exportfs":
                        command => "/usr/sbin/exportfs -r",
                        refreshonly => true,
                        require => Package['nfs-kernel-server'],
                    }
                    file {"/etc/exports":
                        ensure => present,
                        owner => root,
                        group => root,
                        mode => 644,
                        source => "puppet:///modules/nfs/exports.source",
                        notify => Exec['exportfs'],
                    }
                    # Vytvoření adresářové struktury uživatele nfshomecreator
                    file {["/etc/pam-scripts", "/etc/pam-scripts/.ssh"]:
                        ensure => directory,
                        owner => nfshomecreator,
                        group => nogroup,
                        mode => 110,
                    }
                    # Nakopírování veřejného klíče uživatele root z disklessu
                    file {"/etc/pam-scripts/.ssh/authorized_keys":
                        ensure => present,
                        owner => nfshomecreator,
                        group => nogroup,
                        mode => 640,
                        source => "puppet:///modules/nfs/nfshomecreator.key",
                        require => File["/etc/pam-scripts/.ssh"],
                    }
                    # Nakopírování skriptu pro založení domovského adresáře
                    file {"/etc/pam-scripts/createhome.sh":
                        ensure => present,
                        owner => nfshomecreator,
                        group => root,
                        mode => 500,
                        source => "puppet:///modules/nfs/createhome.source",
                        require => File["/etc/pam-scripts"],
                    }
                }
            }
        }
        'client': {
            notify {"Instaluji nfs-common": }
            package {'nfs-common':
                ensure => present,
            }
        }
        default: {
            notify {"Modul pro NFS nemá nakonfigurován žádný typ $type": }
        }
    }
}

Součástí modulu v adresáři ./files jsou tyto soubory:

exports.source 
seznam adresářů publikovaných přes NFS
createhome.source 
skript pro zakládání adresářů
nfshomecreator.key 
veřejný ssh klíč uživatele root z disklessu
Poznámka Adresář /path_to_directory_with_homes musí mít v souboru /etc/exports nastaven atribut root_squash, který zabraňuje jeho namountování.

Proces připojení a odpojení NFS adresáře na straně klienta[edit]

Nastavení pam-scripts[edit]

Proces připojení a odpojení NFS adresáře se realizuje pomocí tzv. PAM skriptů.

Jsou to skripty, které PAM volá po úspěšné autorizaci, když zakládá session a při jejím ukončení. Využívá k tomu knihovnu pam_scripts.so, která je součástí instalačního balíku libpam-script

Názvy volaných skriptů jsou pevně dané. Nás zajímají v podstatě pouze skrity, které se volají při založení a ukončení session.

pam_script_ses_open 
se volá při založení session uživatele, které je podmíněno jeho úspěšným ověřením.
pam_script_ses_close 
se zavolá při jejím ukončení

Nastavení PAM souborů se v Debianu nedělá přímou editací, i když by to bylo možné, ale příkazem pam-auth-update, který zpracovává konfigurační soubory umístěné v adresáři /usr/share/pam-configs.

To tohoto místa je třeba umístit soubor s názvem, který odpovídá názvu modulu s následujícím obsahem:

stroj (diskless) :~# cat /usr/share/pam-configs/scripts 
Name: Session Script Management
Default: yes
Priority: 10
Session-Interactive-Only: yes
Session-Type: Additional
Session-Final:
        optional                        pam_script.so dir=/etc/pam-scripts
stroj (diskless) :~# pam-auth-update

Příkaz pam-auth-update provede nastavení PAM souborů v adresáři /etc/pam.d a v souboru /etc/pam.d/common-session se objeví následující řádek:

session	optional	pam_script.so dir=/etc/pam-scripts
Poznámka Výchozím adresářem, kde knihovna tyto skripty hledá je /usr/share/libpam-script, ale pro nás je výhodnější jejich umístění v adresáři /etc, který je spravován přes git. Proto je výchozí hodnota přenastavena parametrem dir přenastavena.

Obsah souboru pam_script_ses_close[edit]

stroj (diskless) :~# cat /etc/pam-scripts/pam_script_ses_close 
#!/bin/bash
if [ "${PAM_TTY:0:1}" == ':' ]; then
    # logout from X
    echo "$PAM_USER" > "/tmp/unlogged_${PAM_TTY:1}"
else
    # logout from tty
        USER_HOME="/home/$PAM_USER"
        PIDS=$(ps -u "$PAM_USER" -o pid=)
        if [ ${#PIDS} -eq 0 ]; then
            umount "$USER_HOME" 2>> /tmp/testfile
        else
            CONSOLE=$(who -s | grep $PAM_USER)
            if [ ${#CONSOLE} -eq 0 ]; then
                umount "$USER_HOME" 2>> /tmp/testfile
            fi
        fi
fi
Poznámka Session uživatele přihlášeného přes lightdm se nedá vypsat příkazem who Skripty využívají toho, že se po restartu okenního manažeru lightdm opět volá skript pam_script_ses_open. Dočasný soubor, kam se uloží username uživatele má navíc přidané číslo spuštěného X serveru, tudíž se nemůže stát, že by došlo k odpojení adresáře odhlášení uživatele z jiné grafické konzole.

Obsah souboru pam_script_ses_open[edit]

stroj (diskless) :~# cat /etc/pam-scripts/pam_script_ses_open 
#!/bin/bash
    if [ "$PAM_USER" == 'lightdm' ] && [ "$PAM_SERVICE" == 'lightdm' ]; then
        UNLOGGED=$(</tmp/unlogged_${PAM_TTY:1})
        USER_HOME="/home/$UNLOGGED"
        CONSOLE=$(who -s | grep $UNLOGGED)
        if [ ${#CONSOLE} -eq 0 ]; then
            umount "$USER_HOME" 2>> /tmp/testfile && rm "/tmp/unlogged_${PAM_TTY:1}"
        fi
    fi

    if [ $(id -u "$PAM_USER") -gt 2000 ]; then
        REMOTE_HOME="/path_to_directory_with_homes"
        USER_REMOTE_DIR="NFS:$REMOTE_HOME/$PAM_USER"
        USER_HOME="/home/$PAM_USER"
        if [ ! $(grep "$USER_HOME" /proc/1/mountstats) ]; then
            if [ ! -d "$USER_HOME" ]; then
                mkdir -p "$USER_HOME"
                [ $? != 0 ] && echo "Don't create homedir $USER_HOME" >> /tmp/testfile && exit 1
            fi

            mount "$USER_REMOTE_DIR" "$USER_HOME"
            if [ $? != 0 ]; then
                if [ $? == 32 ]; then
                    echo "Home dir is mounted" >> /tmp/testfile
                    exit 0
                else 
                    ssh nfshomecreator@NFS $PAM_USER $REMOTE_HOME
                    mount "$USER_REMOTE_DIR" "$USER_HOME"
                    if [ $? != 0 ]; then
                        echo "Don't mount remote dir $USER_REMOTE_DIR" >> /tmp/testfile && exit 1
                    fi
                fi
            fi
        fi
    fi

Skript pam_script_ses_open v případě že uživatelský adresář na NFS serveru dosud neexistuje přihlášením k NFS serveru na speciálního uživatele nfshomecreator adresář založí.

Skriptu na straně NFS serveru se předávají dva parametry, které vylučují aby byl založen tento uživatelský adresář mimo vypublikovanou NFS strukturu.

Aby se mohl root na uživatele nfshomecreator přihlásit, musí být jeho veřejný klíč umístěn do souboru .ssh/authorized_keys uživatele nfshomecreator na straně NFS serveru.

Pro změnu na straně roota disklessu musí být do souboru .ssh/known_hosts pro každý NFS server umístěn jeho klíč, aby navázání spojení proběhlo bez keců.

Abychom tyto operace nemuseli řešit ručně pro každý NFS server zvlášť, je zde opět výhodné využít puppet.

Puppet - modul diskless[edit]

Zajistí umístění správných souborů do správných míst.