Workshop RHEL 8 Béta: Működő webes alkalmazások készítése

Az RHEL 8 Beta számos új funkciót kínál a fejlesztőknek, amelyek listázása akár oldalakat is igénybe vehet, azonban a gyakorlatban mindig jobb az újdonságok elsajátítása, így az alábbiakban bemutatunk egy workshopot a Red Hat Enterprise Linux 8 Beta alapú alkalmazás-infrastruktúra tényleges létrehozásáról.

Workshop RHEL 8 Béta: Működő webes alkalmazások készítése

Vegyük alapul a Pythont, a fejlesztők körében népszerű programozási nyelvet, a Django és a PostgreSQL kombinációját, amely egy meglehetősen gyakori kombináció az alkalmazások létrehozásához, és állítsuk be az RHEL 8 Bétát, hogy működjön velük. Ezután adunk hozzá még pár (nem osztályozott) hozzávalót.

A tesztkörnyezet megváltozik, mert érdekes az automatizálás, a konténerekkel való munka és a több szerveres környezetek kipróbálásának lehetőségei. Egy új projekt elindításához először egy kicsi, egyszerű prototípust készítsen kézzel, hogy pontosan lássa, minek kell történnie, és hogyan működik együtt, majd továbbléphet az automatizáláshoz és bonyolultabb konfigurációk létrehozásához. Ma egy ilyen prototípus létrehozásáról beszélünk.

Kezdjük az RHEL 8 Beta VM lemezkép telepítésével. Telepíthet egy virtuális gépet a semmiből, vagy használhatja a béta-előfizetéshez elérhető KVM vendégképet. Vendégkép használatakor be kell állítania egy virtuális CD-t, amely metaadatokat és felhasználói adatokat tartalmaz a felhő inicializálásához (felhő-init). Nem kell semmi különöset tennie a lemezszerkezettel vagy a rendelkezésre álló csomagokkal, bármilyen konfiguráció megteszi.

Nézzük meg közelebbről az egész folyamatot.

Django telepítése

A Django legújabb verziójához szükség lesz egy virtuális környezetre (virtualenv) Python 3.5 vagy újabb verzióval. A béta megjegyzésekben láthatja, hogy a Python 3.6 elérhető, nézzük meg, hogy ez valóban így van-e:

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

A Red Hat aktívan használja a Pythont rendszereszközként az RHEL-ben, miért van ez így?

A helyzet az, hogy sok Python fejlesztő még mindig a Python 2-ről Python 2-re való átálláson gondolkodik, miközben maga a Python 3 is aktív fejlesztés alatt áll, és folyamatosan újabb és újabb verziók jelennek meg. Ezért a stabil rendszereszközök iránti igény kielégítése érdekében, miközben a felhasználók hozzáférést biztosítanak a Python különféle új verzióihoz, a Python rendszert áthelyezték egy új csomagba, és lehetővé tette a Python 2.7 és 3.6 telepítését. A változtatásokról és azok okairól bővebb információ a kiadványban található Langdon White blogja (Langdon White).

Tehát a Python működéséhez csak két csomagot kell telepítenie, amelyekben a python3-pip függőségként szerepel.

sudo yum install python36 python3-virtualenv

Miért ne használjon közvetlen modulhívásokat, ahogy Langdon javasolja, és telepítse a pip3-at? A közelgő automatizálást szem előtt tartva ismert, hogy az Ansible futtatásához telepített pip szükséges, mivel a pip modul nem támogatja a virtualenvs-t egyéni pip futtatható fájllal.

Egy működő python3 értelmezővel folytathatja a Django telepítési folyamatát, és a többi komponensünkkel együtt működő rendszerrel rendelkezhet. Az interneten számos megvalósítási lehetőség áll rendelkezésre. Itt egy verziót mutatunk be, de a felhasználók használhatják saját folyamataikat.

Az RHEL 8-ban elérhető PostgreSQL és Nginx verziókat alapértelmezés szerint a Yum használatával telepítjük.

sudo yum install nginx postgresql-server

A PostgreSQL-hez psycopg2 szükséges, de csak virtualenv környezetben kell elérhetőnek lennie, ezért pip3-mal fogjuk telepíteni a Django és a Gunicorn mellett. De először be kell állítanunk a virtualenv-t.

