Opensource-hostausta

Olen aiemmin käyttänyt opensource-projektejani varten jotain yleisessä käytössä olevaa opensource-hostaajaa, kuten Sourceforgea. Nämä olemassaolevat palveluntarjoajat ovat kuitenkin enemmän tai vähemmän toimivia, ruuhkaisia, tai jotenkin muuten käyttöä rajoittavia, tai sitten liimattu liiaksi tiettyihin teknologioihin kuten typerien versionhallintaohjelmien käyttöön. Tästä syystä tarve itse tehdylle versionhallintapalvelimelle on kova, ja antaapa se samalla vapauden käyttää juuri niitä teknologioita ja palvelinohjelmia mitä minä haluan.

Tässä tarinassa palvelimen käyttöjärjestelmänä toimii FreeBSD, koska se on mielestäni paras valinta hommaan kuin hommaan, sekä palvelin- että desktop-käytössä. Se on myös turvallisuutensa puolesta hyvä valinta julkisessa internetissä olevalle koneelle, jossa turvallisuus on ensiarvoista. FreeBSD on myös nopea ja vähän resursseja syövä, joten kevyelläkin raudalla pärjää pitkälle. Lisäksi esimerkiksi zfs tiedostojärjestelmä nostaa levynkäytön ja tiedostojärjestelmä-administeeraamisen kertaheitolla uudelle tasolle.

Palvelimen asennuksessa tarvittavat toimenpiteet ja palvelut sisältävät datalevyn salauksen, palomuurin, http-palvelimen ja tietysti itse versionhallinnan sekä ldap-palvelimen versionhallinnan pääsynhallintaa varten. Alla on tarkempaa sepostusta kustakin palvelusta ja sen asentamisesta. Huomaa, että konffiesimerkit, palomuurisäännöt, komentorivikomennot yms. on tarkoitettu vain esimerkeiksi eikä niitä pidä copy-pastata omaan järjestelmään sellaisenaan, vaikka ne toimivia ovatkin.

Etäyhteydet ja OpenSSH

Palvelimen sujuvaan etähallintaan tarvitaan tietysti etähallintaohjelma, joka on nykyisin lähes poikkeuksetta ssh, eli oikealta nimeltään Secure SHell. ssh hoitaa komentojen lähettämisen ja tiedostojen kopioimisen palvelimelle salattuna. ssh:sta on viime aikoina löytynyt erinäisiä heikkouksia, mutta jotka ovat kuitenkin konffimuutoksella kierrettävissä. Nykyisen ssh version oletuskonfiguraation turvallisuudesta en tiedä, mutta koen paremmaksi ja turvallisemmaksi poistaa käsin käytöstä heikoiksi todetut algoritmit sekä itse salauksesta, avaintenvaihdosta että datan verifioinnista. Näin voin olla varma että heikkoja salausmenetelmiä ei käytetä. Jotta ssh:n turvallisuudesta saisi muutenkin kaiken irti, on suositeltavaa käyttää avainpohjaista autentikaatiota tutun ja »turvallisen» käyttäjätunnus-salasana -parin sijaan. Avainten käyttö on myös tehokas keino suojautua sivullisten kirjautumisyrityksiltä, joita julkisessa internetissä oleva kone saa jatkuvasti.

Oma palvelinpäässä sallittujen salausmenetelmien lista on kutakuinkin seuraava:

 Ciphers chacha20-poly1305@openssh.com,\
         aes256-gcm@openssh.com,\
         aes128-gcm@openssh.com,\
         aes256-ctr,\
         aes192-ctr,\
         aes128-ctr

Avaintenvaihtomenetelmistä sallittuna ovat vain nykymittapuulla turvallisiksi oletetut:

 KexAlgorithms curve25519-sha256@libssh.org,\
               diffie-hellman-group-exchange-sha256

Datan verifioimiseen sallitut MAC algoritmit taas sisältävät seuraavaa. On yleisesti suositeltu estää 96-bittiset ja md5 pohjaiset algoritmit:

 MACs hmac-sha2-512-etm@openssh.com,\
      hmac-sha2-256-etm@openssh.com,\
      umac-128-etm@openssh.com,\
      hmac-sha2-512,\
      hmac-sha2-256,\
      umac-128@openssh.com

