Lokakarya RHEL 8 Beta: Membangun aplikasi web yang berfungsi

RHEL 8 Beta menawarkan banyak fitur baru bagi para pengembang, yang daftarnya bisa memakan banyak halaman, tetapi mempelajari hal-hal baru selalu lebih baik melalui praktik, jadi di bawah ini kami menawarkan panduan praktis untuk membuat infrastruktur aplikasi nyata berdasarkan Red Hat Enterprise. Linux 8 Beta.

Lokakarya RHEL 8 Beta: Membangun aplikasi web yang berfungsi

Mari kita ambil Python, bahasa pemrograman populer di kalangan pengembang, sebagai dasar, kombinasi Django dan PostgreSQL, kombinasi yang cukup umum untuk membuat aplikasi, dan konfigurasikan RHEL 8 Beta untuk bekerja dengannya. Kemudian kami akan menambahkan beberapa bahan lagi (tidak terklasifikasi).

Lingkungan pengujian akan berubah, karena menarik untuk mengeksplorasi kemungkinan otomatisasi, bekerja dengan container, dan mencoba lingkungan dengan banyak server. Untuk memulai proyek baru, Anda dapat memulai dengan membuat prototipe kecil dan sederhana dengan tangan sehingga Anda dapat melihat dengan tepat apa yang perlu terjadi dan bagaimana interaksinya, lalu melanjutkan ke otomatisasi dan membuat konfigurasi yang lebih kompleks. Hari ini kita berbicara tentang pembuatan prototipe semacam itu.

Mari kita mulai dengan men-deploy image RHEL 8 Beta VM. Anda dapat menginstal mesin virtual dari awal, atau menggunakan image tamu KVM yang tersedia dengan langganan Beta Anda. Saat menggunakan image tamu, Anda perlu mengonfigurasi CD virtual yang akan berisi metadata dan data pengguna untuk inisialisasi cloud (cloud-init). Anda tidak perlu melakukan sesuatu yang khusus dengan struktur disk atau paket yang tersedia; konfigurasi apa pun bisa digunakan.

Mari kita lihat lebih dekat keseluruhan prosesnya.

Menginstal Django

Dengan Django versi terbaru, Anda memerlukan lingkungan virtual (virtualenv) dengan Python 3.5 atau lebih baru. Dalam catatan Beta Anda dapat melihat bahwa Python 3.6 tersedia, mari kita periksa apakah memang demikian:

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

Red Hat secara aktif menggunakan Python sebagai perangkat sistem di RHEL, jadi mengapa hal ini terjadi?

Faktanya adalah banyak pengembang Python yang masih memikirkan transisi dari Python 2 ke Python 2, sementara Python 3 sendiri sedang dalam pengembangan aktif, dan semakin banyak versi baru yang terus bermunculan. Oleh karena itu, untuk memenuhi kebutuhan alat sistem yang stabil sambil menawarkan akses kepada pengguna ke berbagai versi baru Python, sistem Python dipindahkan ke paket baru dan menyediakan kemampuan untuk menginstal Python 2.7 dan 3.6. Informasi lebih lanjut tentang perubahan dan alasan perubahan tersebut dilakukan dapat ditemukan dalam publikasi di Blog Langdon White (Langdon Putih).

Jadi, agar Python dapat berfungsi, Anda hanya perlu menginstal dua paket, dengan python3-pip disertakan sebagai dependensi.

sudo yum install python36 python3-virtualenv

Mengapa tidak menggunakan panggilan modul langsung seperti yang disarankan Langdon dan menginstal pip3? Mengingat otomatisasi yang akan datang, diketahui bahwa Ansible akan memerlukan pip diinstal untuk dijalankan, karena modul pip tidak mendukung virtualenvs dengan pip khusus yang dapat dieksekusi.

Dengan juru bahasa python3 yang berfungsi yang Anda inginkan, Anda dapat melanjutkan proses instalasi Django dan memiliki sistem kerja bersama dengan komponen kami yang lain. Ada banyak pilihan implementasi yang tersedia di Internet. Ada satu versi yang disajikan di sini, namun pengguna dapat menggunakan proses mereka sendiri.

Kami akan menginstal versi PostgreSQL dan Nginx yang tersedia di RHEL 8 secara default menggunakan Yum.

