====== Read-only vs Read-write filesystemen ======
In onze omgeving maken wij onderscheid tussen read-only en read-write
filesystemen. Voor de read-only filesystemen geldt dat deze vanaf de
web, applicatie en database servers **niet** gewijzigd kunnen worden.
Deze filesystemen worden gebruikt om de executeerbare delen en de
configuratie van applicaties op te slaan.
In onze omgeving is het zo dat alle web-app en pages directories op read-only
filesystemen liggen. Verder ligt alle configuratie (frontproxy, database,
applicatieserver) op een read-only filesysteem. De read-write filesystemen
worden alleen gebruikt voor logfiles, temp-directories en databases.
De reden hiervoor is dat als een site gehacked wordt, het voor de
hacker onmogelijk is om b.v. jsp of php files te wijzigen.
Concreet houdt dit in dat
bij een geslaagde hack poging de applicatie zichzelf niet kan wijzigen
(op instigatie van de hacker), en dat het dus bijzonder moeilijk zal
zijn om b.v. aan de database inhoud te komen. Overigens is er bij
ons nog nooit een geslaagde hackpoging geweest.
Dit houdt in dat het voor applicaties dus niet mogelijk is om
self-modifying code te gebruiken (bv een jsp die een nieuwe versie van
zichzelf neerzet). In het geval van MMBase houdt dit in dat er niet
via het web-interface nieuwe delen van MMBase geinstalleerd kunnen worden
(want de applicatieserver mag niet schrijven in z'n web-app directory)
Zelfs als u bijvoorbeeld "chmod 777" (= unix speak voor world writable)
op een jsp bestand zou doen, dan nog is het niet te wijzigen vanaf
een applicatieserver. Dit willen we dan ook ten zeerste afraden.
De enige plek vanaf waar naar de read-only filesystemen geschreven mag
worden is de upload server. Da's ook nodig, anders zouden er b.v. nooit nieuwe
jsp bestanden geplaatst kunnen worden.
==== Users en Groups namen ====
In het web- app- en testcluster is i.h.a. een vrij stricte relatie
tussen een usernaam en waar deze voor gebruikt wordt. B.v. een
instantie die leeft onder /e/XX/YYYYYY draait bijna altijd onder
het userid YYYYYYXX. Voorbeeld: de webserver instantie /e/fp/dmd1a
draait onder als user dmd1afp, de postfix instantie /e/ml/dmd2b draait
als dmd2bml.
Alle user accounts worden gecreeerd volgens het "all accounts are
created equal" principe, wat inhoudt dat er nooit intrinsieke rechten
aan een account hangen. De rechten volgen pas door het account toe te
voegen aan specifieke groepen.
Om dit af te dwingen worden accounts altijd gecreeerd met uid=gid (dit
is unix terminologie, en betekent dat elk account in z'n eigen unieke
groep geplaatst wordt). De naam van de groep is gelijk aan de naam van
de user. Oftewel, als er een user X is met uid N, dan is z'n
primary group-id ook N en de bijbehorende groepsnaam is weer
X. Ook aan het uid hangen geen speciale rechten, da's gewoon het
eerstvolgende vrije uid boven de 5000.
Voorbeeld: de user "test1afp". Deze heeft de volgende entry in
/etc/passwd
test1afp:x:5000:5000:Test webserver:/e/fp/test1a:/sbin/nologin
Zie hoe het userid gelijk is aan het group-id (5000), dus in /etc/group
komt de volgende regel voor:
test1afp:x:5000:
Als we nu rechten uit willen delen aan deze user, dan kan dat op basis
van group-membership. Typisch voor een webserver is dat deze data moet
kunnen wegschrijven en derhalve lid van een data writers ("dw") group
moet zijn:
dwtest:x:20000:test1afp,test1bfp,webtoko1
De groeps-id's hebben ook geen speciale betekenis; het eerste vrije uid
boven de 20000. In de groeps namen zit wel enige codering, nl in de
eerste twee letters:
* rd - Reader
De groep voor users die ergens mogen lezen.
Dit bestaat om ervoor te zorgen dat ongerelateerde entiteiten niet
elkaars spullen mogen lezen. De readers omvat normaal gesproken alle
user users die iets met een applicatie te maken hebben: webservers,
applicatieservers, databases, uploaders en beheerders.
* dw - Data writer
De groep voor users die data mogen plaatsen.
Dit zijn de uploaders en de processen die zelf data wegschrijven (bv een
webserver die ge-upload content ergens weg moet kunnen schrijven)
* cw - Content Writer
De groep voor users die content (denk aan php
code) mogen plaatsen. Dit zijn normaal gesproken alleen de uploaders.
Voorbeeld: stel dat er een applicatie
rdfoo:x:20000:uploader1,uploader2,foo1afp,foo1bfp,beheerders
dwfoo:x:20001:uploader1,uploader2,foo1afp,foo1bfp
cwfoo:x:20002:uploader1,uploader2
===== File Permissies =====
==== Het probleem: afscherming en samen kunnen schrijven ====
Er zijn twee problemen die we op willen lossen:
* Afscherming
Je wilt niet dat alles voor iedereen leesbaar is.
De uploaders van de ene omroep moeten niet de code van een andere omroep
kunnen zien.
* Samen schrijven
Je wilt dat verschillende users dingen op het filesysteem met elkaar
kunnen delen. Bijvoorbeeld meerdeer upload accounts die samen aan de
code van 1 applicatie moeten kunnen werken, of meerdere geloadbalancede
webservers die elk onder een gesharede /data spulletjes moeten kunnen
wegschrijven.
Ook wil je vaak dat zowel uploaders als webservers samen onder /data
kunnens chrijven.
==== Oplossing voor Afscherming: Hekjes ====
Een hekje is een directory ergens bovenaan in een directory tree die
niet world readable is, slechts group readable en dus alleen te passeren
voor users die lid zijn van die groep.
Voorbeeld:
Beschouw de volgende groep:
readers:x:10000:uploader1,uploader2,webserver1,webserver2,beheerders
en deze directory:
/d/netapp/ro/00/ap/www.website.nl
Als we die directory nou owner root:readers, mode 750 geven dan is alles
wat daaronder ligt niet meer te benaderen voor users die geen lid van de
groep "readers" zijn. Onafhankelijk van de permissies daaronder!
==== Oplossing voor samen Schrijven: datawriters en contentwriters ====
Voor het schrijven roepen we ook 2 groepen in het leven: de datawriters
en de contentwriters. Contentwriters zijn iha de users met een upload
account, die vanuit de upload server de /pages (e.d.) directory mogen
vullen. In de datawriters groep zitten de webservers en de uploaders
samen. En dat geeft ze rechten om onder /data te schrijven.
Om dit goed te laten werken is het nodig dat zowel datawriters als
contentwriters een umask 002 hanteren, zodat wat ze aanmaken default
group writable is.
En om dat weer veilig te kunnen doen is het nodig dat ALLE users
een uniek primary group ID hebben.
Dus, voorbeeld:
We hebben de users:
webserver1:x:5001:5001:Ik ben een webserver:/var/empty/home:/sbin/nologin
webserver1:x:5002:5002:Ik ben een webserver:/var/empty/home:/sbin/nologin
uploader1:x:5003:5003:Ik ben een uploader:/home/omroep/uploader1:/bin/bash
uploader2:x:5004:5004:Ik ben een uploader:/home/omroep/uploader1:/bin/bash
Dan hebben we de groepen:
readers:x:10000:uploader1,uploader2,webserver1,webserver2,beheerders
contentwriters:x:10001:uploader1,uploader2
datawriters:x:10002:uploader1,uploader2,webserver1,webserver2
En de permissies onder /e/ap/www.website.nl zouden dan zijn:
$ cd /e/ap/www.website.nl
# ls -Lla .
drwxr-x--- 2 root readers 4.0K Jan 14 23:12 .
drwxrwxr-x 2 root contenwriters 4.0K Jan 14 23:12 pages
drwxrwxr-x 2 root datawriters 4.0K Jan 14 23:12 data
==== Granulariteit van readers en content/data-writers ====
=== Readers ===
Laten we per omroep 1 readers groep aanmaken.
Dat betekent dat als webtoko1 en webtoko2 allebei voor $omroep werken
ze elkaars code kunnen lezen en de code die een omroep zelf opgehoest
heeft. Maar, dat zou imo geen probleem moeten zijn.
=== Content/Data-writers ===
Je wilt niet dat webtoko1 en webtoko2 over elkaars code heen kunnen
krassen. Ook wil je een asymmetrische relatie tussen $omroep en
$webtoko, nl $omroep mag wel over de code van $webtoko heenkrassen, maar
niet andersom.
Dit is te regelen door per omroep-webtoko combinatie een groepje aan te
maken:
readers:x:10000:omroep,webtoko1,webtoko2,webserver1,webserver2,beheerders
contentwriters:x:10001:omroep
toko1writers:x:10002:omroep,webtoko1
toko2writers:x:10003:omroep,webtoko2
datawriters:x:10004::omroep,webtoko1,webtoko2,webserver1,webserver2
Op die manier kan toko1 nog wel over de data van toko2 heenschrijven,
maar dat konden ze toch al, als ze in dezelfde apache instantie draaien.
(nl door het apache maar te laten doen)
$omroep dreigt wel lid van veel groepen te worden op die manier
(net zoveel als dat ze gescheiden webtoko's in dienst hebben), dus die
moeten wellicht van tijd tot tijd "newgrp toko1writers" intikken om over
de code van toko1 heen te kunnen krassen.
Als tokoX nou maar 1 account heeft, en niet hoeft te delen met tokoY,
dan kan het simpeler opgelost worden; nl tokoX geen lid te maken van
enige contentwriter group en de pages directory owner tokoX.
Dwz owner tokoX:contentwriters, mode 775.
==== Rechten goed houden met php ====
Bovenstaande rechtenstructuur is essentieel voor de juiste werking van een website. Wanneer er, bijvoorbeeld door de code van de website, wijzigingen in de rechten worden aangebracht kan hierdoor functionaliteit verloren gaan. Het is daarom belangrijk dat de code van de website de rechten niet veranderd wat helaas in php niet altijd voor de hand liggend is. De basis gedachte achter ons platform is: eea is zo opgezet dat de rechten vanzelf goed komen te staan. Wij zien dus het liefst dat er zo min mogelijk gebruik wordt gemaakt van chown/chmod en consorten. Voorwaarde is wel dat het zgn "umask" goed staat; dat moet op '002' staan.
In onze web-, sshd- en ftpservers zorgen wij ervoor dat dat goed staat. In shell accounts adviseren wij om in
een '.profile' een 'umask 002' op te nemen. Enige probleem geval zijn cronjobs. Cron draait met een verkeerd umask (022); indien er cronjobjes gebruikt worden die mogelijk files of directories zouden kunnen creeeren dan is het aan te raden om in het desbetreffende commando een umask op te nemen; bijvoorbeeld zoiets:
*/5 * * * * umask 002; doe_iets.php
Sommige php functies (b.v. mkdir) willen in sommige gevallen dat er permissies opgegeven worden.
De mkdir functie werkt als volgt:
bool mkdir ( string $pathname [, int $mode = 0777 [, bool $recursive = false [, resource $context ]]] )
Dat houdt in dat als je recursive een directory aan wilt maken ("mkdir -p" zeg maar) je opeens verplicht bent om ook permissies op te geven. Gebruik in dat geval de default permissies (hier dus 0777)
dat komt omdat de permissies die bij mkdir opgegeven worden, worden ge-bitmasked met je umask en op die manier toch de juiste rechten gebruikt worden.
Bepaalde CMS'en hebben extra settings nodig om directory's met juiste permissies aan te maken. Bijvoorbeeld **Drupal**; definieer in settings.php:
$settings['file_chmod_directory'] = 02775;