HAProxy dengan SNI dan Pengaturan SSL yang berbeda

9

Saya memiliki HAProxy untuk dua situs saya, salah satunya publik dan satu pribadi.

www.mysite.com private.mysite.com

Atm, saya menggunakan haproxy seperti ini:

frontend mysite_https
  bind *.443 ssl crt /etc/mycert.pem ca-file /etc/myca.pem verify optional no-sslv3
  mode http
  acl domain_www     hdr_beg(host) -i www.
  acl domain_private hdr_beg(host) -i private.
  acl path_ghost     path_beg         /ghost/
  acl clientcert     ssl_c_used

  redirect location https://www.example.com if path_ghost !clientcert
  redirect location https://www.example.com if !domain_www !clientcert

  use_backend bknd_private if domain_private
  use_backend bknd_www     if domain_www

  default_backend bknd_www

Apa yang harus dilakukan adalah meminta sertifikat klien (opsional) dan melanjutkan. Jika domain tersebut bukan www.example.com dan pengunjung tidak dapat memberikan sertifikat yang tepat atau jalurnya adalah / ghost / dan pengunjung tidak dapat memberikan sertifikat yang tepat, itu harus diarahkan ke https://www.example.com

Sejauh ini, ini berfungsi dengan baik. Namun, saya mendapat keluhan oleh pengguna Mac yang menelusuri situs saya dengan Safari bahwa mereka terus dimintai sertifikat ketika ada penjelajahan di https://www.example.com/ sedangkan misalnya Firefox hanya bertanya saat menjelajah https: //private.example .com / atau https://www.example.com/ghost/ .

Tampaknya itulah cara kerja Safari, jadi saya tidak bisa memperbaikinya. Ide saya adalah menggunakan SNI untuk membagi antara berbagai frontend

frontend mysite_https
  bind *.443 ssl crt /etc/mycert.pem no-sslv3

frontend private_https
  bind *.443 ssl crt /etc/mycert.pem ca-file /etc/myca.pem verify optional no-sslv3

Tentu saja itu tidak berhasil karena

Sebuah. Saya tidak dapat memiliki dua frontend mendengarkan pada port 443 dengan hanya satu IP publik b. Saya belum menemukan cara untuk mengatakan "use_frontend if domain_www" atau sesuatu seperti itu. (Hanya use_backend atau use-server)

Saya juga mencoba melakukannya dengan tiga server haproxy

frontend haproxy-sni
bind *:443 ssl crt /etc/mycert.pem no-sslv3
mode tcp

tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }

acl domain_www ssl_fc_sni_end -i www.example.com

use-server server1 haproxy-private.lan  if !domain_www
use-server server2 haproxy-public.lan   if domain_www

Ini berfungsi, masalahnya di sini adalah haproxy-private meminta sertifikat klien, tetapi permintaan tersebut tidak mencapai browser. Entah bagaimana haproxy-sni menjatuhkan permintaan.

Juga, saya sekarang memiliki tiga server haproxy yang tidak diinginkan (walaupun merupakan opsi yang mungkin jika saya tidak dapat menemukan solusi yang lebih baik).

Lebih disukai saya ingin sesuatu seperti ini (dibuat-buat .. tidak tahu opsi yang sebenarnya)

frontend mysite_https
  bind *.443 ssl crt /etc/mycert.pem no-sslv3
  mode http

  acl domain_www     hdr_beg(host) -i www.
  acl domain_private hdr_beg(host) -i private.
  acl path_ghost     path_beg         /ghost/

  ssl_options ca-file /etc/myca.pem verify optional if !www_domain          # made up!
  ssl_options ca-file /etc/myca.pem verify optional if !path_ghost          # made up!

  acl clientcert     ssl_c_used

  redirect location https://www.example.com if path_ghost !clientcert
  redirect location https://www.example.com if !domain_www !clientcert
  ...

Saya berharap ada orang yang bisa membantu saya dalam hal ini...

mohrphium
sumber

Jawaban:

13

Saya menemukan solusi untuk masalah ini, yang tidak memerlukan server atau layanan tambahan. Saya tidak sepenuhnya yakin apakah ini tidak menimbulkan masalah baru. Bagi saya sepertinya berfungsi sekarang.

Cara saya melakukannya, adalah membuat frontend untuk setiap domain yang memerlukan pengaturan ssl berbeda. Saya kemudian mengatur opsi bind dari frontend tersebut ke port tinggi (ini tidak dapat dijangkau oleh publik!).

