company_banner

Введение в Hashicorp Consul’s Kubernetes Авторизацию

Автор оригинала: Shy Wasserman
  • Перевод

Все верно, после релиза Hashicorp Consul 1.5.0 в начале мая 2019 года в Consul можно делать авторизацию приложений и служб, запущенных в Kubernetes, нативно.


В этом руководстве мы шаг за шагом создадим POC (Проверка концепции (Proof of concept, PoC — доказательство [осуществимости] концепции — прим. перев.), продемонстрировав эту новую функцию. От вас ожидаются базовые знания о Kubernetes и Hashicorp’s Consul. И хотя вы можете использовать любую облачную платформу или локальную среду, в этом руководстве мы будем использовать Google’s Cloud Platform.


Обзор


Если мы перейдем к документации Consul по его методу авторизации, мы получим краткий обзор его назначения и варианта использования, а также некоторые технические детали и общий обзор логики. Я настоятельно рекомендую прочитать ее по крайней мере один раз, прежде чем продолжить, так как сейчас я буду все это объяснять и разжевывать.



Схема 1: Официальный обзор метода авторизации Consul


Давайте посмотрим в документацию для конкретного метода авторизации Kubernetes.


Конечно, там есть полезная информация, но нет руководства о том, как на самом деле все это использовать. Поэтому, как любой здравомыслящий человек, вы прочесываете Интернет в поисках руководства. А потом… Терпите поражение. Так бывает. Давайте это исправим.


Прежде чем мы перейдем к созданию нашего POC, давайте вернемся к обзору методов авторизации Consul (Схема 1) и уточним его в контексте Kubernetes.


Архитектура


В этом руководстве мы будем создавать Consul-сервер на отдельной машине, которая будет взаимодействовать с кластером Kubernetes с установленным клиентом Consul. Затем мы создадим наше фиктивное приложение в поде и используем наш настроенный метод авторизации для чтения из нашего Consul key/value хранилища.


Схема ниже детально показывает архитектуру, которую мы создаем в этом руководстве, а также логику метода авторизации, которая будет объяснена позже.



Схема 2: Обзор метода авторизации в Kubernetes


Небольшое замечание: Consul-серверу не нужно жить за пределами кластера Kubernetes, чтобы это работало. Но да, он может и так и сяк.


Итак, взяв обзорную схему Consul (Схема 1) и применив к ней Kubernetes, мы получаем схему выше (Схема 2), и тут логика будет следующая:


  1. К каждому поду будет прикреплена служебная учетная запись, содержащая токен JWT, сгенерированный и известный Kubernetes. Этот токен также вставляется в под по умолчанию.
  2. Наше приложение или сервис внутри пода инициирует команду входа в наш Consul-клиент. В запросе на вход в систему также будет указан наш токен и указано имя специально созданного метода авторизации (типа Kubernetes). Этот шаг № 2 соответствует шагу 1 схемы Consul (Схема 1).
  3. Наш Consul-клиент затем направит этот запрос на наш Consul-сервер.
  4. МАГИЯ! Именно здесь Consul-сервер проверяет подлинность запроса, собирает сведения об идентичности запроса и сравнивает их с какими-нибудь ассоциированными предопределенными правилами. Ниже будет другая схема, чтобы это проиллюстрировать. Этот шаг соответствует шагам 3, 4 и 5 обзорной схемы Consul (Схема 1).
  5. Наш Consul-сервер генерирует Consul токен с разрешениями в соответствии с указанными нами правилами метода авторизации (которые мы определили) в отношении личности запрашивающего. Затем он отправит этот токен обратно. Это соответствует шагу 6 схемы Consul (Схема 1).
  6. Наш Consul-клиент перенаправляет токен запрашивающему приложению или сервису.

Наше приложение или сервис теперь могут использовать этот Consul токен для связи с нашими данными Consul, как было определено привилегиями токена.


Волшебство раскрыто!


Для тех из вас, кто не доволен всего лишь кроликом из шляпы и хочет знать, как это работает… позвольте мне «показать вам, насколько глубока кроличья нора».


Как упоминалось ранее, наш «магический» шаг (Схема 2: Шаг 4) заключается в том, что Consul-сервер проверяет подлинность запроса, собирает сведения об запросе и сравнивает их с любыми ассоциированными предопределенными правилами. Этот шаг соответствует шагам 3, 4 и 5 обзорной схемы Consul (Схема 1). Ниже приведена схема (Схема 3), цель которой наглядно показать, что на самом деле происходит под капотом конкретного метода авторизации Kubernetes.



Схема 3: Волшебство раскрыто!


  1. В качестве отправной точки, наш Consul-клиент перенаправляет запрос на вход на наш Consul-сервер с токеном учетной записи Kubernetes и конкретным именем инстанса метода авторизации, который был создан ранее. Этот шаг соответствует шагу 3 в предыдущем объяснении схемы.
  2. Теперь Consul-серверу (или лидеру) необходимо проверить подлинность полученного токена. Поэтому он проконсультируется с кластером Kubernetes (через Consul-клиент) и, при наличии соответствующих разрешений, мы выясним, является ли токен подлинным, и кому он принадлежит.
  3. Затем проверенный запрос возвращается к Consul-лидеру, и на сервере Consul выполняется поиск инстанса метода авторизации с указанным именем из запроса на вход в систему (и типа Kubernetes).
  4. Consul-лидер определяет указанный инстанс метода авторизации (если он найден) и читает набор правил привязки, которые к нему прикреплены. Затем он читает эти правила и сравнивает их с проверенными атрибутами идентичности.
  5. Тада! Переходим к шагу 5 в предыдущем объяснении схемы.

Запустите Consul-server на обычной виртуальной машине


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


  • Запустите виртуальную машину (инстанс / сервер).


  • Создайте правило для firewall (группа безопасности в AWS):
  • Мне нравится присваивать одно и то же имя машины правилу и сетевому тегу, в данном случае это «skywiz-consul-server-poc».
  • Найдите IP-адрес вашего локального компьютера и добавьте его в список исходных IP-адресов, чтобы мы могли получить доступ к интерфейсу пользователя (UI).
  • Откройте порт 8500 для UI. Нажмите Create (Создать). Мы скоро опять изменим этот firewall [ссылка].
  • Добавьте правило для firewall к инстансу. Вернитесь на панель мониторинга VM на Consul-сервере и добавьте «skywiz-consul-server-poc» в поле сетевых тегов. Нажмите Save (Сохранить).


  • Установите Consul на виртуальную машину, проверьте здесь. Помните, что вам нужна версия Consul ≥ 1.5 [ссылка]
  • Создадим single node Consul — конфигурация следующая.

groupadd --system consul
useradd -s /sbin/nologin --system -g consul consul
mkdir -p /var/lib/consul
chown -R consul:consul /var/lib/consul
chmod -R 775 /var/lib/consul
mkdir /etc/consul.d
chown -R consul:consul /etc/consul.d

  • Более подробное руководство по установке Consul и настройке кластера из 3 нод см. здесь.
  • Создайте файл /etc/consul.d/agent.json следующим образом [ссылка]:

### /etc/consul.d/agent.json
{
 "acl" : {
 "enabled": true,
 "default_policy": "deny",
 "enable_token_persistence": true
 }
}

  • Запустите наш Consul-сервер:

consul agent \
-server \
-ui \
-client 0.0.0.0 \
-data-dir=/var/lib/consul \
-bootstrap-expect=1 \
-config-dir=/etc/consul.d

  • Вы должны увидеть кучу выходных данных и в конечном итоге “… update blocked by ACLs”.
  • Найдите внешний IP-адрес Consul-сервера и откройте браузер с этим IP-адресом на порту 8500. Убедитесь, что открывается UI.
  • Попробуйте добавить пару ключ/значение. Должна быть ошибка. Это потому, что мы загрузили Consul-сервер с помощью ACL и запретили все правила.
  • Вернитесь к своей оболочке на Consul-сервере и запустите процесс в фоновом режиме или каким-либо другим способом, чтобы он работал, и введите следующее:

consul acl bootstrap

  • Найдите значение «SecretID» и вернитесь к UI. На вкладке «ACL» введите секретный идентификатор токена, который вы только что скопировали. Скопируйте SecretID еще куда-нибудь, он понадобится нам позже.
  • Теперь добавьте пару ключ/значение. Для этого POC добавим следующее: ключ: «custom-ns/test_key», значение: «I’m in the custom-ns folder!»

Запуск Kubernetes-кластера для нашего приложения с Consul-клиентом в качестве Daemonset


  • Создайте кластер K8s (Kubernetes). Мы создадим его в той же зоне, что и сервер, для более быстрого доступа, и поэтому мы можем использовать ту же подсеть для простого подключения с внутренними IP-адресами. Мы назовем его «skywiz-app-with-consul-client-poc».


  • Как примечание, вот хорошее руководство, с которым я столкнулся при настройке POC Consul-кластера с Consul Connect.
  • Мы также будем использовать Hashicorp helm chart с расширенным файлом значений.
  • Установите и сконфигурируйте Helm. Шаги конфигурации:

kubectl create serviceaccount tiller --namespace kube-system
kubectl create clusterrolebinding tiller-admin-binding \
   --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
./helm init --service-account=tiller
./helm update


### poc-helm-consul-values.yaml
global:
 enabled: false
 image: "consul:latest"
# Expose the Consul UI through this LoadBalancer
ui:
 enabled: false
# Allow Consul to inject the Connect proxy into Kubernetes containers
connectInject:
 enabled: false
# Configure a Consul client on Kubernetes nodes. GRPC listener is required for Connect.
client:
 enabled: true
 join: ["<PRIVATE_IP_CONSUL_SERVER>"]
 extraConfig: |
{
  "acl" : {
 "enabled": true,   
 "default_policy": "deny",   
 "enable_token_persistence": true 
  }
}
# Minimal Consul configuration. Not suitable for production.
server:
 enabled: false
# Sync Kubernetes and Consul services
syncCatalog:
 enabled: false

  • Примените helm chart:

./helm install -f poc-helm-consul-values.yaml ./consul-helm - name skywiz-app-with-consul-client-poc

  • При попытке запуска, ему понадобятся разрешения для Consul-сервера, так что давайте добавим их.
  • Обратите внимание на «диапазон адресов Pod», расположенный на приборной панели кластера, и вернитесь к нашему правилу для firewall «skywiz-consul-server-poc».
  • Добавьте диапазон адресов для пода в список IP-адресов и откройте порты 8301 и 8300.


  • Перейдите к Consul UI, и через несколько минут вы увидите, что наш кластер появится на вкладке нод.


Настройка метода авторизации путем интеграции Consul с Kubernetes


  • Вернитесь в оболочку Consul-сервера и экспортируйте токен, который вы сохранили ранее:

export CONSUL_HTTP_TOKEN=<SecretID>

  • Нам понадобится информация из нашего Kubernetes-кластера, чтобы создать инстанс метода auth:
  • kubernetes-host

kubectl get endpoints | grep kubernetes

  • kubernetes-service-account-jwt

kubectl get sa <helm_deployment_name>-consul-client -o yaml | grep "\- name:"
kubectl get secret <secret_name_from_prev_command> -o yaml | grep token:

  • Токен закодирован в base64, поэтому расшифруйте его с помощью вашего любимого инструмента [ссылка]
  • kubernetes-ca-cert

kubectl get secret <secret_name_from_prev_command> -o yaml | grep ca.crt:

  • Возьмите сертификат “ca.crt” (после декодирования с base64) и впишите его в файл “ca.crt”.
  • Теперь создайте инстанс метода auth, заменив placeholders на значения, которые вы только что получили.

consul acl auth-method create \
-type "kubernetes" \
-name "auth-method-skywiz-consul-poc" \
-description "This is an auth method using kubernetes for the cluster skywiz-app-with-consul-client-poc" \
-kubernetes-host "<k8s_endpoint_retrieved earlier>" \
-kubernetes-ca-cert=@ca.crt \
-kubernetes-service-account-
jwt="<decoded_token_retrieved_earlier>"

  • Далее мы должны создать правило и прикрепить его к новой роли. Для этой части вы можете использовать Consul UI, но мы будем использовать командную строку.
  • Напишите правило

### kv-custom-ns-policy.hcl
key_prefix "custom-ns/" {
 policy = "write"
}

  • Примените правило

consul acl policy create \
-name kv-custom-ns-policy \
-description "This is an example policy for kv at custom-ns/" \
-rules @kv-custom-ns-policy.hcl

  • Найдите идентификатор правила, которое вы только что создали, из выходных данных.
  • Создайте роль с новым правилом.

consul acl role create \
-name "custom-ns-role" \
-description "This is an example role for custom-ns namespace" \
-policy-id <policy_id>

  • Теперь мы свяжем нашу новую роль с инстансом метода auth. Обратите внимание, что флаг «селектор» определяет, будет ли наш запрос на вход получать эту роль. Проверьте здесь другие опции селектора: https://www.consul.io/docs/acl/auth-methods/kubernetes.html#trusted-identity-attributes

consul acl binding-rule create \
-method=auth-method-skywiz-consul-poc \
-bind-type=role \
-bind-name='custom-ns-role' \
-selector='serviceaccount.namespace=="custom-ns"'

Конфигурации напоследок


Права доступа


  • Создайте права доступа. Нам нужно дать разрешение Consul на проверку и идентификацию удостоверения токена учетной записи службы K8s.
  • Запишите в файл следующее [ссылку]:

###skywiz-poc-consul-server_rbac.yaml
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: review-tokens
 namespace: default
subjects:
- kind: ServiceAccount
 name: skywiz-app-with-consul-client-poc-consul-client
 namespace: default
roleRef:
 kind: ClusterRole
 name: system:auth-delegator
 apiGroup: rbac.authorization.k8s.io
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: service-account-getter
 namespace: default
rules:
- apiGroups: [""]
 resources: ["serviceaccounts"]
 verbs: ["get"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: get-service-accounts
 namespace: default
subjects:
- kind: ServiceAccount
 name: skywiz-app-with-consul-client-poc-consul-client
 namespace: default
roleRef:
 kind: ClusterRole
 name: service-account-getter
 apiGroup: rbac.authorization.k8s.io

  • Создадим права доступа

kubectl create -f skywiz-poc-consul-server_rbac.yaml

Подключение к Consul Client


  • Как отмечалось здесь, есть несколько опций для подключения к daemonset, но мы перейдем к следующему простому решению:
  • Примените следующий файл [ссылка].

### poc-consul-client-ds-svc.yaml
apiVersion: v1
kind: Service
metadata:
 name: consul-ds-client
spec:
 selector:
   app: consul
   chart: consul-helm
   component: client
   hasDNS: "true"
   release: skywiz-app-with-consul-client-poc
 ports:
 - protocol: TCP
   port: 80
   targetPort: 8500

  • Затем примените следующую встроенную команду для создания configmap [ссылка]. Обратите внимание, что мы ссылаемся на название нашего сервиса, замените его при необходимости.

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
 labels:
   addonmanager.kubernetes.io/mode: EnsureExists
 name: kube-dns
 namespace: kube-system
data:
 stubDomains: |
   {"consul": ["$(kubectl get svc consul-ds-client -o jsonpath='{.spec.clusterIP}')"]}
EOF

Тестирование auth-метода


Теперь давайте посмотрим на магию в действии!


  • Создайте еще несколько ключевых папок с тем же ключом верхнего уровня (т. е. <new_folder>/sample_key) и значением по вашему выбору. Создайте соответствующие политики и роли для новых ключевых путей. Мы сделаем привязки позже.


Пользовательский тест пространства имен:


  • Создадим наше собственное пространство имен:

kubectl create namespace custom-ns

  • Создадим под в нашем новом пространстве имен. Напишите конфигурацию для пода.

###poc-ubuntu-custom-ns.yaml
apiVersion: v1
kind: Pod
metadata:
 name: poc-ubuntu-custom-ns
 namespace: custom-ns
spec:
 containers:
 - name: poc-ubuntu-custom-ns
   image: ubuntu
   command: ["/bin/bash", "-ec", "sleep infinity"]
 restartPolicy: Never

  • Создайте под:

kubectl create -f poc-ubuntu-custom-ns.yaml

  • Как только контейнер запустится, зайдите туда и установите curl.

kubectl exec poc-ubuntu-custom-ns -n custom-ns -it /bin/bash
apt-get update && apt-get install curl -y

  • Теперь мы отправим запрос на вход в Consul, используя метод авторизации, который мы создали ранее [ссылка].
  • Чтобы просмотреть введенный токен из своей учетной записи службы:

cat /run/secrets/kubernetes.io/serviceaccount/token

  • Напишите следующее в файл внутри контейнера:

### payload.json
{
 "AuthMethod": "auth-method-test",
 "BearerToken": "<jwt_token>"
}

  • Login!

curl \
--request POST \
--data @payload.json \
consul-ds-client.default.svc.cluster.local/v1/acl/login

  • Чтобы выполнить вышеуказанные шаги в одной строке (поскольку мы будем выполнять несколько тестов), вы можете сделать следующее:

echo "{ \
\"AuthMethod\": \"auth-method-skywiz-consul-poc\", \
\"BearerToken\": \"$(cat /run/secrets/kubernetes.io/serviceaccount/token)\" \
}" \
| curl \
--request POST \
--data @- \
consul-ds-client.default.svc.cluster.local/v1/acl/login

  • Работает! Должно, по крайней мере. Теперь возьмите SecretID и попробуйте получить доступ к ключу/значению, к которому у нас должен быть доступ.

curl \
consul-ds-client.default.svc.cluster.local/v1/kv/custom-ns/test_key --header “X-Consul-Token: <SecretID_from_prev_response>”

  • Вы можете декодировать «Value» base64 и увидеть, что оно соответствует значению в custom-ns/test_key в UI. Если вы использовали то же значение, приведенное выше в этом руководстве, ваше кодированное значение будет IkknbSBpbiB0aGUgY3VzdG9tLW5zIGZvbGRlciEi.

Тест учетной записи пользовательской службы:


  • Создайте пользовательский ServiceAccount с помощью следующей команды [ссылка].

kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
 name: custom-sa
EOF

  • Создайте новый файл конфигурации для пода. Обратите внимание, что я включил установку curl для экономии труда :)

###poc-ubuntu-custom-sa.yaml
apiVersion: v1
kind: Pod
metadata:
 name: poc-ubuntu-custom-sa
 namespace: default
spec:
 serviceAccountName: custom-sa
 containers:
 - name: poc-ubuntu-custom-sa
   image: ubuntu
   command: ["/bin/bash","-ec"]
   args: ["apt-get update && apt-get install curl -y; sleep infinity"]
 restartPolicy: Never

  • После этого запустите оболочку внутри контейнера.

kubectl exec -it poc-ubuntu-custom-sa /bin/bash

  • Login!

echo "{ \
\"AuthMethod\": \"auth-method-skywiz-consul-poc\", \
\"BearerToken\": \"$(cat /run/secrets/kubernetes.io/serviceaccount/token)\" \
}" \
| curl \
--request POST \
--data @- \
consul-ds-client.default.svc.cluster.local/v1/acl/login

  • Permission denied. О, мы забыли добавить новую привязку правил с соответствующими разрешениями, давайте сделаем это сейчас.

Повторите предыдущие шаги выше:
а) Создайте идентичную Политику для префикса «custom-sa/».
б) Создайте Role, назовите ее «custom-sa-role»
в) Прикрепите Политику к Role.


  • Создайте Rule-Binding (возможно только из cli / api). Обратите внимание на другое значение флага селектора.

