Radionica RHEL 8 Beta: Izrada funkcionalnih web aplikacija

RHEL 8 Beta nudi razvojnim programerima mnoge nove značajke, čije bi nabrajanje moglo oduzeti stranice, međutim, učenje novih stvari uvijek je bolje u praksi, stoga u nastavku nudimo radionicu o stvarnom stvaranju aplikacijske infrastrukture temeljene na Red Hat Enterprise Linux 8 Beta.

Radionica RHEL 8 Beta: Izrada funkcionalnih web aplikacija

Uzmimo Python, popularan programski jezik među programerima, kao osnovu, kombinaciju Django i PostgreSQL, prilično uobičajenu kombinaciju za izradu aplikacija, i konfigurirajmo RHEL 8 Beta za rad s njima. Zatim ćemo dodati još par (neklasificiranih) sastojaka.

Testno okruženje će se promijeniti, jer je zanimljivo istraživati ​​mogućnosti automatizacije, rada s kontejnerima i isprobavanja okruženja s više poslužitelja. Da biste započeli s novim projektom, možete započeti ručnim stvaranjem malog, jednostavnog prototipa kako biste mogli točno vidjeti što se treba dogoditi i kako to djeluje, a zatim prijeđite na automatizaciju i stvaranje složenijih konfiguracija. Danas govorimo o stvaranju takvog prototipa.

Počnimo s implementacijom RHEL 8 Beta VM slike. Možete instalirati virtualni stroj od nule ili koristiti KVM gostujuću sliku dostupnu uz vašu beta pretplatu. Kada koristite gostujuću sliku, morat ćete konfigurirati virtualni CD koji će sadržavati metapodatke i korisničke podatke za inicijalizaciju oblaka (cloud-init). Ne morate učiniti ništa posebno sa strukturom diska ili dostupnim paketima; bilo koja konfiguracija će poslužiti.

Pogledajmo pobliže cijeli proces.

Instalacija Djanga

S najnovijom verzijom Djanga trebat će vam virtualno okruženje (virtualenv) s Pythonom 3.5 ili novijim. U beta bilješkama možete vidjeti da je Python 3.6 dostupan, provjerimo je li to doista tako:

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

Red Hat aktivno koristi Python kao sistemski alat u RHEL-u, pa zašto to rezultira?

Činjenica je da mnogi programeri Pythona još uvijek razmišljaju o prijelazu s Pythona 2 na Python 2, dok je sam Python 3 u aktivnom razvoju i stalno se pojavljuje sve više i više novih verzija. Stoga, kako bi se zadovoljila potreba za stabilnim sistemskim alatima dok se korisnicima nudi pristup raznim novim verzijama Pythona, sistemski Python premješten je u novi paket i pruža mogućnost instaliranja Pythona 2.7 i 3.6. Više informacija o promjenama i razlozima do njih možete pronaći u publikaciji u Blog Langdona Whitea (Langdon White).

Dakle, da biste pokrenuli Python, trebate instalirati samo dva paketa, s uključenim python3-pip kao ovisnošću.

sudo yum install python36 python3-virtualenv

Zašto ne koristiti izravne pozive modula kao što Langdon predlaže i instalirati pip3? Imajući na umu nadolazeću automatizaciju, poznato je da će Ansible zahtijevati instaliran pip za rad, budući da pip modul ne podržava virtualenvs s prilagođenom pip izvršnom datotekom.

S funkcionalnim python3 tumačem koji vam je na raspolaganju, možete nastaviti s postupkom instalacije Djanga i imati radni sustav zajedno s ostalim našim komponentama. Na Internetu su dostupne mnoge mogućnosti implementacije. Ovdje je predstavljena jedna verzija, ali korisnici mogu koristiti vlastite procese.

Mi ćemo instalirati PostgreSQL i Nginx verzije dostupne u RHEL 8 prema zadanim postavkama koristeći Yum.

sudo yum install nginx postgresql-server