Mindig sok vita folyik a Django projektek telepítési helyének kiválasztásáról, de ha kétségei vannak, mindig forduljon a Linux fájlrendszer-hierarchia szabványhoz. Konkrétan az FHS azt mondja, hogy az /srv a következőkre szolgál: „gazdagép-specifikus adatok tárolása – a rendszer által előállított adatok, például webszerver-adatok és szkriptek, FTP-kiszolgálókon tárolt adatok és rendszerlerakatok vezérlése.” verziók (megjelenik az FHS-ben -2.3 2004-ben).

Pontosan ez a mi esetünk, ezért mindent, amire szükségünk van, a /srv-be teszünk, ami az alkalmazás felhasználónk (felhő-felhasználó) tulajdonában van.

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 PostgreSQL és a Django beállítása egyszerű: adatbázis létrehozása, felhasználó létrehozása, engedélyek konfigurálása. A PostgreSQL kezdeti telepítése során egy dolgot szem előtt kell tartani, a postgresql-server csomaggal együtt telepített postgresql-setup szkript. Ez a parancsfájl segít az adatbázis-fürt adminisztrációjával kapcsolatos alapvető feladatok elvégzésében, például a fürt inicializálásában vagy a frissítési folyamatban. Új PostgreSQL-példány konfigurálásához egy RHEL rendszeren a következő parancsot kell futtatnunk:

sudo /usr/bin/postgresql-setup -initdb

Ezután elindíthatja a PostgreSQL-t a systemd használatával, létrehozhat egy adatbázist, és beállíthat egy projektet a Django-ban. Ne felejtse el újraindítani a PostgreSQL-t, miután módosította az ügyfél-hitelesítési konfigurációs fájlt (általában pg_hba.conf), hogy konfigurálja a jelszótárolást az alkalmazás felhasználója számára. Ha egyéb nehézségekbe ütközik, mindenképpen módosítsa az IPv4 és IPv6 beállításokat a pg_hba.conf fájlban.

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

A /var/lib/pgsql/data/pg_hba.conf fájlban:

# IPv4 local connections:
host    all        all 0.0.0.0/0                md5
# IPv6 local connections:
host    all        all ::1/128                 md5

A /srv/djangoapp/settings.py fájlban:

# Database
DATABASES = {
   'default': {
       'ENGINE': 'django.db.backends.postgresql_psycopg2',
       'NAME': '{{ db_name }}',
       'USER': '{{ db_user }}',
       'PASSWORD': '{{ db_password }}',
       'HOST': '{{ db_host }}',
   }
}

Miután konfigurálta a settings.py fájlt a projektben, és beállította az adatbázis konfigurációját, elindíthatja a fejlesztőkiszolgálót, hogy megbizonyosodjon arról, hogy minden működik. A fejlesztői szerver elindítása után célszerű létrehozni egy adminisztrátor felhasználót az adatbázishoz való kapcsolódás teszteléséhez.

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

WSGI? Wai?

A fejlesztői kiszolgáló hasznos a teszteléshez, de az alkalmazás futtatásához be kell állítani a megfelelő kiszolgálót és proxyt a Web Server Gateway Interface (WSGI) számára. Számos gyakori kombináció létezik, például az Apache HTTPD az uWSGI-vel vagy az Nginx a Gunicorn-nal.

A Web Server Gateway Interface feladata a kérések továbbítása a webszerverről a Python webes keretrendszerbe. A WSGI a szörnyű múlt emléke, amikor a CGI-motorok léteztek, és ma a WSGI a de facto szabvány, függetlenül a használt webszervertől vagy Python-keretrendszertől. De a széles körben elterjedt használat ellenére még mindig sok árnyalat van ezekkel a keretekkel való munka során, és sok választási lehetőség. Ebben az esetben megpróbálunk interakciót létrehozni a Gunicorn és a Nginx között egy aljzaton keresztül.

Mivel mindkét összetevő ugyanarra a kiszolgálóra van telepítve, próbáljunk meg UNIX socketet használni hálózati socket helyett. Mivel a kommunikációhoz minden esetben szükség van socketre, próbáljunk meg még egy lépést tenni, és konfigurálni a socket aktiválást a Gunicorn számára a systemd-n keresztül.

