Seminaras RHEL 8 Beta: veikiančių žiniatinklio programų kūrimas

RHEL 8 Beta siūlo kūrėjams daug naujų funkcijų, kurių sąrašas gali užtrukti puslapius, tačiau praktikoje išmokti naujų dalykų visada geriau, todėl žemiau siūlome seminarą, kaip iš tikrųjų sukurti taikomųjų programų infrastruktūrą, pagrįstą Red Hat Enterprise Linux 8 Beta.

Seminaras RHEL 8 Beta: veikiančių žiniatinklio programų kūrimas

Paimkime Python, populiarią programavimo kalbą tarp kūrėjų, kaip pagrindą Django ir PostgreSQL derinį, gana įprastą derinį kuriant programas, ir sukonfigūruokite RHEL 8 Beta, kad su jomis veiktų. Tada pridėsime dar porą (neklasifikuotų) ingredientų.

Testavimo aplinka keisis, nes įdomu tyrinėti automatizavimo galimybes, dirbti su konteineriais ir išbandyti aplinkas su keliais serveriais. Norėdami pradėti naują projektą, galite pradėti ranka kurdami nedidelį paprastą prototipą, kad galėtumėte tiksliai matyti, kas turi įvykti ir kaip jis sąveikauja, o tada pereikite prie automatizavimo ir sudėtingesnių konfigūracijų kūrimo. Šiandien mes kalbame apie tokio prototipo sukūrimą.

Pradėkime įdiegdami RHEL 8 Beta VM vaizdą. Galite įdiegti virtualią mašiną nuo nulio arba naudoti KVM svečio vaizdą, pasiekiamą su beta versijos prenumerata. Kai naudojate svečio vaizdą, turėsite sukonfigūruoti virtualų kompaktinį diską, kuriame bus metaduomenys ir vartotojo duomenys, skirti inicijuoti debesyje (debesis-init). Jums nereikia nieko ypatingo daryti su disko struktūra ar turimais paketais; tiks bet kokia konfigūracija.

Pažvelkime į visą procesą atidžiau.

„Django“ diegimas

Naudojant naujausią Django versiją, jums reikės virtualios aplinkos (virtualenv) su Python 3.5 ar naujesne versija. Beta versijos pastabose galite pamatyti, kad yra Python 3.6, patikrinkime, ar taip yra:

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

„Red Hat“ aktyviai naudoja „Python“ kaip sistemos įrankių rinkinį RHEL, tad kodėl taip atsiranda?

Faktas yra tas, kad daugelis Python kūrėjų vis dar svarsto galimybę pereiti nuo Python 2 prie Python 2, o pats Python 3 yra aktyviai kuriamas ir nuolat atsiranda vis daugiau naujų versijų. Todėl, siekiant patenkinti stabilių sistemos įrankių poreikį ir pasiūlyti vartotojams prieigą prie įvairių naujų Python versijų, sistema Python buvo perkelta į naują paketą ir suteikė galimybę įdiegti ir Python 2.7, ir 3.6. Daugiau informacijos apie pakeitimus ir kodėl jie buvo atlikti, rasite leidinyje, esančiame Lengdono Vaito dienoraštis (Langdon White).

Taigi, norint pradėti veikti Python, tereikia įdiegti du paketus su python3-pip kaip priklausomybe.

sudo yum install python36 python3-virtualenv

Kodėl nepasinaudojus tiesioginiais modulių iškvietimais, kaip siūlo Lengdonas, ir neįdiegus pip3? Turint omenyje būsimą automatizavimą, žinoma, kad Ansible reikės įdiegti pip, kad jis veiktų, nes pip modulis nepalaiko virtualenvs su pasirinktiniu pip vykdomuoju failu.

Turėdami veikiantį python3 vertėją, galite tęsti Django diegimo procesą ir turėti veikiančią sistemą kartu su kitais mūsų komponentais. Internete yra daug įgyvendinimo variantų. Čia pateikiama viena versija, tačiau vartotojai gali naudoti savo procesus.

Pagal numatytuosius nustatymus įdiegsime PostgreSQL ir Nginx versijas, kurias galima rasti RHEL 8, naudodami Yum.

