Ограничения для кластера

Ограничения для кластера#

Ограничение по User Agent#

В целях информационной безопасности и обеспечения корректной работы современных веб-приложений требуется ограничить доступ клиентов, использующих устаревшие версии браузеров. Такие браузеры не поддерживают актуальные криптографические протоколы и современные стандарты верстки, что делает их уязвимыми и несовместимыми с функционалом системы.

Ниже в разделах примеры настройки отклонения запросов по заголовку User-Agent на уровнях балансировщика HaProxy и Ingress-контроллера.

Для кластера ограничение можно настроить через HaProxy или Ingress.

HaProxy#

Добавить профиль конфигурации HaProxy для проброса в контейнер ~/nscli/workspace/appkit/profile/haproxy/template/haproxy.cfg:

HaProxy.cfg
global
      log stdout format short local0
      maxconn 40000
      stats socket {{work_dir}}/admin.sock mode 660 level admin
      stats timeout 30s
      user root
      group root
      ca-base /etc/ssl/certs
      crt-base /etc/ssl/private
  ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
  ssl-default-bind-options no-sslv3

  defaults
      log    global
      mode    http
      option    httplog
      option  forwardfor
      option    dontlognull
      timeout connect 120s
      timeout client  7d
      timeout server  7d
      errorfile 400 /etc/haproxy/errors/400.http
      errorfile 403 /etc/haproxy/errors/403.http
      errorfile 408 /etc/haproxy/errors/408.http
      errorfile 500 /etc/haproxy/errors/500.http
      errorfile 502 /etc/haproxy/errors/502.http
      errorfile 504 /etc/haproxy/errors/504.http
      errorfile 503 {{work_dir}}/503.no_servers.http
  {% if state == 'stopped' %}
  backend stopped
      errorfile 503 {{work_dir}}/503.stopped.http
  {% elif state == 'drained' %}
  backend drained
      errorfile 503 {{work_dir}}/503.drained.http
  {% endif %}
  frontend haproxynode{% if tls_crt_file  %}
              bind *:443 ssl crt {{tls_crt_file}} {% else %}
              bind *:8080 {% endif %}
              mode http {% if state == 'stopped' %}
              default_backend stopped {% elif state == 'drained' %}
              default_backend drained {% else %}
              http-request set-var(txn.path) path
              # Блокировка Microsoft Edge
              acl ua_edge hdr_sub(User-Agent) -i Edg/ #Поменять "Edg" на свой User Agent
              http-request deny status 403 if ua_edge
              acl has_x_forwarded_port req.hdr(X-Forwarded-Port) -m found
              http-request set-header X-Forwarded-Port %[req.hdr(X-Forwarded-Port)] if has_x_forwarded_port
              http-request set-header X-Forwarded-Port %[dst_port] unless has_x_forwarded_port
              http-request add-header X-Forwarded-Proto https if { ssl_fc }
              option forwardfor
              default_backend backendnodes
              use_backend debugger_selector if { path_beg /debugger/open }
              use_backend debugger if { path_beg /debugger }
              acl login_page var(txn.path) -i -m beg /login/login.html
              http-response return status 404 errorfile {{work_dir}}/404.shutdown.http if { status 404 } login_page
              
  backend backendnodes
              balance leastconn
              option httpchk
              http-check send meth HEAD uri /
              option persist
              cookie GS_BALANCER_SERVER_NAME insert indirect preserve
              
              {% for host in hosts %}{% if host.active_regular %}
              server {{host.name}} {{host.address}}:8080 check cookie {{host.name}}{% elif host.active_debug %}
              server {{host.name}} {{host.address}}:8080 disabled cookie {{host.name}}{% else %}
              server {{host.name}} {{host.address}}:8080 check cookie {{host.name}} disabled{% endif %}{% endfor %}
              {% if not hosts %}
              http-response return  status 503  errorfile {{work_dir}}/503.no_servers.http
              {% endif %}
              
  backend debugger
              option persist
              cookie GS_BALANCER_SERVER_NAME insert
              
              {% for host in hosts %}{% if host.active_debug %}
              server {{host.name}} {{host.address}}:9020 cookie {{host.name}} disabled{% endif %}{% endfor %}
              
  backend debugger_selector
              option persist
              cookie GS_BALANCER_SERVER_NAME insert
              http-request set-var(txn.query) query,url_dec(1)
              
              {% for host in hosts %}{% if host.active_debug %}
              http-request redirect  code 303 location %[str,concat("/",txn.query)] set-cookie GS_BALANCER_SERVER_NAME={{host.name}} if { path_beg -i /debugger/open/{{host.name}} }{% endif %}{% endfor %}
  {%- endif %}
              

  {% if stat_username  %} 
  listen stats
              bind :5000
              stats enable
              stats uri /
              stats hide-version
              stats auth {{stat_username}}:{{stat_password}}
  {% endif %}

  frontend prometheus
              bind *:8405
              mode http
              http-request use-service prometheus-exporter if { path /metrics }
              no log

  listen health
              bind *:6000
              mode http
              monitor-uri  /is_alive

Применить профиль конфигурации:

./appkit.sh prepare_profile --appkit-dir workspace/appkit 
./appkit.sh push --namespace gs-ctk --source ./workspace/appkit --destination appkit/v1 
./appkit.sh switch_local --config-path ./config.yaml --resgroup gs-cluster-1 --local-appkit ./workspace/appkit --remote-appkit appkit/v1
./appkit.sh start --config-path ./config.yaml --resgroup gs-cluster-1
kubectl apply -f ./config.yaml

Ingress-Nginx#

В ingress-nginx должно быть включено:

allow-snippet-annotations: "true"

EDITOR=nano kubectl edit ingress -n gs-ctk ctk-restapi - отредактировать сщуествующую конфигурацию

или

Применить из файла ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: if ($http_user_agent ~* "Firefox")
      { return 403; }
    nginx.ingress.kubernetes.io/server-snippet: if ($http_user_agent ~* "Firefox")
      { return 403; }
  creationTimestamp: "2026-06-05T14:49:04Z"
  name: ctk-restapi
  namespace: gs-ctk
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - backend:
          service:
            name: gs-cluster-1-haproxy-external
            port:
              number: 8080
        path: /
        pathType: Prefix

Применить конфигурацию kubectl apply -f ingress.yaml

Ingress-HaProxy#

Создайте или отредактируйте ConfigMap haproxy-ingress в namespace haproxy-ingress:

apiVersion: v1
kind: ConfigMap
metadata:
  name: haproxy-ingress
  namespace: haproxy-ingress
  annotations:
    # Защита от перезаписи при helm upgrade
    helm.sh/resource-policy: keep
data:
  # Правила для фронтенда (HTTP/HTTPS)
  config-frontend: |-
    # Блокировка браузера Opera (возвращает 403)
    http-request deny if { hdr_sub(user-agent) -i Opera }
    # Перезапись заголовка Location: убрать :8080 из редиректов
    http-response set-header Location "%[res.hdr(Location),regsub(:8080,,i)]"
  healthz-port: "10253"
  stats-port: "1936"

Применить через kubectl:

kubectl apply -f haproxy-ingress-configmap.yaml