Kategória: Linux a sieť

Zmenené: 18. február 2011

Riadenie prístupu k LDAP

Nedávno som popisoval ako nastaviť šifrovanie komunikácie so serverom LDAP. Avšak zabezpečiť netreba len prenos dát, ale aj dáta samotné, inak ich šifrovanie veľký zmysel nedáva. V tomto článku sa pokúsim ukázať ako sú riešené prístupové práva v OpenLDAP.

Predvolené nastavenie

Tak ako každý softvér, i OpenLDAP má svoje východzie nastavenia. K tomu ešte pridáva predvolenú konfiguráciu autor balíka, a táto sa môže od východzích líšiť. Aj po čerstvej inštalácii servera OpenLDAP v Debiane je poskytnuté východzie nastavenie prístupových práv. To sa dočítate v mnohých návodov. Ale čo to ale re správcu znamená?

Prístupové práva, alebo presnejšie zoznamy prístupových práv (Access Control Lists – ** ACL**) sú definované na viacerých miestach konfigurácie a každá z nich má dosah na inú časť servera OpenLDAP:

  • globálny prístup k databáze;
  • prístup ku konfiguračnej databáze;
  • prístup k dátam v jednotlivých databázach.

V tomto článku popíšem ako zmeniť predvolené nastavenie prístupu k dátam adresára tak, aby na čítanie dát (vyhľadávanie) bolo potrebné úspešné prihlásenie, pričom celý postup popíšem na nastavení predvoleného databázového úložiska HDB, ktorého predvolené prístupové práva v Debiane vyzerajú takto:

ldapsearch -LLL -H ldapi:/// -Y EXTERNAL -b cn=config olcDatabase={1}hdb olcAccess

dn: olcDatabase={1}hdb,cn=config
olcAccess: {0}to attrs=userPassword,shadowLastChange
    by self write
    by anonymous auth
    by dn="cn=admin,dc=skk" write
    by * none
olcAccess: {1}to dn.base=""
    by * read
olcAccess: {2}to *
    by self write
    by dn="cn=admin,dc=skk" write
    by * read

Ako sami vidíte, prístupové práva k dátam adresára sú nastavené v troch hodnotách. Prvá nastavuje prístup len k atribútom userPassword a shadowLastChange, druhá položka nastavuje práva k tzv. root DSE (špeciálna položka, ktorá vypisuje zoznam dostupných operácií LDAP) a nakoniec všeobecná položka, ktorá riadi prístup ku všetkým ostatným objektom adresára. Všetky tri položky prístupových práv používajú rovnakú syntax, pričom číslo v zloženej zátvorke je vlastné poradové číslo ACL.

Popis syntaxe ACL

Všetky definície prístupových práv používajú rovnakú syntax, ktorá všeobecne vyzerá takto:

olcAccess: to [kde] by [kto] [čo]

Pričom:

  • [kde] – udáva rozsah platnosti, na ktoré sa príslušný ACL použije;
  • [kto] – udáva rozsah používateľov, na ktorých sa príslušné právo použije a
  • [čo] – udáva povolenie, ktoré bude aplikované.

Každá definícia pritom môže mať len jednu položku [kde], ale môže obsahovať viac dvojíc [kto] a [čo], vždy oddelených kľúčovým slovom by, tak ako to vidno napríklad hneď v prvej položke ACL. Rozsah platnosti ACL možno definovať rôznymi spôsobmi, pričom v predvolenom nastavení sú použité:

  • * – je zástupný znak, ktorý vyhovuje každej položke;

  • dn= – je aplikovaný na zadanú DN;

  • dn.[rozsah]= – ktorý je aplikovaný na príslušný rozsah:

    • base – je použité na položky so zadaným DN;
    • one – je použité na položky, ktorých rodič je zadané DN (jedna úroveň vnorenia);
    • subtree – je použité na všetky vnorené položky zadaného DN (aj viac úrovňové vnorenie);
    • children – je použité na všetky vnorené položky zadaného DN (ale nie DN samotné);
  • attrs= – je použitý na konkrétne atribúty.

Na ukázanie fungovania formátu dn.[rozsah] si pomôžem vzorovým obsahom databázy, ktorá môže vyzerať napríklad takto:

0: o=sose
1: cn=Manager,o=sose
2: ou=people,o=sose
3: uid=slavko,ou=people,o=sose
4: cn=addresses,uid=slavko,ou=people,o=sose
5: uid=ferko,ou=people,o=sose

Ak teda ACL definujem rôzne rozsahy na to isté DN (ou=people,o=sose), budú jednotlivým ACL vyhovovať rôzne položky:

dn.base="ou=people,o=sose"
  • vyhovuje položka 2, pretože musí vyhovovať presne zadané DN
dn.one="ou=people,o=sose"
  • vyhovujú položky 3 a 5, pretože sú vybrané tie, ktoré majú ako rodiča zadané DN, teda len prvá úroveň vnorenia