HTTP palvelin ja Apache

Tässä asennuksessa http palvelinta tarvitaan pääasiassa versionhallintaliikenteen salaamiseen, autentikoimiseen ja repositoryjen pääsynhallintaan, eli luvitukseen, tai autorisointiin. Samalla Apachella ja pienellä lisävaivalla voidaan myös hostata vaikkapa softaprojektien www-sivuja.

Apache on tullut hyvinkin tutuksi vuosien saatossa, ja ainakin omissa asennuksissani se on de-facto http palvelin. Apachen kenties ainoa miinus on rasittava konffaus, josta johtuen tyyliini kuuluu heivata käyttöjärjestelmän mukana tulevat oletuskonfiguraatiotiedostot mäkeen ja tehdä kokonaan omat. Apachessa, kuten muissakin internetiin näkyvissä palveluissa, on turvallisuus ensiarvoista. Seuraavalla pikku konffikikalla kerrotaan clientille palvelimen halusta käyttää kommunikaatiokanavana ainoastaan salattua https protokollaa, joka tapahtuu kutakuinkin alla kuvatulla tavalla. Lisäksi on tarpeen kääntää http liikenne https porttiin vaikkapa Rewrite ruleja käyttämällä.

 Header always set Strict-Transport-Security "max-age=15768000; includeSubDomains"

Ja tässä pari muuta http header-kikkaa Apachen konffiin turvallisuuden tunnetta lisäämään ja cross-site scripting hyökkäyksiä estämään:

 Header always set X-Content-Type-Options "nosniff"
 Header always set X-Frame-Options "SAMEORIGIN"
 Header always set X-Xss-Protection "1; mode=block"
 Header edit Set-Cookie ^(.*)$ "$1; HttpOnly; Secure"

HTTPS:ää käytettäessä heikoiksi oletettuja tai todettuja salausmenetelmiä on hyvä poistaa käytöstä ja suosia ainoastaan vahvoja salausalgoritmeja. Lisäksi estetään TLS pakkaus CRIME haavoittuvuutta vastaan:

 SSLCipherSuite \
  ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS

 SSLProxyCipherSuite \
  ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS

 SSLProtocol ALL -SSLv2 -SSLv3
 SSLProxyProtocol ALL -SSLv2 -SSLv3

 SSLCompression off
 SSLHonorCipherOrder on

DDOS hyökkäyksiä vastaan apacheen on saatavana näppärä mod_evasive. Evasive moduuli pitää kirjaa toistuvista yhteydenotoista samaan kohteeseen tietyn aikaikkunan sisällä, ja asetetun kynnyksen ylityttyä clientti asetetaan sulkulistalle ennalta asetetuksi ajaksi. Yksinkertaista ja tehokasta tylsistyneiden skriptaajien torjuntaan.

Versionhallinta ja Subversion

Versionhallintaan käytän SVN:ää, koska se toimii, on nopea, helppo ylläpitää, ja sopii omaan käyttööni just' eikä melkein. SVN:n turvallisuudesta ei sinänsä tarvitse olla huolissaan, koska repositoryn perustamisen jälkeen tiedosto-oikeudet ovat mallillaan, ja pääsynhallinnan sekä liikenteen salauksen hoitaa Apache. Pelkkää svn protokollaa ei siis sallita, vaan asioidaan aina https:n yli.

Versionhallinnassa on kuitenkin muutama virittämistä vaativa yksityiskohta. Ensimmäinen, ja ehkäpä tärkein on injektohyökkäyksiä vastaan suojautuminen, tai pikemminkin niiden huomaaminen. Tilanne, jossa ulkopuolinen taho pääsisi ujuttamaan omaa koodiaan versionhallinassa olevaan koodiin olisi melkoisen huolestuttava. Tästä syystä versionhallintaan on hyvä miettiä esimerkiksi lähdekoodin automaattista allekirjoittamista, joka voitaisiin tehdä vaikkapa post-commit hookilla. Tällöin jokainen lähdekooditiedosto voitaisiin verifioida automaattisesti versionhallinnan ohi tapahtuvien muutoksien varalta. Verifitointi voisi myös toimia sekä post-commit- että pre-commit hookeista käsin ja reagoida asianmukaisella vakavuudella mikäli allekirjoituksen verifiointi epäonnistuu.

