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

Автор: | 13/05/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.

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

[simterm]

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

[/simterm]

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

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

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

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

[simterm]

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

[/simterm]

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

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

[simterm]

$ argocd login dev-1-18.argocd.example.com --username testuser --name [email protected]
Password: 
'testuser' logged in successfully
Context '[email protected]' updated

[/simterm]

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

[simterm]

$ argocd login dcontext
CURRENT  NAME                                     SERVER
         [email protected]     dev-1-18.argocd.example.com
*        [email protected]  dev-1-18.argocd.example.com

[/simterm]

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

Роли и RBAC

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

[simterm]

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

[/simterm]

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

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

[simterm]

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

[/simterm]

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

[simterm]

$ 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

[/simterm]

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
...

Проверяем:

[simterm]

$ argocd account can-i create clusters '*'
yes

[/simterm]

Создаём:

[simterm]

$ 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

[/simterm]

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

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

ArgoCD Projects

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

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

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

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

[simterm]

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

[/simterm]

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

[simterm]

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

[/simterm]

И могут бысть созданы из манифеста (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:

[simterm]

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

[/simterm]

Проверяем:

[simterm]

$ 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

[/simterm]

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

[simterm]

$ argocd app set guestbook --project test-project

[/simterm]

Проверяем:

[simterm]

$ 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
...

[/simterm]

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

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

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

[simterm]

$ 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'

[/simterm]

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

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

[simterm]

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

[/simterm]

Проверяем:

[simterm]

$ 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
...

[/simterm]

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

[simterm]

$ 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

[/simterm]

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

Соответсвенно, на 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:''
...

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

[simterm]

$ argocd context [email protected]
Switched to context '[email protected]'

[/simterm]

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

[simterm]

$ 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

[/simterm]

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

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

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

[simterm]

$ argocd proj role create test-project test-role

[/simterm]

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

[simterm]

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

[/simterm]

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

[simterm]

$ 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]

[/simterm]

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

[simterm]

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

[/simterm]

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

[simterm]

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

[/simterm]

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

[simterm]

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

[/simterm]

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

[simterm]

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

[/simterm]

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

[simterm]

$ argocd account can-i create projects '*'
yes

[/simterm]

Группы

В 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 и группы пользователей.