consul acl binding-rule create \
-method=auth-method-skywiz-consul-poc \
-bind-type=role \
-bind-name='custom-sa-role' \
-selector='serviceaccount.name=="custom-sa"'

  • Повторите вход в систему из контейнера «poc-ubuntu-custom-sa». Success!
  • Проверьте наш доступ к ключевому пути custom-sa/.

curl \
consul-ds-client.default.svc.cluster.local/v1/kv/custom-sa/test_key --header “X-Consul-Token: <SecretID>”

  • Вы также можете убедиться, что этот токен не предоставляет доступ к kv в «custom-ns/». Просто повторите приведенную выше команду после замены «custom-sa» на префикс «custom-ns».
    Permission denied.

Пример оверлея:


  • Стоит отметить, что все сопоставления rule-binding будут добавлены в токен с этими правами.
  • Наш контейнер «poc-ubuntu-custom-sa» находится в пространстве имен по умолчанию — так что давайте использовать его для другой rule-binding.
  • Повторите предыдущие шаги:
    а) Создайте идентичную Политику для префикса ключа «default/».
    б) Создайте Role, назовите ее “default-ns-role”
    в) Прикрепите Политику к Role.
  • Создайте Rule-Binding (возможно только из cli / api)

consul acl binding-rule create \
-method=auth-method-skywiz-consul-poc \
-bind-type=role \
-bind-name='default-ns-role' \
-selector='serviceaccount.namespace=="default"'

  • Вернитесь к нашему контейнеру «poc-ubuntu-custom-sa» и попробуйте получить доступ к пути «default/» kv.
  • Permission denied.
    Вы можете просмотреть указанные учетные данные для каждого токена в UI в разделе ACL > Tokens. Как видите, к нашему текущему токену прикреплена только одна «custom-sa-role». Токен, который мы используем в настоящее время, был сгенерирован, когда мы вошли в систему, и тогда было только одно rule-binding, которое тогда соответствовало. Нам нужно снова войти в систему и использовать новый токен.
  • Убедитесь, что вы можете читать как из путей «custom-sa/», так и «default/» kv.
    Success!
    Это связано с тем, что наш «poc-ubuntu-custom-sa» соответствует привязкам правил «custom-sa» и «default-ns».

Заключение


TTL token mgmt?


На момент написания этой статьи не существует интегрированного способа определения TTL для токенов, сгенерированных этим методом авторизации. Это была бы фантастическая возможность — обеспечить безопасную автоматизацию авторизации Consul.


Существует возможность вручную создать токен с TTL:



Надеюсь, в ближайшее время мы сможем контролировать, как генерируются токены (для каждого правила или метода авторизации), и добавлять TTL.


До тех пор предлагается использовать в своей логике конечную точку выхода из системы.



Также читайте другие статьи в нашем блоге:


Nixys
Эксперты в DevOps и Kubernetes

Комментарии 0

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Самое читаемое