sudo yum install nginx postgresql-server

PostgreSQL akan membutuhkan psycopg2, tetapi harus tersedia hanya di lingkungan virtualenv, jadi kami akan menginstalnya menggunakan pip3 bersama dengan Django dan Gunicorn. Tapi pertama-tama kita perlu menyiapkan virtualenv.

Selalu ada banyak perdebatan tentang tempat yang tepat untuk menginstal proyek Django, tetapi jika ragu, Anda selalu dapat merujuk pada standar yang ada. Linux Standar Hierarki Sistem Berkas (Filesystem Hierarchy Standard/FHS). Secara spesifik, FHS menyatakan bahwa /srv digunakan untuk: "menyimpan data khusus host—data yang dihasilkan oleh sistem, seperti data dan skrip server web, data yang disimpan di server FTP, dan repositori sistem kontrol versi (yang muncul di FHS-2.3 pada tahun 2004)."

Inilah kasus kami, jadi kami memasukkan semua yang kami perlukan ke dalam /srv, yang dimiliki oleh pengguna aplikasi kami (pengguna cloud).

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

Menyiapkan PostgreSQL dan Django mudah: membuat database, membuat pengguna, mengkonfigurasi izin. Satu hal yang perlu diingat ketika pertama kali menginstal PostgreSQL adalah skrip pengaturan postgresql yang diinstal dengan paket server postgresql. Skrip ini membantu Anda melakukan tugas dasar yang terkait dengan administrasi klaster database, seperti inisialisasi klaster atau proses pemutakhiran. Untuk mengonfigurasi instance PostgreSQL baru pada sistem RHEL, kita perlu menjalankan perintah:

sudo /usr/bin/postgresql-setup -initdb

Anda kemudian dapat memulai PostgreSQL menggunakan systemd, membuat database, dan menyiapkan proyek di Django. Ingatlah untuk memulai ulang PostgreSQL setelah melakukan perubahan pada file konfigurasi otentikasi klien (biasanya pg_hba.conf) untuk mengonfigurasi penyimpanan kata sandi bagi pengguna aplikasi. Jika Anda mengalami kesulitan lain, pastikan untuk mengubah pengaturan IPv4 dan IPv6 di file 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

Dalam file /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

Dalam berkas /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 }}',
   }
}

Setelah mengonfigurasi file settings.py di proyek dan menyiapkan konfigurasi database, Anda dapat memulai server pengembangan untuk memastikan semuanya berfungsi. Setelah memulai server pengembangan, sebaiknya buat pengguna admin untuk menguji koneksi ke database.

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

WSGI? Tunggu?

Server pengembangan berguna untuk pengujian, tetapi untuk menjalankan aplikasi Anda harus mengkonfigurasi server dan proksi yang sesuai untuk Web Server Gateway Interface (WSGI). Ada beberapa kombinasi umum, misalnya Apache HTTPD dengan uWSGI atau Nginx dengan Gunicorn.

Tujuan dari Web Server Gateway Interface adalah untuk meneruskan permintaan dari server web Mari kita bahas kerangka kerja web Python. WSGI adalah peninggalan masa lalu yang buruk, ketika mekanisme CGI masih digunakan, dan saat ini WSGI merupakan standar de facto, terlepas dari server web atau kerangka kerja Python yang digunakan. Meskipun telah diadopsi secara luas, masih banyak nuansa yang perlu diperhatikan saat bekerja dengan kerangka kerja ini, dan terdapat berbagai pilihan. Dalam hal ini, kita akan mencoba membangun komunikasi antara Gunicorn dan Nginx melalui soket.

Karena kedua komponen ini diinstal pada server yang sama, mari kita coba menggunakan soket UNIX daripada soket jaringan. Karena komunikasi memerlukan soket, mari kita coba mengambil satu langkah lagi dan mengkonfigurasi aktivasi soket untuk Gunicorn melalui systemd.

Proses pembuatan layanan yang diaktifkan soket cukup sederhana. Pertama, file unit dibuat yang berisi direktif ListenStream yang menunjuk ke titik di mana soket UNIX akan dibuat, kemudian file unit untuk layanan di mana direktif Requires akan menunjuk ke file unit soket. Kemudian, dalam file unit layanan, yang tersisa hanyalah memanggil Gunicorn dari lingkungan virtual dan membuat pengikatan WSGI untuk soket UNIX dan aplikasi Django.

