Как разрешить доступ к приложению внутри кластера только от ingress controller’ов?

Если вы хотите ограничить доступ к вашему приложению внутри кластера ТОЛЬКО от подов ingress’а, необходимо в под с приложением добавить контейнер с kube-rbac-proxy:

Пример Deployment для защищенного приложения

1apiVersion: apps/v1
2kind: Deployment
3metadata:
4  name: my-app
5  namespace: my-namespace
6spec:
7  selector:
8    matchLabels:
9      app: my-app
10  replicas: 1
11  template:
12    metadata:
13      labels:
14        app: my-app
15    spec:
16      serviceAccountName: my-sa
17      containers:
18      - name: my-cool-app
19        image: mycompany/my-app:v0.5.3
20        args:
21        - "--listen=127.0.0.1:8080"
22        livenessProbe:
23          httpGet:
24            path: /healthz
25            port: 443
26            scheme: HTTPS
27      - name: kube-rbac-proxy
28        image: flant/kube-rbac-proxy:v0.1.0 # Рекомендуется использовать прокси из нашего репозитория.
29        args:
30        - "--secure-listen-address=0.0.0.0:443"
31        - "--config-file=/etc/kube-rbac-proxy/config-file.yaml"
32        - "--v=2"
33        - "--logtostderr=true"
34        # Если kube-apiserver недоступен, мы не сможем аутентифицировать и авторизовывать пользователей.
35        # Stale Cache хранит только результаты успешной авторизации и используется, только если apiserver недоступен.
36        - "--stale-cache-interval=1h30m"
37        ports:
38        - containerPort: 443
39          name: https
40        volumeMounts:
41        - name: kube-rbac-proxy
42          mountPath: /etc/kube-rbac-proxy
43      volumes:
44      - name: kube-rbac-proxy
45        configMap:
46          name: kube-rbac-proxy

Приложение принимает запросы на адресе 127.0.0.1, это означает, что по незащищенному соединению к нему можно подключиться только изнутри пода. Прокси же слушает на адресе 0.0.0.0 и перехватывает весь внешний трафик к поду.

Как дать минимальные права для Service Account?

Чтобы аутентифицировать и авторизовывать пользователей с помощью kube-apiserver, у прокси должны быть права на создание TokenReview и SubjectAccessReview.

В наших кластерах уже есть готовая ClusterRoled8-rbac-proxy. Создавать ее самостоятельно не нужно! Нужно только прикрепить ее к Service Account’у вашего Deployment’а.

1---
2apiVersion: v1
3kind: ServiceAccount
4metadata:
5  name: my-sa
6  namespace: my-namespace
7---
8apiVersion: rbac.authorization.k8s.io/v1
9kind: ClusterRoleBinding
10metadata:
11  name: my-namespace:my-sa:d8-rbac-proxy
12roleRef:
13  apiGroup: rbac.authorization.k8s.io
14  kind: ClusterRole
15  name: d8:rbac-proxy
16subjects:
17- kind: ServiceAccount
18  name: my-sa
19  namespace: my-namespace

Конфигурация Kube-RBAC-Proxy

1apiVersion: v1
2kind: ConfigMap
3metadata:
4  name: kube-rbac-proxy
5data:
6  config-file.yaml: |+
7    excludePaths:
8    - /healthz # Не требуем авторизацию для liveness пробы.
9    upstreams:
10    - upstream: http://127.0.0.1:8081/ # Куда проксируем.
11      path: / # Location прокси, с которого запросы будут проксированы на upstream.
12      authorization:
13        resourceAttributes:
14          namespace: my-namespace
15          apiGroup: apps
16          apiVersion: v1
17          resource: deployments
18          subresource: http
19          name: my-app

Согласно конфигурации, у пользователя должны быть права на доступ к Deployment с именем my-app и его дополнительному ресурсу http в namespace my-namespace.

Выглядят такие права в виде RBAC так:

1---
2apiVersion: rbac.authorization.k8s.io/v1
3kind: Role
4metadata:
5  name: kube-rbac-proxy:my-app
6  namespace: my-namespace
7rules:
8- apiGroups: ["apps"]
9  resources: ["deployments/http"]
10  resourceNames: ["my-app"]
11  verbs: ["get", "create", "update", "patch", "delete"]
12---
13apiVersion: rbac.authorization.k8s.io/v1
14kind: RoleBinding
15metadata:
16  name: kube-rbac-proxy:my-app
17  namespace: my-namespace
18roleRef:
19  apiGroup: rbac.authorization.k8s.io
20  kind: Role
21  name: kube-rbac-proxy:my-app
22subjects:
23# Все пользовательские сертификаты ingress-контроллеров выписаны для одной конкретной группы.
24- kind: Group
25  name: ingress-nginx:auth

