# mTLS Autocert

<https://habr.com/ru/companies/ruvds/articles/696126/>

![](/files/RvFN37tiAPP6XWIDPGUC)

При публичном веб-браузинге TLS-аутентификация происходит лишь в одном направлении — свои сертификаты показывает только сервер. Передача публичных веб-страниц без аутентификации клиента вполне логична, но не в случае Kubernetes. Если другие субъекты будут получать доступ к уязвимой информации в сервисах/кластерах, то будет логично валидировать личность и таких субъектов тоже.

Повсеместное использование TLS — одна из [рекомендаций](https://kubernetes.io/blog/2018/07/18/11-ways-not-to-get-hacked/#1-tls-everywhere) разработчиков Kubernetes по повышению безопасности и надёжности кластеров.

*«TLS должен быть включён у каждого поддерживающего его компонента, чтобы предотвратить сниффинг трафика, проверять идентификацию сервера и (в случае взаимного TLS) проверять идентификацию клиента».*

В случае доступа клиентов к уязвимым данным в сервисах/кластерах логично валидировать и личность таких клиентов. Это называется взаимным TLS (mutual TLS, mTLS).

## Что такое mutual TLS?

Mutual TLS (mTLS), также называемый двусторонней аутентификацией — это процесс обеспечения безопасности, при котором субъекты перед выполнением обмена данными аутентифицируют друг друга. Это значит, что для установки соединения клиент с сервером должны обменяться своими сертификатами, верифицировать их и использовать. Аутентификация при помощи mTLS — наилучший способ повышения безопасности Kubernetes, он гарантирует, что только аутентифицированные субъекты смогут обмениваться данными с вашими кластерами.

В отличие от VPN и SDN, реализовать mTLS очень просто. Есть только одно препятствие: вам нужны сертификаты, выпущенные вашим собственным сертифицирующим органом (certificate authority, CA). Создание и эксплуатация CA, выпуск сертификатов и их обновление до истечения срока действия может быть сложной задачей. Упрощают весь этот процесс Autocert и Smallstep Certificate Manager.

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

### ▍ Autocert

[Autocert](https://github.com/smallstep/autocert) — это [admission webhook](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#admission-webhooks), выполняющий перехват и патчинг запросов на создание pod при помощи [YAML](https://github.com/smallstep/autocert/blob/master/install/02-autocert.yaml#L26-L44) для инъецирования [init container](https://github.com/smallstep/autocert/blob/master/bootstrapper) и [sidecar](https://github.com/smallstep/autocert/blob/master/renewer), занимающихся получением и обновлением сертификатов. Иными словами, это опенсорсный аддон Kubernetes, автоматически инъецирующий TLS-сертификаты непосредственно в контейнеры.

Autocert полезен, когда вы не доверяете складу данных, в котором хранятся [Kubernetes TLS Secrets](https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets) (часто это `etcd`). В зависимости от конфигурации склада данных, данные могут быть зашифрованы или не зашифрованы. При помощи Autocert сертификаты инъецируются непосредственно в контейнеры, а приватные ключи никогда не передаются по сети и не сохраняются в `etcd`.

Для получения сертификата достаточно лишь сообщить autocert имя рабочей нагрузки при помощи аннотации pod `autocert.step.sm/name`. Autocert выпустит сертификат для pod, сделав его доступным в `var/run/autocert.step.sm`, и будет его обновлять. Однако для выпуска сертификатов требуется certificate authority. И здесь на помощь приходит Smallstep Certificate Manager. В данном руководстве мы расскажем, как сконфигурировать autocert для использования Certificate Manager в качестве вышестоящего CA.

### ▍ Smallstep Certificate Manager

Smallstep Certificate Manager — это расширяемая платформа для инфраструктуры публичных ключей (public key infrastructure, PKI) DevSecOps, обеспечивающая работу certificate authority. Также он предоставляет функции уведомлений и алертов об истечении срока работы, дэшборда управления, Active Revocation и другие возможности. При помощи Smallstep Certificate Manager вы сможете с лёгкостью выпускать приватные сертификаты TLS и [SSH](https://smallstep.com/blog/ssh-vs-x509-certificates/) для всех рабочих нагрузок/разработчиков.

Строго говоря, Kubernetes не *имеет в комплекте* CA. Он имеет точки интеграции, позволяющие использовать любой CA. Поэтому мы будем использовать Smallstep Certificate Manager, поскольку его создают и поддерживают разработчики Autocert.

## Перед началом работы

Прежде чем переходить к главному, вам нужно:

1. [Создать бесплатный аккаунт](https://smallstep.com/signup?product=cm) Smallstep Certificate Manager
2. [Создать Certificate Authority](https://smallstep.com/docs/certificate-manager/getting-started#step-2-create-an-authority) в Certificate Manager, который будет использоваться в качестве вышестоящего CA
3. [Установить step CLI](https://smallstep.com/docs/step-cli/installation). Для взаимодействия с Certificate Manager через терминал вам понадобится команда CLI `step` на локальной машине. Она используется для многих стандартных криптоопераций. Список всех команд можно посмотреть [здесь](https://smallstep.com/docs/step-cli/reference).

## Настройка Autocert

### ▍ 1. Bootstrap с выбранным CA

Бутстреппинг с выбранным Authority конфигурирует вашу рабочую станцию так, чтобы она доверяла корневому сертификату CA. Выполните следующую команду:

```
step ca bootstrap --ca-url [your CA URL] \\
    --fingerprint [your CA fingerprint] \\
    --install
```

### ▍ 2. Добавление Provisioner

Provisioner — это методы, используемые для верификации подлинности запросов на подписание сертификатов и свидетельствующие об идентификации сервиса или человека, выполняющего запрос. Autocert требует JWK provisioner. Показанная ниже команда создаёт стандартный JWK provisioner с именем `autocert`:

```
step ca provisioner add autocert --create
```

Необходимо будет указать пароль для шифрования приватного ключа provisioner.

### ▍ 3. Создание ConfigMaps и секрета для Autocert

В Kubernetes создайте пространство имён для autocert:

```
kubectl create ns step
```

**Результат выполнения команды**:

```
namespace/step created
```

Используйте тот же пароль, который вы ввели при создании provisioner, чтобы создать секрет.

```
kubectl -n step create secret generic autocert-password --from-file=password=autocert-password.txt
```

**Результат выполнения команды**:

```
secret/autocert-password created
```

Теперь создайте `ConfigMap`, содержащую папку конфигурации:

```
kubectl -n step create configmap config --from-file $(step path)/config`
```

**Результат выполнения команды**:

```
configmap/config created
```

Сделаем то же самое для папки `certs`, содержащей корневой сертификат нашего CA:

```
kubectl -n step create configmap certs --from-file $(step path)/certs
```

**Результат выполнения команды**:

```
configmap/certs created
```

### ▍ 4. Развёртывание Autocert

Скачайте YAML-конфигурацию Autocert:

```
curl -O <https://raw.githubusercontent.com/smallstep/autocert/master/install/02-autocert.yaml>
```

Измените `caUrl` в ConfigMap `autocert-config` только что скачанного файла .yaml. Замените значение `https://ca.step.svc.cluster.local` на URL вашего Certificate Manager authority, например, `https://autocert.areed.ca.smallstep.com`.

Затем выполните следующую команду:

```
kubectl apply -f <https://raw.githubusercontent.com/smallstep/autocert/master/install/03-rbac.yaml>
```

**Результат выполнения команды**:

```
clusterrole.rbac.authorization.k8s.io/autocert-controller created
clusterrolebinding.rbac.authorization.k8s.io/autocert-controller created
```

Теперь давайте развернём Autocert. Выполните следующую команду:

```
kubectl apply -f 02-autocert.yaml
```

**Результат выполнения команды**:

```
service/autocert created
configmap/autocert-config created
deployment.apps/autocert created
```

Далее давайте развернём admission webhook. В этом блоке в качестве части клиентской конфигурации для Autocert мы включаем корневой сертификат CA (в base64).

```
cat <<EOF | kubectl apply -f -
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: autocert-webhook-config
  labels: {app: autocert}
webhooks:
  - name: autocert.step.sm
    sideEffects: None
    admissionReviewVersions: ["v1beta1"]
    clientConfig:
      service:
        name: autocert
        namespace: step
        path: "/mutate"
      caBundle: $(cat $(step path)/certs/root_ca.crt | base64 | tr -d '\\n')
    rules:
      - operations: ["CREATE"]
        apiGroups: [""]
        apiVersions: ["v1"]
        resources: ["pods"]
    namespaceSelector:
      matchLabels:
        autocert.step.sm: enabled
EOF
```

**Результат выполнения:**

```
mutatingwebhookconfiguration.admissionregistration.k8s.io/autocert-webhook-config created
```

Теперь Autocert добавлен в кластер и сконфигурирован. Можно выполнить следующую команду, чтобы убедиться в том, что pod-ы autocert помечены правильно.

```
kubectl -n step get deployment/autocert
```

## Использование Autocert для включения mTLS между сервером и клиентом

Давайте создадим тестовое приложение, которое будет использовать Autocert. Это веб-сервер уровня «Hello World», использующий взаимную TLS-сертификацию.

Так как эта среда находится в пространстве имён по умолчанию, пометим её, чтобы приказать Autocert выпускать и обновлять сертификаты для новых pod-ов аннотацией `autocert.step.sm/name`:

```
kubectl label namespace default autocert.step.sm=enabled
```

**Результат выполнения команды**:

```
namespace/default labeled
```

Чтобы протестировать систему, мы создадим среду с аннотацией pod-а `autocert.step.sm/name`. В этом примере используется имя `localhost`, потому что мы будем выполнять тестирование со своей рабочей станции.

```
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: hello-mtls
  name: hello-mtls
spec:
  selector:
    matchLabels:
      app: hello-mtls
  template:
    metadata:
      annotations:
        autocert.step.sm/name: localhost
      labels:
        app: hello-mtls
    spec:
      containers:
      - image: smallstep/hello-mtls-server-go:latest
        name: hello-mtls
EOF
```

**Результат выполнения**:

```
deployment.apps/hello-mtls created
```

Для тестирования перенаправим `localhost:8443` на порт 443 pod-а.

```
kubectl port-forward deploy/hello-mtls 8443:443
```

**Результат выполнения команды**:

```
Forwarding from 127.0.0.1:8443 -> 443
Forwarding from [::1]:8443 -> 443
```

В течение следующих этапов оставим это запущенным на фоне.

Теперь выпустим сертификат клиента, подписанный нашим CA. Это нужно, чтобы аутентифицироваться на тестовом сервере «Hello mTLS».

```
step ca certificate linda.ikechukwu@smallstep.com demo.crt demo.key
```

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

```
curl --cacert $(step path)/certs/root_ca.crt \\
     --cert demo.crt --key demo.key \\
     <https://localhost:8443>
```

**Результат выполнения команды**:

```
Hello linda.ikechukwu@smallstep.com
```

## Заключение

Обеспечение безопасности кластера Kubernetes может быть сложной задачей. Вне зависимости от сетевой архитектуры и политик, автоматизация безопасности всегда повышает безопасность и надёжность рабочей нагрузки кластера.

Autocert вместе с Smallstep Certificate Manager упрощает выпуск сертификатов для среды Kubernetes. Для того, чтобы начать выпускать TLS-сертификаты Kubernetes своих микросервисов и защититься от злоумышленников, достаточно лишь немного YAML.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.konstantinsecurity.com/readme/architect/kubernetes/network-security/mtls-autocert.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