Tiedostojen allekirjoittamiseen itse suosin OpenBSD projektin signify työkalua. signify:llä voi myös helposti tuottaa omien ohjelmien allekirjoitetun tarkistussummalistan jokaisesta ohjelman tiedostosta sen jakeluvaiheessa, joten jokainen softaa käyttävä heppu voi itse verifioida kunkin tiedoston aitouden ja virheettömyyden niin halutessaan.

Autentikaatio ja OpenLDAP

SVN repositoryjen pääsynhallintaa varten Apachen parina toimii OpenLDAP serviisi. Apachen konffaaminen LDAP:n osalta on helppoa, ja jos on tarvetta hienoresoluutioisempaan pääsynhallintaan, eli ryhmäjäsenyyksillä kikkailuun, LDAP:lla tämäkin käy sujuvasti.

Tässä installaatiossa LDAP ei ole avoinna julkiseen internetiin, vaan sen käyttö on rajattu ainoastaan samalla koneella oleville palveluille. Tästä syystä paranoidinen suojaus ei ole ehdottoman tärkeää, suositeltavaa kylläkin. Niin tai näin, käytän siitä huolimatta salattua LDAPS protokollaa ainoastaan TLS sallittuna. Alla olevalla konffinpätkällä voidaan estää SSLv2 ja SSLv3 protokollat ja käyttää ainoastaan TLS:ää:

 TLSCipherSuite -S:HIGH:MEDIUM:+TLSv1
 TLSProtocolMin 3.1

Palomuuri ja OpenBSD pf

Internetiin kytketyssä koneessa on hyvä olla jonkinlainen mekanismi tahallisia portinkoputtelijoita ja muita tylsistyneitä teininörttejä vastaan, ja ehdottomasti keino sulkea sisäisten palveluiden portit ulkomaailmalta. Omassa palvelimessani esimerkiksi ssh porttiin tulee satoja yhteydenottoja tunnissa, suurin osa selkeitä kirjautumisyrityksiä ja porttiskannauksia.

Palvelimen palomuurina kannattaa käyttää jotain tehokasta ja helposti konffattavaa härveliä kuten vaikkapa OpenBSD projektin packet filteriä, joka tunnetaan paremmin nimellä pf. FreeBSD tarjoaa myös ipfw sekä ipfilter palomuurit, mutta itse suosin pf:ää. Lisäksi pf:n konffiformaatti on hyvin selkeää ja helppolukuista vaikkapa Linuxin iptables muuriin verrattuna. Omassa palvelimessani tarkoitus on sallia yhteydet portteihin 22, 80 ja 443, eli sallitaan ainoastaan ssh- ja http(s) liikenne, ja ssh:kin tietyin rajoituksin.

Palomuurin oikeaoppinen säätäminen vaatii jonkinlaisen ymmärryksen TCP/IP liikenteestä. Alempana kuvattu konffitiedosto on ainoastaan esimerkki eikä missään tapauksessa suositeltava käytettäväksi sellaisenaan vaikka sinänsä toimiikin. Myös palomuurin säätämiseen etäyhteyden yli liittyy aina pieni riski sulkea myös itsensä ulkopuolelle. Tästä syystä palomuurin säätämisessä on hyvä olla erityisen tarkkana jotta lopputulos olisi toivottu ja palvelimelle pääsisi kirjautumaan myös jatkossa.

Alla olevassa esimerkissä liian innokkailta ssh yhteyden ottajilta - eli brute-forcella kirjautumista yrittäviltä - suljetaan IP osoitteen perusteella ssh portti lopullisesti jos viidessä sekunnissa tapahtuu enemmän kuin yksi yhteydenottoyritys. Tämä kannattaa muistaa itse salasanaa caps-lock päällä naputellessa.

