RHEL 8 beetatöötuba: toimivate veebirakenduste loomine

RHEL 8 Beta pakub arendajatele palju uusi funktsioone, mille loetlemine võib võtta lehekülgi, kuid praktikas on uute asjade õppimine alati parem, seega pakume allpool töötuba Red Hat Enterprise Linux 8 Beta baasil põhineva rakenduse infrastruktuuri loomisest.

RHEL 8 beetatöötuba: toimivate veebirakenduste loomine

Võtame aluseks arendajate seas populaarse programmeerimiskeele Python, Django ja PostgreSQL-i kombinatsiooni, mis on rakenduste loomiseks üsna levinud kombinatsioon, ning konfigureerime RHEL 8 Beta nendega töötama. Seejärel lisame veel paar (liigitamata) koostisosa.

Testikeskkond muutub, sest huvitav on uurida automatiseerimise võimalusi, töötada konteineritega ja proovida keskkondi mitme serveriga. Uue projektiga alustamiseks võite alustada väikese ja lihtsa prototüübi käsitsi loomisega, et saaksite täpselt näha, mis peab juhtuma ja kuidas see toimib, ning seejärel jätkata automatiseerimise ja keerukamate konfiguratsioonide loomisega. Täna räägime sellise prototüübi loomisest.

Alustame RHEL 8 Beta VM-i kujutise juurutamisega. Saate installida virtuaalse masina nullist või kasutada beetatellimusega saadaolevat KVM-i külalispilti. Külaliskujutise kasutamisel peate konfigureerima virtuaalse CD, mis sisaldab metaandmeid ja kasutajaandmeid pilve lähtestamiseks (pilveinit). Kettastruktuuri ega saadaolevate pakettidega ei pea te midagi erilist tegema, sobib iga konfiguratsioon.

Vaatame kogu protsessi lähemalt.

Django installimine

Django uusima versiooni puhul vajate Python 3.5 või uuema versiooniga virtuaalset keskkonda (virtualenv). Beeta märkustes näete, et Python 3.6 on saadaval, kontrollime, kas see on tõesti nii:

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

Red Hat kasutab Pythonit aktiivselt RHEL-is süsteemi tööriistakomplektina, miks see nii on?

Fakt on see, et paljud Pythoni arendajad kaaluvad endiselt Python 2-lt Python 2-le üleminekut, samal ajal kui Python 3 ise on aktiivses arenduses ning pidevalt ilmub uusi ja uusi versioone. Seetõttu viidi süsteem Python üle uude paketti ja võimaldas installida nii Python 2.7 kui ka 3.6, et rahuldada vajadus stabiilsete süsteemitööriistade järele, pakkudes samal ajal kasutajatele juurdepääsu Pythoni erinevatele uutele versioonidele. Lisateavet muudatuste ja nende tegemise põhjuste kohta leiate väljaandest aastal Langdon White'i ajaveeb (Langdon White).

Nii et Pythoni tööle saamiseks peate installima ainult kaks paketti, mille sõltuvusena on kaasas python3-pip.

sudo yum install python36 python3-virtualenv

Miks mitte kasutada mooduli otsekutseid, nagu Langdon soovitab, ja installida pip3? Pidades silmas eelseisvat automatiseerimist, on teada, et Ansible nõuab töötamiseks installitud pip-i, kuna pip-moodul ei toeta kohandatud pip-käivitatavaga virtualenv-sid.

Kui teie käsutuses on töötav python3 tõlk, saate jätkata Django installiprotsessiga ja omada töötavat süsteemi koos meie muude komponentidega. Internetis on palju rakendusvõimalusi. Siin on üks versioon, kuid kasutajad saavad kasutada oma protsesse.

Installime vaikimisi RHEL 8-s saadaolevad PostgreSQL-i ja Nginxi versioonid Yumi abil.

sudo yum install nginx postgresql-server

PostgreSQL nõuab psycopg2, kuid see peab olema saadaval ainult virtualenv-keskkonnas, nii et installime selle pip3 abil koos Django ja Gunicorniga. Kuid kõigepealt peame seadistama virtualenv.

Django projektide installimiseks õige koha valimise üle vaieldakse alati palju, kuid kahtluse korral võite alati pöörduda Linuxi failisüsteemi hierarhia standardi poole. Täpsemalt ütleb FHS, et /srv kasutatakse: "hostispetsiifiliste andmete salvestamiseks – süsteemi poolt toodetavate andmete, näiteks veebiserveri andmete ja skriptide, FTP-serveritesse salvestatud andmete ja süsteemihoidlate juhtimiseks." versioonid (ilmuvad FHS-is -2.3 aastal 2004).

See on täpselt meie juhtum, seega paneme kõik, mida vajame, /srv-sse, mis kuulub meie rakenduse kasutajale (pilvekasutaja).

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-i ja Django seadistamine on lihtne: looge andmebaas, looge kasutaja, seadistage õigused. Üks asi, mida PostgreSQL-i esmasel installimisel meeles pidada, on postgresql-setup skript, mis installitakse koos paketiga postgresql-server. See skript aitab teil täita andmebaasi klastri administreerimisega seotud põhitoiminguid, nagu klastri initsialiseerimine või täiendusprotsess. Uue PostgreSQL-i eksemplari konfigureerimiseks RHEL-süsteemis peame käivitama käsu:

