Access Control
В данном практическом занятии рассмотрим процесс аутентификации с помощью сертификата и разделение прав с RBAC.
Authn
Для того, чтобы получить сертификат, которому будет доверять api kubernetes, необходимо сгенерировать запрос на подпись - [Certificate Signing Request(csr)] и отправить на подтверждение в api. В данном примере для генерации csr и ключа я воспользуюсь утилитой openssl, в Linux и MacOS данная утилита обычно есть по умолчанию, для Windows список источников для загрузки есть тут.
Generate csr and key
Генерацию ключа и csr можно произвести одной командой:
$ openssl req -new -newkey rsa:2048 -nodes -subj '/CN=Alex' -keyout key.pem -out csr.pem
Generating a 2048 bit RSA private key
.................................................+++++
...............................................+++++
writing new private key to 'key.pem'
-----
В данной команде используются опции:
req -new- создание нового csr-newkey rsa:2048- генерация нового RSA ключа длиной 2048 бит-nodes- не использовать пароль для ключа-subj '/CN=<name>'- указание Subject для сертификата, гдеname- ваше имя-keyout <path>- путь и имя для сохранения ключа-out <path>- путь и имя для сохранения csr
После выполнения данной команды в директории, в которой вы находитесь, создадутся файлы
key.pem и csr.pem.
kind: CertificateSigningRequest
Для возможности подписать наш csr внутрикластерным сертификатом удостоверяющего центра необходимо создать объект CertificateSigningRequest.
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: myuser
spec:
request: $(base64 -w0 < csr.pem)
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400 # one day
usages:
- client auth
EOF
В данном ресурсе указаны поля:
request- содержимое файлаcsr.pemв base64 форматеsignerName- кем будет подписан сертификатexpirationSeconds- время до истечения срока жизни сертификатаusage- опции использования, в нашем случаеclient auth
После создания ресурса необходимо подтвердить выписывание сертификата для данного csr:
$ kubectl certificate approve myuser
certificatesigningrequest.certificates.k8s.io/myuser approved
Когда ручное подтверждение было выполнено контроллер выпишет сертификат и добавить его в поле
.status.certificate в base64 формате нашего ресурса CertificateSigningRequest. Сохраним его в файл
crt.pem декодировав из base64:
$ kubectl get csr myuser -o jsonpath='{.status.certificate}' | base64 -d > crt.pem
kubectl credentials
Теперь у нас есть необходимые файлы для аутентификации в кластере - ключ key.pem и подписанный
сертификат crt.pem, осталось внести изменения в конфигурацию kubectl, чтобы воспользоваться ими.
Создаем пользовательскую конфигурацию myuser указав сертификат и ключ:
$ kubectl config set-credentials myuser --client-certificate crt.pem --client-key key.pem --embed-certs
User "myuser" set.
Модифицируем текущий контекст, указав созданного пользователя, а также можем убедиться, что в конфигурации применились наши изменения:
$ kubectl config set-context --current --user myuser
Context "kind-kind" modified.
$ kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.56.2:6443
name: kind-kind
contexts:
- context:
cluster: kind-kind
user: myuser
name: kind-kind
current-context: kind-kind
kind: Config
preferences: {}
users:
- name: kind-kind
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
- name: myuser
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
Как видно в конфигурации добавился новый пользователь - myuser, а также он применился к текущему
контексту в блоке contexts.
Можно попробовать сделать любой запрос в кластер:
$ kubectl get pods
Error from server (Forbidden): pods is forbidden: User "Alex" cannot list resource "pods" in API group "" in the namespace "default"
Так как наш новый пользователь не имеет никаких прав, то мы получаем данное сообщение.
RBAC Authz
Для выдачи прав нашему пользователю воспользуемся режимом авторизации Role-based access control (RBAC).
Role
Набор прав в неймспейсе можно задать с помощью ресурса Role:
$ kubectl config set-context --current --user kind-kind # вернем пользователя по-умолчанию
Context "kind-kind" modified.
$ kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
EOF
Как видно из правил, данная роль позволяет просматривать поды в неймспейсе default.
Cluster Role
Набор прав на уровне всего кластера можно задать с помощью ресурса ClusterRole:
$ kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cm-reader
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "watch", "list"]
EOF
Данная роль создается на уровне кластера(cluster-wide) и дает права на чтение ресурса configmaps.
RoleBinding
Чтобы присвоить права нашему пользователю в конкретном неймспейсе необходимо создать объект
RoleBinding:
$ kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: Alex
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
EOF
Данный объект связывает созданную ранее роль pod-reader с нашим пользователем. Теперь можем
переключиться на него и проверить:
$ kubectl config set-context --current --user myuser
Context "kind-kind" modified.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
pv-pod-sc 1/1 Running 3 (3h14m ago) 15d
Как видно теперь пользователь обладает правами указанными в объекте Role pod-reader.
RoleBinding with Cluster Role
В объекте RoleBinding также можно ссылаться на ClusterRole, при этом нет необходимости создавать
данную роль в каждом неймспейсе, таким образом выдавая одни и те же права в различных неймспейсах.
$ kubectl config set-context --current --user kind-kind
$ kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-cm
namespace: kube-system
subjects:
- kind: User
name: Alex
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cm-reader
apiGroup: rbac.authorization.k8s.io
EOF
$ kubectl config set-context --current --user myuser
$ kubectl get cm
Error from server (Forbidden): configmaps is forbidden: User "Alex" cannot list resource "configmaps" in API group "" in the namespace "default"
$ kubectl get cm -n kube-system
NAME DATA AGE
coredns 1 29d
extension-apiserver-authentication 6 29d
kube-proxy 2 29d
kube-root-ca.crt 1 29d
kubeadm-config 1 29d
kubelet-config 1 29d
Как видно пользователь получил права в конкретном неймспейсе kube-system.
ClusterRoleBinding
Для получения прав во всем кластере, а не только в конкретных неймспейсах, необходимо воспользоваться
ClusterRoleBinding. Он позволяет связать пользователя с ClusterRole и выдать права на все
неймспейсы, либо права для cluster-wide объектов(например ноды).
$ kubectl config set-context --current --user kind-kind
$ kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-cm
subjects:
- kind: User
name: Alex
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cm-reader
apiGroup: rbac.authorization.k8s.io
EOF
$ kubectl config set-context --current --user myuser
Context "kind-kind" modified.
$ kubectl get cm -A
NAMESPACE NAME DATA AGE
default kube-root-ca.crt 1 29d
ingress-nginx ingress-nginx-controller 1 29d
ingress-nginx kube-root-ca.crt 1 29d
kube-node-lease kube-root-ca.crt 1 29d
kube-public cluster-info 1 29d
kube-public kube-root-ca.crt 1 29d
kube-system coredns 1 29d
kube-system extension-apiserver-authentication 6 29d
kube-system kube-proxy 2 29d
kube-system kube-root-ca.crt 1 29d
kube-system kubeadm-config 1 29d
kube-system kubelet-config 1 29d
local-path-storage kube-root-ca.crt 1 29d
local-path-storage local-path-config 4 29d
Как видно пользователь получил возможность чтения configmaps во всем кластере.