RHEL 8 Beta Workshop: Toimivien verkkosovellusten rakentaminen

RHEL 8 Beta tarjoaa kehittäjille monia uusia ominaisuuksia, joiden listaus voi viedä sivuja, mutta käytännössä uusien asioiden oppiminen on aina parempaa, joten alla tarjoamme työpajan Red Hat Enterprise Linux 8 Betaan perustuvan sovellusinfrastruktuurin varsinaisesta luomisesta.

RHEL 8 Beta Workshop: Toimivien verkkosovellusten rakentaminen

Otetaan perustaksi kehittäjien keskuudessa suosittu ohjelmointikieli Python, Djangon ja PostgreSQL:n yhdistelmä, melko yleinen yhdistelmä sovellusten luomiseen, ja konfiguroidaan RHEL 8 Beta toimimaan niiden kanssa. Sitten lisäämme vielä pari (luokittelematonta) ainesosaa.

Testiympäristö muuttuu, koska on mielenkiintoista tutkia automaation mahdollisuuksia, työskennellä konttien kanssa ja kokeilla ympäristöjä useilla palvelimilla. Aloitaksesi uuden projektin, voit aloittaa luomalla pienen, yksinkertaisen prototyypin käsin, jotta näet tarkalleen, mitä pitää tapahtua ja miten se toimii, ja siirtyä sitten automatisointiin ja monimutkaisempien kokoonpanojen luomiseen. Tänään puhumme tällaisen prototyypin luomisesta.

Aloitetaan ottamalla käyttöön RHEL 8 Beta VM -kuva. Voit asentaa virtuaalikoneen tyhjästä tai käyttää beta-tilauksesi mukana saatavaa KVM-vieraskuvaa. Kun käytät vieraskuvaa, sinun on määritettävä virtuaalinen CD-levy, joka sisältää metatiedot ja käyttäjätiedot pilvialustusta (pilvi-init) varten. Sinun ei tarvitse tehdä mitään erityistä levyrakenteelle tai saatavilla oleville paketeille; mikä tahansa kokoonpano käy.

Katsotaanpa tarkemmin koko prosessia.

Djangon asennus

Djangon uusimmalla versiolla tarvitset virtuaalisen ympäristön (virtualenv), jossa on Python 3.5 tai uudempi. Beta-muistiinpanoissa näet, että Python 3.6 on saatavilla, tarkistetaan, onko näin todella:

[cloud-user@8beta1 ~]$ python
-bash: python: command not found
[cloud-user@8beta1 ~]$ python3
-bash: python3: command not found

Red Hat käyttää aktiivisesti Pythonia järjestelmätyökaluna RHEL:ssä, joten miksi tämä johtaa?

Tosiasia on, että monet Python-kehittäjät harkitsevat edelleen siirtymistä Python 2:sta Python 2:een, kun taas itse Python 3:a kehitetään aktiivisesti ja uusia versioita ilmestyy jatkuvasti. Siksi järjestelmä Python siirrettiin uuteen pakettiin, jotta voidaan vastata vakaiden järjestelmätyökalujen tarpeeseen ja tarjota käyttäjille pääsy useisiin uusiin Python-versioihin, ja se tarjosi mahdollisuuden asentaa sekä Python 2.7 että 3.6. Lisätietoa muutoksista ja niiden tekemisen syistä löytyy julkaisusta Langdon Whiten blogi (Langdon White).

Pythonin käyttö edellyttää siis vain kahden paketin asentamista, ja python3-pip on mukana riippuvuutena.

sudo yum install python36 python3-virtualenv

Mikset käyttäisi suoria moduulikutsuja kuten Langdon ehdottaa ja asenna pip3? Tulevaa automaatiota silmällä pitäen tiedetään, että Ansible vaatii pip-asennuksen toimiakseen, koska pip-moduuli ei tue virtualenvs-sovellusta mukautetulla pip-suoritustiedostolla.

Kun käytössäsi on toimiva python3-tulkki, voit jatkaa Djangon asennusprosessia ja saada toimivan järjestelmän muiden komponentteihimme. Internetissä on monia toteutusvaihtoehtoja. Tässä on yksi versio, mutta käyttäjät voivat käyttää omia prosessejaan.

