# kubectl whoami и проверка прав сервис-аккаунта

Индекс LLMS: [llms.txt](/llms.txt)

---

При деплое приложения в Kubernetes самая частая ошибка — сервис-аккаунт не может сделать то, что должен. Permission denied при создании секрета, запрет на list pods, отказ на update. kubectl whoami и kubectl auth can-i позволяют быстро понять, кто именно и что именно не может.

## Утилита kubectl whoami

> [!NOTE]
> kubectl whoami — это не встроенная команда kubectl. Это плагин из krew или отдельный бинарь. Установка: `kubectl krew install whoami` или скачать с GitHub.

После установки команда показывает текущий контекст и ассоциированный сервис-аккаунт:

```bash
kubectl whoami
```

Вывод:

```
system:serviceaccount:default:myapp
```

Без плагина ту же информацию даёт:

```bash
kubectl auth can-i --list
```

В начале вывода видно `User: system:serviceaccount:default:myapp` — это и есть whoami.

## kubectl auth can-i: проверка прав произвольного субъекта

Встроенная команда `kubectl auth can-i` проверяет права без подключения от имени проверяемого субъекта. Синтаксис:

```bash
kubectl auth can-i <verb> <resource> --as=<subject>
```

Формат `--as` для сервис-аккаунта:

```bash
# В пределах namespace
kubectl auth can-i list pods \
  --as=system:serviceaccount:default:myapp

# Кросс-неймспейс
kubectl auth can-i list pods \
  --as=system:serviceaccount:production:myapp \
  -n production
```

Ответы: `yes` или `no`.

Чтобы проверить весь набор прав SA:

```bash
kubectl auth can-i --list --as=system:serviceaccount:default:myapp
```

> [!TIP]
> Комбинация `--as` с `--list` — быстрый аудит прав сервис-аккаунта. Вывод содержит таблицу с ресурсами, версиями и списком разрешённых действий.

### Флаги kubectl auth can-i

| Флаг | Назначение |
|------|------------|
| `--as <subject>` | Субъект для проверки |
| `-n <namespace>` | Namespace субъекта (для SA) |
| `--list` | Все права субъекта |
| `--quiet` / `-q` | Только exit code, без вывода |
| `--no-headers` | Без заголовков таблицы |

Exit code: 0 при `yes`, 1 при `no`. Это удобно для скриптов:

```bash
kubectl auth can-i delete secrets --as=system:serviceaccount:default:myapp
if [ $? -eq 0 ]; then
  echo "SA может удалять секреты — проверь политику"
fi
```

## Привязка ClusterRole к сервис-аккаунту: RoleBinding vs ClusterRoleBinding

Сервис-аккаунт привязывается к роли через два ресурса. Разница — в области действия.

**RoleBinding** — привязывает Role или ClusterRole к SA в рамках одного namespace:

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: myapp-pod-reader
  namespace: default
subjects:
  - kind: ServiceAccount
    name: myapp
    namespace: default
roleRef:
  kind: ClusterRole        # ссылка на ClusterRole
  name: pod-reader        # имя ClusterRole
  apiGroup: rbac.authorization.k8s.io
```

> [!NOTE]
> RoleBinding может ссылаться и на Role, и на ClusterRole. В первом случае права ограничены неймспейсом, во втором — работают в пределах неймспейса RoleBinding, но наследуют все правила ClusterRole.

**ClusterRoleBinding** — привязывает ClusterRole ко всему кластеру:

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: myapp-cluster-reader
subjects:
  - kind: ServiceAccount
    name: myapp
    namespace: default
roleRef:
  kind: ClusterRole
  name: cluster-reader
  apiGroup: rbac.authorization.k8s.io
```

| Сценарий | Ресурс |
|----------|--------|
| SA нужны права только в одном namespace | RoleBinding → ClusterRole |
| SA нужны права cluster-wide | ClusterRoleBinding |
| Общая роль для разных SA в разных неймспейсах | ClusterRoleBinding с несколькими subjects |

## Subject в CSR: как читать и проверять

CSR (Certificate Signing Request) содержит поле `spec.username` и `spec.groups`. Для SA это выглядит так:

```bash
kubectl get csr <csr-name> -o jsonpath='{.spec}' | jq .
```

Вывод:

```json
{
  "request": "base64-encoded-certificate-request",
  "username": "system:serviceaccount:default:myapp",
  "groups": ["system:serviceaccount", "system:serviceaccounts", "system:serviceaccounts:default"],
  "uid": "...",
  "extra": {
    "authentication.kubernetes.io/credential-id": ["..."],
    "authentication.kubernetes.io/node-name": ["..."]
  }
}
```

Три компонента в username через двоеточие: `system:serviceaccount:<namespace>:<name>`.

Для проверки прав конкретного SA из CSR:

```bash
# Извлечь SA из CSR
SUBJECT=$(kubectl get csr <csr-name> -o jsonpath='{.spec.username}')
kubectl auth can-i list pods --as="$SUBJECT"
```

> [!WARNING]
> CSR создаётся kubelet при подключении node или через ServiceAccount admission. Если SA работает через TokenRequest API (современный способ), CSR не генерируется — токен выдаётся напрямую.

## Быстрая проверка в CI/CD

В пайплайне нужно убедиться, что деплой-сервис-аккаунт имеет достаточные права до запуска манифестов:

```bash
#!/bin/bash
SA="system:serviceaccount:ci-runner:deployer"
RESOURCES=("pods" "services" "configmaps" "secrets")

for RES in "${RESOURCES[@]}"; do
  kubectl auth can-i create "$RES" --as="$SA" -n "$NAMESPACE" || {
    echo "ERROR: SA не может создавать $RES"
    exit 1
  }
done

echo "Права подтверждены"
kubectl auth can-i get pods --as="$SA" -n "$NAMESPACE"
```

> [!TIP]
> Добавьте эту проверку после `kubectl apply` или `helm template` — ранний exit дешевле, чем упавший pod с ImagePullBackOff из-за отсутствия imagePullSecrets.

Полезный вывод для диагностики в логах CI:

```bash
kubectl auth can-i --list --as="system:serviceaccount:default:myapp" --no-headers
```

Строки без заголовков легко заgrepать на предмет подозрительных wildcards типа `*/*` или `*/delete`.
