ArgoCD: пользователи, доступы и RBAC

Автор: | 05/13/2021
 

ArgoCD использует два типа пользователей — локальные, заданные в argocd-cm ConfigMap, и SSO.

Ниже рассмотрим работу с локальными пользователями, а позже добавим SSO и группы, так как для локальных пользователей нельзя создавать группы, см. Local users/accounts.

Разделение доступов выполняется с помощью ролей, которым подключаются политики, описывающие к чему есть доступ, и на какие операции.

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

Начнём с добавления простого пользователя, и понемногу разберёмся с остальным.

Пользователи и роли ArgoCD

Добавление локального пользователя

Тут всё просто — редактируем argocd-cm ConfigMap, и добавляем пользователя:

apiVersion: v1
data:
  accounts.testuser: apiKey,login
...

В apiKey указываем права на генерацию JWT-токенов для аутентификации, см. Security, login — разрешение на логин через WebUI.

Сохраняем, и проверяем список пользователей:

argocd account list
NAME      ENABLED  CAPABILITIES
admin     true     login
testuser  true     apiKey, login

Пользователь admin создан при деплое ArgoCD, и у него нет прав на создание токена (можно перееопределить, добавив его в argocd-cm, хотя его рекомендуется вообще отключить после создания новых пользователей).

Вообще общая идея, как мне кажется — это использовать пользователей для доступа к WebUI, а роли проектов — для получения токенов, а потом эти токены уже использовать в CI/CD пайплайнах.

testuser — создан нами только что, но сейчас он без пароля, и логин с ним не пройдёт.

Что бы создать пароль новому пользователю — вам нужен пароль текущего пользователя admin:

argocd account update-password --account testuser --new-password 1234 --current-password admin-p@ssw0rd
Password updated

Бредовенько, конечно, но как есть. См. Unable to change the user’s password via argocd CLI.

Логинимся с новым юзером:

argocd login dev-1-18.argocd.example.com --username testuser --name testuser@dev-1-18.argocd.example.com
Password:
'testuser' logged in successfully
Context 'testuser@dev-1-18.argocd.example.com' updated

Проверяем локальные контексты:

argocd login dcontext
CURRENT  NAME                                     SERVER
admin@dev-1-18.argocd.example.com     dev-1-18.argocd.example.com
*        testuser@dev-1-18.argocd.example.com  dev-1-18.argocd.example.com

Окей — сейчас под testuser.

Роли и RBAC

По-умолчанию, все новые пользователи используют policy.default из argocd-rbac-cm ConfigMap:

kubectl -n dev-1-18-devops-argocd-ns get configmap argocd-rbac-cm -o yaml
apiVersion: v1
data:
policy.default: role:readonly
...

Для Argo имеется две дефолтных роли — role:readonly и role:admin. Кроме того, policy.default можно задать в role: '', что бы отключить доступ вообще, т.к. если для пользователя не находится ролей/доступов — то будет применена именно policy.default.

Сейчас наш новый юзер может только просматривать ресурсы:

argocd cluster list
SERVER                          NAME        VERSION  STATUS      MESSAGE
https://kubernetes.default.svc  in-cluster  1.18+    Successful

Но не создавать новые, например попробуем добавить новый кластер:

argocd cluster add config-aws-china-eks-account@aws-china-eks-account --kubeconfig ~/.kube/config-aws-china-eks-account@aws-china-eks-account
INFO[0002] ServiceAccount "argocd-manager" already exists in namespace "kube-system"
INFO[0003] ClusterRole "argocd-manager-role" updated
INFO[0004] ClusterRoleBinding "argocd-manager-role-binding" updated
FATA[0006] rpc error: code = PermissionDenied desc = permission denied: clusters, create, https://21D***ECD.gr7.cn-northwest-1.eks.amazonaws.com.cn, sub: testuser, iat: 2021-05-12T14:03:12Z

«permission denied: clusters, create» — ага.

Что бы дать права на создание кластера — редактируем argocd-rbac-cm CondfigMap, добавлям роль role:test-role с правами clusters, create:

...
data:
  policy.default: role:readonly
  policy.csv: |
    p, role:test-role, clusters, create, *, allow
    g, testuser, role:test-role
...

Проверяем:

argocd account can-i create clusters '*'
yes

Создаём:

argocd cluster add config-aws-china-eks-account@aws-china-eks-account --kubeconfig ~/.kube/config-aws-china-eks-account@aws-china-eks-account
INFO[0001] ServiceAccount "argocd-manager" already exists in namespace "kube-system"
INFO[0002] ClusterRole "argocd-manager-role" updated
INFO[0003] ClusterRoleBinding "argocd-manager-role-binding" updated
Cluster 'https://21D***ECD.gr7.cn-northwest-1.eks.amazonaws.com.cn' added

Но что делать, если хочется задать ограничения по неймспейсам? Ведь RBAC в ConfigMap не поддерживает их.

К примеру, у нас есть Web-разработчики, есть backend-разработчики, и у них разные приложения, которые деплоятся в разные неймспейсы, и хочется отделить их — что бы Веб-команда не видела и не трогала ресурсы Бекенда, а Бекенда-команда — не затрагивала ресурсы Веб-команды.

ArgoCD Projects

И тут «Projects comes to the rescue«!

Project позволяет задать доступы для неймпейсов, репозиториев, кластеров и так далее. А затем мы сможем ограничить каждую группу девелоперов доступом к определённому проекту и, соответсвенно, ограничим доступ к неймспейсам.

Посмотрим, как это работает.

При установке, ArgoCD создаёт проект default:

argocd proj list
NAME     DESCRIPTION  DESTINATIONS  SOURCES                                          CLUSTER-RESOURCE-WHITELIST  NAMESPACE-RESOURCE-BLACKLIST  SIGNATURE-KEYS  ORPHANED-RESOURCES
default               *,*           *                                                */*                         <none>                        <none>          disabled

Проекты являются Kubernetes Custom Resource с типом appproject:

kubectl -n dev-1-18-devops-argocd-ns get appproject
NAME      AGE
default   166d

И могут бысть созданы из манифеста (declarative setup ArgoCD рассмотрим в следующих постах):

kind: AppProject
metadata:
  name: example-project
  namespace: dev-1-18-devops-argocd-ns
spec:
  clusterResourceWhitelist:
  - group: '*'
    kind: '*'
  destinations:
  - namespace: argo-test-ns
    server: https://kubernetes.default.svc
  orphanedResources:
    warn: false
  sourceRepos:
  - '*'

Или с помощью ArgoCD CLI:

argocd proj create test-project -d https://kubernetes.default.svc,argo-test-ns -s https://github.com/argoproj/argocd-example-apps.git

Проверяем:

argocd proj list
NAME          DESCRIPTION  DESTINATIONS                                 SOURCES                                              CLUSTER-RESOURCE-WHITELIST  NAMESPACE-RESOURCE-BLACKLIST  SIGNATURE-KEYS  ORPHANED-RESOURCES
default                    *,*                                          *                                                    */*                         <none>                        <none>          disabled
test-project               https://kubernetes.default.svc,argo-test-ns  https://github.com/argoproj/argocd-example-apps.git  <none>                      <none>                        <none>          disabled

Теперь перенесём в этот проект уже имеющееся тестовое приложение guestbook из неймспейса argo-test-ns:

argocd app set guestbook --project test-project

Проверяем:

argocd app get guestbook
Name:               guestbook
Project:            test-project
Server:             https://kubernetes.default.svc
Namespace:          argo-test-ns
URL:                https://dev-1-18.argocd.example.com/applications/guestbook
Repo:               https://github.com/argoproj/argocd-example-apps.git
...

А дальше — проверим, как работает ограничение на неймспейсы.

Для нашего проекта при создании был задан один destinationhttps://kubernetes.default.svc,argo-test-ns.

Попробуем создать в этом проекте новое приложение, но namespace укажем argo-test-2-ns:

argocd app create guestbook-2 --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace argo-test-2-ns --project test-project
FATA[0001] rpc error: code = InvalidArgument desc = application spec is invalid: InvalidSpecError: application destination {https://kubernetes.default.svc argo-test-2-ns} is not permitted in project 'test-project'

«application destination {https://kubernetes.default.svc argo-test-2-ns} is not permitted in project ‘test-project» — отлично!

Обновим проект, добавим ещё один destination — тот же кластер, но неймспейс argo-test-2-ns:

argocd proj add-destination test-project https://kubernetes.default.svc argo-test-2-ns

Проверяем:

argocd proj get test-project
Name:                             test-project
Description:
Destinations:                     https://kubernetes.default.svc,argo-test-ns
https://kubernetes.default.svc,argo-test-2-ns
...

Повторяем создание приложения:

argocd app create guestbook-2 --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace argo-test-2-ns --project test-project
application 'guestbook-2' created

Теперь работает.

Соответсвенно, на Dev-кластере можно будет задать destination в виде '*', так как неймспейсы там динамические — девелоперы деплоят приложения из разных бранчей в разные неймспейсы, а вот для Production кластера — зададим жёсткое ограничение.

Projects и роли

Глобальные роли

Доступ к проектам можно задать как через глобальные настройки в argocd-rbac-cm ConfigMap, так и локально для проекта.

Например, вернёмся к нашей глобальной роли role:test-role, и добавим политику, разрешив доступ к приложениям только из проекта test-project, а в policy.default отключаем read-only доступ ко всем ресурсам, указав role: '':

...
  policy.csv: |
    p, role:test-role, clusters, create, *, allow
    p, role:test-role, applications, *, test-project/*, allow
    g, testuser, role:test-role
  policy.default: role:''
...

Переключаемся на тестового юзера:

argocd context testuser@dev-1-18.argocd.example.com
Switched to context 'testuser@dev-1-18.argocd.example.comd'

Проверяем список доступных приложений:

argocd app list
NAME       CLUSTER                         NAMESPACE     PROJECT       STATUS     HEALTH   SYNCPOLICY  CONDITIONS  REPO                                                 PATH            TARGET
guestbook  https://kubernetes.default.svc  argo-test-ns  test-project  OutOfSync  Missing  <none>      <none>      https://github.com/argoproj/argocd-example-apps.git  helm-guestbook  HEAD

Роли проекта и токены аутентификации

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

Создаём роль test-role проекта test-project:

argocd proj role create test-project test-role

Добавляем политику доступа — любые действия с приложением guestbook:

argocd proj role add-policy test-project test-role --action '*' --permission allow --object guestbook

Политика будет включена в RBAC-роль этого проекта:

kubectl -n dev-1-18-devops-argocd-ns get appproject test-project -o jsonpath='{.spec.roles[].policies}'
[p, proj:test-project:test-role, applications, *, test-project/guestbook, allow]

Получаем токен:

argocd proj role create-token test-project test-role
eyJ***sCA

Или сразу в переменную:

token=$(argocd proj role create-token test-project test-role)

И с его помощью проверяем права, например на синхронизацию приложения:

argocd account can-i sync applications test-project/guestbook --auth-token $token
yes

А вот на добавление кластера прав с этим токеном нет:

argocd account can-i create clusters '*' --auth-token $token
no

Но эти права есть у юзера, так как мы их задавали глобально в argocd-rbac-cm через политику роли test-rolep, role:test-role, clusters, create, *, allow:

argocd account can-i create projects '*'
yes

Группы

В RBAC так же можно объединять роли в группы (но не пользователей), например:

...
  policy.csv: |
    g, argocd-admins, role:admin
...

Затем, используя SSO, в нашем случае это будет Okta, мы замапим группы пользователей на нужные нам роли.

И всё вместе…

«А теперь со всей этой хернёй на борту мы попробуем взлететь!» (с)

Окей, всё это хорошо — но как можно все эти доступы использовать?

Что у нас будет?

Два проекта — web и backend.

У каждого — свои приложения.

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

Дальше — с делением по проектам: один админ на проект, один read-only. Делать ли отдельную учётку для CI/CD? Пока не вижу смысла — Github Actions/Jenkins должны будут и создавать новые аппки в проектах, и удалять, так что подойдёт админ-учётка проекта. А для QA — будет read-only доступ, так им кроме логов подов особо ничего не надо — триггерить деплой они будут через Gitub.

Позже настроим Okta и SSO, и юзеры будут в веб-интерфейс ходить под своими учётками, которым дадим админа на приложения в проекте в зависимости от группы в Окте: бекенду — бекендово, вебу — вебово, а нам фиолетово.

В целом, на этом всё.

Дальше — настроим Okta, потом declarative setup, и можно настраивать Github Actions.

См. продолжение в ArgoCD: интеграция с Okta и группы пользователей.