Verkstæði RHEL 8 Beta: Að byggja upp vinnandi vefforrit

RHEL 8 Beta býður forriturum upp á marga nýja eiginleika, skráning þeirra gæti tekið síður, hins vegar er alltaf betra að læra nýja hluti í reynd, svo hér að neðan bjóðum við upp á vinnustofu um að búa til forritainnviði sem byggir á Red Hat Enterprise Linux 8 Beta.

Verkstæði RHEL 8 Beta: Að byggja upp vinnandi vefforrit

Tökum Python, vinsælt forritunarmál meðal forritara, sem grunn, samsetningu af Django og PostgreSQL, nokkuð algengri samsetningu til að búa til forrit, og stillum RHEL 8 Beta til að vinna með þau. Síðan bætum við nokkrum (óflokkað) hráefnum í viðbót.

Prófumhverfið mun breytast, því það er áhugavert að kanna möguleika á sjálfvirkni, vinna með gáma og prófa umhverfi með mörgum netþjónum. Til að hefjast handa við nýtt verkefni geturðu byrjað á því að búa til litla, einfalda frumgerð með höndunum svo þú getir séð nákvæmlega hvað þarf að gerast og hvernig það hefur samskipti, og síðan haldið áfram að gera sjálfvirkan og búa til flóknari stillingar. Í dag erum við að tala um að búa til slíka frumgerð.

Byrjum á því að dreifa RHEL 8 Beta VM myndinni. Þú getur sett upp sýndarvél frá grunni, eða notað KVM gestamyndina sem er tiltæk með Beta áskriftinni þinni. Þegar gestamynd er notuð þarftu að stilla sýndargeisladisk sem mun innihalda lýsigögn og notendagögn fyrir frumstillingu í skýi (cloud-init). Þú þarft ekki að gera neitt sérstakt við diskbygginguna eða tiltæka pakka; allar stillingar munu duga.

Við skulum skoða allt ferlið nánar.

Að setja upp Django

Með nýjustu útgáfunni af Django þarftu sýndarumhverfi (virtualenv) með Python 3.5 eða nýrri. Í Beta athugasemdunum geturðu séð að Python 3.6 er fáanlegur, við skulum athuga hvort þetta sé örugglega raunin:

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

Red Hat notar Python virkan sem kerfisverkfærasett í RHEL, svo hvers vegna veldur þetta?

Staðreyndin er sú að margir Python forritarar eru enn að íhuga umskiptin frá Python 2 yfir í Python 2, á meðan Python 3 sjálft er í virkri þróun og fleiri og fleiri nýjar útgáfur eru stöðugt að birtast. Þess vegna, til að mæta þörfinni fyrir stöðug kerfisverkfæri en bjóða notendum aðgang að ýmsum nýjum útgáfum af Python, var Python kerfið flutt í nýjan pakka og gaf möguleika á að setja upp bæði Python 2.7 og 3.6. Frekari upplýsingar um breytingarnar og hvers vegna þær voru gerðar má finna í ritinu í Blogg Langdon White (Langdon White).

Svo, til að fá að virka Python, þarftu aðeins að setja upp tvo pakka, með python3-pip innifalinn sem ósjálfstæði.

sudo yum install python36 python3-virtualenv

Af hverju ekki að nota bein einingakall eins og Langdon leggur til og setja upp pip3? Með hliðsjón af komandi sjálfvirkni er vitað að Ansible mun krefjast þess að pip sé sett upp til að keyra, þar sem pip-einingin styður ekki virtualenvs með sérsniðnum pip keyrslu.

Með virkan python3 túlk til umráða geturðu haldið áfram með Django uppsetningarferlið og haft virkt kerfi ásamt öðrum hlutum okkar. Það eru margir útfærslumöguleikar í boði á netinu. Það er ein útgáfa hér, en notendur geta notað eigin ferla.

Við munum setja upp PostgreSQL og Nginx útgáfur sem eru fáanlegar í RHEL 8 sjálfgefið með Yum.

