Контроль доступу на вході

Це завдання показує, як застосувати контроль доступу на основі IP до вхідного шлюзу Istio за допомогою політики авторизації.

Перед початком

Перед початком цього завдання зробіть наступне:

  • Ознайомтеся з концепціями авторизації Istio.

  • Встановіть Istio за допомогою посібника з установки Istio.

  • Розгорніть навантаження, httpbin, у просторі імен foo з увімкненою інʼєкцією sidecar:

    Zip
    $ kubectl create ns foo
    $ kubectl label namespace foo istio-injection=enabled
    $ kubectl apply -f @samples/httpbin/httpbin.yaml@ -n foo
  • Експонуйте httpbin через вхідний шлюз:

Налаштуйте шлюз:

Zip
$ kubectl apply -f @samples/httpbin/httpbin-gateway.yaml@ -n foo

Увімкніть налагодження RBAC в Envoy для вхідного шлюзу:

$ kubectl get pods -n istio-system -o name -l istio=ingressgateway | sed 's|pod/||' | while read -r pod; do istioctl proxy-config log "$pod" -n istio-system --level rbac:debug; done

Слідуйте інструкціям у Визначення IP-адреси та портів вхідного шлюзу, щоб визначити змінні середовища INGRESS_PORT та INGRESS_HOST.

  • Перевірте, що навантаження httpbin і вхідний шлюз працюють як очікувалося, за допомогою цієї команди:

    $ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n"
    200

Отримання трафіку в Kubernetes та Istio

Усі методи отримання трафіку в Kubernetes передбачають відкриття порту на всіх робочих вузлах. Основні елементи, які це забезпечують, — це сервіси NodePort та LoadBalancer. Навіть ресурс Kubernetes Ingress повинен бути підкріплений контролером Ingress, який створить або сервіс NodePort, або сервіс LoadBalancer.

  • NodePort просто відкриває порт у діапазоні 30000-32767 на кожному робочому вузлі та використовує селектор міток для ідентифікації того, яким Podʼам надсилати трафік. Вам потрібно вручну створити якийсь тип балансувальника навантаження перед вашими робочими вузлами або використовувати Round-Robin DNS.

  • LoadBalancer подібний до NodePort, але також створює специфічний для середовища зовнішній балансувальник навантаження для розподілу трафіку між робочими вузлами. Наприклад, у AWS EKS служба LoadBalancer створить Classic ELB з вашими робочими вузлами як цільовими. Якщо ваше середовище Kubernetes не має реалізації LoadBalancer, то воно просто поводитиметься як NodePort. Вхідний шлюз Istio створює сервіс LoadBalancer.

Що робити, якщо Pod, який обробляє трафік з NodePort або LoadBalancer, не працює на робочому вузлі, який отримав трафік? Kubernetes має власний внутрішній проксі kube-proxy, який отримує пакети та пересилає їх на правильний вузол.

IP-адреса оригінального клієнта

Якщо пакет проходить через зовнішній проксі балансувальник навантаження і/або kube-proxy, то оригінальна IP-адреса клієнта втрачається. Нижченаведені підрозділи описують деякі стратегії збереження оригінальної IP-адреси клієнта для ведення журналу або для безпеки для різних типів балансувальників навантаження:

  1. TCP/UDP проксі балансувальник навантаження
  2. Мережевий балансувальник навантаження
  3. HTTP/HTTPS балансувальник навантаження

Для довідки наведено типи балансувальників навантаження, які створює Istio з сервісом LoadBalancer у популярних середовищах Kubernetes, що надаються провадерами послуг:

Хмарний провайдерНазва балансувальника навантаженняТип балансувальника навантаження
AWS EKSClassic Elastic Load BalancerTCP Proxy
GCP GKETCP/UDP Network Load BalancerNetwork
Azure AKSAzure Load BalancerNetwork
IBM IKS/ROKSNetwork Load BalancerNetwork
DO DOKSLoad BalancerNetwork

TCP/UDP проксі балансувальник навантаження

Якщо ви використовуєте зовнішній балансувальник навантаження TCP/UDP (AWS Classic ELB), він може використовувати PROXY Protocol для вбудовування оригінальної IP-адреси клієнта в дані пакета. Для того щоб це працювало, як зовнішній балансувальник навантаження, так і вхідний шлюз Istio повинні підтримувати PROXY протокол.

Ось приклад конфігурації, який показує, як налаштувати вхідний шлюз на AWS EKS для підтримки PROXY Protocol:

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  meshConfig:
    accessLogEncoding: JSON
    accessLogFile: /dev/stdout
    defaultConfig:
      gatewayTopology:
        proxyProtocol: {}
  components:
    ingressGateways:
    - enabled: true
      name: istio-ingressgateway
      k8s:
        hpaSpec:
          maxReplicas: 10
          minReplicas: 5
        serviceAnnotations:
          service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
        ...

Мережевий балансувальник навантаження

Якщо ви використовуєте мережевий балансувальник навантаження TCP/UDP, який зберігає IP-адресу клієнта (AWS Network Load Balancer, GCP External Network Load Balancer, Azure Load Balancer) або використовуєте Round-Robin DNS, ви можете використовувати параметр externalTrafficPolicy: Local, щоб також зберегти IP-адресу клієнта всередині Kubernetes, обходячи kube-proxy і запобігаючи надсиланню трафіку на інші вузли.

Оновіть вхідний шлюз, щоб встановити externalTrafficPolicy: Local, щоб зберегти оригінальну IP-адресу джерела клієнта на вхідному шлюзі, використовуючи наступну команду:

$ kubectl patch svc istio-ingressgateway -n istio-system -p '{"spec":{"externalTrafficPolicy":"Local"}}'

HTTP/HTTPS балансувальник навантаження

Якщо ви використовуєте зовнішній балансувальник навантаження HTTP/HTTPS (AWS ALB, GCP), він може вставити оригінальну IP-адресу клієнта в заголовок X-Forwarded-For. Istio може витягти IP-адресу клієнта з цього заголовка за допомогою певної конфігурації. Дивіться Налаштування топології мережі шлюзу. Швидкий приклад, якщо використовується один балансувальник навантаження перед Kubernetes:

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  meshConfig:
    accessLogEncoding: JSON
    accessLogFile: /dev/stdout
    defaultConfig:
      gatewayTopology:
        numTrustedProxies: 1

Список дозволених та заборонених IP-адрес

Коли використовувати ipBlocks або remoteIpBlocks: Якщо ви використовуєте заголовок X-Forwarded-For HTTP або PROXY Protocol для визначення оригінальної IP-адреси клієнта, тоді слід використовувати remoteIpBlocks у вашій AuthorizationPolicy. Якщо ви використовуєте externalTrafficPolicy: Local, тоді слід використовувати ipBlocks у вашій AuthorizationPolicy.

Тип балансувальника навантаженняДжерело IP-адреси клієнтаipBlocks проти remoteIpBlocks
TCP ProxyPROXY ProtocolremoteIpBlocks
Мережевийадреса джерела пакетаipBlocks
HTTP/HTTPSX-Forwarded-ForremoteIpBlocks
  • Наступна команда створює політику авторизації ingress-policy для вхідного шлюзу Istio. Ця політика встановлює поле action на ALLOW, щоб дозволити IP-адреси, вказані в ipBlocks, доступ до вхідного шлюзу. IP-адреси, яких немає в списку, будуть заблоковані. ipBlocks підтримує як окремі IP-адреси, так і CIDR-нотацію.

ipBlocks:

$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: ingress-policy
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway
  action: ALLOW
  rules:
  - from:
    - source:
        ipBlocks: ["1.2.3.4", "5.6.7.0/24"]
EOF

remoteIpBlocks:

$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: ingress-policy
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway
  action: ALLOW
  rules:
  - from:
    - source:
        remoteIpBlocks: ["1.2.3.4", "5.6.7.0/24"]
EOF
  • Переконайтеся, що запит до вхідного шлюзу відхилено:

    $ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n"
    403
  • Призначте IP-адресу вашого клієнта змінній env. Якщо ви її не знаєте, ви можете знайти її в журналах Envoy за допомогою наступної команди:

ipBlocks:

$ CLIENT_IP=$(kubectl get pods -n istio-system -o name -l istio=ingressgateway | sed 's|pod/||' | while read -r pod; do kubectl logs "$pod" -n istio-system | grep remoteIP; done | tail -1 | awk -F, '{print $3}' | awk -F: '{print $2}' | sed 's/ //') && echo "$CLIENT_IP"
192.168.10.15

remoteIpBlocks:

$ CLIENT_IP=$(kubectl get pods -n istio-system -o name -l istio=ingressgateway | sed 's|pod/||' | while read -r pod; do kubectl logs "$pod" -n istio-system | grep remoteIP; done | tail -1 | awk -F, '{print $4}' | awk -F: '{print $2}' | sed 's/ //') && echo "$CLIENT_IP"
192.168.10.15
  • Оновіть ingress-policy, щоб додати IP-адресу вашого клієнта:

ipBlocks:

$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: ingress-policy
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway
  action: ALLOW
  rules:
  - from:
    - source:
        ipBlocks: ["1.2.3.4", "5.6.7.0/24", "$CLIENT_IP"]
EOF

remoteIpBlocks:

$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: ingress-policy
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway
  action: ALLOW
  rules:
  - from:
    - source:
        remoteIpBlocks: ["1.2.3.4", "5.6.7.0/24", "$CLIENT_IP"]
EOF
  • Переконайтеся, що запит до вхідного шлюзу дозволено:

    $ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n"
    200
  • Оновіть політику авторизації ingress-policy, встановивши ключ action у значення DENY, щоб IP-адреси, вказані в ipBlocks, не мали доступу до вхідного шлюзу:

ipBlocks:

$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: ingress-policy
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway
  action: DENY
  rules:
  - from:
    - source:
        ipBlocks: ["$CLIENT_IP"]
EOF

remoteIpBlocks:

$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: ingress-policy
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway
  action: DENY
  rules:
  - from:
    - source:
        remoteIpBlocks: ["$CLIENT_IP"]
EOF
  • Переконайтеся, що запит до вхідного шлюзу відхилено:

    $ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n"
    403
  • Ви можете скористатися онлайн-проксі-сервісом для доступу до вхідного шлюзу з іншої клієнтської IP-адреси, щоб переконатися, що запит дозволено.

  • Якщо ви не отримуєте очікуваних відповідей, перегляньте журнали вхідного шлюзу, які повинні містити інформацію про налагодження RBAC:

$ kubectl get pods -n istio-system -o name -l istio=ingressgateway | sed 's|pod/||' | while read -r pod; do kubectl logs "$pod" -n istio-system; done

Очищення

  • Видаліть політику авторизації:
$ kubectl delete authorizationpolicy ingress-policy -n istio-system
  • Видалити простір імен foo:

    $ kubectl delete namespace foo
Чи була ця інформація корисною?
Чи є у вас пропозиції щодо покращення?

Дякуємо за ваш відгук!