НОВОСТИ Повышаем безопасность микросервисов с Istio

Alvaros
Онлайн
Регистрация
14.05.16
Сообщения
21.452
Реакции
101
Репутация
204
Всем привет! Меня зовут Илья, я работаю DevOps-инженером в команде разработки. Мы активно используем микросервисный подход, и, из-за специфики нашей работы, для нас важна безопасность межсервисного взаимодействия. В этой статье я хочу описать принцип работы Istio и на примере показать, как использовать некоторые ее возможности по обеспечению безопасности. Надеюсь, это окажется полезным для решения ваших задач. Приятного чтения!

t0kqkgmsjjedd0qvg_4tutpp064.png



Для чего вообще нужна сервисная сеть


Service mesh, в данном случае Istio – это обвязка для всего того, что требуется для управления и конфигурирования межсервисного взаимодействия: маршрутизация, аутентификация, авторизация, трассировка, контроль доступа и многое другое. И хотя существует масса открытых библиотек, чтобы реализовать эти функции непосредственно в коде сервиса, с Istio можно получить все то же самое, ничего не добавляя в сам сервис.

Компоненты


Статья написана для istio 1.6​

Про изменения
Istio развивается семимильными шагами, и это очень чувствуется на практике. Нередки случаи, когда точно помнишь, что настраивал какую-то функциональность определенным образом, но на официальном сайте уже висит мануал с описанием конфигурации совсем других, новых объектов. Так произошло, например, в Istio 1.4 с внедрением новой , когда убрали множество объектов Istio RBAC. Или в версии 1.5 поменяли подход к компонентам, и вместо трех старых отдельных компонентов Pilot, Galley и Citadel появился один общий . Множество пособий по настройке в сети может стать неактуальными из-за этих нововведений. Дальше по ходу статьи я буду специально выделять эти моменты.

Istio логически разбита на плоскость данных (data plane) и плоскость управления (control plane).
Плоскость данных это совокупность прокси-серверов (Envoy), добавленных к pod’у в виде сайдкаров. Эти прокси-серверы обеспечивают и контролируют всю сетевую связь между микросервисами и конфигурируются из плоскости управления.
Плоскость управления (istiod) обеспечивает service discovery, настройку и управление сертификатами. Она конвертирует Istio объекты в понятные для Envoy конфигурации и распространяет их в плоскости данных.

xk7rid5di7ld6bdmpwvw6mbuwmk.png


Компоненты Istio service mesh

Добавить envoy в pod приложения можно как вручную, так и настроив автоматическое добавление с помощью Mutating Admission webhook, который Istio добавляет при своей установке. Для этого нужно проставить на необходимый неймспейс метку istio-injection=enabled.

Кроме прокси-сайдкара с envoy Istio добавит в pod специальный init контейнер, который будет перенаправлять боевой трафик в контейнер с envoy. Но каким же образом это достигается? В данном случае никакой магии нет, и реализуется это установкой дополнительных правил iptables в сетевой неймспейс pod’а.

Про потребление ресурсов
По нашему опыту, в небольшом кластере из примерно 100 сервисов добавление Istio увеличивает задержки ответа микросервисов на ~2-3 мс, каждый envoy занимает порядка 40 Мб памяти, и потребление CPU возрастает в среднем на 5%-7% на pod.


Давайте на практике посмотрим, как сайдкар захватывает входящий и исходящий трафик из контейнера. Для этого взглянем на сетевое пространство какого-нибудь pod’а с добавленным Istio сайдкаром подробнее.

Демо стенд
Для практических примеров я буду использовать свеже установленный Kubernetes кластер с Istio.
Локально развернуть Kubernetes несложно с помощью :
Linux:

curl -Lo minikube && chmod +x minikube
sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/

minikube start --driver= // --driver=none запустит все докер контейнеры прямо на локальной машине.




MacOS:

brew install minikube
minikube start --driver=




Istio с demo профилем можно установить по :


curl -L | sh -
cd istio-1.6.3
export PATH=$PWD/bin:$PATH
istioctl install --set profile=demo



Для примеров межсервисного взаимодействия я буду использовать два микросервиса: productpage и details. Они оба идут в стандартной поставке Istio для демонстрации ее возможностей.
Установка демо микросервисов

kubectl label namespace default istio-injection=enabled
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml





Посмотрим список контейнеров приложения productpage:


kubectl -n default get pods productpage-v1-7df7cb7f86-ntwzz -o jsonpath="{.spec['containers','initContainers'][*].name}"
productpage
istio-proxy
istio-init



Кроме самого productpage, в pod'е работают sidecar istio-proxy (тот самый envoy) и init контейнер istio-init.