Berikut beberapa contoh file unit yang dapat Anda gunakan sebagai dasar. Pertama kita menyiapkan soketnya.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Sekarang Anda perlu mengkonfigurasi daemon 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

Untuk Nginx, cukup dengan membuat file konfigurasi proxy dan menyiapkan direktori untuk menyimpan konten statis jika Anda menggunakannya. Di RHEL, file konfigurasi Nginx terletak di /etc/nginx/conf.d. Anda dapat menyalin contoh berikut ke dalam file /etc/nginx/conf.d/default.conf dan memulai layanan. Pastikan untuk mengatur server_name agar sesuai dengan nama host Anda.

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

Mulai soket Gunicorn dan Nginx menggunakan systemd dan Anda siap untuk memulai pengujian.

Kesalahan Gateway buruk?

Jika Anda memasukkan alamat tersebut ke dalam browser, kemungkinan besar Anda akan mendapatkan kesalahan 502 Bad Gateway. Hal ini dapat disebabkan oleh konfigurasi izin yang salah pada soket UNIX, atau dapat disebabkan oleh masalah yang lebih kompleks terkait kontrol akses di SE.Linux.

Di log kesalahan nginx Anda dapat melihat baris seperti ini:

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"

Jika kita menguji Gunicorn secara langsung, kita akan mendapatkan jawaban yang kosong.

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

Mari kita cari tahu mengapa ini terjadi. Jika Anda membuka log, kemungkinan besar Anda akan melihat bahwa masalah ini terkait dengan SE.LinuxKarena kita menjalankan daemon yang tidak memiliki kebijakan sendiri, maka daemon tersebut ditandai sebagai init_t. Mari kita uji teori ini dalam praktik.

sudo setenforce 0

Semua ini mungkin menimbulkan kritik dan air mata darah, tetapi ini hanya men-debug prototipe. Mari kita nonaktifkan pemeriksaan hanya untuk memastikan bahwa ini masalahnya, setelah itu kita akan mengembalikan semuanya ke tempatnya.

Dengan menyegarkan halaman di browser atau menjalankan kembali perintah curl kami, Anda dapat melihat halaman pengujian Django.

Jadi, setelah memastikan semuanya berfungsi dan tidak ada lagi masalah dengan izin, kita menyalakan SE lagi.Linux.

sudo setenforce 1

Artikel ini tidak akan membahas audit2allow atau membuat kebijakan berbasis peringatan menggunakan sepolgen, karena saat ini belum ada aplikasi Django yang sebenarnya, sehingga belum ada peta lengkap tentang apa yang mungkin ingin diakses Gunicorn dan apa yang harus ditolak. Oleh karena itu, penting untuk tetap menjalankan SE.Linux untuk melindungi sistem, sambil tetap memungkinkan aplikasi untuk berjalan dan meninggalkan pesan di log audit sehingga kebijakan aktual kemudian dapat dibuat berdasarkan pesan-pesan tersebut.

Menentukan domain permisif

Tentang domain yang diizinkan di SELinux Tidak semua orang pernah mendengarnya, tetapi ini bukanlah hal baru. Banyak yang bahkan pernah menggunakannya tanpa menyadarinya. Ketika sebuah kebijakan dibuat berdasarkan pesan audit, kebijakan yang dihasilkan mewakili domain yang diizinkan. Mari kita coba membuat kebijakan izin sederhana.

Untuk membuat domain khusus yang diizinkan untuk Gunicorn, Anda memerlukan semacam kebijakan, dan Anda juga perlu menandai file yang sesuai. Selain itu, diperlukan alat untuk menyusun kebijakan baru.

sudo yum install selinux-policy-devel

Mekanisme domain yang diizinkan adalah alat yang hebat untuk mengidentifikasi masalah, terutama jika menyangkut aplikasi khusus atau aplikasi yang dikirimkan tanpa kebijakan yang sudah dibuat. Dalam hal ini, kebijakan domain yang diizinkan untuk Gunicorn akan sesederhana mungkin - mendeklarasikan tipe utama (gunicorn_t), mendeklarasikan tipe yang akan kita gunakan untuk menandai beberapa executable (gunicorn_exec_t), dan kemudian menyiapkan transisi agar sistem dapat menandai dengan benar proses yang berjalan. Baris terakhir menetapkan kebijakan sebagai diaktifkan secara default pada saat kebijakan dimuat.

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;