A socket aktivált szolgáltatások létrehozásának folyamata meglehetősen egyszerű. Először egy egységfájl jön létre, amely egy ListenStream direktívát tartalmaz, amely arra a pontra mutat, ahol a UNIX socket létrejön, majd egy egységfájlt a szolgáltatáshoz, amelyben a Requires direktíva a socket unit fájlra mutat. Ezután a szolgáltatási egység fájljában nem kell mást tenni, mint meghívni a Gunicornt a virtuális környezetből, és létrehozni egy WSGI-összerendelést a UNIX foglalathoz és a Django alkalmazáshoz.

Íme néhány példa az alapként használható egységfájlokra. Először felállítjuk az aljzatot.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Most be kell állítania a Gunicorn démont.

[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

Az Nginx esetében egyszerűen létre kell hozni proxykonfigurációs fájlokat, és beállítani egy könyvtárat a statikus tartalom tárolására, ha használ ilyet. Az RHEL-ben az Nginx konfigurációs fájlok az /etc/nginx/conf.d fájlban találhatók. A következő példát bemásolhatja az /etc/nginx/conf.d/default.conf fájlba, és elindíthatja a szolgáltatást. Ügyeljen arra, hogy a szerver_neve megegyezzen a gazdagép nevével.

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

Indítsa el a Gunicorn foglalatot és az Nginxet a systemd segítségével, és készen áll a tesztelésre.

Rossz átjáró hiba?

Ha beírja a címet a böngészőbe, nagy valószínűséggel 502 Bad Gateway hibaüzenetet fog kapni. Ennek oka lehet a helytelenül konfigurált UNIX socket engedélyek, vagy a SELinux hozzáférés-vezérlésével kapcsolatos összetettebb problémák.

Az nginx hibanaplójában egy ehhez hasonló sort láthat:

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"

Ha közvetlenül teszteljük a Gunicornt, üres választ kapunk.

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

Nézzük meg, miért történik ez. Ha megnyitja a naplót, valószínűleg látni fogja, hogy a probléma a SELinux-szal kapcsolatos. Mivel olyan démont futtatunk, amelyhez nem hoztak létre házirendet, ezért init_t-ként van megjelölve. Teszteljük ezt az elméletet a gyakorlatban.

sudo setenforce 0

Mindez kritikát és vérkönnyeket okozhat, de ez csak a prototípus hibakeresése. Csak azért kapcsoljuk ki az ellenőrzést, hogy megbizonyosodjunk arról, hogy ez a probléma, ezután mindent visszahelyezünk a helyére.

Az oldal frissítésével a böngészőben vagy a curl parancs újrafuttatásával megtekintheti a Django tesztoldalát.

Tehát, miután megbizonyosodtunk arról, hogy minden működik, és nincs többé jogosultsági probléma, ismét engedélyezzük a SELinuxot.

sudo setenforce 1

Itt nem fogok beszélni az audit2allow-ról vagy a riasztás alapú házirendek létrehozásáról a sepolgen segítségével, mivel jelenleg nincs tényleges Django alkalmazás, így nincs teljes térkép arról, hogy a Gunicorn mit szeretne elérni, és mihez kell megtagadnia a hozzáférést. Ezért a SELinuxot futva kell tartani a rendszer védelme érdekében, ugyanakkor lehetővé kell tenni az alkalmazás futtatását, és üzeneteket hagyni a naplóban, hogy azután létrejöhessen belőlük a tényleges házirend.

Megengedő tartományok megadása

Nem mindenki hallott a SELinuxban engedélyezett domainekről, de ezek nem újdonságok. Sokan úgy is dolgoztak velük, hogy észre sem vették. Ha egy házirend naplózási üzenetek alapján jön létre, a létrehozott házirend a feloldott tartományt képviseli. Próbáljunk meg létrehozni egy egyszerű engedélyezési szabályzatot.

Egy adott engedélyezett tartomány létrehozásához a Gunicorn számára szükség van valamilyen házirendre, és meg kell jelölni a megfelelő fájlokat. Ezenkívül eszközökre van szükség az új irányelvek összeállításához.

sudo yum install selinux-policy-devel

Az engedélyezett tartományok mechanizmusa nagyszerű eszköz a problémák azonosítására, különösen akkor, ha egyéni alkalmazásról vagy olyan alkalmazásokról van szó, amelyek már létrehozott házirendek nélkül kerülnek szállításra. Ebben az esetben a Gunicorn engedélyezett tartományi szabályzata a lehető legegyszerűbb lesz – deklaráljon egy fő típust (gunicorn_t), deklaráljon egy típust, amelyet több végrehajtható fájl megjelölésére használunk (gunicorn_exec_t), majd állítson be egy átmenetet a rendszer számára a helyes megjelöléshez. folyamatok futtatása. Az utolsó sor a házirendet alapértelmezés szerint engedélyezettnek állítja be a betöltésekor.

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;

Lefordíthatja ezt a házirend-fájlt, és hozzáadhatja a rendszeréhez.

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

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

Nézzük meg, hogy a SELinux nem blokkol-e mást, mint amihez ismeretlen démonunk hozzáfér.

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

A SELinux megakadályozza, hogy az Nginx adatokat írjon a Gunicorn által használt UNIX foglalatba. Jellemzően ilyen esetekben kezdenek megváltozni a politikák, de más kihívások is állnak előttük. A tartománybeállításokat korlátozó tartományról engedélyes tartományra is módosíthatja. Most helyezzük át a httpd_t fájlt az engedélyek tartományába. Ez megadja az Nginx számára a szükséges hozzáférést, és folytathatjuk a további hibakeresési munkát.

sudo semanage permissive -a httpd_t

Tehát, ha sikerült megőriznie a SELinux védelmét (valójában nem szabad korlátozott módban hagynia egy SELinux projektet), és az engedélytartományok betöltődnek, ki kell találnia, hogy pontosan mit kell gunicorn_exec_t-ként megjelölni, hogy minden megfelelően működjön. újra. Próbáljuk meg felkeresni a webhelyet, hogy új üzeneteket lássunk a hozzáférési korlátozásokról.

sudo ausearch -m AVC -c gunicorn

Sok olyan üzenetet fog látni, amely tartalmazza a „comm="gunicorn" kifejezést, amelyek különféle műveleteket végeznek a /srv/djangoapp fájlokon, tehát nyilvánvalóan ez az egyik megjelölésre érdemes parancs.

De emellett megjelenik egy ehhez hasonló üzenet:

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

Ha megnézi a gunicorn szolgáltatás állapotát, vagy lefuttatja a ps parancsot, nem fog látni futó folyamatokat. Úgy tűnik, hogy a gunicorn megpróbál hozzáférni a Python értelmezőhöz a virtualenv környezetünkben, esetleg dolgozói szkriptek futtatására. Tehát most jelöljük meg ezt a két végrehajtható fájlt, és ellenőrizzük, hogy meg tudjuk-e nyitni a Django tesztoldalunkat.

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

A Gunicorn szolgáltatást újra kell indítani az új címke kiválasztása előtt. Azonnal újraindíthatja, vagy leállíthatja a szolgáltatást, és hagyhatja, hogy a socket elindítsa, amikor megnyitja a webhelyet a böngészőben. A ps segítségével ellenőrizze, hogy a folyamatok a megfelelő címkéket kapták-e meg.

ps -efZ | grep gunicorn

Ne felejtsen el később létrehozni egy normál SELinux szabályzatot!

Ha most megnézzük az AVC-üzeneteket, az utolsó üzenet a permissive=1-et tartalmazza minden, ami az alkalmazással kapcsolatos, és a permissive=0 értéket a rendszer többi részére. Ha megérti, hogy egy valós alkalmazásnak milyen hozzáférésre van szüksége, gyorsan megtalálhatja az ilyen problémák megoldásának legjobb módját. De addig a legjobb, ha biztonságban tartja a rendszert, és tiszta, használható auditot kap a Django projektről.

sudo ausearch -m AVC

Megtörtént!

Egy működő Django projekt jelent meg Nginx és Gunicorn WSGI alapú frontenddel. A Python 3-at és a PostgreSQL 10-et az RHEL 8 béta tárolóiból konfiguráltuk. Mostantól előreléphet és létrehozhat (vagy egyszerűen telepíthet) Django alkalmazásokat, vagy felfedezhet más elérhető eszközöket az RHEL 8 Beta verziójában a konfigurációs folyamat automatizálásához, a teljesítmény javításához vagy akár a konfiguráció konténerbe helyezéséhez.

Forrás: will.com

Hozzászólás