Cara membatasi frekuensi permintaan di HAProxy: petunjuk langkah demi langkah


Penulis menjelaskan cara menerapkan dalam batas kecepatan kueri HAProxy (pembatasan tingkat) dengan alamat IP tertentu. Tim Mail.ru Cloud Solutions menerjemahkan artikelnya - kami berharap dengan itu Anda tidak perlu menghabiskan banyak waktu dan upaya karena Anda harus menghabiskannya.

Faktanya adalah bahwa ini adalah salah satu metode paling populer untuk melindungi server dari serangan DoS, tetapi sulit untuk menemukan instruksi yang jelas di Internet bagaimana mengkonfigurasinya secara khusus. Dengan coba-coba, penulis memaksa HAProxy untuk membatasi frekuensi permintaan pada daftar alamat IP, yang diperbarui secara real time.

Tidak diperlukan pengetahuan sebelumnya untuk mengkonfigurasi HAProxy, karena semua langkah yang diperlukan diuraikan di bawah ini.

Open source dan HAProxy gratis adalah penyeimbang beban dan server proxy yang sangat mudah diakses. Dalam beberapa tahun terakhir, telah menjadi sangat populer karena memberikan kinerja tinggi dengan sumber daya minimum. Tidak seperti program alternatif, versi nirlaba Edisi Komunitas HAProxy menawarkan cukup fitur untuk penyeimbangan beban yang andal.

Program ini pada awalnya cukup sulit untuk diketahui. Namun, ia memiliki dokumentasi teknis yang sangat teliti dan terperinci . Penulis mengatakan bahwa ini adalah dokumentasi paling rinci di antara semua program open source yang pernah ia gunakan.
Jadi, inilah panduan langkah demi langkah.

Mengkonfigurasi penyeimbang beban


Untuk menghemat waktu dan tidak terganggu oleh pengaturan infrastruktur, ambil Docker dan Docker Compose images dan segera luncurkan komponen utama.

Tugas pertama adalah meningkatkan instance penyeimbang beban HAProxy dengan beberapa server backend Apache.

Kloning repositori


$ git clone git@github.com:stargazer/haproxy-ratelimiter.git
$ cd haproxy-ratelimiter

Anda dapat melihat Dockerfiledan docker-compose.ymldengan parameter instalasi. Diskusi mereka berada di luar cakupan artikel ini, jadi mari kita memikirkan fakta bahwa mereka membuat instance HAProxy yang berfungsi yang disebut loadbalancerdua server backend api01dan api02. Untuk mengkonfigurasi HAProxy, kami awalnya akan menggunakan file haproxy-basic.cfg, dan kemudian beralih ke haproxy-ratelimiting.cfg.

Untuk kesederhanaan, file konfigurasi telah haproxy-basic.cfgdikurangi seminimal mungkin dan dibersihkan dari kelebihan. Mari kita melihatnya:

defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms

frontend proxy
bind *:80

use_backend api

backend api
balance roundrobin

server api01 api01:80
server api02 api02:80

Bagian ini frontend proxymengatur HAProxy untuk mendengarkan pada port 80 dan meneruskan semua permintaan ke kumpulan server apidi backend.

CATEGORY backend apimenentukan kumpulan backend apidengan dua server back-end api01dan api02dan alamat yang sesuai. Server untuk melayani setiap permintaan yang masuk dipilih oleh algoritma load balancing roundrobin, yaitu, pada kenyataannya, dua server yang tersedia digunakan secara bergantian.

Mari kita luncurkan ketiga kontainer kita


$ sudo docker-compose up

Sekarang kami memiliki wadah loadbalanceryang mengalihkan permintaan ke dua backend api01dan server api02. Kami akan mendapat respons dari salah satu dari mereka jika kami memasukkan di bilah alamat http://localhost/.

Sangat menarik untuk menyegarkan halaman beberapa kali dan melihat log docker-compose.