Anda dapat mengkompilasi file kebijakan ini dan menambahkannya ke sistem Anda.

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

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

Mari kita periksa apakah SE sedang memblokir.Linux sesuatu yang lain selain apa yang sedang dibicarakan oleh iblis tak dikenal kita.

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 Hal ini mencegah Nginx menulis data ke soket UNIX yang digunakan oleh Gunicorn. Biasanya, kebijakan diubah dalam kasus seperti ini, tetapi masalah lain masih perlu ditangani. Anda juga dapat mengubah pengaturan domain, mengubahnya dari domain terbatas menjadi domain permisif. Sekarang mari kita pindahkan httpd_t ke domain permisif. Ini akan memberi Nginx akses yang diperlukan, dan kita dapat melanjutkan proses debugging.

sudo semanage permissive -a httpd_t

Jadi, kapan Anda berhasil menyimpan perlindungan SE?Linux (Sebenarnya, Anda sebaiknya tidak meninggalkan proyek ini bersama SE)Linux Jika sistem berada dalam mode terbatas dan domain izin sedang dimuat, kita perlu mencari tahu apa yang sebenarnya perlu ditandai sebagai gunicorn_exec_t agar semuanya berfungsi dengan benar kembali. Mari kita coba mengakses situs web untuk melihat pesan baru tentang pembatasan akses.

sudo ausearch -m AVC -c gunicorn

Anda akan melihat banyak pesan berisi 'comm="gunicorn"' yang melakukan berbagai hal pada berkas di /srv/djangoapp, jadi ini jelas merupakan salah satu perintah yang patut ditandai.

Namun selain itu, muncul pesan seperti ini:

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

Jika Anda melihat status layanan gunicorn atau menjalankan perintah ps, Anda tidak akan melihat proses yang berjalan. Sepertinya gunicorn mencoba mengakses juru bahasa Python di lingkungan virtualenv kami, mungkin untuk menjalankan skrip pekerja. Jadi sekarang mari tandai dua berkas yang dapat dieksekusi ini dan periksa apakah kita dapat membuka halaman pengujian Django kita.

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

Layanan gunicorn perlu dimulai ulang sebelum tag baru dapat dipilih. Anda dapat segera memulai ulang atau menghentikan layanan dan membiarkan soket memulainya saat Anda membuka situs di browser. Verifikasi bahwa proses telah menerima label yang benar menggunakan ps.

ps -efZ | grep gunicorn

Jangan lupa untuk membuat kebijakan SE normal nanti.Linux!

Jika Anda melihat pesan AVC sekarang, pesan terakhir berisi permisif=1 untuk segala sesuatu yang berhubungan dengan aplikasi, dan permisif=0 untuk seluruh sistem. Jika Anda memahami jenis akses yang dibutuhkan aplikasi sebenarnya, Anda dapat dengan cepat menemukan cara terbaik untuk menyelesaikan masalah tersebut. Namun sampai saat itu tiba, yang terbaik adalah menjaga sistem tetap aman dan mendapatkan audit proyek Django yang jelas dan dapat digunakan.

sudo ausearch -m AVC

Telah terjadi!

Proyek Django yang berfungsi telah muncul dengan frontend berdasarkan Nginx dan Gunicorn WSGI. Kami mengonfigurasi Python 3 dan PostgreSQL 10 dari repositori RHEL 8 Beta. Sekarang Anda dapat bergerak maju dan membuat (atau menyebarkan) aplikasi Django atau menjelajahi alat lain yang tersedia di RHEL 8 Beta untuk mengotomatiskan proses konfigurasi, meningkatkan kinerja, atau bahkan memasukkan konfigurasi ini ke dalam container.

Sumber: www.habr.com

Beli hosting yang andal untuk situs dengan perlindungan DDoS, server VPS VDS 🔥 Beli hosting website andal dengan perlindungan DDoS, server VPS VDS | ProHoster