Посмотреть на настроенные в пространстве имена pod’а iptables-правила можно с помощью утилиты nsenter. Для этого нам надо узнать pid процесса контейнера:


docker inspect k8s_productpage --format '{{ .State.Pid }}'
16286



Теперь мы можем посмотреть правила iptables, установленные в этом контейнере.

ou2x1yugs7qqwznyu3ajfvy7vua.png


Видно, что практически весь входящий и исходящий трафик теперь перехватывается и перенаправляется на порты, на которых его уже поджидает envoy.

Включаем взаимное шифрование трафика


Объекты Policy и MeshPolicy были из istio 1.6. Вместо них предлагается использовать объект PeerAuthentication​

Istio позволяет зашифровать весь трафик между контейнерами, причем сами приложения даже не будут знать, что общаются через tls. Делается это самим Istio из коробки буквально одним манифестом, так как в сайдкары-прокси уже смонтированы клиентские сертификаты.

Алгоритм такой:

  1. Прокси-серверы envoy на стороне клиента и на стороне сервера проверяют подлинность друг друга перед отправкой запросов;
  2. Если проверка прошла успешно, клиентский прокси шифрует трафик и отправляет его на серверный прокси;
  3. Прокси-серверная сторона расшифровывает трафик и локально перенаправляет его фактической службе назначения.


Включить mTLS можно на разных уровнях:

  • На уровне всей сети;
  • На уровне неймспейса;
  • На уровне конкретного pod’а.


Режимы работы:

  • PERMISSIVE: разрешен и зашифрованный, и plain text трафик;
  • STRICT: разрешен только TLS;
  • DISABLE: разрешен только plain text.

Обратимся к сервису details из pod’а productpage с помощью curl без включенного TLS и посмотрим, что придет к details с помощью tcpdump:

Запрос:

fiikss2kwcsfc11xqx7aycfgd8s.png


Дампим трафик:

xommnbmvkfqum4zxlgr8nevny0o.png


Все тело и заголовки прекрасно читаемы в plain text.

Включим tls. Для этого создадим объект типа PeerAuthentication в неймспейсе с нашими pod’ами.


apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: default
spec:
mtls:
mode: STRICT



Запустим запрос из product page к details опять и посмотрим, что удастся получить:

hlzyxwrskzr6-wcl-6uqglcmjhg.png


Трафик зашифрован

Авторизация


Объекты ClusterRbacConfig, ServiceRole, and ServiceRoleBinding были вместе с внедрением новой авторизационной политики. Вместо них предлагается использовать объект AuthorizationPolicy.​

С помощью политик авторизации Istio может настраивать доступ одного приложения к другому. Причем, в отличие от чистых Kubernetes network policies, это работает на L7 уровне. Например, для http-трафика можно тонко управлять методами и путями запроса.

Как мы уже видели в предыдущем примере, по умолчанию доступ открыт для всех pod’ов всего кластера.

Теперь запретим все активности в неймспейсе default с помощью такого yaml-файла:


apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: default
spec:
{}



И попробуем достучаться до сервиса details:


curl details:9080
RBAC: access denied



Отлично, теперь наш запрос не проходит.

А теперь настроим доступ так, чтобы проходил только GET запрос и только по пути /details, а все остальные запросы отклонялись. Для этого есть несколько вариантов:

  • Можно настроить, чтобы проходили запросы с определенными хедерами;
  • По сервисному аккаунту приложения;
  • По исходящему ip-адресу;
  • По исходящему неймспейсу;
  • По claims в JWT токене.

Самое простое в обслуживании это настроить доступ по сервисному аккаунту приложения, благо предварительной настройки для этого не потребуется, так как демо-приложение bookinfo уже идет с созданными и подмонитрованными service account.
Для использования политик авторизации на основе сервис аккаунтов необходимо включить взаимную аутентификацию TLS.​

Настраиваем новую политику доступа:


apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: "details-viewer"
namespace: default
spec:
selector:
matchLabels:
app: details
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/bookinfo-productpage"]
to:
- operation:
methods: ["GET"]
paths: ["/details/*"]



И пробуем достучаться вновь:


root@productpage-v1-6b64c44d7c-2fpkc:/# curl details:9080/details/0
{"id":0,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"}



Все работает. Попробуем другие методы и пути:


root@productpage-v1-6b64c44d7c-2fpkc:/# curl -XPOST details:9080/details/0
RBAC: access denied
root@productpage-v1-6b64c44d7c-2fpkc:/#
root@productpage-v1-6b64c44d7c-2fpkc:/# curl -XGET details:9080/ping
RBAC: access denied



Заключение


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