sudo /usr/bin/postgresql-setup -initdb

Seejärel saate käivitada PostgreSQL-i kasutades systemd, luua andmebaasi ja seadistada Djangos projekti. Ärge unustage PostgreSQL-i taaskäivitada pärast kliendi autentimise konfiguratsioonifailis (tavaliselt pg_hba.conf) muutmist, et konfigureerida rakenduse kasutaja paroolisalvestus. Kui teil tekib muid probleeme, muutke failis pg_hba.conf kindlasti IPv4 ja IPv6 sätteid.

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

Failis /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

Failis /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 }}',
   }
}

Pärast faili settings.py seadistamist projektis ja andmebaasi konfiguratsiooni seadistamist saate käivitada arendusserveri, et veenduda, et kõik töötab. Pärast arendusserveri käivitamist on hea luua admin kasutaja, et testida ühendust andmebaasiga.

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

WSGI? Wai?

Arendusserver on testimiseks kasulik, kuid rakenduse käivitamiseks peate konfigureerima Web Server Gateway Interface (WSGI) jaoks sobiva serveri ja puhverserveri. Levinud kombinatsioone on mitu, näiteks Apache HTTPD uWSGI-ga või Nginx Gunicorniga.

Veebiserveri lüüsi liidese ülesanne on päringute edastamine veebiserverist Pythoni veebiraamistikku. WSGI on jäänuk kohutavast minevikust, kui CGI mootorid olid olemas, ja tänapäeval on WSGI de facto standard, olenemata kasutatavast veebiserverist või Pythoni raamistikust. Kuid hoolimata selle laialdasest kasutamisest on nende raamistikega töötamisel endiselt palju nüansse ja palju valikuid. Sel juhul proovime luua Gunicorni ja Nginxi vahelise suhtluse pistikupesa kaudu.

Kuna mõlemad komponendid on installitud samasse serverisse, proovime võrgupesa asemel kasutada UNIX-i pesa. Kuna side nõuab igal juhul pistikupesa, proovime teha veel ühe sammu ja konfigureerida Gunicorni jaoks pistikupesa aktiveerimine systemd kaudu.

Pistikupesaga aktiveeritud teenuste loomise protsess on üsna lihtne. Esiteks luuakse ühikfail, mis sisaldab ListenStreami käskkirja, mis osutab UNIX-i sokli loomise punktile, seejärel teenuse ühikfail, milles käsk Requires osutab sokliüksuse failile. Seejärel jääb teenindusüksuse failis vaid Gunicornile virtuaalsest keskkonnast helistamine ning UNIX-i pesa ja Django rakenduse WSGI-side loomine.

Siin on mõned näited ühikfailidest, mida saate aluseks võtta. Kõigepealt seadistame pistikupesa.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Nüüd peate konfigureerima Gunicorni deemoni.

