# Безопасность

**Авторизация и аутентификация**

По умолчанию аутентификация на основе сертификата, но поддерживаются внешние источники.

Аутентификация на основе сертификата.

Авторизация RBAC (пользователь - действие - ресурс). По умолчанию запрещено все что не разрешено. Роли определяют правила, RoleBindings определяют принадлежность пользователей к ролям. Пример настройки ролей:

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: shield
  name: read-deployments
rules:
- verbs: ["get", "watch", "list"] <<==== Allowed actions
  apiGroups: ["apps"] <<==== on resources
  resources: ["deployments"] <<==== of this type
```

Пример RoleBinding:

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-deployments
  namespace: shield
subjects:
- kind: User
  name: sky <<==== Name of the authenticated user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: read-deployments <<==== This is the Role to bind to the user
  apiGroup: rbac.authorization.k8s.io
```

Свойства правил роли:

verbs \["get", "watch", "list", "create", "update", "patch", "delete"\]

ApiGroups (в пределах namespace):

<table border="1" id="bkmrk-apigroup-%D0%A0%D0%B5%D1%81%D1%83%D1%80%D1%81-%22%22-p" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 50%;"></col><col style="width: 50%;"></col></colgroup><thead><tr><td class="align-center">apiGroup</td><td class="align-center">Ресурс</td></tr></thead><tbody><tr><td>""</td><td>pods, secrets</td></tr><tr><td>“storage.k8s.io”</td><td>storageclass</td></tr><tr><td>“apps”</td><td>deployments</td></tr></tbody></table>

Полный список API ресурсов:

```
kubectl api-resources --sort-by name -o wide
```

Можно использовать звездочку.

Все роли используются только в контексте namespace!

**Кластерные роли и привязки**

ClusterRoleBindings используется для создания шаблонов ролей и привязки их к конкретным ролям.

```
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole <<==== Cluster-scoped role
metadata:
  name: read-deployments
rules:
- verbs: ["get", "watch", "list"]
  apiGroups: ["apps"]
  resources: ["deployments"]

```

**Пользователи**

