RHEL 8 Beta bietet Entwicklern viele neue Funktionen, deren Auflistung Seiten füllen könnte. Doch am besten lernt man Neues durch Übung. Daher bieten wir im Folgenden einen praktischen Leitfaden zum Erstellen einer realen Anwendungsinfrastruktur auf Basis von Red Hat Enterprise. Linux 8-Beta.

Nehmen wir als Grundlage Python, eine bei Entwicklern beliebte Programmiersprache, eine Kombination aus Django und PostgreSQL, einer recht verbreiteten Kombination zum Erstellen von Anwendungen, und konfigurieren wir RHEL 8 Beta für die Arbeit mit ihnen. Dann fügen wir noch ein paar weitere (nicht klassifizierte) Zutaten hinzu.
Die Testumgebung wird sich ändern, da es interessant ist, die Möglichkeiten der Automatisierung zu erkunden, mit Containern zu arbeiten und Umgebungen mit mehreren Servern auszuprobieren. Um mit einem neuen Projekt zu beginnen, können Sie zunächst einen kleinen, einfachen Prototyp von Hand erstellen, damit Sie genau sehen können, was passieren muss und wie es interagiert, und dann mit der Automatisierung und der Erstellung komplexerer Konfigurationen fortfahren. Heute sprechen wir über die Erstellung eines solchen Prototyps.
Beginnen wir mit der Bereitstellung des RHEL 8 Beta VM-Images. Sie können eine virtuelle Maschine von Grund auf installieren oder das mit Ihrem Beta-Abonnement verfügbare KVM-Gast-Image verwenden. Wenn Sie ein Gast-Image verwenden, müssen Sie eine virtuelle CD konfigurieren, die Metadaten und Benutzerdaten für die Cloud-Initialisierung (cloud-init) enthält. Sie müssen nichts Besonderes an der Festplattenstruktur oder den verfügbaren Paketen vornehmen; jede Konfiguration reicht aus.
Schauen wir uns den gesamten Prozess genauer an.
Django installieren
Mit der neuesten Version von Django benötigen Sie eine virtuelle Umgebung (virtualenv) mit Python 3.5 oder höher. In den Beta-Notizen können Sie sehen, dass Python 3.6 verfügbar ist. Schauen wir uns an, ob dies tatsächlich der Fall ist:
[cloud-user@8beta1 ~]$ python
-bash: python: command not found
[cloud-user@8beta1 ~]$ python3
-bash: python3: command not found
Red Hat nutzt Python aktiv als System-Toolkit in RHEL. Warum kommt es zu diesem Ergebnis?
Tatsache ist, dass viele Python-Entwickler immer noch über den Übergang von Python 2 zu Python 2 nachdenken, während sich Python 3 selbst in der aktiven Entwicklung befindet und immer mehr neue Versionen erscheinen. Um den Bedarf an stabilen Systemtools zu decken und Benutzern gleichzeitig Zugriff auf verschiedene neue Versionen von Python zu bieten, wurde System-Python daher in ein neues Paket verschoben und bietet die Möglichkeit, sowohl Python 2.7 als auch 3.6 zu installieren. Weitere Informationen zu den Änderungen und warum sie vorgenommen wurden, finden Sie in der Veröffentlichung in (Langdon White).
Um Python zum Laufen zu bringen, müssen Sie also nur zwei Pakete installieren, wobei python3-pip als Abhängigkeit enthalten ist.
sudo yum install python36 python3-virtualenv
Warum nicht direkte Modulaufrufe verwenden, wie Langdon vorschlägt, und pip3 installieren? Angesichts der bevorstehenden Automatisierung ist bekannt, dass für die Ausführung von Ansible pip installiert sein muss, da das pip-Modul keine virtuellen Umgebungen mit einer benutzerdefinierten ausführbaren pip-Datei unterstützt.
Wenn Ihnen ein funktionierender Python3-Interpreter zur Verfügung steht, können Sie mit dem Django-Installationsprozess fortfahren und zusammen mit unseren anderen Komponenten über ein funktionierendes System verfügen. Im Internet stehen zahlreiche Umsetzungsmöglichkeiten zur Verfügung. Hier wird eine Version vorgestellt, aber Benutzer können ihre eigenen Prozesse verwenden.
Wir werden die in RHEL 8 verfügbaren PostgreSQL- und Nginx-Versionen standardmäßig mit Yum installieren.
sudo yum install nginx postgresql-server
PostgreSQL erfordert psycopg2, aber es muss nur in einer Virtualenv-Umgebung verfügbar sein, daher werden wir es mit pip3 zusammen mit Django und Gunicorn installieren. Aber zuerst müssen wir Virtualenv einrichten.
Es gibt immer wieder Diskussionen darüber, wo Django-Projekte am besten installiert werden sollten, aber im Zweifelsfall kann man sich stets an den Standard halten. Linux Dateisystemhierarchie-Standard. Der FHS legt insbesondere fest, dass /srv verwendet wird für: „Speicherung hostspezifischer Daten – Daten, die vom System erzeugt werden, wie z. B. Webserverdaten und -skripte, auf FTP-Servern gespeicherte Daten und Versionskontrollsystem-Repositories (die in FHS-2.3 im Jahr 2004 eingeführt wurden)“.
Das ist genau unser Fall, also legen wir alles, was wir brauchen, in /srv ab, das unserem Anwendungsbenutzer (Cloud-Benutzer) gehört.
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
Das Einrichten von PostgreSQL und Django ist einfach: Erstellen Sie eine Datenbank, erstellen Sie einen Benutzer, konfigurieren Sie Berechtigungen. Bei der Erstinstallation von PostgreSQL sollten Sie Folgendes beachten: Das Postgresql-Setup-Skript, das mit dem Postgresql-Server-Paket installiert wird. Dieses Skript unterstützt Sie bei der Ausführung grundlegender Aufgaben im Zusammenhang mit der Datenbank-Cluster-Verwaltung, beispielsweise der Cluster-Initialisierung oder dem Upgrade-Prozess. Um eine neue PostgreSQL-Instanz auf einem RHEL-System zu konfigurieren, müssen wir den Befehl ausführen:
sudo /usr/bin/postgresql-setup -initdb
Anschließend können Sie PostgreSQL mit systemd starten, eine Datenbank erstellen und ein Projekt in Django einrichten. Denken Sie daran, PostgreSQL neu zu starten, nachdem Sie Änderungen an der Client-Authentifizierungskonfigurationsdatei (normalerweise pg_hba.conf) vorgenommen haben, um die Passwortspeicherung für den Anwendungsbenutzer zu konfigurieren. Wenn Sie auf andere Schwierigkeiten stoßen, stellen Sie sicher, dass Sie die IPv4- und IPv6-Einstellungen in der Datei pg_hba.conf ändern.
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
In der Datei /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
In der Datei /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 }}',
}
}
Nachdem Sie die Datei „settings.py“ im Projekt konfiguriert und die Datenbankkonfiguration eingerichtet haben, können Sie den Entwicklungsserver starten, um sicherzustellen, dass alles funktioniert. Nach dem Start des Entwicklungsservers empfiehlt es sich, einen Admin-Benutzer anzulegen, um die Verbindung zur Datenbank zu testen.
./manage.py runserver 0.0.0.0:8000
./manage.py createsuperuser
WSGI? Wai?
Der Entwicklungsserver ist zum Testen nützlich, aber um die Anwendung auszuführen, müssen Sie den entsprechenden Server und Proxy für das Web Server Gateway Interface (WSGI) konfigurieren. Es gibt mehrere gängige Kombinationen, zum Beispiel Apache HTTPD mit uWSGI oder Nginx mit Gunicorn.
Die Aufgabe der Web Server Gateway-Schnittstelle besteht darin, Anfragen weiterzuleiten von Webserver Zum Python-Webframework. WSGI ist ein Relikt aus der Zeit der CGI-Mechanismen und heute ein De-facto-Standard, unabhängig vom verwendeten Webserver oder Python-Framework. Trotz seiner weiten Verbreitung gibt es bei der Arbeit mit diesen Frameworks jedoch immer noch viele Feinheiten und eine Vielzahl von Optionen. In diesem Fall versuchen wir, die Kommunikation zwischen Gunicorn und Nginx über einen Socket herzustellen.
Da beide Komponenten auf demselben Server installiert sind, versuchen wir, einen UNIX-Socket anstelle eines Netzwerk-Sockets zu verwenden. Da für die Kommunikation in jedem Fall ein Socket erforderlich ist, versuchen wir noch einen Schritt weiterzugehen und die Socket-Aktivierung für Gunicorn über systemd zu konfigurieren.
Der Prozess zum Erstellen von Socket-aktivierten Diensten ist recht einfach. Zuerst wird eine Unit-Datei erstellt, die eine ListenStream-Direktive enthält, die auf den Punkt zeigt, an dem der UNIX-Socket erstellt wird, und dann eine Unit-Datei für den Dienst, in der die Requires-Direktive auf die Socket-Unit-Datei verweist. Dann müssen Sie in der Service-Unit-Datei nur noch Gunicorn aus der virtuellen Umgebung aufrufen und eine WSGI-Bindung für den UNIX-Socket und die Django-Anwendung erstellen.
Hier finden Sie einige Beispiele für Unit-Dateien, die Sie als Grundlage verwenden können. Zuerst richten wir den Sockel ein.
[Unit]
Description=Gunicorn WSGI socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target
Jetzt müssen Sie den Gunicorn-Daemon konfigurieren.
[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
Für Nginx ist es einfach, Proxy-Konfigurationsdateien zu erstellen und ein Verzeichnis zum Speichern statischer Inhalte einzurichten, falls Sie eines verwenden. In RHEL befinden sich Nginx-Konfigurationsdateien in /etc/nginx/conf.d. Sie können das folgende Beispiel in die Datei /etc/nginx/conf.d/default.conf kopieren und den Dienst starten. Stellen Sie sicher, dass der Servername mit Ihrem Hostnamen übereinstimmt.
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;
}
}
Starten Sie den Gunicorn-Socket und Nginx mit systemd und schon können Sie mit dem Testen beginnen.
Fehler „Bad Gateway“?
Wenn Sie die Adresse in einen Browser eingeben, erhalten Sie wahrscheinlich einen 502 Bad Gateway-Fehler. Dies kann durch falsch konfigurierte Berechtigungen für den UNIX-Socket verursacht werden oder auf komplexere Probleme im Zusammenhang mit der Zugriffskontrolle in SE zurückzuführen sein.Linux.
Im Nginx-Fehlerprotokoll können Sie eine Zeile wie diese sehen:
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"
Wenn wir Gunicorn direkt testen, erhalten wir eine leere Antwort.
curl —unix-socket /run/gunicorn.sock 8beta1.example.com
Lasst uns herausfinden, warum das passiert. Wenn ihr das Protokoll öffnet, werdet ihr höchstwahrscheinlich sehen, dass das Problem mit SE zusammenhängt.LinuxDa wir einen Daemon ausführen, der keine eigene Richtlinie hat, wird er als init_t gekennzeichnet. Testen wir diese Theorie in der Praxis.
sudo setenforce 0
All dies mag Kritik und Tränen des Blutes hervorrufen, aber hier geht es nur um das Debuggen des Prototyps. Deaktivieren wir die Prüfung, um sicherzustellen, dass dies das Problem ist. Anschließend bringen wir alles wieder an seinen Platz zurück.
Durch Aktualisieren der Seite im Browser oder erneutes Ausführen unseres Curl-Befehls können Sie die Django-Testseite sehen.
Nachdem wir sichergestellt haben, dass alles funktioniert und keine Berechtigungsprobleme mehr bestehen, schalten wir SE wieder ein.Linux.
sudo setenforce 1
Dieser Artikel behandelt weder audit2allow noch die Erstellung von warnungsbasierten Richtlinien mit sepolgen, da es aktuell keine echte Django-Anwendung gibt und somit keine vollständige Übersicht darüber existiert, worauf Gunicorn zugreifen möchte und was verweigert werden soll. Daher ist es wichtig, SE aktiv zu halten.Linux um das System zu schützen und gleichzeitig zu ermöglichen, dass die Anwendung ausgeführt wird und Meldungen im Audit-Protokoll hinterlässt, sodass darauf basierend dann tatsächliche Richtlinien erstellt werden können.
Angabe zulässiger Domänen
Informationen zu erlaubten Domains in SELinux Nicht jeder kennt sie, aber sie sind nichts Neues. Viele haben sogar schon damit gearbeitet, ohne es zu wissen. Wenn eine Richtlinie auf Basis von Prüfmeldungen erstellt wird, stellt die resultierende Richtlinie eine zulässige Domäne dar. Versuchen wir, eine einfache Zulassungsrichtlinie zu erstellen.
Um eine bestimmte zulässige Domäne für Gunicorn zu erstellen, benötigen Sie eine Richtlinie und müssen außerdem die entsprechenden Dateien markieren. Darüber hinaus werden Werkzeuge benötigt, um neue Richtlinien zusammenzustellen.
sudo yum install selinux-policy-devel
Der Mechanismus „Zugelassene Domänen“ ist ein hervorragendes Tool zur Identifizierung von Problemen, insbesondere wenn es sich um eine benutzerdefinierte Anwendung oder Anwendungen handelt, die ohne bereits erstellte Richtlinien ausgeliefert werden. In diesem Fall ist die zulässige Domänenrichtlinie für Gunicorn so einfach wie möglich: Deklarieren Sie einen Haupttyp (gunicorn_t), deklarieren Sie einen Typ, den wir zum Markieren mehrerer ausführbarer Dateien verwenden (gunicorn_exec_t), und richten Sie dann einen Übergang ein, damit das System die korrekte Markierung vornimmt laufende Prozesse. Die letzte Zeile legt fest, dass die Richtlinie zum Zeitpunkt des Ladens standardmäßig aktiviert ist.
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;
Sie können diese Richtliniendatei kompilieren und Ihrem System hinzufügen.
make -f /usr/share/selinux/devel/Makefile
sudo semodule -i gunicorn.pp
sudo semanage permissive -a gunicorn_t
sudo semodule -l | grep permissive
Lass uns prüfen, ob SE blockiert.Linux etwas anderes als das, worum sich unser unbekannter Dämon kümmert.
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 Dies verhindert, dass Nginx Daten an den von Gunicorn verwendeten UNIX-Socket schreibt. Normalerweise werden in solchen Fällen die Richtlinien angepasst, es müssen aber noch weitere Probleme behoben werden. Sie können auch die Domain-Einstellungen ändern und die Domain von einer eingeschränkten in eine permissive Domain umwandeln. Verschieben wir nun httpd_t in die permissive Domain. Dadurch erhält Nginx den erforderlichen Zugriff, und wir können mit dem Debuggen fortfahren.
sudo semanage permissive -a httpd_t
Wann ist es Ihnen also gelungen, den SE-Schutz zu retten?Linux (Tatsächlich sollten Sie das Projekt nicht SE überlassen.)Linux Wenn sich das System im eingeschränkten Modus befindet und Berechtigungsdomänen geladen werden, müssen wir herausfinden, was genau als gunicorn_exec_t markiert werden muss, damit alles wieder ordnungsgemäß funktioniert. Versuchen wir, auf die Website zuzugreifen, um zu sehen, ob es neue Meldungen zu Zugriffsbeschränkungen gibt.
sudo ausearch -m AVC -c gunicorn
Sie werden viele Meldungen sehen, die „comm="gunicorn"“ enthalten und verschiedene Dinge mit Dateien in /srv/djangoapp tun, daher ist dies offensichtlich einer der Befehle, die es wert sind, markiert zu werden.
Aber zusätzlich erscheint eine Meldung wie diese:
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
Wenn Sie sich den Status des Gunicorn-Dienstes ansehen oder den Befehl ps ausführen, werden Sie keine laufenden Prozesse sehen. Es sieht so aus, als würde gunicorn versuchen, auf den Python-Interpreter in unserer Virtualenv-Umgebung zuzugreifen, möglicherweise um Worker-Skripte auszuführen. Markieren wir nun diese beiden ausführbaren Dateien und prüfen wir, ob wir unsere Django-Testseite öffnen können.
chcon -t gunicorn_exec_t /srv/djangoapp/django/bin/gunicorn /srv/djangoapp/django/bin/python3.6
Der Gunicorn-Dienst muss neu gestartet werden, bevor das neue Tag ausgewählt werden kann. Sie können ihn sofort neu starten oder den Dienst stoppen und ihn vom Socket starten lassen, wenn Sie die Site im Browser öffnen. Überprüfen Sie mithilfe von ps, ob Prozesse die richtigen Bezeichnungen erhalten haben.
ps -efZ | grep gunicorn
Vergessen Sie nicht, später eine normale SE-Richtlinie zu erstellen.Linux!
Wenn Sie sich jetzt die AVC-Nachrichten ansehen, enthält die letzte Nachricht permissive=1 für alles, was mit der Anwendung zu tun hat, und permissive=0 für den Rest des Systems. Wenn Sie verstehen, welche Art von Zugriff eine echte Anwendung benötigt, können Sie schnell den besten Weg finden, solche Probleme zu lösen. Aber bis dahin ist es am besten, das System sicher zu halten und eine klare, brauchbare Prüfung des Django-Projekts zu erhalten.
sudo ausearch -m AVC
Es stellte sich heraus!
Es ist ein funktionierendes Django-Projekt mit einem Frontend auf Basis von Nginx und Gunicorn WSGI erschienen. Wir haben Python 3 und PostgreSQL 10 aus den RHEL 8 Beta-Repositorys konfiguriert. Jetzt können Sie Django-Anwendungen erstellen (oder einfach bereitstellen) oder andere verfügbare Tools in RHEL 8 Beta erkunden, um den Konfigurationsprozess zu automatisieren, die Leistung zu verbessern oder diese Konfiguration sogar zu containerisieren.
Source: habr.com