[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

Nginxi jaoks on lihtne luua puhverserveri konfiguratsioonifailid ja seadistada kataloog staatilise sisu salvestamiseks, kui kasutate seda. RHEL-is asuvad Nginxi konfiguratsioonifailid /etc/nginx/conf.d. Saate kopeerida järgmise näite faili /etc/nginx/conf.d/default.conf ja käivitada teenus. Veenduge, et serveri_nimi vastaks teie hostinimele.

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äivitage Gunicorni pesa ja Nginx kasutades systemd ja olete valmis testima.

Halb lüüsi viga?

Kui sisestate aadressi oma brauserisse, kuvatakse suure tõenäosusega viga 502 Bad Gateway. Selle põhjuseks võivad olla valesti konfigureeritud UNIX-i pesaõigused või keerulisemad probleemid, mis on seotud SELinuxi juurdepääsukontrolliga.

Nginxi vealogis näete sellist rida:

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"

Kui proovime Gunicorni otse, saame tühja vastuse.

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

Mõelgem välja, miks see juhtub. Kui avate logi, näete suure tõenäosusega, et probleem on seotud SELinuxiga. Kuna meil on deemon, mille jaoks pole poliitikat loodud, märgitakse see kui init_t. Testime seda teooriat praktikas.

sudo setenforce 0

Kõik see võib põhjustada kriitikat ja pisaraid, kuid see on vaid prototüübi silumine. Keelame kontrolli lihtsalt veendumaks, et see on probleem, misjärel tagastame kõik oma kohale tagasi.

Kui värskendate lehte brauseris või käivitate uuesti curl käsu, näete Django testlehte.

Seega, olles veendunud, et kõik töötab ja lubadega probleeme enam pole, lubame SELinuxi uuesti.

sudo setenforce 1

Ma ei räägi siin audit2allowist ega hoiatuspõhiste poliitikate loomisest sepolgeniga, kuna praegu pole tegelikku Django rakendust, seega pole täielikku kaarti selle kohta, millele Gunicorn võiks juurde pääseda ja millele juurdepääsu keelata. Seetõttu on süsteemi kaitsmiseks vaja SELinuxi töös hoida, lubades samal ajal rakendusel töötada ja jätta teateid auditilogi, et nende põhjal saaks luua tegeliku poliitika.

Lubatavate domeenide määramine

Kõik pole kuulnud SELinuxi lubatud domeenidest, kuid need pole midagi uut. Paljud isegi töötasid nendega, ilma et oleks arugi saanud. Kui reegel luuakse audititeadete põhjal, esindab loodud reegel lahendatud domeeni. Proovime luua lihtsa loapoliitika.

Gunicorni jaoks kindla lubatud domeeni loomiseks on vaja mingit poliitikat ja ka vastavad failid tuleb ära märkida. Lisaks on uute poliitikate koostamiseks vaja tööriistu.

sudo yum install selinux-policy-devel

Lubatud domeenide mehhanism on suurepärane tööriist probleemide tuvastamiseks, eriti kui tegemist on kohandatud rakendusega või rakendustega, mis tarnitakse ilma juba loodud poliitikata. Sel juhul on Gunicorni lubatud domeenipoliitika võimalikult lihtne – deklareerige põhitüüp (gunicorn_t), deklareerige tüüp, mida kasutame mitme käivitatava faili märgistamiseks (gunicorn_exec_t) ja seejärel seadistage süsteemile üleminek õigesti märgistamiseks jooksvad protsessid. Viimane rida määrab poliitika laadimise ajal vaikimisi lubatud.

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;

Saate selle poliitikafaili kompileerida ja oma süsteemi lisada.

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

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

Kontrollime, kas SELinux blokeerib midagi muud peale selle, millele meie tundmatu deemon juurde pääseb.

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 takistab Nginxil andmeid kirjutamast Gunicorni kasutatavasse UNIX-i pesasse. Tavaliselt hakkavad sellistel juhtudel poliitika muutuma, kuid ees ootavad muud väljakutsed. Samuti saate muuta domeeni seadeid piirangudomeenilt lubade domeeniks. Liigume nüüd httpd_t lubade domeeni. See annab Nginxile vajaliku juurdepääsu ja saame jätkata edasist silumistööd.

sudo semanage permissive -a httpd_t

Seega, kui olete suutnud SELinuxi kaitstuna hoida (te tõesti ei tohiks jätta SELinuxi projekti piiratud režiimi) ja lubade domeenid on laaditud, peate välja mõtlema, mis täpselt tuleb märkida kui gunicorn_exec_t, et kõik korralikult töötaks uuesti. Proovime külastada veebisaiti, et näha uusi sõnumeid juurdepääsupiirangute kohta.

sudo ausearch -m AVC -c gunicorn

Näete palju sõnumeid, mis sisaldavad 'comm="gunicorn"' ja mis teevad failides /srv/djangoapp erinevaid toiminguid, seega on see ilmselgelt üks käskudest, mida tasub märgistada.

Kuid lisaks ilmub selline teade:

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

Kui vaatate gunicorni teenuse olekut või käivitate käsku ps, ei näe te ühtegi töötavat protsessi. Paistab, et gunicorn üritab meie virtualenv-keskkonnas ligi pääseda Pythoni tõlgile, võib-olla tööliste skriptide käitamiseks. Märgistame nüüd need kaks käivitatavat faili ja kontrollime, kas saame avada oma Django testlehe.

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

Gunicorni teenus tuleb enne uue sildi valimist taaskäivitada. Saate selle kohe taaskäivitada või teenuse peatada ja lasta pesal selle käivitada, kui avate saidi brauseris. Kontrollige ps-i abil, et protsessid on saanud õiged sildid.

ps -efZ | grep gunicorn

Ärge unustage hiljem luua tavalist SELinuxi poliitikat!

Kui vaatate praegu AVC sõnumeid, sisaldab viimane teade permissive=1 kõige jaoks, mis on seotud rakendusega, ja permissive=0 ülejäänud süsteemi jaoks. Kui mõistate, millist juurdepääsu tegelik rakendus vajab, saate kiiresti leida parima viisi selliste probleemide lahendamiseks. Kuid seni on kõige parem hoida süsteem turvalisena ja saada selge ja kasutatav Django projekti audit.

sudo ausearch -m AVC

Juhtus!

Ilmunud on töötav Django projekt koos Nginxil ja Gunicorn WSGI-l põhineva esiosaga. Konfigureerisime Python 3 ja PostgreSQL 10 RHEL 8 beetahoidlatest. Nüüd saate edasi liikuda ja luua (või lihtsalt juurutada) Django rakendusi või uurida muid saadaolevaid tööriistu RHEL 8 beetaversioonis, et automatiseerida konfiguratsiooniprotsessi, parandada jõudlust või isegi selle konfiguratsiooni konteinerisse paigutada.

Allikas: www.habr.com

Lisa kommentaar