Vault with k8s: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
 
(не показаны 22 промежуточные версии этого же участника)
Строка 1: Строка 1:
 
[[Категория:K8s]]
 
[[Категория:K8s]]
 
[[Категория:Hashicorp_Vault]]
 
[[Категория:Hashicorp_Vault]]
  +
[[Категория:Vault]]
 
[[Категория:Linux]]
 
[[Категория:Linux]]
   
Строка 12: Строка 13:
 
1. Создается сервисный аккаунт <BR>
 
1. Создается сервисный аккаунт <BR>
 
2. Запускается POD с этим сервисным аккаунтом <BR>
 
2. Запускается POD с этим сервисным аккаунтом <BR>
3. Под получает адрес Vault (в моем случае - вычитывает из Consul но это не принципиально) <BR>
+
3. POD получает адрес Vault каким-то способом (в моем случае - вычитывает из Consul но это не принципиально, можно через переменную окружения или еще как-то) <BR>
 
4. Авторизуется в Vault под определенной ролью используя JWT <BR>
 
4. Авторизуется в Vault под определенной ролью используя JWT <BR>
5 Vault возвращает токе с политиками назначенными на роль <BR>
+
5 Vault возвращает токен с политиками назначенными на роль <BR>
 
5. POD читает из Vault используя полученный токен <BR>
 
5. POD читает из Vault используя полученный токен <BR>
   
Строка 49: Строка 50:
 
+-------------------------------------------------------------------------------------------------------------------------------+
 
+-------------------------------------------------------------------------------------------------------------------------------+
 
</PRE>
 
</PRE>
  +
 
==Настройка==
 
==Настройка==
 
===k8s===
 
===k8s===
Строка 61: Строка 63:
 
namespace: test-namespace
 
namespace: test-namespace
 
</PRE>
 
</PRE>
===Права сервисного аккаунта===
+
====Права сервисного аккаунта====
 
Для того что б аккаунт мог проверить JWT у других сервисных аккаунтов ему назначается
 
Для того что б аккаунт мог проверить JWT у других сервисных аккаунтов ему назначается
 
ClusterRole <B>system:auth-delegator</B>
 
ClusterRole <B>system:auth-delegator</B>
Строка 118: Строка 120:
 
export NAMESPACE="my-namespace-name"
 
export NAMESPACE="my-namespace-name"
 
</PRE>
 
</PRE>
Получить имя "секрета"
+
Получить имя "секрета" для сервисного аккаунта vault-tokenreview-service-accoun (аккаунт под которым Vault работает с K8S API)
 
<PRE>
 
<PRE>
 
export SECRET_NAME=$( \
 
export SECRET_NAME=$( \
Строка 148: Строка 150:
 
-o jsonpath="{.data['ca\.crt']}" \
 
-o jsonpath="{.data['ca\.crt']}" \
 
| base64 --decode; echo )
 
| base64 --decode; echo )
  +
</PRE>
 
 
====Настройка доступа Vault в K8S====
 
====Настройка доступа Vault в K8S====
 
Настроить vault (адрес API можно взять из конфигурации kubectl)
 
Настроить vault (адрес API можно взять из конфигурации kubectl)
Строка 166: Строка 168:
 
* При авторизации POD запрашивает токен для <B>роли</B>
 
* При авторизации POD запрашивает токен для <B>роли</B>
 
* На токен будут назначены политики из привязки
 
* На токен будут назначены политики из привязки
 
   
 
====Привязка сервисных аккаунтов K8S к ролям Vault====
 
====Привязка сервисных аккаунтов K8S к ролям Vault====
Строка 173: Строка 174:
 
export VAULT_K8S_ROLE="k8s-test-role"
 
export VAULT_K8S_ROLE="k8s-test-role"
 
</PRE>
 
</PRE>
  +
Здесь VAULT_K8S_SERVICE_ACCOUNT - это сервисный аккаунт в k8s который можно создать например так:
 
  +
<PRE>
  +
---
  +
apiVersion: v1
  +
kind: ServiceAccount
  +
metadata:
  +
name: k8s-service-account
  +
namespace: my-namespace-name
  +
</PRE>
  +
<B>Важно:</B> Это сервисный аккаунт для запуска PODов, и это НЕ ТОТ сервисный аккаунт который используется Vault
  +
<BR>
 
Создать привязку
 
Создать привязку
 
<PRE>
 
<PRE>
  +
vault \
${VAULT} \
 
 
write \
 
write \
 
auth/kubernetes/role/${VAULT_K8S_ROLE} \
 
auth/kubernetes/role/${VAULT_K8S_ROLE} \
Строка 185: Строка 196:
 
</PRE>
 
</PRE>
 
Обратить внимание - политики <B>policy1,policy2</B> уже существуют (созданы до этого). Если политик нет их необходимо создать.
 
Обратить внимание - политики <B>policy1,policy2</B> уже существуют (созданы до этого). Если политик нет их необходимо создать.
  +
  +
==Деплоймент в K8S==
  +
Примерная конфигурация PODа
  +
<PRE>
  +
apiVersion: extensions/v1beta1
  +
kind: Deployment
  +
metadata:
  +
name: my-deployment
  +
spec:
  +
replicas: 1
  +
selector:
  +
matchLabels:
  +
app: my-deployment-pod
  +
template:
  +
metadata:
  +
labels:
  +
app: my-deployment-pod
  +
spec:
  +
serviceAccountName: "k8s-test-service-account"
  +
containers:
  +
- name: my-container-name
  +
image: ...
  +
imagePullPolicy: Always
  +
args: ...
  +
env:
  +
- name: VAULT_K8S_ROLE
  +
value: "k8s-test-role"
  +
</PRE>
   
 
==Получение токена==
 
==Получение токена==
  +
Адрес Vault известен (через переменную окружения или из Consul)<BR>
  +
Токен сервисного аккаунта монтируется как вольюм
  +
<BR>
  +
Изнутри контейнера:
  +
<PRE>
  +
export VAULT_ADDR="http://192.168.1.4:8200"
  +
export JWT="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
  +
</PRE>
  +
  +
  +
===Авторизация используя утилиту vault===
  +
<PRE>
  +
vault write auth/kubernetes/login role=k8s-test-role jwt=${JWT}
  +
</PRE>
  +
<PRE>
  +
Key Value
  +
--- -----
  +
token s.SyMDLTmAYLtEA13vBVfjqyfq
  +
token_accessor 3pQbarDfUWChuIgWZRnnKMMB
  +
token_duration 1h
  +
token_renewable true
  +
token_policies ["policy1" "policy2" "default" ]
  +
identity_policies []
  +
policies token_policies ["policy1" "policy2" "default" ]
  +
token_meta_service_account_name k8s-test-service-account
  +
token_meta_service_account_namespace test-namespace
  +
token_meta_service_account_secret_name k8s-test-service-account-token-klp4w
  +
token_meta_service_account_uid fe7fc17f-2305-11e9-b347-4201c0a8bf08
  +
token_meta_role k8s-testi-role
  +
  +
</PRE>
  +
  +
===Авторизация через Curl===
  +
<PRE>
  +
curl \
  +
--request POST \
  +
--data '{"jwt": "'"${JWT}"'", "role": "k8s-test-role"}' \
  +
${VAULT_ADDR}/v1/auth/kubernetes/login
  +
</PRE>
  +
<PRE>
  +
{
  +
"request_id": "8d524407-ee6b-a6c2-b011-d02572ae2ce9",
  +
"lease_id": "",
  +
"renewable": false,
  +
"lease_duration": 0,
  +
"data": null,
  +
"wrap_info": null,
  +
"warnings": null,
  +
"auth": {
  +
"client_token": "s.3YsrjrkBZLOXF5sAmR2ceqrs",
  +
"accessor": "I532wSMIIXYSiAocKcShEhe7",
  +
"policies": [
  +
"policy1",
  +
"policy2",
  +
"default"
  +
],
  +
"token_policies": [
  +
"policy1",
  +
"policy2",
  +
"default"
  +
],
  +
"metadata": {
  +
"role": "k8s-test-role",
  +
"service_account_name": "k8s-test-service-account",
  +
"service_account_namespace": "test-namespace",
  +
"service_account_secret_name": "k8s-test-service-account-token-klp4w",
  +
"service_account_uid": "fe7fc17f-2305-11e9-b347-4201c0a8bf08"
  +
},
  +
"lease_duration": 3600,
  +
"renewable": true,
  +
"entity_id": "5d4ec129-0298-54a6-bf03-a51dbda0a917",
  +
"token_type": "service"
  +
}
  +
}
  +
</PRE>
   
 
=Ссылки=
 
=Ссылки=
Строка 193: Строка 307:
 
* https://coreos.com/tectonic/docs/latest/vault-operator/user/kubernetes-auth-backend.html
 
* https://coreos.com/tectonic/docs/latest/vault-operator/user/kubernetes-auth-backend.html
 
* https://medium.com/@gmaliar/dynamic-secrets-on-kubernetes-pods-using-vault-35d9094d169
 
* https://medium.com/@gmaliar/dynamic-secrets-on-kubernetes-pods-using-vault-35d9094d169
  +
* https://blog.openshift.com/vault-integration-using-kubernetes-authentication-method/
  +
* https://www.vaultproject.io/docs/auth/kubernetes.html

Текущая версия на 20:33, 8 октября 2021


Авторизация контейнеров/PODов в Hashicorp Vault

Задача - использовать сервисные аккаунты кубернетиса для авторизации а Hashicorp Vault

Схема работы

1. Создается сервисный аккаунт
2. Запускается POD с этим сервисным аккаунтом
3. POD получает адрес Vault каким-то способом (в моем случае - вычитывает из Consul но это не принципиально, можно через переменную окружения или еще как-то)
4. Авторизуется в Vault под определенной ролью используя JWT
5 Vault возвращает токен с политиками назначенными на роль
5. POD читает из Vault используя полученный токен

+-------------------------------------------------------------------------------------------------------------------------------+
| Google Cloud Engine                                                                                                           |
|                                                                                                                               |
|                                                                                                                               |
| +-----------------------------------------------------------+                                                                 |
| | K8S Cluster (in GKE)                                      |                                                                 |
| |                                                           |                                                                 |
| |                                                           |                                                                 |
| |  +---------------------------------------------------+    |                                                                 |
| |  | POD                                               |    |                                                                 |
| |  |   spec:                                           |    |                                                                 |
| |  |     serviceAccountName: k8s-test-service-account  |    |                                                                 |
| |  |     ...                                           |    |                                                                 |
| |  |     containers:                                   |    |                                                                 |
| |  |     - name: container-name                        |    |                                                                 |
| |  |       image: ...                                  |    |                                          +-------------------+  |
| |  |       imagePullPolicy: Always                     |    |                                          | VM Instance       |  |
| |  |       env:                                        |    |                                          |                   |  |
| |  |       - name: VAULT_K8S_ROLE                      |    |                                          |    +------------+ |  |
| |  |         value: k8s-test-role                      | ---|-->---> Token Request for role ->-->-->---|    | Vault      | |  |
| |  +---------------------------------------------------+    |   * POD's SA JWT                         |    | Process    | |  |
| |                                                           |   * Role Name                            |    |            | |  |
| |                                                           |                                          |    |            | |  |
| |  +--------------------+                                   |  Verify POS's Service Account JWT        |    |            | |  |
| |  | K8S API Endpoint   |<--------<--------<----------------|-( auth with Vault's Service Account )-<--|    |            | |  |
| |  +--------------------+                                   |                                          |    +------------+ |  |
| |                                                           |                                          |                   |  |
| +-----------------------------------------------------------+                                          +-------------------+  |
|                                                                                                                               |
+-------------------------------------------------------------------------------------------------------------------------------+

Настройка

k8s

Сервисный аккаунт

Это аккаунт с которым Vault подключается к API k8s для валидации JWT

 

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: vault-tokenreview-service-account
  namespace: test-namespace

Права сервисного аккаунта

Для того что б аккаунт мог проверить JWT у других сервисных аккаунтов ему назначается ClusterRole system:auth-delegator
Важно: Назначить права нужно в 2 неймспейсах - если назначить только в test-namespace то прав для проверки JWT недостаточно (что совершенно не очевидно из конфигурации)

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: vault-tokenreview-service-account-role-binding
  namespace: test-namespace
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  name: vault-tokenreview-service-account
  namespace: test-namespace


---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: vault-tokenreview-service-account-role-binding-2
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  name: vault-tokenreview-service-account
  namespace: test-namespace

Vault

Для настройки Vault потребуется токен с рутовыми правами адрес Vault дан для примера. В моем случае он вычитывается из Consul.

export VAULT_TOKEN="<ROOT_TOKEN>"
export VAULT_ADDR="http://192.168.1.4:8200"

Включить поддержку k8s в Vault

vault auth-enable kubernetes


Получение необходимых секретов из K8S

Так-как в моем случае все PODы находятся в отдельном namespace то:

export NAMESPACE="my-namespace-name"

Получить имя "секрета" для сервисного аккаунта vault-tokenreview-service-accoun (аккаунт под которым Vault работает с K8S API)

export SECRET_NAME=$( \
    kubectl \
    --namespace ${NAMESPACE} \
    get \ 
    serviceaccount \
    vault-tokenreview-service-account \
   -o jsonpath='{.secrets[0].name}' )

Зная имя секрета можно получить его токен:

export ACCOUNT_TOKEN=$( \
    kubectl \
    --namespace ${NAMESPACE}  \
    get \
    secret ${SECRET_NAME} \
    -o jsonpath='{.data.token}' \
    | base64 --decode )

В том же секрете содержится сертификат СА:

export SERVICE_ACCOUNT_CA_CRT=$( \
    kubectl \
    --namespace ${NAMESPACE} \
    get \
    secret ${SECRET_NAME} \
    -o jsonpath="{.data['ca\.crt']}" \
    | base64 --decode; echo )

Настройка доступа Vault в K8S

Настроить vault (адрес API можно взять из конфигурации kubectl)

vault \
    write \
    auth/kubernetes/config \
    kubernetes_host="https://192.168.191.2:443" \
    kubernetes_ca_cert="${SERVICE_ACCOUNT_CA_CRT}" \
    token_reviewer_jwt="${ACCOUNT_TOKEN}"

Обратить внимание:

  • Service Account - это аккаунт с которым будет деплоиться POD. Это аккаунт в k8s а не в Vault.
  • Роль существует только в пределах Vault (а не в K8S)
  • При авторизации POD запрашивает токен для роли
  • На токен будут назначены политики из привязки

Привязка сервисных аккаунтов K8S к ролям Vault

export VAULT_K8S_SERVICE_ACCOUNT="k8s-test-service-account" 
export VAULT_K8S_ROLE="k8s-test-role" 

Здесь VAULT_K8S_SERVICE_ACCOUNT - это сервисный аккаунт в k8s который можно создать например так:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: k8s-service-account
  namespace: my-namespace-name

Важно: Это сервисный аккаунт для запуска PODов, и это НЕ ТОТ сервисный аккаунт который используется Vault
Создать привязку

vault \
    write \
    auth/kubernetes/role/${VAULT_K8S_ROLE} \
    bound_service_account_names=${VAULT_K8S_SERVICE_ACCOUNT} \
    bound_service_account_namespaces=${NAMESPACE} \
    policies=policy1,policy2,default \
    ttl=1h

Обратить внимание - политики policy1,policy2 уже существуют (созданы до этого). Если политик нет их необходимо создать.

Деплоймент в K8S

Примерная конфигурация PODа

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-deployment-pod
  template:
    metadata:
      labels:
        app: my-deployment-pod
    spec:
      serviceAccountName: "k8s-test-service-account"
      containers:
      - name: my-container-name
        image:  ...
        imagePullPolicy: Always
        args: ...
        env:
        - name: VAULT_K8S_ROLE
          value: "k8s-test-role"

Получение токена

Адрес Vault известен (через переменную окружения или из Consul)
Токен сервисного аккаунта монтируется как вольюм
Изнутри контейнера:

export VAULT_ADDR="http://192.168.1.4:8200"
export JWT="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"


Авторизация используя утилиту vault

 vault write auth/kubernetes/login  role=k8s-test-role jwt=${JWT}
Key                                       Value
---                                       -----
token                                     s.SyMDLTmAYLtEA13vBVfjqyfq
token_accessor                            3pQbarDfUWChuIgWZRnnKMMB
token_duration                            1h
token_renewable                           true
token_policies                            ["policy1" "policy2" "default" ]
identity_policies                         []
policies                                  token_policies                            ["policy1" "policy2" "default" ]
token_meta_service_account_name           k8s-test-service-account
token_meta_service_account_namespace      test-namespace
token_meta_service_account_secret_name    k8s-test-service-account-token-klp4w
token_meta_service_account_uid            fe7fc17f-2305-11e9-b347-4201c0a8bf08
token_meta_role                           k8s-testi-role

Авторизация через Curl

curl \
    --request POST \
    --data '{"jwt": "'"${JWT}"'", "role": "k8s-test-role"}' \
    ${VAULT_ADDR}/v1/auth/kubernetes/login
{
  "request_id": "8d524407-ee6b-a6c2-b011-d02572ae2ce9",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": null,
  "wrap_info": null,
  "warnings": null,
  "auth": {
    "client_token": "s.3YsrjrkBZLOXF5sAmR2ceqrs",
    "accessor": "I532wSMIIXYSiAocKcShEhe7",
    "policies": [
      "policy1",
      "policy2",
      "default"
    ],
    "token_policies": [
      "policy1",
      "policy2",
      "default"
    ],
    "metadata": {
      "role": "k8s-test-role",
      "service_account_name": "k8s-test-service-account",
      "service_account_namespace": "test-namespace",
      "service_account_secret_name": "k8s-test-service-account-token-klp4w",
      "service_account_uid": "fe7fc17f-2305-11e9-b347-4201c0a8bf08"
    },
    "lease_duration": 3600,
    "renewable": true,
    "entity_id": "5d4ec129-0298-54a6-bf03-a51dbda0a917",
    "token_type": "service"
  }
}

Ссылки