PostgreSQL će zahtijevati psycopg2, ali mora biti dostupan samo u virtualenv okruženju, pa ćemo ga instalirati koristeći pip3 zajedno s Djangom i Gunicorn. Ali prvo moramo postaviti virtualenv.

Uvijek postoji mnogo rasprava o odabiru pravog mjesta za instalaciju Django projekata, ali kada ste u nedoumici, uvijek se možete obratiti na Linux Filesystem Hierarchy Standard. Konkretno, FHS kaže da se /srv koristi za: "pohranjivanje podataka specifičnih za host—podataka koje sustav proizvodi, kao što su podaci i skripte web poslužitelja, podaci pohranjeni na FTP poslužiteljima i spremišta sustava za kontrolu." verzije (koje se pojavljuju u FHS-u -2.3 u 2004. godini)."

Ovo je upravo naš slučaj pa sve što nam treba stavljamo u /srv koji je u vlasništvu korisnika naše aplikacije (cloud-user).

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

Postavljanje PostgreSQL-a i Djanga je jednostavno: izradite bazu podataka, stvorite korisnika, konfigurirajte dopuštenja. Jedna stvar koju morate imati na umu kada početno instalirate PostgreSQL je postgresql-setup skripta koja je instalirana s postgresql-server paketom. Ova skripta vam pomaže u obavljanju osnovnih zadataka povezanih s administracijom klastera baze podataka, kao što je inicijalizacija klastera ili proces nadogradnje. Da bismo konfigurirali novu PostgreSQL instancu na RHEL sustavu, moramo pokrenuti naredbu:

sudo /usr/bin/postgresql-setup -initdb

Zatim možete pokrenuti PostgreSQL koristeći systemd, stvoriti bazu podataka i postaviti projekt u Djangu. Ne zaboravite ponovno pokrenuti PostgreSQL nakon što napravite promjene u konfiguracijskoj datoteci provjere autentičnosti klijenta (obično pg_hba.conf) kako biste konfigurirali pohranu lozinki za korisnika aplikacije. Ako naiđete na druge poteškoće, svakako promijenite IPv4 i IPv6 postavke u datoteci pg_hba.conf.

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

U datoteci /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

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

Nakon konfiguriranja datoteke settings.py u projektu i postavljanja konfiguracije baze podataka, možete pokrenuti razvojni poslužitelj kako biste bili sigurni da sve radi. Nakon pokretanja razvojnog poslužitelja, dobra je ideja stvoriti admin korisnika kako bi se testirala veza s bazom podataka.

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

WSGI? Wai?

Razvojni poslužitelj je koristan za testiranje, ali za pokretanje aplikacije morate konfigurirati odgovarajući poslužitelj i proxy za sučelje pristupnika web poslužitelja (WSGI). Postoji nekoliko uobičajenih kombinacija, na primjer, Apache HTTPD s uWSGI ili Nginx s Gunicorn.

Posao sučelja pristupnika web poslužitelja je prosljeđivanje zahtjeva s web poslužitelja web okviru Python. WSGI je relikt užasne prošlosti kada su postojali CGI motori, a danas je WSGI de facto standard, bez obzira na web poslužitelj ili Python okvir koji se koristi. No unatoč širokoj upotrebi, još uvijek postoji mnogo nijansi pri radu s tim okvirima i mnogo izbora. U ovom slučaju pokušat ćemo uspostaviti interakciju između Gunicorna i Nginxa putem socketa.

Budući da su obje ove komponente instalirane na istom poslužitelju, pokušajmo koristiti UNIX utičnicu umjesto mrežne utičnice. Budući da komunikacija u svakom slučaju zahtijeva utičnicu, pokušajmo napraviti još jedan korak i konfigurirati aktivaciju utičnice za Gunicorn putem systemd-a.