sudo yum install nginx postgresql-server

PostgreSQL reikės psycopg2, tačiau jis turi būti pasiekiamas tik virtualenv aplinkoje, todėl įdiegsime naudodami pip3 kartu su Django ir Gunicorn. Bet pirmiausia turime nustatyti virtualenv.

Visada kyla daug diskusijų, kaip pasirinkti tinkamą vietą Django projektams įdiegti, tačiau kilus abejonių visada galite kreiptis į Linux failų sistemos hierarchijos standartą. Konkrečiai, FHS sako, kad /srv naudojamas: „saugoti konkrečius pagrindinio kompiuterio duomenis – duomenis, kuriuos sukuria sistema, pvz., žiniatinklio serverio duomenis ir scenarijus, duomenis, saugomus FTP serveriuose, ir valdyti sistemos saugyklas.“ versijos (rodomos FHS -2.3 2004 m.).

Tai yra būtent mūsų atvejis, todėl viską, ko reikia, įdedame į /srv, kuri priklauso mūsų programos vartotojui (debesų naudotojui).

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“ ir „Django“ nustatymas yra paprastas: sukurkite duomenų bazę, sukurkite vartotoją, sukonfigūruokite leidimus. Vienas dalykas, kurį reikia atsiminti iš pradžių diegiant PostgreSQL, yra postgresql-setup scenarijus, kuris įdiegiamas kartu su postgresql-server paketu. Šis scenarijus padeda atlikti pagrindines užduotis, susijusias su duomenų bazės klasterio administravimu, pvz., grupės inicijavimą arba atnaujinimo procesą. Norėdami sukonfigūruoti naują PostgreSQL egzempliorių RHEL sistemoje, turime paleisti komandą:

sudo /usr/bin/postgresql-setup -initdb

Tada galite paleisti PostgreSQL naudodami systemd, sukurti duomenų bazę ir nustatyti projektą Django. Nepamirškite iš naujo paleisti PostgreSQL, kai atlikote pakeitimus kliento autentifikavimo konfigūracijos faile (dažniausiai pg_hba.conf), kad sukonfigūruotumėte programos vartotojo slaptažodžio saugyklą. Jei susiduriate su kitais sunkumais, būtinai pakeiskite IPv4 ir IPv6 parametrus faile 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

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

В файле /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 }}',
   }
}

Sukonfigūravę failą settings.py projekte ir nustatę duomenų bazės konfigūraciją, galite paleisti kūrimo serverį, kad įsitikintumėte, jog viskas veikia. Paleidus kūrimo serverį, naudinga sukurti administratoriaus vartotoją, kad būtų galima išbandyti ryšį su duomenų baze.

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

WSGI? Wai?

Kūrimo serveris yra naudingas testavimui, tačiau norėdami paleisti programą turite sukonfigūruoti atitinkamą žiniatinklio serverio šliuzo sąsajos (WSGI) serverį ir tarpinį serverį. Yra keletas bendrų derinių, pavyzdžiui, Apache HTTPD su uWSGI arba Nginx su Gunicorn.

Žiniatinklio serverio šliuzo sąsajos užduotis yra persiųsti užklausas iš žiniatinklio serverio į Python žiniatinklio sistemą. WSGI yra baisios praeities, kai buvo CGI varikliai, reliktas, o šiandien WSGI yra de facto standartas, nepaisant naudojamo žiniatinklio serverio ar Python sistemos. Tačiau nepaisant plačiai paplitusio naudojimo, dirbant su šiomis sistemomis vis dar yra daug niuansų ir daugybė pasirinkimų. Tokiu atveju bandysime užmegzti Gunicorn ir Nginx sąveiką per lizdą.

Kadangi abu šie komponentai yra įdiegti tame pačiame serveryje, pabandykime vietoj tinklo lizdo naudoti UNIX lizdą. Kadangi ryšiui bet kuriuo atveju reikalingas lizdas, pabandykime žengti dar vieną žingsnį ir sukonfigūruoti Gunicorn lizdo aktyvavimą per systemd.