[Интересная статья](https://habr.com/ru/companies/flant/articles/470503/) [Еще одна, тоже стоит почитать](https://devopstales.github.io/kubernetes/k8s-user-accounts/)

Обычных пользователей нельзя добавить через вызовы API. Возможные варианты:

- Базовая аутентификация *(basic auth)*: 
    - передача конфигурации API-серверу со следующим (или похожим) содержимым: password, username, uid, group;
- Клиентский сертификат X.509: 
    - создание секретного ключа пользователя и запроса на подпись сертификата;
    - заверение его в центре сертификации (Kubernetes CA) для получения сертификата пользователя;
- Bearer-токены (JSON Web Tokens, JWT): 
    - OpenID Connect;
    - слой аутентификации поверх OAuth 2.0;
    - веб-хуки *(webhooks)*.

Структура файла ~/.kube/config

- Clusters - список кластеров. Сертификат кластера, адрес и внутреннее имя
- Users - пользователи. Внутреннее имя, сертификат и ключ
- Contexts - объединение пользователя и кластера. Внутреннее имя, внутреннее имя кластера и внутреннее имя пользователя
- Current-context - имя текущего контекста

---

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

---

**Пример создания пользователя с авторизацией через X.509 сертификат.**

Создаем директорию хранения информации о пользователях и генерируем в нее ключ

```
mkdir -p users/sergey/.certs
openssl genrsa -out ~/users/sergey/.certs/sergey.key 2048
```

Генерируем запрос на сертификат

```
openssl req -new -key ~/users/sergey/.certs/sergey.key -out ~/users/sergey/.certs/sergey.csr -subj "/CN=sergey/O=testgroup"
```

Обработка запроса на сертификат

```
openssl x509 -req -in ~/users/sergey/.certs/sergey.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ~/users/sergey/.certs/sergey.crt -days 500
```

В некоторых ресурсах говорится, что команда kubectl config set-credentials ... создает пользователя в кластере Kubernetes. Но это не так, команда kubectl config ... создает/модифицирует файл .kube/config, поэтому нужно быть осторожным и не побить свой файл. А Kubernetes авторизует всех пользователей, чей сертификат подписан его центром сертификации.

Добавляем пользователя sergey

```
kubectl config set-credentials sergey \
--client-certificate=/root/users/sergey/.certs/sergey.crt \
--client-key=/root/users/sergey/.certs/sergey.key \
--embed-certs=true
```

Если нужно - создали бы настройки кластера, но у нас есть, поэтому создаем контекст с существующим кластером. Namespace, если нужно, указывается в настройках контекста.

```
kubectl config set-context sergey-context --cluster=kubernetes --user=sergey --namespace=sergey-ns
```

Теперь осталось пользователю определить права.

Например определим роль sergey-ns-full с полным доступом к namespace sergey-ns

```
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: sergey-ns-full
  namespace: sergey-ns
rules:
  - apiGroups: [ "*" ]
    resources: [ "*" ]
    verbs: [ "*" ]
```

Сейчас вместо привязки пользователя, привяжем группу к роли.

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: testgroup-rolebinding  # Название RoleBinding
  namespace: sergey-ns         # Namespace, где применяется
subjects:
- kind: Group                 # Тип субъекта — группа
  name: testgroup             # Название группы
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role                  # Тип привязываемой роли (Role или ClusterRole)
  name: sergey-ns-full        # Название роли
  apiGroup: rbac.authorization.k8s.io
```

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

```
kubectl config use-context sergey-context
```

Создаем простой под

```
kind: Pod
apiVersion: v1
metadata:
  name: hello-pod
  labels:
    zone: prod
    version: v1
spec:
  containers:
  - name: hello-ctr
    image: nigelpoulton/k8sbook:1.0
    ports:
    - containerPort: 8080
    resources:
      limits:
        memory: 128Mi
        cpu: 0.5
```

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

```
kubectl get pods
```

Удалось!

**Основные команды управления пользователями**

<span style="color: rgb(224, 62, 45);">Если при создании ... указать флаг --embed-certs=true то тогда вместо путей к файлам сертификатов, в файл настройки будут встроено содержание сертификатов в Base64.</span>

<table border="1" id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5-ki-1" style="width: 100%; height: 524.109px;"><thead><tr style="height: 29.7969px;"><td class="align-center" style="width: 33.4923%; height: 29.7969px;">Команда</td><td class="align-center" style="width: 15.9789%; height: 29.7969px;">**Доп. параметры**  
</td><td class="align-center" style="width: 50.5288%; height: 29.7969px;">Описание</td></tr></thead><tbody><tr style="height: 63.3906px;"><td style="width: 33.4923%; height: 63.3906px;">kubectl get clusterroles.rbac.authorization.k8s.io --all-namespaces</td><td style="width: 15.9789%; height: 63.3906px;">  
</td><td style="width: 50.5288%; height: 63.3906px;">Список пользователей</td></tr><tr style="height: 29.7969px;"><td style="width: 33.4923%; height: 29.7969px;">kubectl config view</td><td style="width: 15.9789%; height: 29.7969px;">  
</td><td style="width: 50.5288%; height: 29.7969px;">Показать текущую конфигурацию (.kube/config)</td></tr><tr style="height: 29.7969px;"><td style="width: 33.4923%; height: 29.7969px;">kubectl config current-context</td><td style="width: 15.9789%; height: 29.7969px;">  
</td><td style="width: 50.5288%; height: 29.7969px;">Показать текущий активный контекст</td></tr><tr style="height: 29.7969px;"><td style="width: 33.4923%; height: 29.7969px;">kubectl config get-contexts</td><td style="width: 15.9789%; height: 29.7969px;">  
</td><td style="width: 50.5288%; height: 29.7969px;">Список всех контекстов</td></tr><tr style="height: 29.7969px;"><td style="width: 33.4923%; height: 29.7969px;">kubectl config use-context cont\_name</td><td style="width: 15.9789%; height: 29.7969px;">  
</td><td style="width: 50.5288%; height: 29.7969px;">Переключиться на контекст cont\_name</td></tr><tr style="height: 99.359px;"><td style="width: 33.4923%; height: 99.359px;">kubectl config set-cluster clast\_name</td><td style="width: 15.9789%; height: 99.359px;">  
</td><td style="width: 50.5288%; height: 99.359px;">Добавить/изменить кластер ```
kubectl config set-cluster my-new-cluster \
  --server=https://10.0.0.1:6443 \
  --certificate-authority=./ca.crt
```

</td></tr><tr style="height: 29.7969px;"><td style="width: 33.4923%; height: 29.7969px;">kubectl config set-credentials</td><td style="width: 15.9789%; height: 29.7969px;">  
</td><td style="width: 50.5288%; height: 29.7969px;">Добавить/изменить учетные данные пользователя ```
kubectl config set-credentials sergey \
--client-certificate=/root/users/sergey/.certs/sergey.crt \
--client-key=/root/users/sergey/.certs/sergey.key \
--embed-certs=true
```

</td></tr><tr style="height: 63.3906px;"><td style="width: 33.4923%; height: 63.3906px;">kubectl config set-context cont\_name</td><td style="width: 15.9789%; height: 63.3906px;">--cluster=dev-cluster \\  
--user=dev-user \\  
--namespace=dev-ns</td><td style="width: 50.5288%; height: 63.3906px;">Создать/изменить контекст</td></tr><tr style="height: 29.7969px;"><td style="width: 33.4923%; height: 29.7969px;">kubectl config delete-context</td><td style="width: 15.9789%; height: 29.7969px;">  
</td><td style="width: 50.5288%; height: 29.7969px;">Удалить контекст</td></tr><tr style="height: 29.7969px;"><td style="width: 33.4923%; height: 29.7969px;">kubectl config delete-cluster </td><td style="width: 15.9789%; height: 29.7969px;">  
</td><td style="width: 50.5288%; height: 29.7969px;">Удалить кластер</td></tr><tr style="height: 29.7969px;"><td style="width: 33.4923%; height: 29.7969px;">kubectl config delete-user user\_name</td><td style="width: 15.9789%; height: 29.7969px;">  
</td><td style="width: 50.5288%; height: 29.7969px;">Удалить пользователя</td></tr><tr style="height: 29.7969px;"><td style="width: 33.4923%; height: 29.7969px;">kubectl config rename-context </td><td style="width: 15.9789%; height: 29.7969px;">  
</td><td style="width: 50.5288%; height: 29.7969px;">Переименовать контекст</td></tr></tbody></table>

**Безопасность, общая теория**

[Инструменты](https://habr.com/ru/companies/flant/articles/465141/)

**Запрет передачи ключей SA**

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

```
apiVersion: v1
kind: Pod
metadata:
  name: service-account-example-pod
spec:
  serviceAccountName: some-service-account
  automountServiceAccountToken: false <<==== This line
<Snip>
```

Также можно передавать временные ключи, но это потом.

**Контроль целостности ресурсов**

- Ограничьте доступ к серверам, на которых запущены компоненты Kubernetes, особенно к компонентам control plane
- Ограничьте доступ к репозиториям, хранящим конфигурационные файлы Kubernetes
- Передача файлов и управление только через SSH
- Проверка контрольной суммы после скачивания
- Ограничьте доступ к регистру образов и связанным хранилищам

**Файловая система пода в read-only режим**

```
apiVersion: v1
kind: Pod
metadata:
  name: readonly-test
spec:
  securityContext:
    readOnlyRootFilesystem: true <<==== R/O root filesystem
    allowedHostPaths: <<==== Make anything below
      - pathPrefix: "/test" <<==== this mount point
        readOnly: true <<==== read-only (R/O)
<Snip>
```

**Лог действий на кластере и связанной инфраструктуре**

**Защита данных кластера**

Cluster store (обычно etcd) хранит все данные. Необходимо ограничить и контролировать доступ к серверам, на которых работает Cluster store.

**DoS**

Подвергается API сервер. Должно быть минимум 3 Control plane сервера и 3 worker ноды. Изоляция etcd на сетевом уровне. Ограничения ресурсов для подов и количества подов.

```
apiVersion: v1
kind: ResourceQuota
metadata:
  name: pod-quota
  namespace: skippy
spec:
  hard:
    pods: "100"
```

Доп. опция podPidsLimit ограничивает количество процессов одним подом. Также можно ограничить кол-во подов на одной ноде.

По умолчанию etcd устанавливается на сервер с control plane. На production кластере нужно разделять.

Запретить сетевое взаимодействие между подами и внешние взаимодействия (где это не нужно) при помощи сетевых политик Kubernetes.

**Защита подов и контейнеров**

Запрет запуска процессов от root

```
apiVersion: v1
kind: Pod
metadata:
  name: demo
spec:
  securityContext: <<==== Applies to all containers in this Pod
    runAsUser: 1000 <<==== Non-root user
  containers:
    - name: demo
      image: example.io/simple:1.0

```

Это запускает все контейнеры от одного непривилегированного пользователя, но позволяет контейнерам использовать общие ресурсы. При запуске нескольких подов, будет аналогично. Поэтому лучше дополнительно настраивать пользователей контейнера:

```
apiVersion: v1
kind: Pod
metadata:
  name: demo
spec:
  securityContext: <<==== Applies to all containers in this Pod
    runAsUser: 1000 <<==== Non-root user
  containers:
    - name: demo
      image: example.io/simple:1.0
      securityContext:
        runAsUser: 2000 <<==== Overrides the Pod-level setting
```

Рутовые права складываются примерно из 30 capabilities. Простой способ - в тестовом окружении ограничить все и по логам добавлять нужные. Естественно финальное тестирование должно быть максимально всеобъемлющим. Пример разрешений:

```
apiVersion: v1
kind: Pod
metadata:
  name: capability-test
spec:
  containers:
    - name: demo
      image: example.io/simple:1.0
      securityContext:
        capabilities:
          add: ["NET_ADMIN", "CHOWN"]

```

Фильтрация системных вызовов.

Похоже на capabilities, но фильтрует системные вызовы. Способы поиска минимальных разрешений: разрешить все + логгирование, запрет + постепенное разрешение.

Также есть Pod Security Standarts (PSS) и Pod Security Admission (PSA). PSA применяют PSS при старте пода.

**Основные команды**

<table border="1" id="bkmrk-%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5-%C2%A0k" style="width: 100%; height: 119.188px;"><thead><tr style="height: 29.7969px;"><td class="align-center" style="width: 45.1534%; height: 29.7969px;">Параметр</td><td class="align-center" style="width: 54.8466%; height: 29.7969px;">Описание</td></tr></thead><tbody><tr style="height: 29.7969px;"><td style="width: 45.1534%; height: 29.7969px;"> kubectl describe clusterrole role\_name</td><td style="width: 54.8466%; height: 29.7969px;">Описание роли</td></tr><tr style="height: 29.7969px;"><td style="width: 45.1534%; height: 29.7969px;">kubectl get clusterrolebindings | grep role\_name</td><td style="width: 54.8466%; height: 29.7969px;">Список пользователей с такой ролью</td></tr><tr style="height: 29.7969px;"><td style="width: 45.1534%; height: 29.7969px;">kubectl describe clusterrolebindings role\_name</td><td style="width: 54.8466%; height: 29.7969px;">Информация по сопоставлению</td></tr><tr><td style="width: 45.1534%;">Аналогично для ролей (clusterrolebindings -&gt; rolebindings)</td><td style="width: 54.8466%;">  
</td></tr></tbody></table>