pf.conf

 my_if = "{ em0 }"

 set block-policy drop
 set loginterface egress
 set skip on lo

 scrub in all

 block in log
 block quick from <bruteforce>
 pass out quick

 pass in log on $my_if proto tcp from any to any port ssh \
      flags S/SA keep state \
      (max-src-conn 10, max-src-conn-rate 1/5, \
      overload <bruteforce> flush global)

 pass in on $my_if proto tcp from any to any port { http, https } \
      flags S/SA keep state

pf kirjoittaa myös lokia niin halutessa, joka tosin pitää aktivoida lisäämällä seuraava rivi rc.conf:iin:

 pflog_enable="YES"

Loki on tavallisuudesta poikkeavasti binääritavaraa, jonka saa kuitenkin hyvin helposti muutettua luettavaan muotoon tcpdump:lla:

 # tcpdump -e -n -ttt -r /var/log/pflog

Levyn salaus ja ZFS

Levyjen salaaminen on hyvä käytäntö fyysisten väärinkäytösten estämiseen. Oma palvelinkoneeni sijaitsee jossain datacenterissä Saksanmaalla tuhansien muiden koneiden seassa. Koneräkkien välissä huseeraa sekalainen määrä sysadmineita, joilla pitäisi olla jonkinlainen kunnioitus toisten dataa kohtaan, mutta liian varovainen ei voi tässäkään olla. Lisäksi levyn salaaminen on hyvä tapa siinäkin tapauksessa, että levyn mennessä vaihtoon sitä ei ole itse mahdollista hävittää jolloin levy datoineen saattaa päätyä ties minne.

FreeBSD:llä levyn salaamiseen suosin geli(8) menetelmää. Geliä käytettäessä levy salataan ensin, jonka jälkeen levylle tehdään tiedostojärjestelmä, eli niin sanotusti formatoidaan. Alla on selostettu pääpiirteittäin yhden levyn salaamisvaiheet, jossa oma salattava levyni näkyy systeemissä ada1:nä. Tämän sepostuksen ei ole tarkoitus olla levyn salaamisen mummo-ohje. Jos olet aikeissa salata levysi, tutustu kunkin komennon ohjesivuun ja ymmärrä mitä olet tekemässä. Väärin salaamalla saat salattua datan myös itseltäsi. Salausavainten varmuuskopioinnista kannattaa myös huolehtia asianmukaisesti.

Vaiheet

Mikäli levy tarvitsee partitioinnin, voidaan se tehdä vaikka näin:

 # gpart destroy -F ada1
 # gpart create -s gpt ada1
 # gpart add -t freebsd-zfs -a 4096 ada1

Levyn salaamiseen tarvitaan ensin salausavain, jonka saa kätevästi satunnaislukugeneraattorista. Avain tallennetaan rootin kotihakemistossa keys-alihakemistoon:

 # mkdir /root/keys
 # chmod 0700 /root/keys
 # dd if=/dev/urandom of=/root/keys/ada1.key bs=4096 count=1
 # chmod 0400 /root/keys/ada1.key

Avaimen luonnin jälkeen levy alustetaan yllä luodulla avaimella:

 # geli init -e AES-XTS -s 4096 -K /root/keys/ada1.key /dev/ada1p1
 # geli attach -k /root/keys/ada1.key /dev/ada1p1

Tämän jälkeen salattu levy näkyy systeemissä /dev/ada1p1.eli:nä, johon voidaan luoda tiedostojärjestelmä:

 # zpool create tank /dev/ada1p1.eli

Tiedostojärjestelmän luonnin jälkeen salattu levy on käytettävissä. Bootin jälkeen tarvitaan kuitenkin pari ylimääräistä komentoa joilla salattu zfs tiedostojärjestelmä saadaan käyttöön:

 # geli attach -j - -k /root/keys/ada1.key /dev/ada1p1
 # zpool import -R tank

~ Jani Salonen, 30.10.2016