api01_1 | 192.168.192.3 - - [08 / Jan / 2019: 11: 38: 09 +0000] "DAPATKAN / HTTP / 1.1" 200 45
api02_1 | 192.168.192.3 - - [08 / Jan / 2019: 11: 38: 10 +0000] "DAPATKAN / HTTP / 1.1" 304 -
api01_1 | 192.168.192.3 - - [08 / Jan / 2019: 11: 38: 10 +0000] "DAPATKAN / HTTP / 1.1" 304 -
api02_1 | 192.168.192.3 - - [08 / Jan / 2019: 11: 38: 11 +0000] "DAPATKAN / HTTP / 1.1" 304 -
api01_1 | 192.168.192.3 - - [08 / Jan / 2019: 11: 38: 11 +0000] "DAPATKAN / HTTP / 1.1" 304 -
api02_1 | 192.168.192.3 - - [08 / Jan / 2019: 11: 38: 11 +0000] "DAPATKAN / HTTP / 1.1" 304 -

Seperti yang Anda lihat, dua server apimemproses permintaan secara bergantian.

Kami sekarang memiliki instance HAProxy dengan konfigurasi penyeimbangan beban yang sangat sederhana, dan kami memiliki beberapa gagasan tentang cara kerjanya.

Tambahkan batas pada jumlah permintaan


Untuk menetapkan batas jumlah permintaan ke penyeimbang beban, Anda perlu memodifikasi file konfigurasi dalam instance HAProxy. Pastikan bahwa wadah loadbalancermenggunakan file konfigurasi haproxy-ratelimiter.cfg.

Cukup modifikasi Dockerfile untuk mengganti file konfigurasi.

FROM haproxy:1.7
COPY haproxy-ratelimiter.cfg /usr/local/etc/haproxy/haproxy.cfg

Batas pengaturan


Semua pengaturan terdaftar dalam file konfigurasi haproxy-ratelimiter.cfg. Mari kita pelajari dengan seksama.

defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms

frontend proxy
bind *:80

# ACL function declarations
acl is_abuse src_http_req_rate(Abuse) ge 10
acl inc_abuse_cnt src_inc_gpc0(Abuse) gt 0
acl abuse_cnt src_get_gpc0(Abuse) gt 0

# Rules
tcp-request connection track-sc0 src table Abuse
tcp-request connection reject if abuse_cnt
http-request deny if abuse_cnt
http-request deny if is_abuse inc_abuse_cnt

use_backend api
backend api
balance roundrobin

server api01 api01:80
server api02 api02:80

backend Abuse
stick-table type ip size 100K expire 30m store gpc0,http_req_rate(10s)

HAProxy menawarkan serangkaian primitif tingkat rendah yang memberikan lebih banyak fleksibilitas dan cocok untuk berbagai kasus penggunaan. Penghitungnya sering mengingatkan saya pada register akumulatif (adder) di CPU. Mereka menyimpan hasil antara, mengambil semantik yang berbeda sebagai input, tetapi pada akhirnya mereka hanya angka. Untuk memahami semuanya dengan baik, masuk akal untuk memulai dari bagian paling akhir dari file konfigurasi.

Meja Abuse


backend Abuse
stick-table type ip size 100K expire 30m store gpc0,http_req_rate(10s)


Di sini kami membuat backend dummy yang disebut Abuse("penyalahgunaan"). Fiktif, karena hanya digunakan untuk stick-table, yang konfigurasi selanjutnya dapat merujuk nama Abuse. Stick-table adalah tabel yang disimpan dalam memori proses, di mana untuk setiap catatan Anda dapat menentukan masa pakai.

Meja kami memiliki karakteristik sebagai berikut:

  • type ip: Permintaan disimpan dalam tabel dengan alamat IP sebagai kunci. Dengan demikian, permintaan dari alamat IP yang sama akan merujuk pada catatan yang sama. Pada dasarnya, ini berarti kami melacak alamat IP dan data terkait.
  • size 100K: Tabel ini berisi maksimal 100 ribu catatan.
  • expire 30m: Periode penyimpanan catatan adalah 30 menit tidak aktif.
  • store gpc0,http_req_rate(10s): Penghitung gpc0dan jumlah permintaan alamat IP selama 10 detik terakhir disimpan dengan entri . Dengan bantuan, gpc0kami akan melacak berapa kali alamat IP diperhatikan dalam pelanggaran. Faktanya, nilai penghitung positif berarti bahwa alamat IP sudah ditandai sebagai mencurigakan. Mari kita sebut penghitung ini abuse indicator.

