Включение модуля
Включите модуль, применив ModuleConfig
, как представлено ниже:
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: stronghold
spec:
enabled: true
или выполните команду:
kubectl -n d8-system exec deploy/deckhouse -c deckhouse -it -- deckhouse-controller module enable stronghold
По умолчению модуль запустится в режиме Automatic
с инлетом Ingress
.
В текущей версии другие режимы и инлеты отсутствуют.
Как выключить модуль
Выключить модуль можно, установив в moduleconfig stronghold
значение enabled
на false
Либо выполнив команду:
kubectl -n d8-system exec deploy/deckhouse -c deckhouse -it -- deckhouse-controller module disable stronghold
ВНИМАНИЕ!
При отключении модуля удалятся все контейнеры Stronghold из неймспейса d8-stronghold
, а так же секрет stronghold-keys
с root и unseal ключами. При этом данные сервиса не удалятся с ноды. Вы можете включить модуль снова, создать и поместить в неймспейс d8-stronghold
сохраненную копию секрета stronghold-keys
, тогда доступ к данным будет восстановлен.
Если старые данные больше не нужны, нужно предварительно удалить каталог /var/lib/deckhouse/stronghold
со всех мастер-нод кластера.
Ручное распечатывание кластера
Для ручного распечатывания кластера Stronghold:
- Заходим на мастер-ноду
- Подготовить инструмент командной строки stronghold для работы
- Устанавливаем переменные окружения:
export VAULT_ADDR=https://`kubectl -n d8-stronghold get ingress stronghold -o jsonpath='{.spec.rules[0].host}'`
export VAULT_SKIP_VERIFY=true
- Получаем ключ из Secret
kubectl -n d8-stronghold get secret stronghold-keys -o jsonpath='{.data.unsealKey}' | base64 -d;echo
- Выполняем команду
stronghold operator unseal
- Вводим unseal ключ.
Получение доступа к сервису
Доступ к сервису осуществляется через инлеты. Инлет - это источник входных данных для пода. В примере доступен один инлет - Ingress
Адрес веб-интерфейса Stronghold формируется следующим образом: в шаблоне publicDomainTemplate глобального параметра конфигурации Deckhouse ключ %s
заменяется на stronghold
.
Например, если publicDomainTemplate
установлен как %s-kube.mycompany.tld
, веб-интерфейс Stronghold будет доступен по адресу stronghold-kube.cmycompany.tld
.
Использование хранилища данных. Режимы работы
Информация, содержащаяся в Stronghold, защищена шифрованием. Для того чтобы раскрыть данные хранилища, нужен ключ шифрования. Этот ключ также сохраняется вместе с данными (в хранилище ключей), однако он зашифрован иным ключом шифрования, который известен как корневой ключ.
Для раскрытия данных Stronghold расшифрует ключ шифрования, требующий для этого корневой ключ. Доступ к корневому ключу можно получить с помощью процесса, называемого разблокировкой хранилища. Корневой ключ сохраняется вместе со всеми остальными данными хранилища, однако шифруется еще одной технологией: ключом разблокировки.
В текущей версии модуля присутствует только режим Automatic
, в котором при первом запуске модуля происходит автоматическая инициализация хранилища. В процессе инициализации ключ разблокирования и root-token помещаются в секрет stronghold-keys
неймспейса kubernetes d8-stronghold
. После инициализации модуль автоматически разблокирует ноды кластера Stronghold.
В автоматическом режиме, при перезапуске узлов Stronghold, хранилище также будет автоматически разблокировано без вмешательства пользователя.
Управление доступами
В автоматическом режиме Automatic
в Stronghold после инициализации хранилища создается роль deckhouse_administrators
, для которой включается доступ к веб-интерфейсу через OIDC аутентификацию Dex.
Также настраивается автоматическое подключение текущего кластера Deckhouse к Stronghold для работы модуля secrets-store-integration.
Для того, чтоб выдать пользователям, находящимся в группе admins
(членство в группе передаётся из используемого IdP или LDAP с помощью Dex), нужно указать эту группу в массиве administrators
в ModuleConfig
:
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: stronghold
spec:
enabled: true
version: 1
settings:
management:
mode: Automatic
administrators:
- type: Group
name: admins
Для того, чтоб выдать права administrator
пользователям manager
и securityoperator
, можно использовать следующие параметры в ModuleConfig
:
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: stronghold
spec:
enabled: true
version: 1
settings:
management:
mode: Automatic
administrators:
- type: User
name: manager@mycompany.tld
- type: User
name: securityoperator@mycompany.tld
Несмотря на то, что доступ можно выдавать конкретным пользователям индивидуально, при этом сами пользователи должны находиться в какой-либо группе из-за ограничений аутентификации через OIDC.
В дальнейшем можно создать пользователей в Stronghold с различными правами доступа к секретам с помощью встроенного механизма хранилища.
Первый запуск
Первый запуск подразумевает отсутствие папки /var/lib/deckhouse/stronghold
в файловой системе узлов, на которых будут запускаться ноды Stronghold (по умолчанию это master-узлы) и отключенный модуль Stronghold.
Так же нужен опыт работы с утилитой
kubectl
Ниже приведены варианты организации доступа к модулю через инлет Ingress и далее процесс включения модуля и проверки работоспособности.
Способы организации доступа через инлет Ingress
ClusterIssuer LetsEncrypt
Этот метод получения сертификата настроен по умолчанию. Однако, подойдёт только для сервисов доступных из Интернета (не для внутренних сетей). Выполняем проверку доступности:
- Получаем адрес платформы аутентификации командой:
Под столбцом
kubectl -n d8-user-authn get ing dex # Ожидаемый ответ # NAME CLASS HOSTS ADDRESS PORTS AGE # dex nginx dex.mycompany.tld 34.85.243.109 80, 443 4d20h
HOSTS
наш проверяемый домен, а подADDRESS
– его IP адрес. Теперь нужно убедиться, что домен правильно резолвится на указанный IP адрес. Для этого выполняем команду:Если ответом стала ошибка с кодомnslookup dex.mycompany.tld 8.8.8.8 # Ожидаемый ответ # ... # Name: dex.mycompany.tld # Address: 34.85.243.109 # ... # Либо dig @8.8.8.8 dex.mycompany.tld # Ожидаемый ответ # ... # ;; ANSWER SECTION: # dex.mycompany.tld. 3600 IN A 34.85.243.109 # ...
NXDOMAIN
, нужно настроить DNS пользователя. - В браузере открываем https://dex.mycompany.tld/healthz, либо выполняем команду
curl -kL https://dex.mycompany.tld/healthz
. Должен вернуться ответHealth check passed
. - Проверяем, что Ingress контроллер обрабатывает запросы на ваш поддомен
stronghold.mycompany.tld
. Снова в браузере, либо командойcurl -kL
открываем https://stronghold.mycompany.tld. Должна вернуться 404 ошибка.
ClusterIssuer с самоподписанным центром сертификации
Эта опция подходит, если вы хотите использовать свой самоподписанный Центр сертификации. В качестве примера мы будем использовать уже созданный ClusterIssuer
ресурс selfsigned. Для добавления Issuer или ClusterIssuer со своим самоподписанным Центром сертификации, воспользуйтесь официальной документацией
Для этого способа подойдут как наличие публичного доменного имени, так и доступ только из внутренней сети.
Редактируем настройки global модуля. Сделать это можно, например, командой kubectl edit mc global
.
Добавляем параметр settings.modules.https.certManager.clusterIssuerName: selfsigned
. В результате конфигурация модуля должна выглядеть так:
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: global
spec:
settings:
modules:
https:
certManager:
clusterIssuerName: selfsigned # Единственный параметр, который нужно добавить
publicDomainTemplate: '%s.mycompany.tld'
version: 1
Далее редактируем настройки user-authn модуля. Выполняем команду kubectl edit mc user-authn
и изменяем параметр settings.controlPlaneConfigurator.dexCAMode
на FromIngressSecret
:
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: user-authn
spec:
enabled: true
settings:
controlPlaneConfigurator:
dexCAMode: FromIngressSecret # Параметр, который нужно изменить
...
Перед запуском модуля убедимся, что ключевые сервисы доступны из рабочей сети.
- Получаем адрес платформы аутентификации командой:
Под столбцом
kubectl -n d8-user-authn get ing dex # Ожидаемый ответ # NAME CLASS HOSTS ADDRESS PORTS AGE # dex nginx dex.mycompany.tld 34.85.243.109 80, 443 4d20h
HOSTS
наш проверяемый домен, а подADDRESS
– его IP адрес. Теперь нужно убедиться, что домен правильно резолвится на указанный IP адрес. Для этого выполняем команду:Если ответом стала ошибка с кодомnslookup dex.mycompany.tld # Ожидаемый ответ # ... # Name: dex.mycompany.tld # Address: 34.85.243.109 # ... # Либо dig dex.mycompany.tld # Ожидаемый ответ # ... # ;; ANSWER SECTION: # dex.mycompany.tld. 3600 IN A 34.85.243.109 # ...
NXDOMAIN
, нужно настроить DNS пользователя. Если домен не доступен из Интернета, дополнительно необходимо выполнить дополнительный шагКак временное решение можно добавить следующую строку в файл
/etc/hosts
вашей Unix системы34.85.243.109 dex.mycompany.tld stronghold.mycompany.tld
- В браузере открываем https://dex.mycompany.tld/healthz, либо выполняем команду
curl -kL https://dex.mycompany.tld/healthz
. Должен вернуться ответHealth check passed
. - Проверяем, что Ingress контроллер обрабатывает запросы на ваш поддомен
stronghold.mycompany.tld
. Снова в браузере, либо командойcurl -kL
открываем https://stronghold.mycompany.tld. Должна вернуться 404 ошибка.
Используя файл сертификата
Нужно создать СА, сертификат, и подписать его созданым СА. Если уже есть СА, сертификат можно подписать существущим. Важно сделать сертификат с цепочкой (fullchain).
Ниже представлен скрипт createCertificate.sh
, который с помощью openssl создает нужную пару сертификат + ключ
для домена mycompany.tld
(*.mycompany.tld
).
#!/bin/bash
set -e
caName="MyOrg-RootCA" # Имя CA (CN)
publicDomain="mycompany.tld" # Имя кластерного домена (см. publicDomainTemplate)
certName="kubernetes" # Имя сертификата для кластера (CN)
mkdir -p "${caName}"
cd "${caName}"
[ ! -f "${caName}.key" ] && openssl genrsa -out "${caName}.key" 4096
[ ! -f "${caName}.crt" ] && openssl req -x509 -new -nodes -key "${caName}.key" -sha256 -days 1826 -out "${caName}.crt" \
-subj "/CN=${caName}/O=MyOrganisation"
openssl req -new -nodes -out ${certName}.csr -newkey rsa:4096 -keyout "${certName}.key" \
-subj "/CN=${certName}/O=MyOrganisation"
# v3 ext file
cat > "${certName}.v3.ext" << EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = ${publicDomain}
DNS.2 = *.${publicDomain}
EOF
openssl x509 -req -in "${certName}.csr" -CA "${caName}.crt" -CAkey "${caName}.key" -CAcreateserial -out "${certName}.crt" -days 730 -sha256 -extfile "${certName}.v3.ext"
cat "${certName}.crt" "${caName}.crt" > "${certName}_fullchain.crt"
Используя полученные файлы kubernetes.key
и kubernetes_fullchain.crt
нужно создать секрет в неймспейсе d8-system
kubectl -n d8-system create secret tls mycompany-wildcard-tls --cert=kubernetes_fullchain.crt --key=kubernetes.key
Для использования полученного сертификата в кластере нужно привести конфигурацию модуля global
к такому виду.
Сделать это можно например командой kubectl edit mc global
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: global
spec:
settings:
modules:
https:
customCertificate:
secretName: mycompany-wildcard-tls # здесь указываем название объекта secret, содержащий fullchain сертификат и ключ
mode: CustomCertificate # меняем режим работы с tls для всех модулей
publicDomainTemplate: '%s.mycompany.tld'
Так же требуется настроить модуль user-authn
, включив в настройках controlPlaneConfigurator.dexCAMode
в значение FromIngressSecret
В этом случае CA будет получен из цепочки, которую мы поместили в файл kubernetes_fullchain.crt
Пример
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: user-authn
spec:
enabled: true
settings:
controlPlaneConfigurator:
dexCAMode: FromIngressSecret
...
Перед запуском модуля убедимся, что ключевые сервисы доступны из рабочей сети.
- Получаем адрес платформы аутентификации командой:
Под столбцом
kubectl -n d8-user-authn get ing dex # Ожидаемый ответ # NAME CLASS HOSTS ADDRESS PORTS AGE # dex nginx dex.mycompany.tld 34.85.243.109 80, 443 4d20h
HOSTS
наш проверяемый домен, а подADDRESS
– его IP адрес. Теперь нужно убедиться, что домен правильно резолвится на указанный IP адрес. Для этого выполняем команду:Если ответом стала ошибка с кодомnslookup dex.mycompany.tld # Ожидаемый ответ # ... # Name: dex.mycompany.tld # Address: 34.85.243.109 # ... # Либо dig dex.mycompany.tld # Ожидаемый ответ # ... # ;; ANSWER SECTION: # dex.mycompany.tld. 3600 IN A 34.85.243.109 # ...
NXDOMAIN
, нужно настроить DNS пользователя. Если домен не доступен из Интернета, дополнительно необходимо выполнить дополнительный шагКак временное решение можно добавить следующую строку в файл
/etc/hosts
вашей Unix системы34.85.243.109 dex.mycompany.tld stronghold.mycompany.tld
- В браузере открываем https://dex.mycompany.tld/healthz, либо выполняем команду
curl -kL https://dex.mycompany.tld/healthz
. Должен вернуться ответHealth check passed
. - Проверяем, что Ingress контроллер обрабатывает запросы на ваш поддомен
stronghold.mycompany.tld
. Снова в браузере, либо командойcurl -kL
открываем https://stronghold.mycompany.tld. Должна вернуться 404 ошибка.
Не резолвится доменное имя dex.mycompany.tld
Если ваш домен не резолвится через DNS и вы планируете использвать файл hosts, то для работы dex нужно добавить
адрес балансировщика или IP фронт-ноды в кластерный DNS. В его роли можно использовать модуль kube-dns, чтобы поды могли получить доступ к домену dex.mycompany.tld
по имени.
Пример получения IP для ингресса nginx-load-balancer
с типом LoadBlancer
kubectl -n d8-ingress-nginx get svc nginx-load-balancer -o jsonpath='{ .spec.clusterIP }'
Допустим наш адрес 34.85.243.109
, тогда модуль-конфиг kube-dns будет выглядеть так
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: kube-dns
spec:
version: 1
enabled: true
settings:
hosts:
- domain: dex.mycompany.tld
ip: 34.85.243.109
Включаем модуль
После этого можно включить модуль stronghold
, инициализация и настройка интеграции с dex
произойдет автоматически.
kubectl -n d8-system exec deploy/deckhouse -c deckhouse -it -- deckhouse-controller module enable stronghold
После запуска модуля проследить:
- убедиться в наличии сертификата для домена stronghold.*
kubectl -n d8-stronhold get ingress-tls
(либо через Консоль) В разделе Трудности есть описания решений возможных проблем с отсутствием сертификата. - Убедиться в доступности адреса https://stronghold.mycompany.tld/v1/sys/health
- Проверить соответствие Издателя сертификата с CA сертификатом (Опционально)
Трудности
Поды в состоянии ContainerCreating, объекта Secret с названием ingress-tls нет
Проверьте статус пода Stronghold:
kubectl -n d8-stronghold describe pod stronghold-0
Ищем строку:
MountVolume.SetUp failed for volume "certificates" : secret "ingress-tls" not found
При использовании метода ClusterIssuer с LetsEncrypt может возникнуть проблема с автоматическим созданием сертификата для домена stronghold.mycompany.tld
центром сертификации LetsEncrypt.
Получаем список CertificateRequest
kubectl -n d8-stronghold get certificaterequest
Ищем среди них объект начинающийся с stronghold-, для примера это будет stronghold-b5wc6
Смотрим его статус
kubectl -n d8-stronghold describe certificaterequest stronghold-b5wc6
Одной из причин может быть ошибка too many certificates already issued for mycompany.tld
, в особенности, если используется бесплатный dynDNS сервис наподобие sslip.io
или getmoss.site
. В таком случае нужно либо подождать, пока не пройдёт таймаут ограничения, либо сменить способ создания сертификата для домена stronghold.mycompany.tld
(ClusterIssuer selfsigned, ручная подпись сертификата).
При успешном завершении генерации сертификата в статусе CertificateRequest должны быть строчки:
Message: Certificate fetched from issuer successfully
Reason: Issued
Status: True
Type: Ready
и наличествовать объект Secret типа kubernetes.io/tls
с названием ingress-tls
Как получить бинарный файл stronghold
На мастер-ноде кластера необходимо выполнить следующие команды через root
пользователя:
mkdir $HOME/bin
sudo cp /proc/$(pidof stronghold)/root/usr/bin/stronghold bin && sudo chmod a+x bin/stronghold
export PATH=$PATH:$HOME/bin
Команда stronhold
готова к использованию.