sudo yum install nginx postgresql-server

PostgreSQL mun krefjast psycopg2, en það þarf aðeins að vera fáanlegt í virtualenv umhverfi, svo við munum setja það upp með pip3 ásamt Django og Gunicorn. En fyrst þurfum við að setja upp virtualenv.

Það er alltaf mikil umræða um efnið að velja réttan stað til að setja upp Django verkefni, en þegar þú ert í vafa geturðu alltaf snúið þér að Linux Filesystem Hierarchy Standard. Nánar tiltekið segir FHS að /srv sé notað til að: „geyma hýsilsértæk gögn — gögn sem kerfið framleiðir, svo sem gögn á vefþjóni og forskriftir, gögn sem eru geymd á FTP netþjónum og stjórnkerfisgeymslum.“ útgáfur (birtast í FHS -2.3 árið 2004)."

Þetta er einmitt okkar mál, svo við setjum allt sem við þurfum í /srv, sem er í eigu forritsnotanda okkar (skýjanotanda).

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

Það er auðvelt að setja upp PostgreSQL og Django: búa til gagnagrunn, búa til notanda, stilla heimildir. Eitt sem þarf að hafa í huga þegar PostgreSQL er sett upp í upphafi er postgresql-uppsetningarforritið sem er sett upp með postgresql-server pakkanum. Þetta handrit hjálpar þér að framkvæma grunnverkefni sem tengjast gagnagrunnsklasastjórnun, svo sem frumstillingu klasa eða uppfærsluferlið. Til að stilla nýtt PostgreSQL tilvik á RHEL kerfi þurfum við að keyra skipunina:

sudo /usr/bin/postgresql-setup -initdb

Þú getur síðan ræst PostgreSQL með systemd, búið til gagnagrunn og sett upp verkefni í Django. Mundu að endurræsa PostgreSQL eftir að hafa gert breytingar á stillingarskrá viðskiptavinar auðkenningar (venjulega pg_hba.conf) til að stilla lykilorðageymslu fyrir forritsnotandann. Ef þú lendir í öðrum erfiðleikum, vertu viss um að breyta IPv4 og IPv6 stillingum í pg_hba.conf skránni.

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

Í skránni /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

Í skránni /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 }}',
   }
}

Eftir að hafa stillt settings.py skrána í verkefninu og sett upp gagnagrunnsstillingar geturðu ræst þróunarþjóninn til að ganga úr skugga um að allt virki. Eftir að þróunarþjónninn er ræstur er gott að búa til admin notanda til að prófa tenginguna við gagnagrunninn.

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

WSGI? Vá?

Þróunarþjónninn er gagnlegur til að prófa, en til að keyra forritið verður þú að stilla viðeigandi netþjón og umboðsþjón fyrir vefþjónsgáttviðmótið (WSGI). Það eru nokkrar algengar samsetningar, til dæmis Apache HTTPD með uWSGI eða Nginx með Gunicorn.

Hlutverk vefþjónsgáttarviðmótsins er að senda beiðnir frá vefþjóninum yfir á Python veframma. WSGI er minjar um hræðilega fortíð þegar CGI vélar voru til og í dag er WSGI staðallinn í reynd, óháð því hvaða vefþjóni eða Python ramma er notaður. En þrátt fyrir útbreidda notkun þess, þá eru enn mörg blæbrigði þegar unnið er með þessa ramma, og margir valkostir. Í þessu tilfelli munum við reyna að koma á samskiptum milli Gunicorn og Nginx í gegnum fals.

Þar sem báðir þessir þættir eru settir upp á sama netþjóni skulum við reyna að nota UNIX fals í stað nettengis. Þar sem samskipti krefjast fals í öllum tilvikum, við skulum reyna að taka eitt skref í viðbót og stilla innstunguvirkjun fyrir Gunicorn í gegnum systemd.

Ferlið við að búa til falsvirkjaða þjónustu er frekar einfalt. Fyrst er einingaskrá búin til sem inniheldur ListenStream tilskipun sem vísar á þann stað þar sem UNIX falsið verður búið til, síðan einingaskrá fyrir þjónustuna þar sem Requires tilskipunin mun benda á innstungueiningaskrána. Síðan, í þjónustueiningaskránni, er allt sem eftir er að hringja í Gunicorn úr sýndarumhverfinu og búa til WSGI bindingu fyrir UNIX falsið og Django forritið.

Hér eru nokkur dæmi um einingaskrár sem þú getur notað sem grunn. Fyrst settum við upp innstunguna.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Nú þarftu að stilla Gunicorn púkann.

[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

Fyrir Nginx er það einfalt mál að búa til proxy stillingarskrár og setja upp möppu til að geyma kyrrstætt efni ef þú ert að nota slíka. Í RHEL eru Nginx stillingarskrár staðsettar í /etc/nginx/conf.d. Þú getur afritað eftirfarandi dæmi í skrána /etc/nginx/conf.d/default.conf og ræst þjónustuna. Gakktu úr skugga um að stilla server_name þannig að það passi við gestgjafanafnið þitt.

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

Byrjaðu Gunicorn falsið og Nginx með því að nota systemd og þú ert tilbúinn til að byrja að prófa.

Slæm hliðarvilla?

Ef þú slærð inn heimilisfangið í vafrann þinn færðu líklega 502 Bad Gateway villu. Það gæti stafað af rangt stilltum UNIX falsheimildum, eða það gæti verið vegna flóknari vandamála sem tengjast aðgangsstýringu í SELinux.

Í nginx villuskránni geturðu séð línu eins og þessa:

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"

Ef við prófum Gunicorn beint fáum við tómt svar.

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

Við skulum reikna út hvers vegna þetta gerist. Ef þú opnar logann muntu líklegast sjá að vandamálið tengist SELinux. Þar sem við erum að keyra púka sem engin stefna hefur verið búin til fyrir, er hann merktur sem init_t. Prófum þessa kenningu í verki.

sudo setenforce 0

Allt þetta getur valdið gagnrýni og blóðtárum, en þetta er bara að kemba frumgerðina. Við skulum slökkva á ávísuninni bara til að ganga úr skugga um að þetta sé vandamálið, eftir það munum við skila öllu aftur á sinn stað.

Með því að endurnýja síðuna í vafranum eða endurræsa krulluskipunina okkar geturðu séð Django prófunarsíðuna.

Svo, eftir að hafa gengið úr skugga um að allt virki og engin leyfisvandamál séu lengur, virkum við SELinux aftur.

sudo setenforce 1

Ég ætla ekki að tala um audit2allow eða búa til viðvörunartengdar stefnur með sepolgen hér, þar sem það er ekkert raunverulegt Django forrit í augnablikinu, svo það er ekkert fullkomið kort af því sem Gunicorn gæti viljað fá aðgang að og hverju það ætti að neita aðgangi að. Þess vegna er nauðsynlegt að halda SELinux gangandi til að vernda kerfið, en á sama tíma leyfa forritinu að keyra og skilja eftir skilaboð í endurskoðunarskránni svo hægt sé að búa til raunverulega stefnu úr þeim.

Að tilgreina leyfileg lén

Ekki hafa allir heyrt um leyfð lén í SELinux, en þau eru ekkert nýtt. Margir unnu jafnvel með þeim án þess að átta sig á því. Þegar stefna er búin til á grundvelli endurskoðunarskilaboða, táknar stofnaða stefnan leyst lén. Við skulum reyna að búa til einfalda leyfisstefnu.

Til að búa til ákveðið leyfilegt lén fyrir Gunicorn þarftu einhvers konar stefnu og þú þarft líka að merkja viðeigandi skrár. Auk þess þarf verkfæri til að setja saman nýjar stefnur.

sudo yum install selinux-policy-devel

Leyfilegt lénskerfi er frábært tæki til að bera kennsl á vandamál, sérstaklega þegar kemur að sérsniðnu forriti eða forritum sem eru send án stefnu sem þegar hefur verið búið til. Í þessu tilviki verður leyfileg lénsstefna fyrir Gunicorn eins einföld og mögulegt er - lýstu yfir aðaltegund (gunicorn_t), lýstu yfir tegund sem við munum nota til að merkja margar keyrslur (gunicorn_exec_t), og settu síðan upp umskipti fyrir kerfið til að merkja rétt hlaupandi ferla. Síðasta línan stillir regluna sem sjálfgefið virka þegar hún er hlaðin.

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;

Þú getur sett saman þessa stefnuskrá og bætt henni við kerfið þitt.

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

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

Við skulum athuga hvort SELinux sé að loka fyrir eitthvað annað en það sem óþekkti púkinn okkar hefur aðgang að.

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 kemur í veg fyrir að Nginx geti skrifað gögn í UNIX falsið sem Gunicorn notar. Venjulega, í slíkum tilfellum, byrja stefnur að breytast, en það eru aðrar áskoranir framundan. Þú getur líka breytt lénsstillingum úr takmörkunarléni í heimildarlén. Nú skulum við færa httpd_t yfir á leyfislénið. Þetta mun veita Nginx nauðsynlegan aðgang og við getum haldið áfram með frekari villuleit.

sudo semanage permissive -a httpd_t

Svo, þegar þér hefur tekist að halda SELinux varið (þú ættir í raun ekki að skilja SELinux verkefni eftir í takmörkuðum ham) og leyfislénin eru hlaðin, þarftu að finna út hvað nákvæmlega þarf að merkja sem gunicorn_exec_t til að allt virki rétt aftur. Við skulum reyna að heimsækja vefsíðuna til að sjá ný skilaboð um aðgangstakmarkanir.

sudo ausearch -m AVC -c gunicorn

Þú munt sjá fullt af skilaboðum sem innihalda 'comm="gunicorn"' sem gera ýmsa hluti á skrám í /srv/djangoapp, svo þetta er augljóslega ein af skipunum sem vert er að flagga.

En auk þess birtast skilaboð eins og þessi:

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

Ef þú skoðar stöðu gunicorn þjónustunnar eða keyrir ps skipunina muntu ekki sjá neina hlaupandi ferli. Það lítur út fyrir að gunicorn sé að reyna að fá aðgang að Python túlknum í virtualenv umhverfinu okkar, mögulega til að keyra starfsmannaforskriftir. Svo nú skulum við merkja þessar tvær keyrsluskrár og athuga hvort við getum opnað Django prófunarsíðuna okkar.

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

Endurræsa þarf byssuhornsþjónustuna áður en hægt er að velja nýja merkið. Þú getur endurræst hana strax eða stöðvað þjónustuna og látið innstunguna ræsa hana þegar þú opnar síðuna í vafranum. Staðfestu að ferlar hafi fengið rétta merkimiða með því að nota ps.

ps -efZ | grep gunicorn

Ekki gleyma að búa til venjulega SELinux stefnu síðar!

Ef þú skoðar AVC skilaboðin núna, þá inniheldur síðasta skilaboðin permissive=1 fyrir allt sem tengist forritinu og permissive=0 fyrir restina af kerfinu. Ef þú skilur hvers konar aðgang raunverulegt forrit þarfnast geturðu fljótt fundið bestu leiðina til að leysa slík vandamál. En þangað til er best að halda kerfinu öruggu og fá skýra, nothæfa úttekt á Django verkefninu.

sudo ausearch -m AVC

Gerðist!

Vinnandi Django verkefni hefur birst með framenda byggt á Nginx og Gunicorn WSGI. Við stilltum Python 3 og PostgreSQL 10 frá RHEL 8 Beta geymslunum. Nú geturðu haldið áfram og búið til (eða einfaldlega sett inn) Django forrit eða kannað önnur tiltæk verkfæri í RHEL 8 Beta til að gera sjálfvirkan stillingarferlið, bæta afköst eða jafnvel setja þessa stillingu í gáma.

Heimild: www.habr.com

Bæta við athugasemd