Saya membuat frontend lain mendengarkan pada port: 443 untuk membagi lalu lintas berdasarkan SNI, dan mengatur server backend ke 127.0.0.1:high-port.

Dengan cara ini, saya membuat semacam loop di haproxy

[incoming]->[haproxy:443]->[haproxy:7000]->[www.intern.lan]
[incoming]->[haproxy:443]->[haproxy:8000]->[private.intern.lan]

Inilah bagian konfigurasi.

frontend frnd_snipt                                             # Frontend_SNI-PassThrough (snipt)
  bind *:443                                                    # Do not use bind *:8443 ssl crt etc....!
  option tcplog
  mode tcp 

  tcp-request inspect-delay 5s
  tcp-request content accept if { req_ssl_hello_type 1 } 

  acl subdomain_is_www   req_ssl_sni -i www.example.com
  acl subdomain_is_www   req_ssl_sni -i example.com
  acl subdomain_is_private req_ssl_sni -i private.example.com

  use_backend bknd_snipt_private if subdomain_is_private
  use_backend bknd_snipt_www  if subdomain_is_www

backend bknd_snipt_www
  mode tcp                                              # tcp mode must match the frontend mode - already set as default in [global]
  server snipt-www 127.0.0.1:7000                       # run without "check", otherwise haproxy checks itself all the time!

backend bknd_snipt_private
  mode tcp     
  server snipt-private 127.0.0.1:8000                   # also, don't add "ssl" when in tcp mode. "ssl" is an http mode option (result in "NO-SRV" when set in tcp)

##### NORMAL HAPROXY PART #####
frontend www_example_com                                # this frontend can be in tcp or http mode...
  bind *:7000 ssl crt /etc/mycert.pem no-sslv3          # www. frontend with normal https
  mode http
  option httplog


frontend private_example_com
  bind *:8000 ssl crt /etc/mycert.pem ca-file /etc/myca.pem verify optional no-sslv3        # private. frontend with client certificate request.
  mode http
  option httplog
  ... # whatever you have in your frontend

Jika ada yang memiliki pemikiran tentang ini, atau ada ide mengapa ini bisa menjadi ide yang buruk tolong beri tahu saya. Berhasil, tapi saya bertanya-tanya mengapa use_frontend bukan pilihan. Mungkin karena itu adalah sesuatu yang tidak boleh dilakukan untuk alasan apa pun.

mohrphium
sumber
Ide bagus. Saya tidak dapat menemukan dokumentasi pada pengaturan ini juga. Apakah kinerjanya mirip dengan loop HAProxy ini?
JB. Dengan Monica.
Sry, saya tidak tahu bagaimana performannya karena A: tidak menggunakannya lama (karena filter ip sumber), B: tidak memiliki situs traffic tinggi, di mana optimalisasi kinerja akan lebih menarik ...
mohrphium
Saya hanya meletakkan apache2 di depan haproxy, yang berfungsi tetapi agak bodoh karena satu-titik-kegagalan di depan hapeoxy cluster dan (saya pikir) bottleneck kinerja (saya pikir hap lebih cepat daripada ap2, tidak mendapat data nyata tentang meskipun begitu.)
mohrphium
3

versi terbaru haproxy mendukung pengaturan yang disebut crt-listyang memungkinkan Anda menentukan pengaturan TLS berbeda berdasarkan sertifikat yang cocok

Anda dapat menggunakannya seperti ini:

haproxy.conf:

frontend https
    mode http
    bind *:443 ssl crt-list /etc/haproxy/crt-list.conf ca-file ca.pem

    use_backend test if { ssl_fc_sni -i test.area.example.org }
    use_backend private if { ssl_fc_sni -i private.example.org }
    default_backend www

crt-list.conf:

www.pem [verify none]
www.pem [verify required] *.area.example.org
private.pem [verify required]

info lebih lanjut: https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#5.1-crt-list

catatan tentang keamanan: selalu cocokkan nama host Anda (sensitif) dengan SNI ssl_fc_sni, bukan nama host HTTP. Kalau tidak, seorang penyerang mungkin dapat mem-bypass klien Anda dengan mengirimkan TLS SNI www.example.orgtetapi tetapkan nama host HTTP menjadi private.example.org!

orang aneh
sumber
OP menggunakan sertifikat yang sama untuk keduanya. Pertanyaannya lebih tentang ca-filepengaturan yang berbeda .
gre_gor