Lizdų aktyvuotų paslaugų kūrimo procesas yra gana paprastas. Pirmiausia sukuriamas vieneto failas, kuriame yra ListenStream direktyva, nurodanti tašką, kuriame bus sukurtas UNIX lizdas, tada paslaugos vieneto failas, kuriame reikalaujama direktyva nukreips į lizdo vieneto failą. Tada paslaugų vieneto faile belieka iš virtualios aplinkos iškviesti Gunicorn ir sukurti WSGI susiejimą UNIX lizdui ir programai Django.

Štai keletas vienetinių failų, kuriuos galite naudoti kaip pagrindą, pavyzdžių. Pirmiausia nustatome lizdą.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Dabar reikia sukonfigūruoti Gunicorn demoną.

[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

„Nginx“ paprasta sukurti tarpinio serverio konfigūracijos failus ir nustatyti katalogą statiniam turiniui saugoti, jei jį naudojate. RHEL sistemoje Nginx konfigūracijos failai yra /etc/nginx/conf.d. Galite nukopijuoti šį pavyzdį į failą /etc/nginx/conf.d/default.conf ir paleisti paslaugą. Įsitikinkite, kad serverio_pavadinimas atitinka jūsų pagrindinio kompiuterio pavadinimą.

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

Paleiskite Gunicorn lizdą ir Nginx naudodami systemd ir būsite pasiruošę pradėti testavimą.

Blogas šliuzo klaida?

Jei įvesite adresą į savo naršyklę, greičiausiai gausite 502 Bad Gateway klaidą. Tai gali sukelti netinkamai sukonfigūruoti UNIX lizdo leidimai arba sudėtingesnės problemos, susijusios su prieigos valdymu SELinux.

Nginx klaidų žurnale galite pamatyti tokią eilutę:

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"

Jei išbandysime Gunicorn tiesiogiai, gausime tuščią atsakymą.

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

Išsiaiškinkime, kodėl taip nutinka. Jei atidarysite žurnalą, greičiausiai pamatysite, kad problema yra susijusi su SELinux. Kadangi mes vykdome demoną, kuriam nebuvo sukurta jokia politika, jis pažymėtas kaip init_t. Išbandykime šią teoriją praktiškai.

sudo setenforce 0

Visa tai gali sukelti kritikos ir kraujo ašarų, tačiau tai tik prototipo derinimas. Išjunkite patikrinimą, kad įsitikintume, ar tai yra problema, po kurios viską grąžinsime į savo vietas.

Atnaujinę puslapį naršyklėje arba iš naujo paleisdami curl komandą, galite pamatyti Django bandomąjį puslapį.

Taigi, įsitikinę, kad viskas veikia ir nebėra problemų dėl leidimų, vėl įjungiame SELinux.

sudo setenforce 1

Čia nekalbėsiu apie audit2allow ar įspėjimais pagrįstų strategijų kūrimą naudojant sepolgen, nes šiuo metu nėra jokios tikrosios „Django“ programos, todėl nėra viso žemėlapio, ką „Gunicorn“ gali norėti pasiekti ir ką jis turėtų neleisti pasiekti. Todėl būtina, kad SELinux veiktų, kad būtų apsaugota sistema, tuo pat metu leisti programai veikti ir palikti pranešimus audito žurnale, kad iš jų būtų galima sukurti tikrąją politiką.

Leidžiamų domenų nurodymas

Ne visi yra girdėję apie leidžiamus domenus SELinux, tačiau jie nėra naujiena. Daugelis net to nesuvokdami dirbo su jais. Kai strategija sukuriama remiantis audito pranešimais, sukurta strategija atspindi išspręstą domeną. Pabandykime sukurti paprastą leidimų išdavimo politiką.

Norėdami sukurti konkretų leistiną Gunicorn domeną, jums reikia tam tikros politikos, taip pat turite pažymėti atitinkamus failus. Be to, reikalingos priemonės kuriant naują politiką.

sudo yum install selinux-policy-devel

Leidžiamų domenų mechanizmas yra puikus įrankis problemoms nustatyti, ypač kai kalbama apie pasirinktinę programą ar programas, kurios pristatomos be jau sukurtos politikos. Tokiu atveju leistina Gunicorn domeno politika bus kuo paprastesnė – nurodykite pagrindinį tipą (gunicorn_t), nurodykite tipą, kurį naudosime keliems vykdomiesiems failams pažymėti (gunicorn_exec_t), tada nustatykite perėjimą, kad sistema teisingai pažymėtų. veikiantys procesai. Paskutinėje eilutėje politika nustatoma kaip įjungta pagal numatytuosius nustatymus, kai ji įkeliama.

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;

Galite sudaryti šį politikos failą ir įtraukti jį į savo sistemą.

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

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

Pažiūrėkime, ar SELinux blokuoja ką nors kita, nei tai, ką pasiekia mūsų nežinomas demonas.

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 neleidžia Nginx įrašyti duomenų į UNIX lizdą, kurį naudoja Gunicorn. Paprastai tokiais atvejais politika pradeda keistis, tačiau laukia kiti iššūkiai. Taip pat galite pakeisti domeno nustatymus iš apribojimo domeno į leidimo domeną. Dabar perkelkime httpd_t į leidimų domeną. Tai suteiks „Nginx“ reikalingą prieigą ir galėsime tęsti tolesnį derinimo darbą.

sudo semanage permissive -a httpd_t

Taigi, kai pavyksta apsaugoti SELinux (tikrai neturėtumėte palikti SELinux projekto ribotame režime) ir įkeltus leidimų domenus, turite išsiaiškinti, ką tiksliai reikia pažymėti kaip gunicorn_exec_t, kad viskas veiktų tinkamai. vėl. Pabandykime apsilankyti svetainėje ir pamatyti naujų pranešimų apie prieigos apribojimus.

sudo ausearch -m AVC -c gunicorn

Pamatysite daug pranešimų, kuriuose yra „comm="gunicorn", kurie atlieka įvairius veiksmus su failais, esančiais /srv/djangoapp, todėl akivaizdu, kad tai yra viena iš komandų, kurias verta pažymėti.

Be to, pasirodo toks pranešimas:

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

Jei pažvelgsite į gunicorn tarnybos būseną arba paleisite komandą ps, nematysite jokių veikiančių procesų. Panašu, kad gunicorn bando pasiekti Python interpretatorių mūsų virtualenv aplinkoje, galbūt paleisti darbuotojo scenarijus. Taigi dabar pažymėkime šiuos du vykdomuosius failus ir pažiūrėkime, ar galime atidaryti „Django“ bandomąjį puslapį.

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

Kad būtų galima pasirinkti naują žymą, „Gunicorn“ paslaugą reikės paleisti iš naujo. Galite nedelsdami ją paleisti iš naujo arba sustabdyti paslaugą ir leisti lizdui ją paleisti, kai atidarote svetainę naršyklėje. Naudodami ps patikrinkite, ar procesai gavo tinkamas etiketes.

ps -efZ | grep gunicorn

Nepamirškite vėliau susikurti įprastos SELinux politikos!

Jei pažvelgsite į AVC pranešimus dabar, paskutiniame pranešime yra permissive = 1 viskam, kas susiję su programa, ir permissive = 0 likusiai sistemos daliai. Jei suprantate, kokios prieigos reikia tikrai programai, galite greitai rasti geriausią būdą tokioms problemoms išspręsti. Tačiau iki tol geriausia užtikrinti sistemos saugumą ir gauti aiškų, naudingą Django projekto auditą.

sudo ausearch -m AVC

Įvyko!

Pasirodė veikiantis „Django“ projektas su sąsaja, pagrįsta Nginx ir Gunicorn WSGI. Mes sukonfigūravome Python 3 ir PostgreSQL 10 iš RHEL 8 beta saugyklų. Dabar galite judėti pirmyn ir kurti (arba tiesiog įdiegti) „Django“ programas arba tyrinėti kitus galimus įrankius RHEL 8 Beta versijoje, kad automatizuotumėte konfigūravimo procesą, pagerintumėte našumą ar net sutalpintumėte šią konfigūraciją.

Šaltinis: www.habr.com

Добавить комментарий