Asennamme oletuksena RHEL 8:ssa saatavilla olevat PostgreSQL- ja Nginx-versiot Yumin avulla.

sudo yum install nginx postgresql-server

PostgreSQL vaatii psycopg2:n, mutta sen on oltava saatavilla vain virtualenv-ympäristössä, joten asennamme sen pip3:lla yhdessä Djangon ja Gunicornin kanssa. Mutta ensin meidän on määritettävä virtualenv.

Django-projektien oikean asennuspaikan valinnasta käydään aina paljon keskustelua, mutta jos olet epävarma, voit aina kääntyä Linuxin tiedostojärjestelmähierarkiastandardin puoleen. Tarkemmin sanottuna FHS sanoo, että /srv:tä käytetään: "tallentamaan isäntäkohtaisia ​​tietoja – järjestelmän tuottamia tietoja, kuten verkkopalvelintietoja ja komentosarjoja, FTP-palvelimille tallennettuja tietoja ja ohjaamaan järjestelmätietovarastoja." versiot (näkyy FHS:ssä -2.3 vuonna 2004).

Tämä on juuri meidän tapaus, joten laitamme kaiken tarvitsemamme /srv:hen, joka on sovelluksemme käyttäjän (pilvikäyttäjä) omistama.

sudo mkdir /srv/djangoapp
sudo chown cloud-user:cloud-user /srv/djangoapp
cd /srv/djangoapp
virtualenv django
source django/bin/activate
pip3 install django gunicorn psycopg2
./django-admin startproject djangoapp /srv/djangoapp

PostgreSQL:n ja Djangon käyttöönotto on helppoa: luo tietokanta, luo käyttäjä, määritä käyttöoikeudet. Yksi asia, joka tulee muistaa PostgreSQL:n asennuksen alussa, on postgresql-setup-skripti, joka asennetaan postgresql-server-paketin mukana. Tämä komentosarja auttaa sinua suorittamaan tietokantaklusterin hallintaan liittyviä perustehtäviä, kuten klusterin alustuksen tai päivitysprosessin. Uuden PostgreSQL-ilmentymän määrittämiseksi RHEL-järjestelmässä meidän on suoritettava komento:

sudo /usr/bin/postgresql-setup -initdb

Tämän jälkeen voit käynnistää PostgreSQL:n systemd:llä, luoda tietokannan ja määrittää projektin Djangossa. Muista käynnistää PostgreSQL uudelleen sen jälkeen, kun olet tehnyt muutoksia asiakkaan todennuksen määritystiedostoon (yleensä pg_hba.conf) salasanan tallennuksen määrittämiseksi sovelluksen käyttäjälle. Jos kohtaat muita ongelmia, muista muuttaa IPv4- ja IPv6-asetukset pg_hba.conf-tiedostossa.

systemctl enable -now postgresql

sudo -u postgres psql
postgres=# create database djangoapp;
postgres=# create user djangouser with password 'qwer4321';
postgres=# alter role djangouser set client_encoding to 'utf8';
postgres=# alter role djangouser set default_transaction_isolation to 'read committed';
postgres=# alter role djangouser set timezone to 'utc';
postgres=# grant all on DATABASE djangoapp to djangouser;
postgres=# q

Tiedostossa /var/lib/pgsql/data/pg_hba.conf:

# IPv4 local connections:
host    all        all 0.0.0.0/0                md5
# IPv6 local connections:
host    all        all ::1/128                 md5

Tiedostossa /srv/djangoapp/settings.py:

# Database
DATABASES = {
   'default': {
       'ENGINE': 'django.db.backends.postgresql_psycopg2',
       'NAME': '{{ db_name }}',
       'USER': '{{ db_user }}',
       'PASSWORD': '{{ db_password }}',
       'HOST': '{{ db_host }}',
   }
}

Kun olet määrittänyt tiedoston settings.py projektissa ja määrittänyt tietokannan asetukset, voit käynnistää kehityspalvelimen varmistaaksesi, että kaikki toimii. Kehityspalvelimen käynnistämisen jälkeen on hyvä idea luoda admin-käyttäjä, joka testaa yhteyttä tietokantaan.

