RHEL 8 Beta radionica: Izrada radnih web aplikacija

RHEL 8 Beta nudi programerima mnoge nove funkcije, čija lista može zauzeti stranice, međutim, učenje novih stvari je uvijek bolje u praksi, pa u nastavku nudimo radionicu o stvarnom kreiranju infrastrukture aplikacije zasnovane na Red Hat Enterprise Linux 8 Beta.

RHEL 8 Beta radionica: Izrada radnih web aplikacija

Uzmimo Python, popularni programski jezik među programerima, kao osnovu, kombinaciju Djanga i PostgreSQL-a, prilično uobičajenu kombinaciju za kreiranje aplikacija, i konfigurišite RHEL 8 Beta da radi sa njima. Zatim ćemo dodati još par (neklasifikovanih) sastojaka.

Testno okruženje će se promeniti, jer je zanimljivo istražiti mogućnosti automatizacije, rada sa kontejnerima i isprobavanje okruženja sa više servera. Da biste započeli s novim projektom, možete započeti kreiranjem malog, jednostavnog prototipa ručno kako biste mogli vidjeti što se točno treba dogoditi i kako to djeluje, a zatim preći na automatizaciju i kreiranje složenijih konfiguracija. Danas govorimo o stvaranju takvog prototipa.

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

Pogledajmo detaljnije ceo proces.

Instaliranje Djanga

Uz najnoviju verziju Djanga, trebat će vam virtualno okruženje (virtualenv) sa Python-om 3.5 ili novijim. U beta beleškama možete videti da je Python 3.6 dostupan, hajde da proverimo da li je to zaista slučaj:

[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 je to rezultat?

Č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, a sve više i više novih verzija se stalno pojavljuje. Stoga, kako bi se zadovoljila potreba za stabilnim sistemskim alatima, dok korisnicima nudi pristup raznim novim verzijama Pythona, sistemski Python je premješten u novi paket i omogućio je instalaciju i Python 2.7 i 3.6. Više informacija o promjenama i zašto su napravljene možete pronaći u publikaciji u Blog Langdona Whitea (Langdon Vajt).

Dakle, da bi Python mogao da radi, potrebno je da instalirate samo dva paketa, sa uključenim python3-pip kao zavisnošću.

sudo yum install python36 python3-virtualenv

Zašto ne koristite direktne pozive modula kao što Langdon predlaže i instalirate pip3? Imajući u vidu nadolazeću automatizaciju, poznato je da će Ansible zahtijevati instaliran pip za pokretanje, budući da pip modul ne podržava virtualenvs sa prilagođenim izvršnim pip-om.

Sa ispravnim python3 interpretatorom koji vam je na raspolaganju, možete nastaviti sa procesom instalacije Djanga i imati radni sistem zajedno sa našim ostalim komponentama. Na Internetu su dostupne mnoge mogućnosti implementacije. Ovdje je predstavljena jedna verzija, ali korisnici mogu koristiti svoje vlastite procese.

Instalirat ćemo PostgreSQL i Nginx verzije dostupne u RHEL 8 po defaultu koristeći Yum.

sudo yum install nginx postgresql-server

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

Uvek postoji mnogo debata na temu izbora pravog mesta za instalaciju Django projekata, ali kada ste u nedoumici, uvek se možete obratiti Linux standardu hijerarhije sistema datoteka. Konkretno, FHS kaže da se /srv koristi za: „pohranjivanje podataka specifičnih za host—podataka koje sistem proizvodi, kao što su podaci web servera i skripte, podaci pohranjeni na FTP serverima i kontrolna spremišta sistema.“ verzije (koji se pojavljuju u FHS-u -2.3 u 2004.).

To je upravo naš slučaj, pa smo sve što nam treba stavili 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: kreirajte bazu podataka, kreirajte korisnika, konfigurirajte dozvole. Jedna stvar koju treba imati na umu pri početnoj instalaciji PostgreSQL-a je skripta postgresql-setup koja se instalira sa paketom postgresql-server. Ova skripta vam pomaže u izvođenju osnovnih zadataka povezanih s administracijom klastera baze podataka, kao što je inicijalizacija klastera ili proces nadogradnje. Da konfigurišemo novu PostgreSQL instancu na RHEL sistemu, moramo da pokrenemo naredbu:

sudo /usr/bin/postgresql-setup -initdb

Zatim možete pokrenuti PostgreSQL koristeći systemd, kreirati bazu podataka i postaviti projekat u Djangu. Ne zaboravite ponovo pokrenuti PostgreSQL nakon što napravite promjene u konfiguracijskoj datoteci za autentifikaciju klijenta (obično pg_hba.conf) kako biste konfigurirali pohranu lozinki za korisnika aplikacije. Ako naiđete na druge poteškoće, obavezno 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 konfigurisanja datoteke settings.py u projektu i podešavanja konfiguracije baze podataka, možete pokrenuti razvojni server da biste bili sigurni da sve radi. Nakon pokretanja razvojnog servera, dobra je ideja kreirati administratorskog korisnika kako bi se testirala veza s bazom podataka.

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

WSGI? Wai?

Razvojni server je koristan za testiranje, ali da biste pokrenuli aplikaciju morate konfigurisati odgovarajući server i proxy za interfejs mrežnog prolaza servera (WSGI). Postoji nekoliko uobičajenih kombinacija, na primjer, Apache HTTPD sa uWSGI ili Nginx sa Gunicorn.

Posao interfejsa mrežnog prolaza servera je da prosleđuje zahteve sa veb servera na Python web framework. WSGI je relikt užasne prošlosti kada su CGI motori postojali, a danas je WSGI de facto standard, bez obzira na korišteni web server ili Python framework. Ali unatoč širokoj upotrebi, još uvijek postoje mnoge nijanse pri radu s ovim okvirima i mnogo izbora. U ovom slučaju pokušat ćemo uspostaviti interakciju između Gunicorn-a i Nginxa preko socketa.

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

Proces kreiranja usluga aktiviranih utičnicom je prilično jednostavan. Prvo se kreira jedinična datoteka koja sadrži direktivu ListenStream koja ukazuje na tačku u kojoj će se kreirati UNIX soket, zatim jedinična datoteka za uslugu u kojoj će direktiva Requires pokazivati ​​na datoteku jedinice utičnice. Zatim, u datoteci servisne jedinice, sve što ostaje je da pozovete Gunicorn iz virtuelnog okruženja i kreirate WSGI vezu za UNIX socket i Django aplikaciju.

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

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Sada morate 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 je jednostavno kreiranje proxy konfiguracijskih datoteka i postavljanje direktorija za pohranjivanje statičkog sadržaja ako ga koristite. U RHEL-u, Nginx konfiguracijske datoteke se nalaze u /etc/nginx/conf.d. Možete kopirati sljedeći primjer u datoteku /etc/nginx/conf.d/default.conf i pokrenuti uslugu. Obavezno postavite server_name 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 mrežnog prolaza?

Ako unesete adresu u svoj pretraživač, najvjerovatnije ćete dobiti grešku 502 Bad Gateway. To može biti uzrokovano neispravno konfiguriranim dozvolama UNIX socketa, ili može biti uzrokovano složenijim problemima vezanim za kontrolu pristupa u SELinuxu.

U nginx dnevniku grešaka možete vidjeti ovu liniju:

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 direktno testiramo Gunicorn, dobićemo prazan odgovor.

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

Hajde da shvatimo zašto se to dešava. Ako otvorite dnevnik, najvjerovatnije ćete vidjeti da je problem povezan sa SELinuxom. Pošto pokrećemo demon za koji nije kreirana politika, on je označen kao init_t. Testirajmo ovu teoriju u praksi.

sudo setenforce 0

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

Osvježavanjem stranice u pretraživaču ili ponovnim pokretanjem naše curl komande, možete vidjeti Django test stranicu.

Dakle, nakon što smo se uverili da sve radi i da više nema problema sa dozvolama, ponovo omogućavamo SELinux.

sudo setenforce 1

Neću ovdje govoriti o audit2allow ili kreiranju politika zasnovanih na upozorenjima sa sepolgenom, pošto trenutno ne postoji stvarna Django aplikacija, tako da ne postoji potpuna mapa čemu bi Gunicorn mogao pristupiti i čemu bi trebao odbiti pristup. Zbog toga je neophodno da se SELinux nastavi da radi kako bi se zaštitio sistem, dok istovremeno dozvoljava da se aplikacija pokreće i ostavlja poruke u dnevniku revizije tako da se stvarna politika onda može kreirati iz njih.

Određivanje dozvoljenih domena

Nisu svi čuli za dozvoljene domene u SELinuxu, ali nisu ništa novo. Mnogi su čak i radili s njima, a da toga nisu ni svjesni. Kada se politika kreira na osnovu poruka revizije, kreirana politika predstavlja riješen domen. Pokušajmo kreirati jednostavnu politiku izdavanja dozvola.

Da biste kreirali određeni dozvoljeni domen za Gunicorn, potrebna vam je neka vrsta politike, a također morate označiti odgovarajuće datoteke. Osim toga, potrebni su alati za sastavljanje novih politika.

sudo yum install selinux-policy-devel

Mehanizam dozvoljenih domena je odličan alat za identifikaciju problema, posebno kada je u pitanju prilagođena aplikacija ili aplikacije koje se isporučuju bez već kreiranih politika. U ovom slučaju, dozvoljena politika domene za Gunicorn će biti š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 sistem da ispravno označi pokrenuti procesi. Poslednji red postavlja politiku kao podrazumevano omogućenu u trenutku kada se učita.

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 politike i dodati je svom sistemu.

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

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

Hajde da proverimo da li SELinux blokira nešto drugo osim onome čemu pristupa naš nepoznati demon.

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 sprečava Nginx da upiše podatke u UNIX socket koji koristi Gunicorn. Obično se u takvim slučajevima politike počinju mijenjati, ali pred nama su i drugi izazovi. Također možete promijeniti postavke domene iz domene ograničenja u domenu dopuštenja. Sada premjestimo httpd_t na domenu dozvola. Ovo će dati Nginx-u neophodan pristup i možemo nastaviti sa daljim radom na otklanjanju grešaka.

sudo semanage permissive -a httpd_t

Dakle, kada ste uspjeli zadržati SELinux zaštićenim (zaista ne biste trebali ostaviti SELinux projekat u ograničenom načinu rada) i kada se domeni dozvola učitaju, morate shvatiti šta tačno treba biti označeno kao gunicorn_exec_t da bi sve funkcionisalo kako treba opet. Pokušajmo posjetiti web stranicu da vidimo 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 koje vrijedi označiti.

Ali pored 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. Izgleda da gunicorn pokušava pristupiti Python interpreteru u našem virtualenv okruženju, možda da bi pokrenuo radne skripte. Dakle, hajde da označimo 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

Gunicorn uslugu će trebati ponovo pokrenuti prije nego što se može odabrati nova oznaka. Možete ga odmah ponovo pokrenuti ili zaustaviti uslugu i pustiti utičnicu da je pokrene kada otvorite stranicu u pretraživaču. Provjerite da li su procesi primili ispravne oznake pomoću ps.

ps -efZ | grep gunicorn

Ne zaboravite kasnije kreirati normalnu SELinux politiku!

Ako sada pogledate AVC poruke, zadnja poruka sadrži permissive=1 za sve što se odnosi na aplikaciju i permissive=0 za ostatak sistema. Ako shvatite kakav pristup stvarnoj aplikaciji treba, možete brzo pronaći najbolji način za rješavanje takvih problema. Ali do tada, najbolje je da sistem bude siguran i da dobijete jasnu, upotrebljivu reviziju Django projekta.

sudo ausearch -m AVC

Desilo se!

Pojavio se radni Django projekat sa frontendom baziranim na Nginxu i Gunicorn WSGI. Konfigurisali smo Python 3 i PostgreSQL 10 iz RHEL 8 Beta spremišta. Sada možete krenuti naprijed i kreirati (ili jednostavno implementirati) Django aplikacije ili istražiti druge dostupne alate u RHEL 8 Beta kako biste automatizirali proces konfiguracije, poboljšali performanse ili čak spremili ovu konfiguraciju.

izvor: www.habr.com

Dodajte komentar