Taller RHEL 8 Beta: Creació d'aplicacions web de treball

RHEL 8 Beta ofereix als desenvolupadors moltes funcions noves, la llista de les quals podria ocupar pàgines, però, aprendre coses noves sempre és millor a la pràctica, de manera que a continuació oferim un taller sobre com crear una infraestructura d'aplicacions basada en Red Hat Enterprise Linux 8 Beta.

Taller RHEL 8 Beta: Creació d'aplicacions web de treball

Prenem Python, un llenguatge de programació popular entre els desenvolupadors, com a base, una combinació de Django i PostgreSQL, una combinació força habitual per crear aplicacions, i configurem RHEL 8 Beta perquè funcioni amb ells. Després hi afegirem un parell d'ingredients més (no classificats).

L'entorn de prova canviarà, perquè és interessant explorar les possibilitats d'automatització, treballar amb contenidors i provar entorns amb múltiples servidors. Per començar amb un projecte nou, podeu començar creant a mà un prototip petit i senzill perquè pugueu veure exactament què ha de passar i com interactua, i després passar a automatitzar i crear configuracions més complexes. Avui parlem de la creació d'aquest prototip.

Comencem desplegant la imatge RHEL 8 Beta VM. Podeu instal·lar una màquina virtual des de zero o utilitzar la imatge de convidat KVM disponible amb la vostra subscripció beta. Quan utilitzeu una imatge de convidat, haureu de configurar un CD virtual que contindrà metadades i dades d'usuari per a la inicialització del núvol (cloud-init). No cal que feu res especial amb l'estructura del disc o els paquets disponibles; qualsevol configuració servirà.

Fem una ullada més de prop a tot el procés.

Instal·lant Django

Amb la versió més recent de Django, necessitareu un entorn virtual (virtualenv) amb Python 3.5 o posterior. A les notes Beta podeu veure que Python 3.6 està disponible, comprovem si realment és així:

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

Red Hat utilitza activament Python com a conjunt d'eines del sistema a RHEL, per què resulta això?

El fet és que molts desenvolupadors de Python encara estan contemplant la transició de Python 2 a Python 2, mentre que el mateix Python 3 està en desenvolupament actiu, i cada cop apareixen més versions noves. Per tant, per satisfer la necessitat d'eines estables del sistema alhora que ofereix als usuaris accés a diverses noves versions de Python, el sistema Python es va traslladar a un paquet nou i va oferir la possibilitat d'instal·lar tant Python 2.7 com 3.6. Podeu trobar més informació sobre els canvis i per què es van fer a la publicació a Bloc de Langdon White (Langdon White).

Per tant, per fer funcionar Python, només cal instal·lar dos paquets, amb python3-pip inclòs com a dependència.

sudo yum install python36 python3-virtualenv

Per què no utilitzar trucades directes de mòduls com suggereix Langdon i instal·lar pip3? Tenint en compte la propera automatització, se sap que Ansible requerirà pip instal·lat per funcionar, ja que el mòdul pip no admet virtualenvs amb un executable pip personalitzat.

Amb un intèrpret Python3 que funcioni a la vostra disposició, podeu continuar amb el procés d'instal·lació de Django i tenir un sistema que funcioni juntament amb els nostres altres components. Hi ha moltes opcions d'implementació disponibles a Internet. Aquí es presenta una versió, però els usuaris poden utilitzar els seus propis processos.

Instal·larem les versions de PostgreSQL i Nginx disponibles a RHEL 8 per defecte mitjançant Yum.

sudo yum install nginx postgresql-server

PostgreSQL requerirà psycopg2, però només ha d'estar disponible en un entorn virtualenv, de manera que l'instal·larem fent servir pip3 juntament amb Django i Gunicorn. Però primer hem de configurar virtualenv.

Sempre hi ha molt de debat sobre el tema de triar el lloc adequat per instal·lar els projectes Django, però en cas de dubte, sempre podeu recórrer a l'estàndard de jerarquia del sistema de fitxers de Linux. Concretament, l'FHS diu que /srv s'utilitza per: "emmagatzemar dades específiques de l'amfitrió: dades que produeix el sistema, com ara dades i scripts del servidor web, dades emmagatzemades en servidors FTP i repositoris del sistema de control". -2.3 el 2004)."

Aquest és exactament el nostre cas, així que posem tot el que necessitem a /srv, que és propietat del nostre usuari de l'aplicació (usuari del núvol).

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

Configurar PostgreSQL i Django és fàcil: creeu una base de dades, creeu un usuari, configureu els permisos. Una cosa a tenir en compte quan instal·leu inicialment PostgreSQL és l'script postgresql-setup que s'instal·la amb el paquet postgresql-server. Aquest script us ajuda a realitzar tasques bàsiques associades a l'administració del clúster de bases de dades, com ara la inicialització del clúster o el procés d'actualització. Per configurar una nova instància PostgreSQL en un sistema RHEL, hem d'executar l'ordre:

sudo /usr/bin/postgresql-setup -initdb

A continuació, podeu iniciar PostgreSQL amb systemd, crear una base de dades i configurar un projecte a Django. Recordeu reiniciar PostgreSQL després de fer canvis al fitxer de configuració d'autenticació del client (normalment pg_hba.conf) per configurar l'emmagatzematge de contrasenyes per a l'usuari de l'aplicació. Si trobeu altres dificultats, assegureu-vos de canviar la configuració IPv4 i IPv6 al fitxer 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

Al fitxer /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

Al fitxer /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 }}',
   }
}

Després de configurar el fitxer settings.py al projecte i configurar la configuració de la base de dades, podeu iniciar el servidor de desenvolupament per assegurar-vos que tot funciona. Després d'iniciar el servidor de desenvolupament, és una bona idea crear un usuari administrador per provar la connexió a la base de dades.

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

WSGI? Wai?

El servidor de desenvolupament és útil per fer proves, però per executar l'aplicació heu de configurar el servidor i el proxy adequats per a la interfície de passarel·la del servidor web (WSGI). Hi ha diverses combinacions comunes, per exemple, Apache HTTPD amb uWSGI o Nginx amb Gunicorn.

La funció de la interfície de la passarel·la del servidor web és reenviar les sol·licituds del servidor web al marc web de Python. WSGI és una relíquia del terrible passat quan hi havia motors CGI, i avui WSGI és l'estàndard de facto, independentment del servidor web o del marc Python utilitzat. Però, malgrat el seu ús generalitzat, encara hi ha molts matisos quan es treballa amb aquests marcs i moltes opcions. En aquest cas, intentarem establir la interacció entre Gunicorn i Nginx mitjançant un sòcol.

Com que tots dos components estan instal·lats al mateix servidor, provem d'utilitzar un sòcol UNIX en lloc d'un sòcol de xarxa. Com que la comunicació requereix un sòcol en qualsevol cas, intentem fer un pas més i configurar l'activació del sòcol per a Gunicorn mitjançant systemd.

El procés de creació de serveis activats per socket és bastant senzill. En primer lloc, es crea un fitxer d'unitat que conté una directiva ListenStream que apunta al punt en què es crearà el sòcol UNIX, després un fitxer d'unitat per al servei en què la directiva Requires apuntarà al fitxer d'unitat del sòcol. Aleshores, al fitxer de la unitat de servei, només queda trucar a Gunicorn des de l'entorn virtual i crear un enllaç WSGI per al sòcol UNIX i l'aplicació Django.

Aquests són alguns exemples de fitxers d'unitat que podeu utilitzar com a base. Primer instal·lem el sòcol.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Ara heu de configurar el dimoni Gunicorn.

[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

Per a Nginx, és senzill crear fitxers de configuració de proxy i configurar un directori per emmagatzemar contingut estàtic si n'esteu utilitzant un. A RHEL, els fitxers de configuració de Nginx es troben a /etc/nginx/conf.d. Podeu copiar l'exemple següent al fitxer /etc/nginx/conf.d/default.conf i iniciar el servei. Assegureu-vos d'establir el nom del servidor perquè coincideixi amb el vostre nom d'amfitrió.

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

Inicieu el sòcol Gunicorn i Nginx amb systemd i ja podreu començar a provar.

Error de passarel·la incorrecta?

Si introduïu l'adreça al vostre navegador, probablement rebeu un error 502 Bad Gateway. Pot ser causat per permisos de socket UNIX configurats incorrectament, o pot ser degut a problemes més complexos relacionats amb el control d'accés a SELinux.

Al registre d'errors de nginx podeu veure una línia com aquesta:

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"

Si posem a prova Gunicorn directament, tindrem una resposta buida.

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

Anem a esbrinar per què passa això. Si obriu el registre, probablement veureu que el problema està relacionat amb SELinux. Com que estem executant un dimoni per al qual no s'ha creat cap política, es marca com a init_t. Comprovem aquesta teoria a la pràctica.

sudo setenforce 0

Tot això pot provocar crítiques i llàgrimes de sang, però això només està depurant el prototip. Desactivem la comprovació només per assegurar-nos que aquest és el problema, després del qual tornarem tot al seu lloc.

Si actualitzeu la pàgina al navegador o torneu a executar la nostra ordre curl, podeu veure la pàgina de prova de Django.

Per tant, després d'assegurar-nos que tot funciona i que no hi ha més problemes de permís, tornem a habilitar SELinux.

sudo setenforce 1

No parlaré aquí d'audit2allow ni de crear polítiques basades en alertes amb sepolgen, ja que no hi ha cap aplicació Django real en aquest moment, de manera que no hi ha un mapa complet del que Gunicorn podria voler accedir i a què hauria de negar l'accés. Per tant, és necessari mantenir SELinux en execució per protegir el sistema, alhora que permet que l'aplicació s'executi i deixi missatges al registre d'auditoria perquè després es pugui crear la política real a partir d'ells.

Especificació de dominis permissius

No tothom ha sentit parlar de dominis permesos a SELinux, però no són res de nou. Molts fins i tot van treballar amb ells sense ni adonar-se'n. Quan es crea una política basada en missatges d'auditoria, la política creada representa el domini resolt. Intentem crear una política de permisos senzilla.

Per crear un domini permès específic per a Gunicorn, necessiteu algun tipus de política i també heu de marcar els fitxers adequats. A més, calen eines per muntar noves polítiques.

sudo yum install selinux-policy-devel

El mecanisme de dominis permesos és una gran eina per identificar problemes, especialment quan es tracta d'una aplicació personalitzada o aplicacions que s'envien sense polítiques ja creades. En aquest cas, la política de domini permesa per a Gunicorn serà tan senzilla com sigui possible: declareu un tipus principal (gunicorn_t), declareu un tipus que farem servir per marcar diversos executables (gunicorn_exec_t) i, a continuació, configureu una transició perquè el sistema marqui correctament. processos en execució. L'última línia estableix la política com a activada per defecte en el moment en què es carrega.

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;

Podeu compilar aquest fitxer de polítiques i afegir-lo al vostre sistema.

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

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

Comprovem per veure si SELinux està bloquejant una altra cosa que no sigui el que accedeix el nostre dimoni desconegut.

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 impedeix que Nginx escrigui dades al sòcol UNIX utilitzat per Gunicorn. Normalment, en aquests casos, les polítiques comencen a canviar, però hi ha altres reptes per davant. També podeu canviar la configuració del domini d'un domini de restricció a un domini de permís. Ara movem httpd_t al domini de permisos. Això donarà a Nginx l'accés necessari i podrem continuar amb més treballs de depuració.

sudo semanage permissive -a httpd_t

Per tant, un cop hàgiu aconseguit mantenir SELinux protegit (realment no hauríeu de deixar un projecte SELinux en mode restringit) i els dominis de permís es carreguen, heu d'esbrinar què s'ha de marcar exactament com a gunicorn_exec_t perquè tot funcioni correctament. de nou. Provem de visitar el lloc web per veure missatges nous sobre restriccions d'accés.

sudo ausearch -m AVC -c gunicorn

Veureu molts missatges que contenen 'comm="gunicorn"' que fan diverses coses als fitxers de /srv/djangoapp, de manera que aquesta és, òbviament, una de les ordres que val la pena marcar.

Però a més, apareix un missatge com aquest:

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

Si mireu l'estat del servei gunicorn o executeu l'ordre ps, no veureu cap procés en execució. Sembla que gunicorn està intentant accedir a l'intèrpret de Python al nostre entorn virtualenv, possiblement per executar scripts de treball. Així que ara marquem aquests dos fitxers executables i comprovem si podem obrir la nostra pàgina de prova de Django.

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

El servei gunicorn s'haurà de reiniciar abans que es pugui seleccionar la nova etiqueta. Podeu reiniciar-lo immediatament o aturar el servei i deixar que el socket l'iniciï quan obriu el lloc al navegador. Comproveu que els processos hagin rebut les etiquetes correctes amb ps.

ps -efZ | grep gunicorn

No us oblideu de crear una política SELinux normal més tard!

Si mireu ara els missatges AVC, l'últim missatge conté permissive=1 per a tot allò relacionat amb l'aplicació, i permissive=0 per a la resta del sistema. Si enteneu quin tipus d'accés necessita una aplicació real, podreu trobar ràpidament la millor manera de resoldre aquests problemes. Però fins aleshores, el millor és mantenir el sistema segur i obtenir una auditoria clara i utilitzable del projecte Django.

sudo ausearch -m AVC

Succeït!

Ha aparegut un projecte Django que funciona amb una interfície basada en Nginx i Gunicorn WSGI. Hem configurat Python 3 i PostgreSQL 10 des dels repositoris RHEL 8 Beta. Ara podeu avançar i crear (o simplement desplegar) aplicacions de Django o explorar altres eines disponibles a RHEL 8 Beta per automatitzar el procés de configuració, millorar el rendiment o fins i tot contenidor aquesta configuració.

Font: www.habr.com

Afegeix comentari