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

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

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

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

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

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

HaProxy#

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

Если директория workspace/appkit/profile отсутствует, создайте ее командой:

./appkit.sh prepare_profile --appkit-dir workspace/appkit 
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

Внимание

Обратите внимание, в конце HaProxy.cfg должны быть две пустые строки!

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

./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