Vault with k8s v2: различия между версиями
Sirmax (обсуждение | вклад) (→CA) |
Sirmax (обсуждение | вклад) |
||
(не показаны 82 промежуточные версии этого же участника) | |||
Строка 1: | Строка 1: | ||
+ | [[Категория:Hashicorp]] |
||
+ | [[Категория:Linux]] |
||
+ | [[Категория:Vault]] |
||
+ | [[Категория:K8s]] |
||
=Авторизация K8S POD в Vault= |
=Авторизация K8S POD в Vault= |
||
Строка 23: | Строка 27: | ||
# После успешной авторизации POD может читать "секреты" из VAULT согласно политик которые привязаны к роле (политики и роли тут - это объекты в Vault) |
# После успешной авторизации POD может читать "секреты" из VAULT согласно политик которые привязаны к роле (политики и роли тут - это объекты в Vault) |
||
+ | <BR><BR> |
||
+ | ''' |
||
+ | <big> |
||
+ | Другими словами в качестве пары логин/пароль выступает роль <BR> |
||
+ | (которую POD "знает" из переменных окружения, и которая не является "секретом") <BR> |
||
+ | и токен сервисного аккаунта (к которому имеет доступ только POD запущенный с правами этого сервисного аккаунта)<BR> |
||
+ | </big> |
||
+ | ''' |
||
− | =Настройка |
+ | =Настройка со стороны k8s= |
− | + | Настройка K8S состоит из следующих шагов: |
|
+ | * Создать отдельное пространство имен (опционально: можно использовать default) |
||
− | ===Namespace=== |
||
+ | * Создать сервисные аккаунт для проверки токенов и назначить ему права |
||
+ | * Создать сервисные аккаунты для запуска POD-ов |
||
+ | ==Namespace== |
||
* Создать пространство (имен если не создано) |
* Создать пространство (имен если не создано) |
||
* Имя пространства имен выбрано произвольно ('''kilda''' в этом примере) |
* Имя пространства имен выбрано произвольно ('''kilda''' в этом примере) |
||
Строка 49: | Строка 64: | ||
</PRE> |
</PRE> |
||
− | + | ==Сервисный аккаунт для проверки токенов== |
|
* Это аккаунт с которым Vault подключается к API k8s для валидации JWT |
* Это аккаунт с которым Vault подключается к API k8s для валидации JWT |
||
Строка 72: | Строка 87: | ||
</PRE> |
</PRE> |
||
− | + | ==Права сервисного аккаунта== |
|
* Для того что б аккаунт мог проверить JWT у других сервисных аккаунтов ему назначается '''ClusterRole system:auth-delegator''' |
* Для того что б аккаунт мог проверить JWT у других сервисных аккаунтов ему назначается '''ClusterRole system:auth-delegator''' |
||
Строка 78: | Строка 93: | ||
Если назначить только в '''kilda-namespace''' то прав для проверки JWT '''<big>недостаточно</big>''' (что совершенно не очевидно из конфигурации)<BR> |
Если назначить только в '''kilda-namespace''' то прав для проверки JWT '''<big>недостаточно</big>''' (что совершенно не очевидно из конфигурации)<BR> |
||
− | + | ===kilda-namespace=== |
|
* Права назначаются на аккаунт созданный ранее: '''kilda-vault-token-review-service-account''' в ''' kilda-namespace''' |
* Права назначаются на аккаунт созданный ранее: '''kilda-vault-token-review-service-account''' в ''' kilda-namespace''' |
||
* '''kubectl apply -f kilda-vault-token-review-service-account-role-binding-in-kilda-namespace.yaml''' |
* '''kubectl apply -f kilda-vault-token-review-service-account-role-binding-in-kilda-namespace.yaml''' |
||
Строка 88: | Строка 103: | ||
metadata: |
metadata: |
||
name: kilda-vault-token-review-service-account-role-binding-in-kilda-namespace |
name: kilda-vault-token-review-service-account-role-binding-in-kilda-namespace |
||
− | namespace: kilda |
+ | namespace: kilda |
roleRef: |
roleRef: |
||
apiGroup: rbac.authorization.k8s.io |
apiGroup: rbac.authorization.k8s.io |
||
Строка 96: | Строка 111: | ||
- kind: ServiceAccount |
- kind: ServiceAccount |
||
name: kilda-vault-token-review-service-account |
name: kilda-vault-token-review-service-account |
||
− | namespace: kilda |
+ | namespace: kilda |
</PRE> |
</PRE> |
||
− | + | ===default-namespace=== |
|
* Права назначаются на аккаунт созданный ранее: '''kilda-vault-token-review-service-account''' в ''' default-namespace''' |
* Права назначаются на аккаунт созданный ранее: '''kilda-vault-token-review-service-account''' в ''' default-namespace''' |
||
* '''kubectl apply -f kilda-vault-token-review-service-account-role-binding-in-default-namespace.yaml''' |
* '''kubectl apply -f kilda-vault-token-review-service-account-role-binding-in-default-namespace.yaml''' |
||
* Содержимое файла '''kilda-vault-token-review-service-account-role-binding-in-default-namespace.yaml''': |
* Содержимое файла '''kilda-vault-token-review-service-account-role-binding-in-default-namespace.yaml''': |
||
− | |||
− | |||
<PRE> |
<PRE> |
||
--- |
--- |
||
Строка 122: | Строка 135: | ||
namespace: kilda-namespace |
namespace: kilda-namespace |
||
</PRE> |
</PRE> |
||
+ | ===Проверка=== |
||
− | |||
− | ====Проверка==== |
||
* Проверить: '''kubectl get clusterRoleBinding''' |
* Проверить: '''kubectl get clusterRoleBinding''' |
||
<PRE> |
<PRE> |
||
Строка 132: | Строка 144: | ||
... |
... |
||
</PRE> |
</PRE> |
||
+ | ==Сервисные аккаунты для POD== |
||
− | |||
+ | * Это сервисные аккаунты предназначенные для запуска POD |
||
− | ==Собственно настройка Vault== |
||
+ | * Аккаунты будут смаплены на разные политики Vault и иметь разные права доступа (могут читать разные ветки в key/values storage) |
||
− | |||
+ | * Два аккаунта = '''common-service-account''' и '''kilda-service-account''' (имена могут быть любые) |
||
− | ===Доступ к Vault=== |
||
+ | ===common-service-account=== |
||
− | Для настройки Vault потребуется токен с рутовыми правами. |
||
+ | * '''kubectl apply -f common-service-account.yaml''' |
||
− | * Токен для примера (отличается для каждой инсталляции Vault) |
||
− | * В случае https - требуется добавить CA в доверенные (если не добавлен до того) |
||
<PRE> |
<PRE> |
||
+ | --- |
||
− | export VAULT_TOKEN="s.pRFenxR9CANXqLtGI0b6fvy3" |
||
+ | apiVersion: v1 |
||
− | export VAULT_ADDR="https://vault.domain.tld:8200" |
||
+ | kind: ServiceAccount |
||
+ | metadata: |
||
+ | name: common-service-account |
||
+ | namespace: kilda |
||
</PRE> |
</PRE> |
||
+ | ===kilda-service-account=== |
||
− | |||
+ | * '''kubectl apply -f kilda-service-account.yaml''' |
||
− | ===Включить поддержку k8s в Vault=== |
||
− | * Предполагается использование нескольких кластеров с одним Vault, для этого указывается отдельный путь'''-path kilda-fred''' для каждого кластера kubernetes. |
||
<PRE> |
<PRE> |
||
+ | --- |
||
− | vault auth enable -path kilda-fred kubernetes |
||
+ | apiVersion: v1 |
||
− | Success! Enabled kubernetes auth method at: kilda-fred/ |
||
+ | kind: ServiceAccount |
||
+ | metadata: |
||
+ | name: kilda-service-account |
||
+ | namespace: kilda |
||
</PRE> |
</PRE> |
||
+ | |||
− | * проверка |
||
+ | |||
+ | |||
+ | ===Провека=== |
||
+ | '''kubectl get serviceAccount --namespace kilda''' |
||
<PRE> |
<PRE> |
||
+ | NAME SECRETS AGE |
||
− | vault auth list |
||
− | + | common-service-account 1 15s |
|
− | + | default 1 160m |
|
+ | kilda-service-account 1 23s |
||
− | kilda-fred/ kubernetes auth_kubernetes_34db5104 n/a |
||
+ | kilda-vault-token-review-service-account 1 155m |
||
− | ... |
||
</PRE> |
</PRE> |
||
+ | =Получение необходимых секретов из K8S= |
||
− | |||
− | ===Получение необходимых секретов из K8S=== |
||
* В примере все объекты находятся в отдельном пространстве имен - '''kilda''' |
* В примере все объекты находятся в отдельном пространстве имен - '''kilda''' |
||
+ | * Токен сервисного аккаунта (нужен для того что бы Vault мог авторизоваться в кластере K8S) |
||
+ | * CA кластера нужен для установки '''https''' соединения (СА может быть получен и из конфига kubecl) |
||
− | + | ==Получение имени "секрета"== |
|
* Получить имя "секрета" для сервисного аккаунта '''kilda-vault-token-review-service-account''' |
* Получить имя "секрета" для сервисного аккаунта '''kilda-vault-token-review-service-account''' |
||
* '''kilda-vault-token-review-service-account''' это аккаунт с которым Vault подключается к API k8s для валидации JWT (создан выше) |
* '''kilda-vault-token-review-service-account''' это аккаунт с которым Vault подключается к API k8s для валидации JWT (создан выше) |
||
Строка 207: | Строка 230: | ||
− | + | ==Получение данных из "секрета"== |
|
* имя секрета получено на предыдущем шаге - '''kilda-vault-token-review-service-account-token-sdz49''' |
* имя секрета получено на предыдущем шаге - '''kilda-vault-token-review-service-account-token-sdz49''' |
||
* не забывать что используется отдельное пространство имен - '''kilda''' |
* не забывать что используется отдельное пространство имен - '''kilda''' |
||
− | + | ===Токен=== |
|
Зная имя секрета можно получить его токен: |
Зная имя секрета можно получить его токен: |
||
<PRE> |
<PRE> |
||
Строка 252: | Строка 275: | ||
eyJhbGciOiJSU <тут вырезано >MT3cuTbiL7rZr8oiBM331iCpZ6BK-nybCpptg3lnKOnjJbs26HoMGIY2_DvunNo_TiHRzq03h3z344F5SAqgEe27LWtaiGD1xA |
eyJhbGciOiJSU <тут вырезано >MT3cuTbiL7rZr8oiBM331iCpZ6BK-nybCpptg3lnKOnjJbs26HoMGIY2_DvunNo_TiHRzq03h3z344F5SAqgEe27LWtaiGD1xA |
||
</PRE> |
</PRE> |
||
− | + | === CA === |
|
* В том же секрете содержится сертификат СА |
* В том же секрете содержится сертификат СА |
||
* Этот же сертификат содержится в конфиге kubectl |
* Этот же сертификат содержится в конфиге kubectl |
||
Строка 271: | Строка 294: | ||
qOY4fQ== |
qOY4fQ== |
||
-----END CERTIFICATE----- |
-----END CERTIFICATE----- |
||
+ | </PRE> |
||
+ | |||
+ | =Настройка Vault= |
||
+ | * настроить доступ к Vault (авторизация требует рутовых прав) |
||
+ | * создать политики доступа |
||
+ | * включить авторизацию через k8s |
||
+ | |||
+ | ==Доступ к Vault== |
||
+ | Для настройки Vault потребуется токен с рутовыми правами. |
||
+ | * Токен для примера (отличается для каждой инсталляции Vault) |
||
+ | * В случае https - требуется добавить CA в доверенные (если не добавлен до того) |
||
+ | <PRE> |
||
+ | export VAULT_TOKEN="s.pRFenxR9CANXqLtGI0b6fvy3" |
||
+ | export VAULT_ADDR="https://vault.domain.tld:8200" |
||
+ | </PRE> |
||
+ | |||
+ | ==Создание политик доступа== |
||
+ | * Cоздаем 2 политики: |
||
+ | ** kilda-policy для аккаунта kilda-service-account |
||
+ | ** kv-common-policy для аккаунта common-service-account |
||
+ | ===kilda-policy=== |
||
+ | Используем предсозданнную политику - https://noname.com.ua/mediawiki/index.php/Vault_Basic_Setup#.D0.9F.D0.BE.D0.BB.D0.B8.D1.82.D0.B8.D0.BA.D0.B8_.D0.B4.D0.BB.D1.8F_KV |
||
+ | ===kv-common-policy=== |
||
+ | Аналогично |
||
+ | <PRE> |
||
+ | path "kv/data/common/*" { |
||
+ | capabilities = ["read", "list", "create", "update"] |
||
+ | } |
||
+ | |||
+ | path "kv/data/common/readonly/*" { |
||
+ | capabilities = ["read"] |
||
+ | } |
||
+ | |||
+ | path "kv/data/common/readonly" { |
||
+ | capabilities = ["read"] |
||
+ | } |
||
+ | |||
+ | path "kv/data/common/read_and_update/*" { |
||
+ | capabilities = ["read", "update"] |
||
+ | } |
||
+ | |||
+ | path "kv/data/common/read_and_update" { |
||
+ | capabilities = ["read", "update"] |
||
+ | } |
||
+ | |||
+ | path "kv/data/common/noaccess" { |
||
+ | capabilities = ["deny"] |
||
+ | } |
||
+ | </PRE> |
||
+ | ===Просмотр политик=== |
||
+ | <PRE> |
||
+ | vault policy list |
||
+ | </PRE> |
||
+ | <PRE> |
||
+ | default |
||
+ | kilda-policy |
||
+ | kv-common-policy |
||
+ | root |
||
+ | </PRE> |
||
+ | |||
+ | <PRE> |
||
+ | vault policy read kilda-policy |
||
+ | </PRE> |
||
+ | <PRE> |
||
+ | path "kv/data/kilda/*" { |
||
+ | capabilities = ["read", "list", "create", "update"] |
||
+ | } |
||
+ | |||
+ | |||
+ | path "kv/data/kilda/readonly/*" { |
||
+ | capabilities = ["read"] |
||
+ | } |
||
+ | |||
+ | path "kv/data/kilda/read_and_update/*" { |
||
+ | capabilities = ["read", "update"] |
||
+ | } |
||
+ | |||
+ | path "kv/data/kilda/read_and_update" { |
||
+ | capabilities = ["read", "update"] |
||
+ | } |
||
+ | |||
+ | |||
+ | path "kv/data/kilda/noaccess" { |
||
+ | capabilities = ["deny"] |
||
+ | } |
||
+ | </PRE> |
||
+ | |||
+ | ==Включить поддержку k8s в Vault== |
||
+ | * Предполагается использование нескольких кластеров с одним Vault, для этого указывается отдельный путь '''-path kilda-fred''' для каждого кластера kubernetes. |
||
+ | * Имя пути (в примере '''kilda-fred''') может быть выбрано произвольно |
||
+ | <PRE> |
||
+ | vault auth enable -path kilda-fred kubernetes |
||
+ | Success! Enabled kubernetes auth method at: kilda-fred/ |
||
+ | </PRE> |
||
+ | * проверка |
||
+ | <PRE> |
||
+ | vault auth list |
||
+ | Path Type Accessor Description |
||
+ | ---- ---- -------- ----------- |
||
+ | kilda-fred/ kubernetes auth_kubernetes_34db5104 n/a |
||
+ | ... |
||
</PRE> |
</PRE> |
||
==Настройка доступа Vault в K8S== |
==Настройка доступа Vault в K8S== |
||
+ | |||
− | Настроить vault (адрес API можно взять из конфигурации kubectl) |
||
+ | На этом шаге указывается к какому кластеру "ходить" за проверкой, и с каким токеном авторизоваться в этом кластере |
||
+ | |||
+ | * ACCOUNT_TOKEN - получен на предыдущем шаге |
||
+ | * API - адрес API kubernetes |
||
+ | * SERVICE_ACCOUNT_CA_CRT - CA (получен на предыдущем шаге или взят из конфигурации '''kubectl''' - это один и тот же CA) |
||
+ | * '''kilda-fred''' - это путь указаный ранее |
||
+ | <PRE> |
||
+ | #!/bin/bash |
||
+ | |||
+ | ACCOUNT_TOKEN="eyJhbGci<skipped>uZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImtpbGRhLXZhd |
||
+ | API="https://https://vault.domain.tld::6443" |
||
+ | |||
+ | SERVICE_ACCOUNT_CA_CRT="-----BEGIN CERTIFICATE----- |
||
+ | MIIDADCCAeigAwIBAgIUXvcRvJKO5x/sOIXOxVD2VIQXY3QwDQYJKoZIhvcNAQEL |
||
+ | <Skipped> |
||
+ | PVGSuNobYcdns4Z+E1O2QLYbnoDsLd+sqf0r9aaFSZQZry8bP783VCuBXg6Zy0BR |
||
+ | eTh8bGZMYcccstj+sPLyprG8bueXzo6hDgaKkz4NXKlgP/b1gB/uycVKuS351mxF |
||
+ | qOY4fQ== |
||
+ | -----END CERTIFICATE----- |
||
+ | " |
||
+ | |||
vault \ |
vault \ |
||
write \ |
write \ |
||
− | auth/ |
+ | auth/kilda-fred/config \ |
− | kubernetes_host=" |
+ | kubernetes_host="${API}" \ |
kubernetes_ca_cert="${SERVICE_ACCOUNT_CA_CRT}" \ |
kubernetes_ca_cert="${SERVICE_ACCOUNT_CA_CRT}" \ |
||
token_reviewer_jwt="${ACCOUNT_TOKEN}" |
token_reviewer_jwt="${ACCOUNT_TOKEN}" |
||
+ | </PRE> |
||
− | Обратить внимание: |
||
+ | <PRE> |
||
− | Service Account - это аккаунт с которым будет деплоиться POD. Это аккаунт в k8s а не в Vault. |
||
+ | Success! Data written to: auth/kilda-fred/config |
||
− | Роль существует только в пределах Vault (а не в K8S) |
||
+ | </PRE> |
||
− | При авторизации POD запрашивает токен для роли |
||
+ | |||
− | На токен будут назначены политики из привязки |
||
+ | ==Назначение политик Vault для сервисных аккаунтов== |
||
− | Привязка сервисных аккаунтов K8S к ролям Vault[править] |
||
+ | * назначаются политики на 2 сервисных аккауната '''kilda-service-account''' и '''common-service-account ''' |
||
− | export VAULT_K8S_SERVICE_ACCOUNT="k8s-test-service-account" |
||
+ | * Service Account - это аккаунт с которым будет деплоиться POD. Это аккаунт в k8s а не в Vault. (созданы при настройке k8s выше) |
||
− | export VAULT_K8S_ROLE="k8s-test-role" |
||
+ | * Роль существует только в пределах Vault (а не в K8S) |
||
− | Здесь VAULT_K8S_SERVICE_ACCOUNT - это сервисный аккаунт в k8s который можно создать например так: |
||
+ | * При авторизации POD запрашивает '''токен Vault''' для роли используя для авторизации '''токен service account из k8s''' |
||
− | --- |
||
+ | * На '''токен vault ''' будут назначены политики vault из роли |
||
− | apiVersion: v1 |
||
+ | |||
− | kind: ServiceAccount |
||
+ | |||
− | metadata: |
||
+ | |||
− | name: k8s-service-account |
||
+ | '''Другими словами в качестве пары логин/пароль выступает роль (которую POD "знает" из переменных окружения, и которая не является "секретом") и токен сервисного аккаунта (к которому имеет доступ только POD запущенный с правами этого сервисного аккаунта)''' |
||
− | namespace: my-namespace-name |
||
+ | ===kilda-service-account=== |
||
− | Важно: Это сервисный аккаунт для запуска PODов, и это НЕ ТОТ сервисный аккаунт который используется Vault |
||
+ | Назначаются 3 политики vault : kilda-policy,kv-common-policy,default |
||
− | Создать привязку |
||
+ | <PRE> |
||
+ | export NAMESPACE="kilda" |
||
+ | export VAULT_K8S_SERVICE_ACCOUNT="kilda-service-account" |
||
+ | export VAULT_K8S_ROLE="kilda-role" |
||
+ | export POLICIES="kilda-policy,kv-common-policy,default" |
||
+ | |||
vault \ |
vault \ |
||
write \ |
write \ |
||
− | auth/ |
+ | auth/kilda-fred/role/${VAULT_K8S_ROLE} \ |
bound_service_account_names=${VAULT_K8S_SERVICE_ACCOUNT} \ |
bound_service_account_names=${VAULT_K8S_SERVICE_ACCOUNT} \ |
||
bound_service_account_namespaces=${NAMESPACE} \ |
bound_service_account_namespaces=${NAMESPACE} \ |
||
− | policies= |
+ | policies=kilda-policy,kv-common-policy,default \ |
+ | </PRE> |
||
+ | |||
+ | ===common-service-account=== |
||
+ | <PRE> |
||
+ | export NAMESPACE="kilda" |
||
+ | export VAULT_K8S_SERVICE_ACCOUNT="common-service-account" |
||
+ | export VAULT_K8S_ROLE="common-role" |
||
+ | export POLICIES="kv-common-policy,default" |
||
+ | |||
+ | vault \ |
||
+ | write \ |
||
+ | auth/kilda-fred/role/${VAULT_K8S_ROLE} \ |
||
+ | bound_service_account_names=${VAULT_K8S_SERVICE_ACCOUNT} \ |
||
+ | bound_service_account_namespaces=${NAMESPACE} \ |
||
+ | policies=kv-common-policy,default \ |
||
ttl=1h |
ttl=1h |
||
+ | |||
− | Обратить внимание - политики policy1,policy2 уже существуют (созданы до этого). Если политик нет их необходимо создать. |
||
+ | </PRE> |
||
+ | |||
+ | =Тестирование= |
||
+ | ==План тестирования== |
||
+ | |||
+ | # запустить POD в сервисном аккаунте kilda-service-account |
||
+ | # авторизоваться в Vault используя токен сервисного аккаунта |
||
+ | # Проверить возможность чтения из разрешенных путей key/value |
||
+ | # Проверить невозможность чтения из запрещенных путей key/value |
||
+ | |||
+ | # запустить POD в сервисном аккаунте common-service-account |
||
+ | # авторизоваться в Vault используя токен сервисного аккаунта |
||
+ | # Проверить возможность чтения из разрешенных путей key/value |
||
+ | # Проверить невозможность чтения из запрещенных путей key/value |
||
+ | |||
+ | |||
+ | <PRE> |
||
+ | vault kv put kv/common/somepath commonkey=commonvalue |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | created_time 2022-02-09T14:23:30.169927438Z |
||
+ | custom_metadata <nil> |
||
+ | deletion_time n/a |
||
+ | destroyed false |
||
+ | </PRE> |
||
+ | |||
+ | ==Проверка kilda-service-account== |
||
+ | ===Создание POD=== |
||
+ | '''kubectl apply -f pod-kilda-service-account.yaml''' |
||
+ | <PRE> |
||
+ | apiVersion: v1 |
||
+ | kind: Pod |
||
+ | metadata: |
||
+ | name: test-kilda-service-acc |
||
+ | namespace: kilda |
||
+ | labels: |
||
+ | role: test |
||
+ | spec: |
||
+ | serviceAccountName: "kilda-service-account" |
||
+ | hostAliases: |
||
+ | - ip: "10.14.15.201" |
||
+ | hostnames: |
||
+ | - "vault.domain.tld.com" |
||
+ | containers: |
||
+ | - name: web |
||
+ | image: ubuntu:20.04 |
||
+ | imagePullPolicy: Always |
||
+ | command: ["sleep", "3600000"] |
||
+ | env: |
||
+ | - name: VAULT_K8S_ROLE |
||
+ | value: "common-role" |
||
+ | - name: VAULT_ADDR |
||
+ | value: "https://vault.domain.tld:8200" |
||
+ | - name: VAULT_AUTH_PATH |
||
+ | value: "kilda-fred" |
||
+ | </PRE> |
||
+ | |||
+ | ===Авторизация в Vault=== |
||
+ | * Все действия из контейнера |
||
+ | <PRE> |
||
+ | kubectl --namespace kilda exec -ti test-kilda-service-acc -- bash |
||
+ | </PRE> |
||
+ | * Получение токена '''сервисного аккаунта k8''' |
||
+ | <PRE> |
||
+ | export JWT="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" |
||
+ | </PRE> |
||
+ | * Просмотре переменных окружения |
||
+ | <PRE> |
||
+ | env | grep VAULT |
||
+ | VAULT_K8S_ROLE=kilda-role |
||
+ | VAULT_ADDR=https://vault.domain.tld:8200 |
||
+ | VAULT_K8S_ROLE=kilda-role |
||
+ | VAULT_AUTH_PATH=kilda-fred |
||
+ | </PRE> |
||
+ | |||
+ | * Авторизация в Vault используя роль и токен сервисного аккаунта: получение токена |
||
+ | |||
+ | '''vault write auth/kilda-fred/login role=${VAULT_K8S_ROLE} jwt=${JWT}''' |
||
+ | <PRE> |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | token s.vGsxWHAW9xHzdryEHolw3Xw1 |
||
+ | token_accessor x4JGArK99k6wkh9QqgPE6dwF |
||
+ | token_duration 1h |
||
+ | token_renewable true |
||
+ | token_policies ["default" "kilda-policy" "kv-common-policy"] |
||
+ | identity_policies [] |
||
+ | policies ["default" "kilda-policy" "kv-common-policy"] |
||
+ | token_meta_role kilda-role |
||
+ | token_meta_service_account_name kilda-service-account |
||
+ | token_meta_service_account_namespace kilda |
||
+ | token_meta_service_account_secret_name n/a |
||
+ | token_meta_service_account_uid 50b15622-38d9-4725-96b1-1c56f4ca0da1 |
||
+ | </PRE> |
||
+ | * логин с использованием токена |
||
+ | |||
+ | '''vault login s.vGsxWHAW9xHzdryEHolw3Xw1''' |
||
+ | <PRE> |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | token s.vGsxWHAW9xHzdryEHolw3Xw1 |
||
+ | token_accessor x4JGArK99k6wkh9QqgPE6dwF |
||
+ | token_duration 59m26s |
||
+ | token_renewable true |
||
+ | token_policies ["default" "kilda-policy" "kv-common-policy"] |
||
+ | identity_policies [] |
||
+ | policies ["default" "kilda-policy" "kv-common-policy"] |
||
+ | token_meta_role kilda-role |
||
+ | token_meta_service_account_name kilda-service-account |
||
+ | token_meta_service_account_namespace kilda |
||
+ | token_meta_service_account_secret_name n/a |
||
+ | token_meta_service_account_uid 50b15622-38d9-4725-96b1-1c56f4ca0da1 |
||
+ | </PRE> |
||
+ | * Просмотр токена и его прав ( в том числе политик) |
||
+ | * результат соответсвует ожидаемому: '''policies [default kilda-policy kv-common-policy]''' |
||
+ | |||
+ | '''vault token lookup''' |
||
+ | <PRE> |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | accessor x4JGArK99k6wkh9QqgPE6dwF |
||
+ | creation_time 1644416277 |
||
+ | creation_ttl 1h |
||
+ | display_name kilda-fred-kilda-kilda-service-account |
||
+ | entity_id ab9837eb-ff5c-71e4-cb78-16065ef5a7eb |
||
+ | expire_time 2022-02-09T15:17:57.790015655Z |
||
+ | explicit_max_ttl 0s |
||
+ | id s.vGsxWHAW9xHzdryEHolw3Xw1 |
||
+ | issue_time 2022-02-09T14:17:57.79003263Z |
||
+ | meta map[role:kilda-role service_account_name:kilda-service-account service_account_namespace:kilda service_account_secret_name: service_account_uid:50b15622-38d9-4725-96b1-1c56f4ca0da1] |
||
+ | num_uses 0 |
||
+ | orphan true |
||
+ | path auth/kilda-fred/login |
||
+ | policies [default kilda-policy kv-common-policy] |
||
+ | renewable true |
||
+ | ttl 59m21s |
||
+ | type service |
||
+ | </PRE> |
||
+ | |||
+ | ===Проверить возможность чтения из разрешенных путей key/value=== |
||
+ | '''vault kv get kv/kilda/subpath''' (чтение возможно - результат соответсвует ожиданием) |
||
+ | <PRE> |
||
+ | ======= Metadata ======= |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | created_time 2022-02-08T14:59:04.275447933Z |
||
+ | custom_metadata <nil> |
||
+ | deletion_time n/a |
||
+ | destroyed false |
||
+ | version 1 |
||
+ | |||
+ | ===== Data ===== |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | somekey somedata |
||
+ | </PRE> |
||
+ | |||
+ | '''vault kv get kv/common/somepath''' (чтение возможно - результат соответсвует ожиданием) |
||
+ | <PRE> |
||
+ | ======= Metadata ======= |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | created_time 2022-02-09T14:23:30.169927438Z |
||
+ | custom_metadata <nil> |
||
+ | deletion_time n/a |
||
+ | destroyed false |
||
+ | version 1 |
||
+ | |||
+ | ====== Data ====== |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | commonkey commonvalue |
||
+ | </PRE> |
||
+ | |||
+ | ===Проверить невозможность чтения из запрещенных путей key/value=== |
||
+ | '''vault kv get kv/kilda/noaccess''' (чтение '''НЕ''' возможно - результат соответсвует ожиданием) |
||
+ | <PRE> |
||
+ | Error reading kv/data/kilda/noaccess: Error making API request. |
||
+ | |||
+ | URL: GET https://vault.domain.tld:8200/v1/kv/data/kilda/noaccess |
||
+ | Code: 403. Errors: |
||
+ | |||
+ | * 1 error occurred: |
||
+ | * permission denied |
||
+ | </PRE> |
||
+ | |||
+ | ==Проверка common-service-account== |
||
+ | ===Создание POD=== |
||
+ | '''kubectl apply -f pod-common-service-account.yaml''' |
||
+ | <PRE> |
||
+ | apiVersion: v1 |
||
+ | kind: Pod |
||
+ | metadata: |
||
+ | name: test-common-service-acc |
||
+ | namespace: kilda |
||
+ | labels: |
||
+ | role: test |
||
+ | spec: |
||
+ | serviceAccountName: "common-service-account" |
||
+ | hostAliases: |
||
+ | - ip: "10.14.15.201" |
||
+ | hostnames: |
||
+ | - "vault.domain.tld" |
||
+ | containers: |
||
+ | - name: web |
||
+ | image: ubuntu:20.04 |
||
+ | imagePullPolicy: Always |
||
+ | command: ["sleep", "3600000"] |
||
+ | env: |
||
+ | - name: VAULT_K8S_ROLE |
||
+ | value: "common-role" |
||
+ | - name: VAULT_ADDR |
||
+ | value: "https://vault.domain.tld:8200" |
||
+ | - name: VAULT_AUTH_PATH |
||
+ | value: "kilda-fred" |
||
+ | </PRE> |
||
+ | |||
+ | ===Авторизация в Vault=== |
||
+ | * Все действия из контейнера |
||
+ | <PRE> |
||
+ | kubectl --namespace kilda exec -ti test-common-service-acc -- bash |
||
+ | </PRE> |
||
+ | * Получение токена '''сервисного аккаунта k8''' |
||
+ | <PRE> |
||
+ | export JWT="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" |
||
+ | </PRE> |
||
+ | * Просмотре переменных окружения |
||
+ | <PRE> |
||
+ | env | grep VAULT |
||
+ | VAULT_K8S_ROLE=common-role |
||
+ | VAULT_ADDR=https://vault.domain.tld:8200 |
||
+ | VAULT_AUTH_PATH=kilda-fred |
||
+ | </PRE> |
||
+ | |||
+ | * Авторизация в Vault используя роль и токен сервисного аккаунта: получение токена |
||
+ | |||
+ | '''vault write auth/kilda-fred/login role=${VAULT_K8S_ROLE} jwt=${JWT}''' |
||
+ | <PRE> |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | token s.fj4OxBwSn3jJjZ1FECwxSS6D |
||
+ | token_accessor 7TOZSFyiCRnTeAydmUxlKdLb |
||
+ | token_duration 1h |
||
+ | token_renewable true |
||
+ | token_policies ["default" "kv-common-policy"] |
||
+ | identity_policies [] |
||
+ | policies ["default" "kv-common-policy"] |
||
+ | token_meta_service_account_name common-service-account |
||
+ | token_meta_service_account_namespace kilda |
||
+ | token_meta_service_account_secret_name n/a |
||
+ | token_meta_service_account_uid 70f30a0a-4efb-4356-b90d-be9210f47117 |
||
+ | token_meta_role common-role |
||
+ | </PRE> |
||
+ | * логин с использованием токена |
||
+ | |||
+ | '''vault login s.fj4OxBwSn3jJjZ1FECwxSS6D''' |
||
+ | <PRE> |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | token s.fj4OxBwSn3jJjZ1FECwxSS6D |
||
+ | token_accessor 7TOZSFyiCRnTeAydmUxlKdLb |
||
+ | token_duration 59m18s |
||
+ | token_renewable true |
||
+ | token_policies ["default" "kv-common-policy"] |
||
+ | identity_policies [] |
||
+ | policies ["default" "kv-common-policy"] |
||
+ | token_meta_service_account_secret_name n/a |
||
+ | token_meta_service_account_uid 70f30a0a-4efb-4356-b90d-be9210f47117 |
||
+ | token_meta_role common-role |
||
+ | token_meta_service_account_name common-service-account |
||
+ | token_meta_service_account_namespace kilda |
||
+ | |||
+ | </PRE> |
||
+ | * Просмотр токена и его прав ( в том числе политик) |
||
+ | * результат соответсвует ожидаемому: '''policies [default kilda-policy kv-common-policy]''' |
||
+ | |||
+ | '''vault token lookup''' |
||
+ | <PRE> |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | accessor 7TOZSFyiCRnTeAydmUxlKdLb |
||
+ | creation_time 1644506420 |
||
+ | creation_ttl 1h |
||
+ | display_name kilda-fred-kilda-common-service-account |
||
+ | entity_id 522a6514-5e13-44d8-0377-c213154e0d44 |
||
+ | expire_time 2022-02-10T16:20:20.254743135Z |
||
+ | explicit_max_ttl 0s |
||
+ | id s.fj4OxBwSn3jJjZ1FECwxSS6D |
||
+ | issue_time 2022-02-10T15:20:20.254757455Z |
||
+ | meta map[role:common-role service_account_name:common-service-account service_account_namespace:kilda service_account_secret_name: service_account_uid:70f30a0a-4efb-4356-b90d-be9210f47117] |
||
+ | num_uses 0 |
||
+ | orphan true |
||
+ | path auth/kilda-fred/login |
||
+ | policies [default kv-common-policy] |
||
+ | renewable true |
||
+ | ttl 58m33s |
||
+ | type service |
||
+ | </PRE> |
||
+ | |||
+ | ===Проверить возможность чтения из разрешенных путей key/value=== |
||
+ | |||
+ | '''vault kv get kv/common/somepath''' (чтение возможно - результат соответсвует ожиданием) |
||
+ | <PRE> |
||
+ | ======= Metadata ======= |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | created_time 2022-02-09T14:23:30.169927438Z |
||
+ | custom_metadata <nil> |
||
+ | deletion_time n/a |
||
+ | destroyed false |
||
+ | version 1 |
||
+ | |||
+ | ====== Data ====== |
||
+ | Key Value |
||
+ | --- ----- |
||
+ | commonkey commonvalue |
||
+ | </PRE> |
||
+ | |||
+ | ===Проверить невозможность чтения из запрещенных путей key/value=== |
||
+ | '''vault kv get kv/kilda/subpath''' |
||
+ | (чтение '''НЕ''' возможно - результат соответсвует ожиданием) |
||
+ | <PRE> |
||
+ | |||
+ | Error reading kv/data/kilda/subpath: Error making API request. |
||
+ | |||
+ | URL: GET https://vault.domain.tld:8200/v1/kv/data/kilda/subpath |
||
+ | Code: 403. Errors: |
||
+ | * 1 error occurred: |
||
+ | * permission denied |
||
+ | </PRE> |
||
+ | |||
+ | =Выводы= |
||
+ | |||
+ | * Сервисный аккаунт kilda-service-account имеет доступ к k/v '''kv/kilda/*''' и '''kv/common/*''' |
||
+ | * Сервисный аккаунт common-service-account имеет доступ к k/v ''kv/common/*''' и не имеет доступа к '''k/v '''kv/kilda/*''' |
||
+ | * те все работает так как должно |
Текущая версия на 08:41, 30 октября 2023
Авторизация K8S POD в Vault
Постановка задачи
- Получать "секреты" из Vault при этом не передавая в POD пароли, токены или другую секретную информацию
Предварительны условия
- Установлен и настроен Vault
(базовая настройка - https://noname.com.ua/mediawiki/index.php/Vault_Basic_Setup)
- кластер Kubernetes установлен и настроен
- kubectl настроен для работы с кластером
Принципы работы
- Создается один или несколько Service Account
- POD запускается в определенном Service Account
- POD может воспользоваться токеном этого Service Account
- В качестве входных данных POD получает НЕ СЕКРЕТНУЮ информацию
- Адрес Vault в переменной окружения VAULT_ADDR
- Имя роли в переменной окружения VAULT_K8S_ROLE
- POD авторизуется в VAULT под ролью переданной в переменной VAULT_K8S_ROLE используя для этого JWT принадлежащий Service Account
- Vault настроен на проверку прав токена PODs в API K8S (Сам процесс VAULT использует ДРУГОЙ сервисный аккаунт, отличный от того под которым запускается POD для проверки токена PODa)
- После успешной авторизации POD может читать "секреты" из VAULT согласно политик которые привязаны к роле (политики и роли тут - это объекты в Vault)
Другими словами в качестве пары логин/пароль выступает роль
(которую POD "знает" из переменных окружения, и которая не является "секретом")
и токен сервисного аккаунта (к которому имеет доступ только POD запущенный с правами этого сервисного аккаунта)
Настройка со стороны k8s
Настройка K8S состоит из следующих шагов:
- Создать отдельное пространство имен (опционально: можно использовать default)
- Создать сервисные аккаунт для проверки токенов и назначить ему права
- Создать сервисные аккаунты для запуска POD-ов
Namespace
- Создать пространство (имен если не создано)
- Имя пространства имен выбрано произвольно (kilda в этом примере)
- kubectl apply -f kilda-namespace.yaml
- Содержимое kilda-namespace.yaml:
--- apiVersion: v1 kind: Namespace metadata: name: kilda
- проверка: kubectl get namespaces
NAME STATUS AGE default Active 56d kilda Active 7s kube-public Active 56d kube-system Active 56d metallb-system Active 56d ...
Сервисный аккаунт для проверки токенов
- Это аккаунт с которым Vault подключается к API k8s для валидации JWT
- Этот аккаунт отличается от того который используется для запуска POD
- Создается в правильном пространстве имен (в частном случае может использоваться default)
- Имя аккаунта выбрано произвольно
- kubectl apply -f kilda-vault-token-review-service-account.yaml
- Содержимое файла kilda-vault-token-review-service-account.yaml:
--- apiVersion: v1 kind: ServiceAccount metadata: name: kilda-vault-token-review-service-account namespace: kilda
- Проверка: kubectl get serviceAccount --namespace kilda
NAME SECRETS AGE default 1 9m12s kilda-vault-token-review-service-account 1 3m37s
Права сервисного аккаунта
- Для того что б аккаунт мог проверить JWT у других сервисных аккаунтов ему назначается ClusterRole system:auth-delegator
Важно: Назначить права нужно в 2 пространствах имен
Если назначить только в kilda-namespace то прав для проверки JWT недостаточно (что совершенно не очевидно из конфигурации)
kilda-namespace
- Права назначаются на аккаунт созданный ранее: kilda-vault-token-review-service-account в kilda-namespace
- kubectl apply -f kilda-vault-token-review-service-account-role-binding-in-kilda-namespace.yaml
- Содержимое файла kilda-vault-token-review-service-account-role-binding-in-kilda-namespace.yaml:
--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kilda-vault-token-review-service-account-role-binding-in-kilda-namespace namespace: kilda roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:auth-delegator subjects: - kind: ServiceAccount name: kilda-vault-token-review-service-account namespace: kilda
default-namespace
- Права назначаются на аккаунт созданный ранее: kilda-vault-token-review-service-account в default-namespace
- kubectl apply -f kilda-vault-token-review-service-account-role-binding-in-default-namespace.yaml
- Содержимое файла kilda-vault-token-review-service-account-role-binding-in-default-namespace.yaml:
--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kilda-vault-token-review-service-account-role-binding-in-default-namespace namespace: default roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:auth-delegator subjects: - kind: ServiceAccount name: kilda-vault-token-review-service-account namespace: kilda-namespace
Проверка
- Проверить: kubectl get clusterRoleBinding
NAME ROLE ... kilda-vault-token-review-service-account-role-binding-in-default-namespace ClusterRole/system:auth-delegator kilda-vault-token-review-service-account-role-binding-in-kilda-namespace ClusterRole/system:auth-delegator ...
Сервисные аккаунты для POD
- Это сервисные аккаунты предназначенные для запуска POD
- Аккаунты будут смаплены на разные политики Vault и иметь разные права доступа (могут читать разные ветки в key/values storage)
- Два аккаунта = common-service-account и kilda-service-account (имена могут быть любые)
common-service-account
- kubectl apply -f common-service-account.yaml
--- apiVersion: v1 kind: ServiceAccount metadata: name: common-service-account namespace: kilda
kilda-service-account
- kubectl apply -f kilda-service-account.yaml
--- apiVersion: v1 kind: ServiceAccount metadata: name: kilda-service-account namespace: kilda
Провека
kubectl get serviceAccount --namespace kilda
NAME SECRETS AGE common-service-account 1 15s default 1 160m kilda-service-account 1 23s kilda-vault-token-review-service-account 1 155m
Получение необходимых секретов из K8S
- В примере все объекты находятся в отдельном пространстве имен - kilda
- Токен сервисного аккаунта (нужен для того что бы Vault мог авторизоваться в кластере K8S)
- CA кластера нужен для установки https соединения (СА может быть получен и из конфига kubecl)
Получение имени "секрета"
- Получить имя "секрета" для сервисного аккаунта kilda-vault-token-review-service-account
- kilda-vault-token-review-service-account это аккаунт с которым Vault подключается к API k8s для валидации JWT (создан выше)
kubectl \ --namespace kilda \ get \ serviceaccount \ kilda-vault-token-review-service-account \ -o json
{ "apiVersion": "v1", "kind": "ServiceAccount", "metadata": { "annotations": { "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"annotations\":{},\"name\":\"kilda-vault-token-review-service-account\",\"namespace\":\"kilda\"}}\n" }, "creationTimestamp": "2022-02-09T10:17:40Z", "name": "kilda-vault-token-review-service-account", "namespace": "kilda", "resourceVersion": "8768345", "uid": "33b39f30-ba7e-4ef3-a12d-59e0cee9abee" }, "secrets": [ { "name": "kilda-vault-token-review-service-account-token-sdz49" } ] }
Тут имя секрета =.secrets[0].name, его можно получить одной командой непосредственно используя jq или встроенную в kubectl фильтрацию
kubectl \ --namespace kilda \ get \ serviceaccount \ kilda-vault-token-review-service-account \ -o jsonpath='{.secrets[0].name}'
Результат - kilda-vault-token-review-service-account-token-sdz49
Получение данных из "секрета"
- имя секрета получено на предыдущем шаге - kilda-vault-token-review-service-account-token-sdz49
- не забывать что используется отдельное пространство имен - kilda
Токен
Зная имя секрета можно получить его токен:
kubectl \ --namespace kilda \ get \ secret kilda-vault-token-review-service-account-token-sdz49 \ -o json
- Пример вывода (длинные поля заменены описанием для простоты):
{ "apiVersion": "v1", "data": { "ca.crt": "<тут base64-encoded CA>=", "namespace": "a2lsZGE=", "token": "<тут тут base64-encoded tocken>" }, "kind": "Secret", "metadata": { "annotations": { "kubernetes.io/service-account.name": "kilda-vault-token-review-service-account", "kubernetes.io/service-account.uid": "33b39f30-ba7e-4ef3-a12d-59e0cee9abee" }, "creationTimestamp": "2022-02-09T10:17:40Z", "name": "kilda-vault-token-review-service-account-token-sdz49", "namespace": "kilda", "resourceVersion": "8768344", "uid": "e509252c-3e36-4344-930f-9e988156442c" }, "type": "kubernetes.io/service-account-token" }
Здесь интересует поле .data - можно получить одной командой, не сохраняя промежуточные данные
kubectl --namespace kilda get secret kilda-vault-token-review-service-account-token-sdz49 -o jsonpath='{.data.token}' | base64 -d
Токен выглядит примерно так:
eyJhbGciOiJSU <тут вырезано >MT3cuTbiL7rZr8oiBM331iCpZ6BK-nybCpptg3lnKOnjJbs26HoMGIY2_DvunNo_TiHRzq03h3z344F5SAqgEe27LWtaiGD1xA
CA
- В том же секрете содержится сертификат СА
- Этот же сертификат содержится в конфиге kubectl
kubectl \ --namespace kilda \ get \ secret kilda-vault-token-review-service-account-token-sdz49 \ -o jsonpath="{.data['ca\.crt']}" \ | base64 --decode;
-----BEGIN CERTIFICATE----- MIIDADCCAeigAwIBAgIUXvcRvJKO5x/sOIXOxVD2VIQXY3QwDQYJKoZIhvcNAQEL BQAwGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTAeFw0yMTEyMTQxNjQ5MDBaFw0z <skipped> eTh8bGZMYcccstj+sPLyprG8bueXzo6hDgaKkz4NXKlgP/b1gB/uycVKuS351mxF qOY4fQ== -----END CERTIFICATE-----
Настройка Vault
- настроить доступ к Vault (авторизация требует рутовых прав)
- создать политики доступа
- включить авторизацию через k8s
Доступ к Vault
Для настройки Vault потребуется токен с рутовыми правами.
- Токен для примера (отличается для каждой инсталляции Vault)
- В случае https - требуется добавить CA в доверенные (если не добавлен до того)
export VAULT_TOKEN="s.pRFenxR9CANXqLtGI0b6fvy3" export VAULT_ADDR="https://vault.domain.tld:8200"
Создание политик доступа
- Cоздаем 2 политики:
- kilda-policy для аккаунта kilda-service-account
- kv-common-policy для аккаунта common-service-account
kilda-policy
Используем предсозданнную политику - https://noname.com.ua/mediawiki/index.php/Vault_Basic_Setup#.D0.9F.D0.BE.D0.BB.D0.B8.D1.82.D0.B8.D0.BA.D0.B8_.D0.B4.D0.BB.D1.8F_KV
kv-common-policy
Аналогично
path "kv/data/common/*" { capabilities = ["read", "list", "create", "update"] } path "kv/data/common/readonly/*" { capabilities = ["read"] } path "kv/data/common/readonly" { capabilities = ["read"] } path "kv/data/common/read_and_update/*" { capabilities = ["read", "update"] } path "kv/data/common/read_and_update" { capabilities = ["read", "update"] } path "kv/data/common/noaccess" { capabilities = ["deny"] }
Просмотр политик
vault policy list
default kilda-policy kv-common-policy root
vault policy read kilda-policy
path "kv/data/kilda/*" { capabilities = ["read", "list", "create", "update"] } path "kv/data/kilda/readonly/*" { capabilities = ["read"] } path "kv/data/kilda/read_and_update/*" { capabilities = ["read", "update"] } path "kv/data/kilda/read_and_update" { capabilities = ["read", "update"] } path "kv/data/kilda/noaccess" { capabilities = ["deny"] }
Включить поддержку k8s в Vault
- Предполагается использование нескольких кластеров с одним Vault, для этого указывается отдельный путь -path kilda-fred для каждого кластера kubernetes.
- Имя пути (в примере kilda-fred) может быть выбрано произвольно
vault auth enable -path kilda-fred kubernetes Success! Enabled kubernetes auth method at: kilda-fred/
- проверка
vault auth list Path Type Accessor Description ---- ---- -------- ----------- kilda-fred/ kubernetes auth_kubernetes_34db5104 n/a ...
Настройка доступа Vault в K8S
На этом шаге указывается к какому кластеру "ходить" за проверкой, и с каким токеном авторизоваться в этом кластере
- ACCOUNT_TOKEN - получен на предыдущем шаге
- API - адрес API kubernetes
- SERVICE_ACCOUNT_CA_CRT - CA (получен на предыдущем шаге или взят из конфигурации kubectl - это один и тот же CA)
- kilda-fred - это путь указаный ранее
#!/bin/bash ACCOUNT_TOKEN="eyJhbGci<skipped>uZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImtpbGRhLXZhd API="https://https://vault.domain.tld::6443" SERVICE_ACCOUNT_CA_CRT="-----BEGIN CERTIFICATE----- MIIDADCCAeigAwIBAgIUXvcRvJKO5x/sOIXOxVD2VIQXY3QwDQYJKoZIhvcNAQEL <Skipped> PVGSuNobYcdns4Z+E1O2QLYbnoDsLd+sqf0r9aaFSZQZry8bP783VCuBXg6Zy0BR eTh8bGZMYcccstj+sPLyprG8bueXzo6hDgaKkz4NXKlgP/b1gB/uycVKuS351mxF qOY4fQ== -----END CERTIFICATE----- " vault \ write \ auth/kilda-fred/config \ kubernetes_host="${API}" \ kubernetes_ca_cert="${SERVICE_ACCOUNT_CA_CRT}" \ token_reviewer_jwt="${ACCOUNT_TOKEN}"
Success! Data written to: auth/kilda-fred/config
Назначение политик Vault для сервисных аккаунтов
- назначаются политики на 2 сервисных аккауната kilda-service-account и common-service-account
- Service Account - это аккаунт с которым будет деплоиться POD. Это аккаунт в k8s а не в Vault. (созданы при настройке k8s выше)
- Роль существует только в пределах Vault (а не в K8S)
- При авторизации POD запрашивает токен Vault для роли используя для авторизации токен service account из k8s
- На токен vault будут назначены политики vault из роли
Другими словами в качестве пары логин/пароль выступает роль (которую POD "знает" из переменных окружения, и которая не является "секретом") и токен сервисного аккаунта (к которому имеет доступ только POD запущенный с правами этого сервисного аккаунта)
kilda-service-account
Назначаются 3 политики vault : kilda-policy,kv-common-policy,default
export NAMESPACE="kilda" export VAULT_K8S_SERVICE_ACCOUNT="kilda-service-account" export VAULT_K8S_ROLE="kilda-role" export POLICIES="kilda-policy,kv-common-policy,default" vault \ write \ auth/kilda-fred/role/${VAULT_K8S_ROLE} \ bound_service_account_names=${VAULT_K8S_SERVICE_ACCOUNT} \ bound_service_account_namespaces=${NAMESPACE} \ policies=kilda-policy,kv-common-policy,default \
common-service-account
export NAMESPACE="kilda" export VAULT_K8S_SERVICE_ACCOUNT="common-service-account" export VAULT_K8S_ROLE="common-role" export POLICIES="kv-common-policy,default" vault \ write \ auth/kilda-fred/role/${VAULT_K8S_ROLE} \ bound_service_account_names=${VAULT_K8S_SERVICE_ACCOUNT} \ bound_service_account_namespaces=${NAMESPACE} \ policies=kv-common-policy,default \ ttl=1h
Тестирование
План тестирования
- запустить POD в сервисном аккаунте kilda-service-account
- авторизоваться в Vault используя токен сервисного аккаунта
- Проверить возможность чтения из разрешенных путей key/value
- Проверить невозможность чтения из запрещенных путей key/value
- запустить POD в сервисном аккаунте common-service-account
- авторизоваться в Vault используя токен сервисного аккаунта
- Проверить возможность чтения из разрешенных путей key/value
- Проверить невозможность чтения из запрещенных путей key/value
vault kv put kv/common/somepath commonkey=commonvalue Key Value --- ----- created_time 2022-02-09T14:23:30.169927438Z custom_metadata <nil> deletion_time n/a destroyed false
Проверка kilda-service-account
Создание POD
kubectl apply -f pod-kilda-service-account.yaml
apiVersion: v1 kind: Pod metadata: name: test-kilda-service-acc namespace: kilda labels: role: test spec: serviceAccountName: "kilda-service-account" hostAliases: - ip: "10.14.15.201" hostnames: - "vault.domain.tld.com" containers: - name: web image: ubuntu:20.04 imagePullPolicy: Always command: ["sleep", "3600000"] env: - name: VAULT_K8S_ROLE value: "common-role" - name: VAULT_ADDR value: "https://vault.domain.tld:8200" - name: VAULT_AUTH_PATH value: "kilda-fred"
Авторизация в Vault
- Все действия из контейнера
kubectl --namespace kilda exec -ti test-kilda-service-acc -- bash
- Получение токена сервисного аккаунта k8
export JWT="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
- Просмотре переменных окружения
env | grep VAULT VAULT_K8S_ROLE=kilda-role VAULT_ADDR=https://vault.domain.tld:8200 VAULT_K8S_ROLE=kilda-role VAULT_AUTH_PATH=kilda-fred
- Авторизация в Vault используя роль и токен сервисного аккаунта: получение токена
vault write auth/kilda-fred/login role=${VAULT_K8S_ROLE} jwt=${JWT}
Key Value --- ----- token s.vGsxWHAW9xHzdryEHolw3Xw1 token_accessor x4JGArK99k6wkh9QqgPE6dwF token_duration 1h token_renewable true token_policies ["default" "kilda-policy" "kv-common-policy"] identity_policies [] policies ["default" "kilda-policy" "kv-common-policy"] token_meta_role kilda-role token_meta_service_account_name kilda-service-account token_meta_service_account_namespace kilda token_meta_service_account_secret_name n/a token_meta_service_account_uid 50b15622-38d9-4725-96b1-1c56f4ca0da1
- логин с использованием токена
vault login s.vGsxWHAW9xHzdryEHolw3Xw1
Key Value --- ----- token s.vGsxWHAW9xHzdryEHolw3Xw1 token_accessor x4JGArK99k6wkh9QqgPE6dwF token_duration 59m26s token_renewable true token_policies ["default" "kilda-policy" "kv-common-policy"] identity_policies [] policies ["default" "kilda-policy" "kv-common-policy"] token_meta_role kilda-role token_meta_service_account_name kilda-service-account token_meta_service_account_namespace kilda token_meta_service_account_secret_name n/a token_meta_service_account_uid 50b15622-38d9-4725-96b1-1c56f4ca0da1
- Просмотр токена и его прав ( в том числе политик)
- результат соответсвует ожидаемому: policies [default kilda-policy kv-common-policy]
vault token lookup
Key Value --- ----- accessor x4JGArK99k6wkh9QqgPE6dwF creation_time 1644416277 creation_ttl 1h display_name kilda-fred-kilda-kilda-service-account entity_id ab9837eb-ff5c-71e4-cb78-16065ef5a7eb expire_time 2022-02-09T15:17:57.790015655Z explicit_max_ttl 0s id s.vGsxWHAW9xHzdryEHolw3Xw1 issue_time 2022-02-09T14:17:57.79003263Z meta map[role:kilda-role service_account_name:kilda-service-account service_account_namespace:kilda service_account_secret_name: service_account_uid:50b15622-38d9-4725-96b1-1c56f4ca0da1] num_uses 0 orphan true path auth/kilda-fred/login policies [default kilda-policy kv-common-policy] renewable true ttl 59m21s type service
Проверить возможность чтения из разрешенных путей key/value
vault kv get kv/kilda/subpath (чтение возможно - результат соответсвует ожиданием)
======= Metadata ======= Key Value --- ----- created_time 2022-02-08T14:59:04.275447933Z custom_metadata <nil> deletion_time n/a destroyed false version 1 ===== Data ===== Key Value --- ----- somekey somedata
vault kv get kv/common/somepath (чтение возможно - результат соответсвует ожиданием)
======= Metadata ======= Key Value --- ----- created_time 2022-02-09T14:23:30.169927438Z custom_metadata <nil> deletion_time n/a destroyed false version 1 ====== Data ====== Key Value --- ----- commonkey commonvalue
Проверить невозможность чтения из запрещенных путей key/value
vault kv get kv/kilda/noaccess (чтение НЕ возможно - результат соответсвует ожиданием)
Error reading kv/data/kilda/noaccess: Error making API request. URL: GET https://vault.domain.tld:8200/v1/kv/data/kilda/noaccess Code: 403. Errors: * 1 error occurred: * permission denied
Проверка common-service-account
Создание POD
kubectl apply -f pod-common-service-account.yaml
apiVersion: v1 kind: Pod metadata: name: test-common-service-acc namespace: kilda labels: role: test spec: serviceAccountName: "common-service-account" hostAliases: - ip: "10.14.15.201" hostnames: - "vault.domain.tld" containers: - name: web image: ubuntu:20.04 imagePullPolicy: Always command: ["sleep", "3600000"] env: - name: VAULT_K8S_ROLE value: "common-role" - name: VAULT_ADDR value: "https://vault.domain.tld:8200" - name: VAULT_AUTH_PATH value: "kilda-fred"
Авторизация в Vault
- Все действия из контейнера
kubectl --namespace kilda exec -ti test-common-service-acc -- bash
- Получение токена сервисного аккаунта k8
export JWT="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
- Просмотре переменных окружения
env | grep VAULT VAULT_K8S_ROLE=common-role VAULT_ADDR=https://vault.domain.tld:8200 VAULT_AUTH_PATH=kilda-fred
- Авторизация в Vault используя роль и токен сервисного аккаунта: получение токена
vault write auth/kilda-fred/login role=${VAULT_K8S_ROLE} jwt=${JWT}
Key Value --- ----- token s.fj4OxBwSn3jJjZ1FECwxSS6D token_accessor 7TOZSFyiCRnTeAydmUxlKdLb token_duration 1h token_renewable true token_policies ["default" "kv-common-policy"] identity_policies [] policies ["default" "kv-common-policy"] token_meta_service_account_name common-service-account token_meta_service_account_namespace kilda token_meta_service_account_secret_name n/a token_meta_service_account_uid 70f30a0a-4efb-4356-b90d-be9210f47117 token_meta_role common-role
- логин с использованием токена
vault login s.fj4OxBwSn3jJjZ1FECwxSS6D
Key Value --- ----- token s.fj4OxBwSn3jJjZ1FECwxSS6D token_accessor 7TOZSFyiCRnTeAydmUxlKdLb token_duration 59m18s token_renewable true token_policies ["default" "kv-common-policy"] identity_policies [] policies ["default" "kv-common-policy"] token_meta_service_account_secret_name n/a token_meta_service_account_uid 70f30a0a-4efb-4356-b90d-be9210f47117 token_meta_role common-role token_meta_service_account_name common-service-account token_meta_service_account_namespace kilda
- Просмотр токена и его прав ( в том числе политик)
- результат соответсвует ожидаемому: policies [default kilda-policy kv-common-policy]
vault token lookup
Key Value --- ----- accessor 7TOZSFyiCRnTeAydmUxlKdLb creation_time 1644506420 creation_ttl 1h display_name kilda-fred-kilda-common-service-account entity_id 522a6514-5e13-44d8-0377-c213154e0d44 expire_time 2022-02-10T16:20:20.254743135Z explicit_max_ttl 0s id s.fj4OxBwSn3jJjZ1FECwxSS6D issue_time 2022-02-10T15:20:20.254757455Z meta map[role:common-role service_account_name:common-service-account service_account_namespace:kilda service_account_secret_name: service_account_uid:70f30a0a-4efb-4356-b90d-be9210f47117] num_uses 0 orphan true path auth/kilda-fred/login policies [default kv-common-policy] renewable true ttl 58m33s type service
Проверить возможность чтения из разрешенных путей key/value
vault kv get kv/common/somepath (чтение возможно - результат соответсвует ожиданием)
======= Metadata ======= Key Value --- ----- created_time 2022-02-09T14:23:30.169927438Z custom_metadata <nil> deletion_time n/a destroyed false version 1 ====== Data ====== Key Value --- ----- commonkey commonvalue
Проверить невозможность чтения из запрещенных путей key/value
vault kv get kv/kilda/subpath (чтение НЕ возможно - результат соответсвует ожиданием)
Error reading kv/data/kilda/subpath: Error making API request. URL: GET https://vault.domain.tld:8200/v1/kv/data/kilda/subpath Code: 403. Errors: * 1 error occurred: * permission denied
Выводы
- Сервисный аккаунт kilda-service-account имеет доступ к k/v kv/kilda/* и kv/common/*
- Сервисный аккаунт common-service-account имеет доступ к k/v kv/common/* и не имеет доступа к k/v kv/kilda/*
- те все работает так как должно