Пример назначения прав администратору кластера

Для назначения прав администратору кластера используйте роль d8:manage:all:manager в ClusterRoleBinding.

Пример назначения прав администратору кластера (User joe):

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-admin-joe
subjects:
- kind: User
  name: joe
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: d8:manage:all:manager
  apiGroup: rbac.authorization.k8s.io

Права, которые получит пользователь

Права, которые получит пользователь, будут ограничены рамками пространств имён, начинающихся с d8- или kube-.

Пользователю будут доступны следующие права:

  • Просмотр, изменение, удаление и создание ресурсов Kubernetes и модулей DKP.
  • Изменение конфигурации модулей (просмотр, изменение, удаление и создание ресурсов moduleConfig).
  • Выполнение следующих команд к подам и сервисам:
    • kubectl attach;
    • kubectl exec;
    • kubectl port-forward;
    • kubectl proxy.

Пример назначения прав сетевому администратору

Для назначения прав сетевому администратору на управление сетевой подсистемой кластера используйте роль d8:manage:networking:manager в ClusterRoleBinding.

Пример назначения прав сетевому администратору (User joe):

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: network-admin-joe
subjects:
- kind: User
  name: joe
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: d8:manage:networking:manager
  apiGroup: rbac.authorization.k8s.io

Список прав, которые получит пользователь

Права, которые получит пользователь, будут ограничены следующим списком пространств имён модулей DKP из подсистемы networking (фактический список зависит от списка включённых в кластере модулей):

  • d8-cni-cilium;
  • d8-cni-flannel;
  • d8-cni-simple-bridge;
  • d8-ingress-nginx;
  • d8-istio;
  • d8-metallb;
  • d8-network-gateway;
  • d8-openvpn;
  • d8-static-routing-manager;
  • d8-system;
  • kube-system.

Пользователю будут доступны следующие права:

  • Просмотр, изменение, удаление и создание стандартных ресурсов Kubernetes в пространстве имён модулей из подсистемы networking.

    Пример ресурсов, которыми сможет управлять пользователь (список не полный):

    • Certificate;
    • CertificateRequest;
    • ConfigMap;
    • ControllerRevision;
    • CronJob;
    • DaemonSet;
    • Deployment;
    • Event;
    • HorizontalPodAutoscaler;
    • Ingress;
    • Issuer;
    • Job;
    • Lease;
    • LimitRange;
    • NetworkPolicy;
    • PersistentVolumeClaim;
    • Pod;
    • PodDisruptionBudget;
    • ReplicaSet;
    • ReplicationController;
    • ResourceQuota;
    • Role;
    • RoleBinding;
    • Secret;
    • Service;
    • ServiceAccount;
    • StatefulSet;
    • VerticalPodAutoscaler;
    • VolumeSnapshot.
  • Просмотр, изменение, удаление и создание ресурсов в пространстве имён модулей из подсистемы networking.

    Список ресурсов, которыми сможет управлять пользователь:

    • EgressGateway;
    • EgressGatewayPolicy;
    • FlowSchema;
    • IngressClass;
    • IngressIstioController;
    • IngressNginxController;
    • IPRuleSet;
    • IstioFederation;
    • IstioMulticluster;
    • RoutingTable.
  • Изменение конфигурации модулей (просмотр, изменение, удаление и создание ресурсов moduleConfig) из подсистемы networking.

    Список модулей, которыми сможет управлять пользователь:

    • cilium-hubble;
    • cni-cilium;
    • cni-flannel;
    • cni-simple-bridge;
    • flow-schema;
    • ingress-nginx;
    • istio;
    • kube-dns;
    • kube-proxy;
    • metallb;
    • network-gateway;
    • network-policy-engine;
    • node-local-dns;
    • openvpn;
    • static-routing-manager.
  • Выполнение следующих команд к подам и сервисам в пространстве имён модулей из подсистемы networking:

    • kubectl attach;
    • kubectl exec;
    • kubectl port-forward;
    • kubectl proxy.

Пример назначения административных прав пользователю в рамках пространства имён

Для назначения прав на управление ресурсами приложений в рамках пространства имён, но без возможности настройки модулей DKP, используйте роль d8:use:role:admin в RoleBinding в соответствующем пространстве имён.

Пример назначения прав разработчику приложений (User app-developer) в пространстве имён myapp:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: myapp-developer
  namespace: myapp
subjects:
- kind: User
  name: app-developer
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: d8:use:role:admin
  apiGroup: rbac.authorization.k8s.io