Proces kreiranja usluga aktiviranih utičnicama prilično je jednostavan. Najprije se kreira jedinična datoteka koja sadrži ListenStream direktivu koja pokazuje na točku u kojoj će se kreirati UNIX utičnica, zatim jedinična datoteka za uslugu u kojoj će direktiva Requires upućivati ​​na jediničnu datoteku utičnice. Zatim, u datoteci jedinice usluge, sve što preostaje je pozvati Gunicorn iz virtualnog okruženja i stvoriti WSGI vezanje za UNIX utičnicu i Django aplikaciju.

Evo nekoliko primjera datoteka jedinica koje možete koristiti kao osnovu. Prvo smo postavili utičnicu.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Sada trebate konfigurirati Gunicorn demona.

[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

Za Nginx, to je jednostavna stvar stvaranja proxy konfiguracijskih datoteka i postavljanja direktorija za pohranu statičkog sadržaja ako ga koristite. U RHEL-u, Nginx konfiguracijske datoteke nalaze se u /etc/nginx/conf.d. Sljedeći primjer možete kopirati u datoteku /etc/nginx/conf.d/default.conf i pokrenuti uslugu. Provjerite jeste li postavili server_name tako da odgovara vašem imenu hosta.

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;
   }
}

Pokrenite Gunicorn socket i Nginx koristeći systemd i spremni ste za početak testiranja.

Greška lošeg pristupnika?

Ako unesete adresu u svoj preglednik, najvjerojatnije ćete dobiti grešku 502 Bad Gateway. To može biti uzrokovano neispravno konfiguriranim dozvolama za UNIX utičnicu ili može biti posljedica složenijih problema povezanih s kontrolom pristupa u SELinuxu.

U zapisniku grešaka nginxa možete vidjeti redak poput ovog:

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"

Ako izravno testiramo Gunicorn, dobit ćemo prazan odgovor.

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

Hajdemo shvatiti zašto se to događa. Ako otvorite dnevnik, najvjerojatnije ćete vidjeti da je problem povezan sa SELinuxom. Budući da pokrećemo demon za koji nije kreirana politika, označen je kao init_t. Provjerimo ovu teoriju u praksi.

sudo setenforce 0

Sve ovo može izazvati kritike i krvave suze, ali ovo je samo otklanjanje pogrešaka prototipa. Isključimo provjeru samo da se uvjerimo da je to problem, nakon čega ćemo sve vratiti na svoje mjesto.

Osvježavanjem stranice u pregledniku ili ponovnim pokretanjem naše naredbe curl, možete vidjeti Django test stranicu.

Dakle, nakon što smo se uvjerili da sve radi i da više nema problema s dozvolama, ponovno uključujemo SELinux.

sudo setenforce 1

Ovdje neću govoriti o audit2allow ili stvaranju pravila temeljenih na upozorenjima sa sepolgenom, budući da trenutačno ne postoji stvarna Django aplikacija, tako da ne postoji potpuna mapa onoga čemu bi Gunicorn mogao pristupiti i čemu bi trebao zabraniti pristup. Stoga je neophodno da SELinux radi radi zaštite sustava, dok u isto vrijeme dopušta aplikaciji da radi i ostavlja poruke u revizijskom dnevniku tako da se stvarna politika može kreirati iz njih.

Određivanje permisivnih domena

Nisu svi čuli za dopuštene domene u SELinuxu, ali one nisu ništa novo. Mnogi su i radili s njima, a da toga nisu bili svjesni. Kada se politika kreira na temelju poruka revizije, kreirana politika predstavlja razriješenu domenu. Pokušajmo stvoriti jednostavnu politiku izdavanja dozvola.

Da biste stvorili određenu dopuštenu domenu za Gunicorn, potrebna vam je neka vrsta pravila, a također morate označiti odgovarajuće datoteke. Osim toga, potrebni su alati za sastavljanje novih pravila.

sudo yum install selinux-policy-devel