./manage.py runserver 0.0.0.0:8000
./manage.py createsuperuser

WSGI? Wai?

Kehityspalvelin on hyödyllinen testaukseen, mutta sovelluksen suorittamiseksi sinun on määritettävä Web Server Gateway Interface (WSGI) -palvelin ja -välityspalvelin. On olemassa useita yleisiä yhdistelmiä, esimerkiksi Apache HTTPD uWSGI:n kanssa tai Nginx Gunicornilla.

Web Server Gateway Interfacen tehtävänä on välittää pyynnöt web-palvelimelta Python-verkkokehykseen. WSGI on jäänne kauheasta menneisyydestä, kun CGI-moottorit olivat olemassa, ja nykyään WSGI on tosiasiallinen standardi käytetystä verkkopalvelimesta tai Python-kehyksestä riippumatta. Mutta huolimatta sen laajasta käytöstä, näiden kehysten kanssa työskentelyssä on edelleen monia vivahteita ja monia valintoja. Tässä tapauksessa yritämme luoda vuorovaikutuksen Gunicornin ja Nginxin välille pistorasian kautta.

Koska molemmat komponentit on asennettu samalle palvelimelle, yritetään käyttää UNIX-liitäntää verkkopistokkeen sijaan. Koska viestintä vaatii joka tapauksessa pistorasian, yritetään ottaa vielä yksi askel ja konfiguroida pistorasian aktivointi Gunicornille systemd:n ​​kautta.

Socket-aktivoitujen palveluiden luontiprosessi on melko yksinkertainen. Ensin luodaan yksikkötiedosto, joka sisältää ListenStream-käskyn, joka osoittaa kohtaan, jossa UNIX-kanta luodaan, ja sitten palvelulle yksikkötiedosto, jossa Requires-direktiivi osoittaa socket-yksikkötiedostoon. Sitten palveluyksikkötiedostossa ei jää enää muuta kuin kutsua Gunicornia virtuaaliympäristöstä ja luoda WSGI-sidos UNIX-socketille ja Django-sovellukselle.

Tässä on esimerkkejä yksikkötiedostoista, joita voit käyttää perustana. Ensin asetamme pistorasia.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Nyt sinun on määritettävä Gunicorn-daemon.

[Unit]
Description=Gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=cloud-user
Group=cloud-user
WorkingDirectory=/srv/djangoapp

ExecStart=/srv/djangoapp/django/bin/gunicorn 
         —access-logfile - 
         —workers 3 
         —bind unix:gunicorn.sock djangoapp.wsgi

[Install]
WantedBy=multi-user.target

Nginxille on yksinkertainen asia luoda välityspalvelimen määritystiedostoja ja määrittää hakemisto staattisen sisällön tallentamiseksi, jos käytät sellaista. RHEL:ssä Nginx-määritystiedostot sijaitsevat hakemistossa /etc/nginx/conf.d. Voit kopioida seuraavan esimerkin tiedostoon /etc/nginx/conf.d/default.conf ja käynnistää palvelun. Varmista, että asetat palvelimen_nimi vastaamaan isäntänimeäsi.

server {
   listen 80;
   server_name 8beta1.example.com;

   location = /favicon.ico { access_log off; log_not_found off; }
   location /static/ {
       root /srv/djangoapp;
   }

   location / {
       proxy_set_header Host $http_host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
       proxy_pass http://unix:/run/gunicorn.sock;
   }
}

Käynnistä Gunicorn-pistoke ja Nginx systemd:llä ja olet valmis aloittamaan testauksen.

Huono yhdyskäytävävirhe?

Jos kirjoitat osoitteen selaimeesi, saat todennäköisesti 502 Bad Gateway -virheilmoituksen. Se voi johtua väärin määritetyistä UNIX-socketin käyttöoikeuksista tai monimutkaisemmista ongelmista, jotka liittyvät SELinuxin pääsynhallintaan.

Nginx-virhelokissa näet seuraavanlaisen rivin:

2018/12/18 15:38:03 [crit] 12734#0: *3 connect() to unix:/run/gunicorn.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.122.1, server: 8beta1.example.com, request: "GET / HTTP/1.1", upstream: "http://unix:/run/gunicorn.sock:/", host: "8beta1.example.com"

Jos testaamme Gunicornia suoraan, saamme tyhjän vastauksen.

curl —unix-socket /run/gunicorn.sock 8beta1.example.com

Selvitetään, miksi näin tapahtuu. Jos avaat lokin, näet todennäköisesti, että ongelma liittyy SELinuxiin. Koska käytämme demonia, jolle ei ole luotu käytäntöä, se on merkitty muodossa init_t. Testataan tätä teoriaa käytännössä.

sudo setenforce 0

Kaikki tämä voi aiheuttaa kritiikkiä ja veren kyyneleitä, mutta tämä on vain prototyypin virheenkorjausta. Poistetaan tarkistus käytöstä vain varmistaaksemme, että tämä on ongelma, minkä jälkeen palautamme kaiken takaisin paikoilleen.

Päivittämällä sivun selaimessa tai suorittamalla curl-komennon uudelleen, näet Django-testisivun.

Joten varmistuttuamme, että kaikki toimii ja lupaongelmia ei enää ole, otamme SELinuxin uudelleen käyttöön.

sudo setenforce 1

En puhu tässä audit2allowista tai hälytyspohjaisten käytäntöjen luomisesta sepolgenin avulla, koska varsinaista Django-sovellusta ei tällä hetkellä ole, joten ei ole täydellistä karttaa siitä, mitä Gunicorn saattaa haluta käyttää ja mihin sen pitäisi kieltää pääsy. Siksi on välttämätöntä pitää SELinux käynnissä järjestelmän suojaamiseksi ja samalla sallia sovelluksen toimia ja jättää viestejä tarkastuslokiin, jotta niistä voidaan sitten luoda varsinainen käytäntö.

Sallivien verkkotunnusten määrittäminen

Kaikki eivät ole kuulleet sallituista verkkotunnuksista SELinuxissa, mutta ne eivät ole mitään uutta. Monet jopa työskentelivät heidän kanssaan tietämättään. Kun käytäntö luodaan valvontasanomien perusteella, luotu käytäntö edustaa ratkaistua toimialuetta. Yritetään luoda yksinkertainen lupakäytäntö.

Luodaksesi tietyn sallitun verkkotunnuksen Gunicornille, tarvitset jonkinlaisen käytännön ja sinun on myös merkittävä asianmukaiset tiedostot. Lisäksi tarvitaan työkaluja uusien politiikkojen kokoamiseen.

sudo yum install selinux-policy-devel

Sallittujen verkkotunnusten mekanismi on loistava työkalu ongelmien tunnistamiseen, varsinkin kun kyseessä on mukautettu sovellus tai sovelluksia, jotka toimitetaan ilman jo luotuja käytäntöjä. Tässä tapauksessa Gunicornin sallittu verkkotunnuksen käytäntö on mahdollisimman yksinkertainen – määritä päätyyppi (gunicorn_t), ilmoita tyyppi, jota käytämme useiden suoritettavien tiedostojen merkitsemiseen (gunicorn_exec_t), ja määritä sitten siirtymäjärjestelmä, jotta se merkitsee oikein. käynnissä olevat prosessit. Viimeinen rivi asettaa käytännön oletusarvoisesti käyttöön, kun se ladataan.

gunicorn.te:

policy_module(gunicorn, 1.0)

type gunicorn_t;
type gunicorn_exec_t;
init_daemon_domain(gunicorn_t, gunicorn_exec_t)
permissive gunicorn_t;

Voit kääntää tämän käytäntötiedoston ja lisätä sen järjestelmääsi.

make -f /usr/share/selinux/devel/Makefile
sudo semodule -i gunicorn.pp

sudo semanage permissive -a gunicorn_t
sudo semodule -l | grep permissive

Katsotaanpa, estääkö SELinux jotain muuta kuin mitä tuntematon demonimme käyttää.

sudo ausearch -m AVC

type=AVC msg=audit(1545315977.237:1273): avc:  denied { write } for pid=19400 comm="nginx" name="gunicorn.sock" dev="tmpfs" ino=52977 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:var_run_t:s0 tclass=sock_file permissive=0

SELinux estää Nginxiä kirjoittamasta tietoja Gunicornin käyttämään UNIX-liitäntään. Yleensä tällaisissa tapauksissa politiikka alkaa muuttua, mutta edessä on muita haasteita. Voit myös muuttaa verkkotunnuksen asetuksia rajoitustoimialueesta käyttöoikeusverkkotunnukseksi. Siirretään nyt httpd_t käyttöoikeusverkkotunnukseen. Tämä antaa Nginxille tarvittavat käyttöoikeudet ja voimme jatkaa edelleen virheenkorjaustyötä.

sudo semanage permissive -a httpd_t

Joten kun olet onnistunut pitämään SELinuxin suojattuna (sinun ei todellakaan pidä jättää SELinux-projektia rajoitettuun tilaan) ja käyttöoikeusalueet on ladattu, sinun on selvitettävä, mikä tarkalleen on merkittävä gunicorn_exec_t, jotta kaikki toimisi oikein uudelleen. Yritetään vierailla verkkosivustolla nähdäksesi uusia viestejä pääsyrajoituksista.

sudo ausearch -m AVC -c gunicorn

Näet paljon viestejä, jotka sisältävät 'comm="gunicorn"' ja jotka tekevät eri asioita tiedostoissa /srv/djangoapp, joten tämä on selvästikin yksi niistä komennoista, jotka kannattaa merkitä.

Mutta lisäksi näkyviin tulee tällainen viesti:

type=AVC msg=audit(1545320700.070:1542): avc:  denied { execute } for pid=20704 comm="(gunicorn)" name="python3.6" dev="vda3" ino=8515706 scontext=system_u:system_r:init_t:s0 tcontext=unconfined_u:object_r:var_t:s0 tclass=file permissive=0

Jos katsot gunicorn-palvelun tilaa tai suoritat ps-komennon, et näe käynnissä olevia prosesseja. Näyttää siltä, ​​​​että gunicorn yrittää käyttää Python-tulkkia virtualenv-ympäristössämme mahdollisesti suorittaakseen työkomentosarjoja. Joten nyt merkitään nämä kaksi suoritettavaa tiedostoa ja tarkistetaan, voimmeko avata Django-testisivumme.

chcon -t gunicorn_exec_t /srv/djangoapp/django/bin/gunicorn /srv/djangoapp/django/bin/python3.6

Gunicorn-palvelu on käynnistettävä uudelleen ennen kuin uusi tunniste voidaan valita. Voit käynnistää sen heti uudelleen tai lopettaa palvelun ja antaa socketin käynnistää sen, kun avaat sivuston selaimessa. Varmista ps:n avulla, että prosessit ovat vastaanottaneet oikeat tarrat.

ps -efZ | grep gunicorn

Älä unohda luoda normaalia SELinux-käytäntöä myöhemmin!

Jos katsot nyt AVC-viestejä, viimeinen viesti sisältää permissive=1 kaikelle sovellukseen liittyvälle ja permissive=0 muulle järjestelmälle. Jos ymmärrät, millaisen pääsyn todellinen sovellus tarvitsee, voit nopeasti löytää parhaan tavan ratkaista tällaiset ongelmat. Mutta siihen asti on parasta pitää järjestelmä suojattuna ja saada selkeä, käyttökelpoinen tarkastus Django-projektista.

sudo ausearch -m AVC

Tapahtui!

Toimiva Django-projekti on ilmestynyt Nginxiin ja Gunicorn WSGI:hen perustuvalla käyttöliittymällä. Määritimme Python 3:n ja PostgreSQL 10:n RHEL 8:n beta-arkistoista. Nyt voit siirtyä eteenpäin ja luoda (tai yksinkertaisesti ottaa käyttöön) Django-sovelluksia tai tutkia muita käytettävissä olevia työkaluja RHEL 8 Betassa automatisoidaksesi määritysprosessin, parantaaksesi suorituskykyä tai jopa säilöäksesi tämän kokoonpanon.

Lähde: will.com

Lisää kommentti