Список прав, которые получит пользователь

В рамках пространства имён myapp пользователю будут доступны следующие права:

  • Просмотр, изменение, удаление и создание ресурсов Kubernetes. Например, следующих ресурсов (список не полный):
    • Certificate;
    • CertificateRequest;
    • ConfigMap;
    • ControllerRevision;
    • CronJob;
    • DaemonSet;
    • Deployment;
    • Event;
    • HorizontalPodAutoscaler;
    • Ingress;
    • Issuer;
    • Job;
    • Lease;
    • LimitRange;
    • NetworkPolicy;
    • PersistentVolumeClaim;
    • Pod;
    • PodDisruptionBudget;
    • ReplicaSet;
    • ReplicationController;
    • ResourceQuota;
    • Role;
    • RoleBinding;
    • Secret;
    • Service;
    • ServiceAccount;
    • StatefulSet;
    • VerticalPodAutoscaler;
    • VolumeSnapshot.
  • Просмотр, изменение, удаление и создание следующих ресурсов модулей DKP:
    • DexAuthenticator;
    • DexClient;
    • PodLogginConfig.
  • Выполнение следующих команд к подам и сервисам:
    • kubectl attach;
    • kubectl exec;
    • kubectl port-forward;
    • kubectl proxy.

Пример ClusterAuthorizationRule

apiVersion: deckhouse.io/v1
kind: ClusterAuthorizationRule
metadata:
  name: test-rule
spec:
  subjects:
  - kind: User
    name: some@example.com
  - kind: ServiceAccount
    name: gitlab-runner-deploy
    namespace: d8-service-accounts
  - kind: Group
    name: some-group-name
  accessLevel: PrivilegedUser
  portForwarding: true
  # Опция доступна только при включенном режиме enableMultiTenancy.
  allowAccessToSystemNamespaces: false
  # Опция доступна только при включенном режиме enableMultiTenancy.
  namespaceSelector:
    labelSelector:
      matchExpressions:
      - key: stage
        operator: In
        values:
        - test
        - review
      matchLabels:
        team: frontend

Создание пользователя

В Kubernetes есть две категории пользователей:

  • ServiceAccount’ы, учёт которых ведёт сам Kubernetes через API.
  • Остальные пользователи и группы, учёт которых ведёт не сам Kubernetes, а некоторый внешний софт, который настраивает администратор кластера, — существует множество механизмов аутентификации и, соответственно, множество способов заводить пользователей. В настоящий момент поддерживаются способы аутентификации:
    • Через модуль user-authn. Модуль поддерживает следующие внешние провайдеры и протоколы аутентификации: GitHub, GitLab, Atlassian Crowd, BitBucket Cloud, Crowd, LDAP, OIDC. Подробнее — в документации модуля user-authn.
    • С помощью сертификатов.

При выпуске сертификата для аутентификации нужно указать в нём имя (CN=<имя>), необходимое количество групп (O=<группа>) и подписать его с помощью корневого CA-кластера. Именно этим механизмом вы аутентифицируетесь в кластере, когда, например, используете kubectl на master-узле.

Создание ServiceAccount для сервера и предоставление ему доступа