Для ingress’а ресурса необходимо добавить параметры:

1nginx.ingress.kubernetes.io/backend-protocol: HTTPS
2nginx.ingress.kubernetes.io/configuration-snippet: |
3  proxy_ssl_certificate /etc/nginx/ssl/client.crt;
4  proxy_ssl_certificate_key /etc/nginx/ssl/client.key;
5  proxy_ssl_protocols TLSv1.2;
6  proxy_ssl_session_reuse on;

Подробнее о том, как работает аутентификация по сертификатам, можно прочитать в документации Kubernetes.

Как сконфигурировать балансировщик нагрузки для проверки доступности IngressNginxController?

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

  • протокол: HTTP;
  • путь: /healthz;
  • порт: 80 (в случае использования inlet’а HostPort нужно указать номер порта, соответствующий параметру httpPort.

Как настроить работу через MetalLB с доступом только из внутренней сети?

Пример MetalLB с доступом только из внутренней сети.

1apiVersion: deckhouse.io/v1
2kind: IngressNginxController
3metadata:
4  name: main
5spec:
6  ingressClass: "nginx"
7  inlet: "LoadBalancer"
8  loadBalancer:
9    sourceRanges:
10    - 192.168.0.0/24

Как добавить дополнительные поля для логирования в nginx-controller?

1apiVersion: deckhouse.io/v1
2kind: IngressNginxController
3metadata:
4  name: main
5spec:
6  ingressClass: "nginx"
7  inlet: "LoadBalancer"
8  additionalLogFields:
9    my-cookie: "$cookie_MY_COOKIE"

Как включить HorizontalPodAutoscaling для IngressNginxController?

Важно! Режим HPA возможен только для контроллеров с inlet’ом LoadBalancer или LoadBalancerWithProxyProtocol. Важно! Режим HPA возможен только при minReplicas != maxReplicas, в противном случае deployment hpa-scaler не создается.

HPA выставляется с помощью аттрибутов minReplicas и maxReplicas в IngressNginxController CR.

IngressNginxController разворачивается с помощью DaemonSet. DaemonSet не предоставляет возможности горизонтального масштабирования, поэтому создается дополнительный deployment hpa-scaler и HPA resource, который следит за предварительно созданной метрикой prometheus-metrics-adapter-d8-ingress-nginx-cpu-utilization-for-hpa. Если CPU utilization превысит 50%, HPA закажет новую реплику для hpa-scaler (с учетом minReplicas и maxReplicas).

hpa-scaler deployment обладает HardPodAntiAffinity, поэтому он попытается заказать себе новый узел (если это возможно в рамках своей NodeGroup), куда автоматически будет размещен еще один Ingress-контроллер.

Примечания:

  • Минимальное реальное количество реплик IngressNginxController не может быть меньше минимального количества узлов в NodeGroup, в которую разворачивается IngressNginxController.
  • Максимальное реальное количество реплик IngressNginxController не может быть больше максимального количества узлов в NodeGroup, в которую разворачивается IngressNginxController.

Как использовать IngressClass с установленными IngressClassParameters?

Начиная с версии 1.1 IngressNginxController, Deckhouse создает объект IngressClass самостоятельно. Если вы хотите использовать свой IngressClass, например с установленными IngressClassParameters, достаточно добавить к нему label ingress-class.deckhouse.io/external: "true"

1apiVersion: networking.k8s.io/v1
2kind: IngressClass
3metadata:
4  labels:
5    ingress-class.deckhouse.io/external: "true"
6  name: my-super-ingress
7spec:
8  controller: ingress-nginx.deckhouse.io/my-super-ingress
9  parameters:
10    apiGroup: elbv2.k8s.aws
11    kind: IngressClassParams
12    name: awesome-class-cfg

В таком случае, при указании данного IngressClass в CRD IngressNginxController, Deckhouse не будет создавать объект, а использует уже существующий.

Как отключить сборку детализированной статистики Ingress-ресурсов?

По умолчанию Deckhouse собирает подробную статистику со всех Ingress-ресурсов в кластере, что может генерировать высокую нагрузку на систему мониторинга.

Для отключения сбора статистики добавьте label ingress.deckhouse.io/discard-metrics: "true" к соответствующему namespace или Ingress-ресурсу.

Пример отключения сбора статистики (метрик) для всех Ingress-ресурсов в пространстве имен review-1:

1kubectl label ns review-1 ingress.deckhouse.io/discard-metrics=true

Пример отключения сбора статистики (метрик) для всех Ingress-ресурсов test-site в пространстве имен development:

1kubectl label ingress test-site -n development ingress.deckhouse.io/discard-metrics=true