Secara umum, tabel ini Abusememungkinkan Anda untuk melacak apakah alamat IP ditandai sebagai mencurigakan, serta frekuensi permintaan saat ini dari alamat ini. Oleh karena itu, kami memiliki riwayat catatan, serta informasi waktu nyata.

Sekarang mari kita beralih ke bagian frontend proxydan melihat apa yang baru di sana.

Fungsi dan Aturan ACL


frontend proxy
bind *:80

# ACL function declarations
acl is_abuse src_http_req_rate(Abuse) ge 10
acl inc_abuse_cnt src_inc_gpc0(Abuse) gt 0
acl abuse_cnt src_get_gpc0(Abuse) gt 0

# Rules
tcp-request connection track-sc0 src table Abuse
tcp-request connection reject if abuse_cnt
http-request deny if abuse_cnt
http-request deny if is_abuse inc_abuse_cnt

use_backend api

Daftar Kontrol Akses (ACL) adalah deklarasi fungsi yang dipanggil hanya ketika aturan ditetapkan.

Mari kita lihat lebih dekat ketiga entri ACL. Perlu diingat bahwa mereka semua secara eksplisit merujuk tabel Abuseyang menggunakan alamat IP sebagai kunci, sehingga setiap fungsi berlaku untuk permintaan alamat IP:

  • acl is_abuse src_http_req_rate(Abuse) ge 10: Fungsi is_abusekembali Truejika frekuensi permintaan saat ini lebih besar atau sama dengan sepuluh.
  • acl inc_abuse_cnt src_inc_gpc0(Abuse) gt 0: Fungsi inc_abuse_cntkembali Truejika nilai kenaikan gpc0lebih besar dari nol. Karena nilai awal gpc0adalah nol, fungsi ini selalu kembali True. Dengan kata lain, itu meningkatkan nilai abuse indicator, pada dasarnya menandakan penyalahgunaan dari alamat IP ini.
  • acl abuse_cnt src_get_gpc0(Abuse) gt 0: Fungsi abuse_cntkembali Truejika nilainya gpc0lebih besar dari nol. Dengan kata lain, dia mengatakan jika alamat IP ini telah ditemukan dalam pelanggaran.

Seperti yang disebutkan sebelumnya, ACL hanyalah deklarasi, yaitu deklarasi fungsi. Mereka tidak berlaku untuk permintaan masuk sampai beberapa aturan dipicu.

Masuk akal untuk melihat aturan yang didefinisikan di bagian yang sama frontend. Aturan diterapkan untuk setiap permintaan yang masuk satu per satu - dan menjalankan fungsi dari ACL yang baru saja kita tetapkan.

Mari kita lihat apa yang dilakukan masing-masing aturan:

  • tcp-request connection track-sc0 src table Abuse: Menambahkan kueri ke tabel Abuse. Karena kuncinya adalah alamat IP dalam tabel, aturan ini menambah daftar alamat IP.
  • tcp-request connection reject if abuse_cnt: TCP-, IP- , abuse. , TCP- IP-.
  • http-request deny if abuse_cnt: , IP- . IP-, abuse.
  • http-request deny if is_abuse inc_abuse_cnt: , is_abuse inc_abuse_cnt True. , , IP- , IP- .