Создание ServiceAccount с доступом к Kubernetes API может потребоваться, например, при настройке развёртывания приложений через CI-системы.

  1. Создайте ServiceAccount, например в пространстве имён d8-service-accounts:

    kubectl create -f - <<EOF
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: gitlab-runner-deploy
      namespace: d8-service-accounts
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: gitlab-runner-deploy-token
      namespace: d8-service-accounts
      annotations:
        kubernetes.io/service-account.name: gitlab-runner-deploy
    type: kubernetes.io/service-account-token
    EOF
    
  2. Дайте необходимые ServiceAccount-права (используя custom resource ClusterAuthorizationRule):

    kubectl create -f - <<EOF
    apiVersion: deckhouse.io/v1
    kind: ClusterAuthorizationRule
    metadata:
      name: gitlab-runner-deploy
    spec:
      subjects:
      - kind: ServiceAccount
        name: gitlab-runner-deploy
        namespace: d8-service-accounts
      accessLevel: SuperAdmin
      # Опция доступна только при включенном режиме enableMultiTenancy.
      allowAccessToSystemNamespaces: true      
    EOF
    

    Если в конфигурации Deckhouse включён режим мультитенантности (в параметре enableMultiTenancy), настройте доступные для ServiceAccount пространства имён (в параметре namespaceSelector).

  3. Определите значения переменных (они будут использоваться далее), выполнив следующие команды (подставьте свои значения):

    export CLUSTER_NAME=my-cluster
    export USER_NAME=gitlab-runner-deploy.my-cluster
    export CONTEXT_NAME=${CLUSTER_NAME}-${USER_NAME}
    export FILE_NAME=kube.config
    
  4. Сгенерируйте секцию cluster в файле конфигурации kubectl:

    Используйте один из следующих вариантов доступа к API-серверу кластера:

    • Если есть прямой доступ до API-сервера:
      1. Получите сертификат CA-кластера Kubernetes:

        kubectl get cm kube-root-ca.crt -o jsonpath='{ .data.ca\.crt }' > /tmp/ca.crt
        
      2. Сгенерируйте секцию cluster (используется IP-адрес API-сервера для доступа):

        kubectl config set-cluster $CLUSTER_NAME --embed-certs=true \
          --server=https://$(kubectl get ep kubernetes -o json | jq -rc '.subsets[0] | "\(.addresses[0].ip):\(.ports[0].port)"') \
          --certificate-authority=/tmp/ca.crt \
          --kubeconfig=$FILE_NAME
        
    • Если прямого доступа до API-сервера нет, используйте один следующих вариантов:
      • включите доступ к API-серверу через Ingress-контроллер (параметр publishAPI) и укажите адреса, с которых будут идти запросы (параметр whitelistSourceRanges);
      • укажите адреса, с которых будут идти запросы, в отдельном Ingress-контроллере (параметр acceptRequestsFrom).
    • Если используется непубличный CA:

      1. Получите сертификат CA из секрета с сертификатом, который используется для домена api.%s:

        kubectl -n d8-user-authn get secrets -o json \
          $(kubectl -n d8-user-authn get ing kubernetes-api -o jsonpath="{.spec.tls[0].secretName}") \
          | jq -rc '.data."ca.crt" // .data."tls.crt"' \
          | base64 -d > /tmp/ca.crt
        
      2. Сгенерируйте секцию cluster (используется внешний домен и CA для доступа):

        kubectl config set-cluster $CLUSTER_NAME --embed-certs=true \
          --server=https://$(kubectl -n d8-user-authn get ing kubernetes-api -ojson | jq '.spec.rules[].host' -r) \
          --certificate-authority=/tmp/ca.crt \
          --kubeconfig=$FILE_NAME
        
    • Если используется публичный CA. Сгенерируйте секцию cluster (используется внешний домен для доступа):

      kubectl config set-cluster $CLUSTER_NAME \
        --server=https://$(kubectl -n d8-user-authn get ing kubernetes-api -ojson | jq '.spec.rules[].host' -r) \
        --kubeconfig=$FILE_NAME
      
  5. Сгенерируйте секцию user с токеном из секрета ServiceAccount в файле конфигурации kubectl:

    kubectl config set-credentials $USER_NAME \
      --token=$(kubectl -n d8-service-accounts get secret gitlab-runner-deploy-token -o json |jq -r '.data["token"]' | base64 -d) \
      --kubeconfig=$FILE_NAME
    
  6. Сгенерируйте контекст в файле конфигурации kubectl:

    kubectl config set-context $CONTEXT_NAME \
      --cluster=$CLUSTER_NAME --user=$USER_NAME \
      --kubeconfig=$FILE_NAME
    
  7. Установите сгенерированный контекст как используемый по умолчанию в файле конфигурации kubectl:

    kubectl config use-context $CONTEXT_NAME --kubeconfig=$FILE_NAME
    

Создание пользователя с помощью клиентского сертификата

Этот способ рекомендуется использовать для системных нужд (аутентификация kubelet’ов, компонентов control plane и пр.). Если нужно создать «обычного» пользователя (например, с доступом через консоль, kubectl и т.д.), используйте генерацию kubeconfig.

При создании пользователя с помощью клиентского сертификата можно использовать OpenSSL или Kubernetes API (объект CertificateSigningRequest).

Сертификаты, выпущенные любым из этих способов, отозвать нельзя. В случае компрометации сертификата потребуется убрать все права этого пользователя (это может быть сложно, если пользователь добавлен в какие-нибудь группы: придётся также удалять все соответствующие группы).

Создание пользователя с помощью сертификата, выпущенного через OpenSSL

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

ca.crt и ca.keyне должны покидать master-узел: подписывайте CSR только на нём.

При подписании CSR вне master-узла есть риск компрометации корневого сертификата кластера.