Mehanizam dopuštenih domena izvrstan je alat za prepoznavanje problema, posebno kada se radi o prilagođenoj aplikaciji ili aplikacijama koje se isporučuju bez već kreiranih pravila. U ovom slučaju, politika dopuštene domene za Gunicorn bit će što je moguće jednostavnija - deklarirajte glavni tip (gunicorn_t), deklarirajte tip koji ćemo koristiti za označavanje više izvršnih datoteka (gunicorn_exec_t), a zatim postavite prijelaz za sustav da ispravno označi pokrenuti procesi. Posljednji redak postavlja pravilo kao omogućeno prema zadanim postavkama u trenutku učitavanja.

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;

Možete kompajlirati ovu datoteku pravila i dodati je svom sustavu.

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

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

Provjerimo blokira li SELinux još nešto osim onoga čemu naš nepoznati demon pristupa.

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 sprječava Nginx da zapisuje podatke u UNIX utičnicu koju koristi Gunicorn. Obično se u takvim slučajevima politika počinje mijenjati, ali pred nama su drugi izazovi. Također možete promijeniti postavke domene iz domene ograničenja u domenu dopuštenja. Sada premjestimo httpd_t u domenu dozvola. To će Nginxu dati potreban pristup i možemo nastaviti s daljnjim radom na uklanjanju pogrešaka.

sudo semanage permissive -a httpd_t

Dakle, nakon što ste uspjeli održati SELinux zaštićenim (stvarno ne biste trebali ostaviti SELinux projekt u ograničenom načinu rada) i domene dopuštenja su učitane, trebate shvatiti što točno treba biti označeno kao gunicorn_exec_t da bi sve ispravno radilo opet. Pokušajmo posjetiti web stranicu kako bismo vidjeli nove poruke o ograničenjima pristupa.

sudo ausearch -m AVC -c gunicorn

Vidjet ćete puno poruka koje sadrže 'comm="gunicorn"' koje rade razne stvari na datotekama u /srv/djangoapp, tako da je ovo očito jedna od naredbi koju vrijedi označiti.

Ali osim toga, pojavljuje se poruka poput ove:

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

Ako pogledate status usluge gunicorn ili pokrenete naredbu ps, nećete vidjeti pokrenute procese. Čini se da gunicorn pokušava pristupiti Python tumaču u našem okruženju virtualenv, vjerojatno da bi pokrenuo radne skripte. Označimo sada ove dvije izvršne datoteke i provjerimo možemo li otvoriti našu Django test stranicu.

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

Uslugu gunicorn trebat će ponovno pokrenuti prije nego što se može odabrati nova oznaka. Možete ga odmah ponovno pokrenuti ili zaustaviti uslugu i pustiti da je socket pokrene kada otvorite stranicu u pregledniku. Provjerite jesu li procesi primili ispravne oznake koristeći ps.

ps -efZ | grep gunicorn

Ne zaboravite kasnije stvoriti normalnu SELinux politiku!

Ako sada pogledate AVC poruke, posljednja poruka sadrži permissive=1 za sve što se odnosi na aplikaciju i permissive=0 za ostatak sustava. Ako razumijete kakvu vrstu pristupa treba prava aplikacija, možete brzo pronaći najbolji način za rješavanje takvih problema. Ali do tada, najbolje je održavati sustav sigurnim i dobiti jasnu, upotrebljivu reviziju Django projekta.

sudo ausearch -m AVC

Dogodilo se!

Pojavio se radni Django projekt s sučeljem temeljenim na Nginxu i Gunicorn WSGI. Konfigurirali smo Python 3 i PostgreSQL 10 iz repozitorija RHEL 8 Beta. Sada možete krenuti naprijed i kreirati (ili jednostavno implementirati) Django aplikacije ili istražiti druge dostupne alate u RHEL 8 Beta za automatizaciju procesa konfiguracije, poboljšanje performansi ili čak kontejnerizaciju ove konfiguracije.

Izvor: www.habr.com

Dodajte komentar