Intinya, kami memperkenalkan dua jenis cek: secara waktu nyata dan dalam daftar hitam dari riwayat kueri. Aturan kedua menolak semua koneksi TCP baru jika alamat IP telah diketahui dalam penyalahgunaan. Aturan ketiga melarang layanan permintaan HTTP untuk alamat IP dari daftar hitam, terlepas dari frekuensi permintaan saat ini dari alamat ini. Aturan keempat memastikan bahwa permintaan HTTP dari alamat IP ditolak pada saat itu juga setelah ambang untuk frekuensi permintaan telah diatasi. Dengan demikian, aturan kedua terutama bekerja pada koneksi TCP baru, yang ketiga dan keempat pada koneksi yang sudah mapan, yang pertama adalah pemeriksaan historis, dan yang kedua adalah pemeriksaan waktu-nyata.

Mari kita coba filter dalam aksi!


Sekarang kita dapat merakit dan meluncurkan wadah kita lagi.

$ sudo docker-compose down
$ sudo docker-compose build
$ sudo docker-compose up

Load balancer harus dimulai sebelum dua server backend.

Mari arahkan browser kita ke http://localhost/. Jika kami menyegarkan halaman dengan cepat selusin kali, kami akan melebihi ambang batas sepuluh permintaan dalam interval sepuluh detik - dan permintaan kami akan ditolak. Jika kami terus menyegarkan halaman, permintaan baru akan segera ditolak - bahkan sebelum koneksi TCP dibuat.

Pertanyaan


Mengapa batas sepuluh permintaan per sepuluh detik?


Tabel Abusemenentukan http_req_rate(10s), yaitu, frekuensi permintaan diukur dalam jendela sepuluh detik. Fungsi is_abusedari ACL kembali Truepada tingkat permintaan ≥10 dalam interval yang ditentukan. Dengan demikian, penyalahgunaan dianggap sebagai frekuensi permintaan sepuluh atau lebih permintaan dalam sepuluh detik.

Pada artikel ini, misalnya, kami memutuskan untuk menetapkan batas rendah agar lebih mudah untuk memeriksa operasi pembatas.

Apa perbedaan antara aturan koneksi http-request dan tcp-request?


Dari dokumentasi :

http-request: pernyataan http-request mendefinisikan seperangkat aturan yang berlaku pada lapisan jaringan 7 [model OSI]

Dari dokumentasi :
koneksi tcp-request: melakukan aksi pada koneksi yang masuk tergantung pada kondisi di lapisan jaringan 4

HTTP-, TCP-?


Bayangkan bahwa permintaan HTTP ke server mengirim beberapa koneksi TCP dari alamat IP yang sama. Frekuensi permintaan HTTP akan dengan cepat melebihi ambang batas. Saat itulah aturan keempat mulai berlaku, yang membuang permintaan dan memasukkan alamat IP ke daftar hitam.

Sekarang sangat mungkin bahwa koneksi HTTP dari alamat IP yang sama tetap terbuka (lihat koneksi HTTP persisten ), dan frekuensi permintaan HTTP telah turun di bawah nilai ambang batas. Aturan ketiga menjamin terus memblokir permintaan HTTP, karena abuse indicatordipicu pada IP ini.

Sekarang anggaplah bahwa setelah beberapa menit IP yang sama mencoba untuk membuat koneksi TCP. Mereka langsung dibuang, karena aturan kedua berlaku: ia melihat alamat IP berlabel dan segera menjatuhkan koneksi.

Kesimpulan


Pada awalnya, mungkin sulit untuk memahami keterbatasan kecepatan pemrosesan permintaan menggunakan HAProxy. Untuk melakukan semuanya dengan benar, Anda memerlukan pemikiran "tingkat rendah" dan sejumlah tindakan non-intuitif. Dokumentasi dalam bagian ini mungkin terlalu teknis dan tidak memiliki contoh dasar. Kami berharap bahwa panduan ini akan menebus kekurangan dan menunjukkan arah kepada semua orang yang ingin mengambil jalan ini.

Apa lagi yang harus dibaca :

  1. Bagaimana arsitektur toleran-kesalahan diimplementasikan dalam platform Mail.ru Cloud Solutions .
  2. 10 Trik dan Tip Kubernet Teratas .
  3. Saluran Telegram kami tentang transformasi digital .

All Articles