dn.subtree="ou=people,o=sose"
  • vyhovujú položky 2, 3, 4 a 5, pretože vyhovuje zadané DN a všetky jeho vnorené položky, bez ohľadu na úroveň vnorenia
dn.children="ou=people,o=sose"
  • vyhovujú položky 3, 4, a 5, pretože ACL je použitý len na potomkov baz ohľadu na úroveň vnorenia, ale nie na samotný DN

Myslím, že použitie formátu na konkrétne atribúty je jasné, ale pre úplnosť spomeniem, že možno definovať viac atribútov naraz, oddelených čiarkou. Ďalšia časť nastavenia práv je určenie používateľov, na ktorých sa zadané právo vzťahuje, tu je k dispozícii niekoľko formátov, z nich vyberám len tie základné:

  • * – opäť predstavuje všetkých používateľov (vrátane anonymných);
  • annonymous – predstavuje neautentifikovaných používateľov;
  • users – predstavuje autentifikovaných používateľov;
  • self – predstavuje vlastné položky autentifikovaného používateľa;
  • dn= – predstavuje konkrétneho používateľa (prípadne rozsah používateľov).

No a na koniec ostala povolená akcia. K dispozícii ich je niekoľko a k tým základným patria:

  • none – zakázaný prístup;
  • auth – môže sa autentifikovať;
  • read – môže čítať (vyhľadávať);
  • write – môže zapisovať (meniť).

Popis predvolených práv

Po vysvetlení syntaxe možno pristúpiť k skúmaniu práv, ktoré sú v Debiane nastavené ako predvolené. Prvá položka ACL:

olcAccess: to attrs=userPassword,shadowLastChange
    by self write
    by anonymous auth
    by dn="cn=admin,dc=skk" write
    by * none

Teraz už viete, že ACL začína definíciou rozsahu. V tomto prípade je rozsah obmedzený na atribúty userPassword a shadowLastChange, teda atribúty ktoré súvisia s heslom používateľa. Za definíciou rozsahu nasleduje definícia používateľa a akcie, teda v tomto prípade štyri definície:

  • self write udáva, že každý môže zapisovať (meniť) svoje vlastné heslo (a čas jeho zmeny);
  • anonymous auth udáva, že anonymní (neautentifikovaní) používatelia môžu tieto atribúty použi na autentifikáciu;
  • nasleduje právo zápisu pre používateľa s DN cn=admin,dc=skk (predpokladám, že viete, že je to predvolená položka správcu servera LDAP);
  • posledná položka, * none udáva, že všetci ostatní majú prístup k týmto atribútom zakázaný.

Dobre, tento ACL je trochu špecifický, ale začal som ním, pretože je prvý v zozname. nasleduje ho ACL prístupu k root DSE, ktorú preskočím a prejdem priamo k poslednej položke, ktorá vyzerá takto:

olcAccess: to *
    by self write
    by dn="cn=admin,dc=skk" write
    by * read

Táto položka nastavuje prístupové právy ku všetkým ostatným položkám adresára, pretože jej rozsah je definovaný pomocou znaku * a definuje tri rôzne úrovne prístupu:

  • najprv udeľuje právo každému meniť svoje vlastné položky (self write);
  • potom prideľuje právo zmeny aj správcovi servera a nakoniec
  • povoľuje každému čítať obsah adresára (* read).

Z uvedeného vyplýva, že ak použijete príkaz ldapsearch na výpis obsahu databázy adresára bez zadania hesla, server LDAP bez rečí svoj obsah poskytne.

Zatiaľ som preskočil spomínané poradové číslo. Z časti dôležité nie je, pretože sa priamo nezúčastňuje prideľovania práv. Jeho význam však spočíva v definovaní poradia prístupových práv, ktoré už dôležité je, pretože práva sú nastavované postupne, a to vždy tak, právo s väčším rozsahom už nemožno obmedziť. Ak by teda bolo najprv nastavené právo čítania všetkým (by * read), ktoré by ste chceli upraviť tak, aby mohli používatelia svoje vlastné položky meniť (self write), nefungovalo by to. Poradie musí byť opačné, teda najprv právo s menším rozsahom a až potom všeobecnejšie, a to sa týka aj samotných položiek v konkrétnom ACL, nie len poradia ACL ako takých.

Obmedzenie anonymného prístupu

V minulom článku som napísal, že predvolené prístupové práva sú postačujúce a netreba ich meniť. Záleží to však od účelu, ktorý adresár LDAP plní. Ak má slúžiť ako adresár kontaktov, iste predvolené práva vyhovujú a nikomu nebude vadiť, že si jeho obsah môže prečítať každý. Ak však budete mať v adresári uložené osobné údaje zamestnancov a budete chcieť svoj adresár sprístupniť aj v sieti internet, asi by nebolo celkom vhodné aby si mohol zoznam zamestnancov pozerať každý.