Особенности этого способа:

  • Клиентский сертификат должен подписываться на master-узле, чтобы не допустить компрометации кластерного сертификата.
  • Необходим доступ к CA-ключу кластера (ca.key). Подписывать сертификаты может только администратор кластера.

Чтобы создать пользователя с помощью клиентского сертификата, выпущенного через OpenSSL, выполните следующие шаги:

  1. Получите корневой сертификат кластера (ca.crt и ca.key).
  2. Сгенерируйте ключ пользователя:

     openssl genrsa -out myuser.key 2048
    
  3. Создайте CSR, указав в нём имя пользователя myuser, который состоит в группах mygroup1 и mygroup2:

     openssl req -new -key myuser.key -out myuser.csr -subj "/CN=myuser/O=mygroup1/O=mygroup2"
    
  4. Загрузите созданный на предыдущем шаге CSR (в этом примере — myuser.csr) на master-узел и подпишите его корневым сертификатом кластера. Пример команды для подписания CSR на мастер-узле (убедитесь, что в команде указаны верные для вашего случая пути к myuser.csr, ca.crt и ca.key):

     openssl x509 -req -in myuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out myuser.crt -days 10
    

Полученный сертификат можно указывать в конфигурационном файле:

cat << EOF
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: $(cat /etc/kubernetes/pki/ca.crt | base64 -w0)
    server: https://<хост кластера>:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: myuser
  name: myuser@kubernetes
current-context: myuser@kubernetes
kind: Config
preferences: {}
users:
- name: myuser
  user:
    client-certificate-data: $(cat myuser.crt | base64 -w0)
    client-key-data: $(cat myuser.key | base64 -w0)
EOF

Создание пользователя с помощью сертификата, выпущенного через Kubernetes API

Это более безопасный способ, т.к. для подписания сертификата используется специальный API kubernetes.

Особенности этого способа:

  • Подписание сертификата через Kubernetes API: CSR отправляется на подпись через API и прямой доступ к ca.key не требуется.
  • Выпускать клиентские сертификаты может не только администратор кластера. Право на создание CSR и их подписание можно назначить определенному пользователю.

Чтобы создать пользователя с помощью клиентского сертификата, выпущенного через Kubernetes API, выполните следующие шаги:

  1. Сгенерируйте ключ пользователя:

     openssl genrsa -out myuser.key 2048
    
  2. Создайте CSR, указав в нём имя пользователя myuser, который состоит в группах mygroup1 и mygroup2:

     openssl req -new -key myuser.key -out myuser.csr -subj "/CN=myuser/O=mygroup1/O=mygroup2"
    
  3. Создайте манифест объекта CertificateSigningRequest и сохраните его в файл (в этом примере — csr.yaml):

    В поле request укажите содержимое CSR, созданного на предыдущем этапе, закодированное в Base64.

     apiVersion: certificates.k8s.io/v1
     kind: CertificateSigningRequest
     metadata:
     name: demo-client-cert
     spec:
       request: # CSR в Base64
       signerName: "kubernetes.io/kube-apiserver-client"
       expirationSeconds: 7200
       usages:
       - "digital signature"
       - "client auth"
    
  4. Примените манифест, чтобы создать запрос на подпись сертификата:

     kubectl apply -f csr.yaml
    
  5. Убедитесь, что сертификат подтвержден:

     kubectl get csr demo-client-cert
    

    Если сертификат подтвержден, в колонке CONDITION у него будет значение Approved,Issued. Пример вывода:

     NAME               AGE     SIGNERNAME                            REQUESTOR          REQUESTEDDURATION   CONDITION
     demo-client-cert   8m24s   kubernetes.io/kube-apiserver-client   kubernetes-admin   120m                Approved,Issued
    

    Если сертификат не подтвердился автоматически, подтвердите его:

     kubectl certificate approve demo-client-cert
    

    После этого убедитесь, что сертификат подтвержден.

  6. Извлеките закодированный сертификат из CSR с именем demo-client-cert, декодируйте его из Base64 и сохраните в файл (в этом примере — myuser.crt), созданный на шаге 2:

     kubectl get csr demo-client-cert -ojsonpath="{.status.certificate}" | base64 -d > myuser.crt
    

Полученный сертификат необходимо указать в конфигурационном файле:

cat << EOF
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: $(cat /etc/kubernetes/pki/ca.crt | base64 -w0)
    server: https://<хост кластера>:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: myuser
  name: myuser@kubernetes