V takom prípade je potrebné prístupové práva zmeniť tak, aby sa k obsahu mohol každý dostať až po úspešnom zadaní mena a hesla, teda po úspešnej autentifikácii. K tomu je treba vlastne len zmeniť všetky položky by * read na by users read. Inou možnosťou je ponechanie zápisu by * read bez zmeny, ale pridať pre to ešte položku by anonymous none. Existuje veľa návodov ako to urobiť, ale všetky ktoré som našiel jednoducho popisujú starý spôsob nastavenia pomocou konfiguračného súboru slapd.conf, ktorý východzia inštalácia OpenLDAP v Debiane už nepoužíva.

Server OpenLDAP v Debiane Squeeze používa tzv. dynamickú konfiguráciu, ktorú možno pomeniť za chodu servera (teda bez jeho reštartu), a to pomocou štandardných súborov LDIF. Aby sme teda mohli ACL, musíme si pripraviť súbor LDIF, ktorý potom nahráme do konfigurácie a máme hotovo. Súbor LDIF môžete samozrejme vytvoriť jeho napísaním, ale oveľa vhodnejší spôsobom sa mi zdá jeho pripravenie pomocou vypísania existujúceho nastavenia. Takto vygenerovaný súbor LDIF potom treba už len trochu upraviť.

Takže najprv vygenerovanie. O to sa postará už spomenutý príkaz, ktorého výstup jednoducho presmerujem do súboru:

ldapsearch -LLL -H ldapi:/// -Y EXTERNAL -b cn=config olcDatabase={1}hdb olcAccess > dbacl.ldif

Poznamenám, že je použitá voľba -LLL, ktorej zmysle spočíva vo vynútení výstupu vo formáte LDIF. Aktuálny stav ACL je teda v súbore dbacl.ldif a treba v ňom urobiť dve úpravy úpravy, a to pridať zamýšľanú operáciu (riadky changetype a replace) a zmeniť spomínané práva. Výsledkom bude takýto súbor LDIF:

dn: olcDatabase={1}hdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=skk" write by * none
olcAccess: {1}to dn.base="" by users read by * none
olcAccess: {2}to * by self write by dn="cn=admin,dc=skk" write by users read by * none

Takto pripravený súbor potom ostáva načítať do konfigurácie OpenLDAP pomocou príkazu ldapmodify:

ldapmodify -Y EXTERNAL -H ldapi:/// -f dbacl.ldif

modifying entry "olcDatabase={1}hdb,cn=config"

Ak všetko dopadlo ako má, sú nové prístupové práva aplikované, čo si môžete overiť opätovným pokusom o vypísanie obsahu adresára:

ldapsearch -LLL -x -b dc=skk
No such object (32)

Sami môžete vidieť, že teraz už server neposkytol žiadny obsah, ale vrátil chybu 32 neexistujúci objekt. Ak však spustíte príkaz s menom používateľa a zadáte správne heslo, dostanete opäť výpis:

ldapsearch -LLL -W -D "cn=admin,dc=skk"
Enter LDAP Password:
dn: dc=skk
objectClass: top
objectClass: dcObject
objectClass: organization
...

Prípadne môžete lokálne ako root pristupovať pomocou:

ldapsearch -LLL -H ldapi:/// -Y EXTERNAL

Vytvorenie Bind DN

BindDN je používateľ v externom serveri LDAP, ktorý má povolené prehľadávať adresár LDAP (v zadanom rozsahu). Vo väčšinep rípadov bude mať bindDN povolené prehľadávať celý adresár. Úlohou bindDN je aj realizovať požiadavky na DN (distinguished name) pri autentifikácii používateľov. Ak teda obmedzíte prístup k prehľadávaniu obsahu adresára pre anonymných používateľov, je teba vytvoriť špeciálneho používateľa, ktorý môže byť priamo pod koreňom (podobne ako admin), aby sa týmto účtom nedalo prihlasovať, ale slúžil len na autentifikáciu. Ako príklad ukážem súbor LDIF, ktorý vytvorí taký účet, nazvaný binddn:

dn: cn=binddn,dc=skk
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: binddn
description: LDAP bind DN account
userPassword: {MD5}4QrcOUm6Wau+VuBX8g+IPg==

Po vytvorení používateľa ho treba pridať (aj s heslom) do nastavení služieb, ktoré LDAP používajú. V ich konfigurácii hľadajte voľbu binddn. Napríklad v /etc/nslcd.conf:

# The DN to bind with for normal lookups.
binddn cn=binddn,dc=skk
bindpw 123456

Pridanie ďalších ACL

Naši používatelia síce príkazy chfn a chsh nepoužívajú, ale keby niekedy v budúcnosti chceli, je dobré im to povoliť, ako to odporúča stránka Debianu:

olcAccess to attrs=loginShell,gecos
    by dn="cn=admin,dc=skk" write
    by self write
    by * read