current-context: myuser@kubernetes
kind: Config
preferences: {}
users:
- name: myuser
  user:
    client-certificate-data: $(cat myuser.crt | base64 -w0)
    client-key-data: $(cat myuser.key | base64 -w0)
EOF

Предоставление доступа созданному пользователю

Для предоставления доступа созданному пользователю создайте ClusterAuthorizationRule.

Пример ClusterAuthorizationRule:

apiVersion: deckhouse.io/v1
kind: ClusterAuthorizationRule
metadata:
  name: myuser
spec:
  subjects:
  - kind: User
    name: myuser
  accessLevel: PrivilegedUser
  portForwarding: true

Настройка kube-apiserver для работы в режиме multi-tenancy

Режим multi-tenancy, позволяющий ограничивать доступ к пространству имён, включается параметром enableMultiTenancy модуля.

Работа в режиме multi-tenancy требует включения плагина авторизации Webhook и выполнения настройки kube-apiserver. Все необходимые для работы режима multi-tenancy действия выполняются автоматически модулем control-plane-manager, никаких ручных действий не требуется.

Изменения манифеста kube-apiserver, которые произойдут после включения режима multi-tenancy:

  • исправление аргумента --authorization-mode. Перед методом RBAC добавится метод Webhook (например, --authorization-mode=Node,Webhook,RBAC);
  • добавление аргумента --authorization-webhook-config-file=/etc/kubernetes/authorization-webhook-config.yaml;
  • добавление volumeMounts:

    - name: authorization-webhook-config
      mountPath: /etc/kubernetes/authorization-webhook-config.yaml
      readOnly: true
    
  • добавление volumes:

    - name: authorization-webhook-config
      hostPath:
        path: /etc/kubernetes/authorization-webhook-config.yaml
        type: FileOrCreate
    

Как проверить, что у пользователя есть доступ?

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

  • resourceAttributes (как в RBAC) — к чему мы проверяем доступ;
  • user — имя пользователя;
  • groups — группы пользователя.

При совместном использовании с модулем user-authn группы и имя пользователя можно посмотреть в логах Dex — kubectl -n d8-user-authn logs -l app=dex (видны только при авторизации).

cat  <<EOF | 2>&1 kubectl  create --raw  /apis/authorization.k8s.io/v1/subjectaccessreviews -f - | jq .status
{
  "apiVersion": "authorization.k8s.io/v1",
  "kind": "SubjectAccessReview",
  "spec": {
    "resourceAttributes": {
      "namespace": "",
      "verb": "watch",
      "version": "v1",
      "resource": "pods"
    },
    "user": "system:kube-controller-manager",
    "groups": [
      "Admins"
    ]
  }
}
EOF

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

{
  "allowed": true,
  "reason": "RBAC: allowed by ClusterRoleBinding \"system:kube-controller-manager\" of ClusterRole \"system:kube-controller-manager\" to User \"system:kube-controller-manager\""
}

Если в кластере включён режим multi-tenancy, нужно выполнить ещё одну проверку, чтобы убедиться, что у пользователя есть доступ в пространство имён:

cat  <<EOF | 2>&1 kubectl --kubeconfig /etc/kubernetes/deckhouse/extra-files/webhook-config.yaml create --raw / -f - | jq .status
{
  "apiVersion": "authorization.k8s.io/v1",
  "kind": "SubjectAccessReview",
  "spec": {
    "resourceAttributes": {
      "namespace": "",
      "verb": "watch",
      "version": "v1",
      "resource": "pods"
    },
    "user": "system:kube-controller-manager",
    "groups": [
      "Admins"
    ]
  }
}
EOF
{
  "allowed": false
}

Сообщение allowed: false значит, что вебхук не блокирует запрос. В случае блокировки запроса вебхуком вы получите, например, следующее сообщение:

{
  "allowed": false,
  "denied": true,
  "reason": "making cluster scoped requests for namespaced resources are not allowed"
}

Настройка прав высокоуровневых ролей

Если требуется добавить прав для определённой высокоуровневой роли, достаточно создать ClusterRole с аннотацией user-authz.deckhouse.io/access-level: <AccessLevel>.

Пример:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    user-authz.deckhouse.io/access-level: Editor
  name: user-editor
rules:
- apiGroups:
  - kuma.io
  resources:
  - trafficroutes
  - trafficroutes/finalizers
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - flagger.app
  resources:
  - canaries
  - canaries/status
  - metrictemplates
  - metrictemplates/status
  - alertproviders
  - alertproviders/status
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete