Kubernetes the hard way etcd setup: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
Строка 525: Строка 525:
 
Это часть [[Vault_PKI_Intermediate_ca_etcd_Roles_and_permissions_for_real_cliuster_Kubernetes_the_hard_way_v2#.D0.A1.D0.B5.D1.80.D1.82.D0.B8.D1.84.D0.B8.D0.BA.D0.B0.D1.82.D1.8B_.D0.B4.D0.BB.D1.8F_.D0.B0.D0.B2.D1.82.D0.BE.D1.80.D0.B8.D0.B7.D0.B0.D1.86.D0.B8.D0.B8_.D1.81_.D0.B8.D0.BC.D0.B5.D0.BD.D0.B5.D0.BC_.D0.BF.D0.BE.D0.BB.D1.8C.D0.B7.D0.BE.D0.B2.D0.B0.D1.82.D0.B5.D0.BB.D1.8F_.D0.B2_ETCd|настройки ETCd]]
 
Это часть [[Vault_PKI_Intermediate_ca_etcd_Roles_and_permissions_for_real_cliuster_Kubernetes_the_hard_way_v2#.D0.A1.D0.B5.D1.80.D1.82.D0.B8.D1.84.D0.B8.D0.BA.D0.B0.D1.82.D1.8B_.D0.B4.D0.BB.D1.8F_.D0.B0.D0.B2.D1.82.D0.BE.D1.80.D0.B8.D0.B7.D0.B0.D1.86.D0.B8.D0.B8_.D1.81_.D0.B8.D0.BC.D0.B5.D0.BD.D0.B5.D0.BC_.D0.BF.D0.BE.D0.BB.D1.8C.D0.B7.D0.BE.D0.B2.D0.B0.D1.82.D0.B5.D0.BB.D1.8F_.D0.B2_ETCd|настройки ETCd]]
 
и вынесено в отдельную секцию
 
и вынесено в отдельную секцию
* проверить авторизацию с сертификатом для root (БЕЗ пароля!)
+
* проверить авторизацию с сертификатом для root (БЕЗ пароля!) Все дальнейшие действия - от рута, с сертификатом
 
<PRE>
 
<PRE>
 
ETCDCTL="etcdctl \
 
ETCDCTL="etcdctl \
Строка 538: Строка 538:
 
</PRE>
 
</PRE>
 
(ролей еще нет)
 
(ролей еще нет)
  +
  +
* Создать 2 пользователей (для того что бы проверить разделение прав, один из них зарезервирован под аписервер)
  +
<PRE>
  +
echo testuser | ${ETCDCTL} --interactive=false user add testuser
  +
echo kubeapiserver | ${ETCDCTL} --interactive=false user add kubeapiserver
  +
</PRE>
  +
  +
* 2 роли
  +
<PRE>
  +
${ETCDCTL} role add testrole
  +
${ETCDCTL} role add k8s
  +
</PRE>
  +
  +
* дать права для ролей
  +
<PRE>
  +
${ETCDCTL} role grant-permission testrole --prefix=true readwrite /testprefix/
  +
${ETCDCTL} role grant-permission k8s --prefix=true readwrite /k8s
  +
</PRE>
  +
  +
* дать роли пользователям
  +
<PRE>
  +
${ETCDCTL} user grant-role kubeapiserver k8s
  +
${ETCDCTL} user grant-role testuser testrole
  +
</PRE>
  +
* Записать ключ-значение
  +
<PRE>
  +
{ETCDCTL} put /k8s/a c
  +
{ETCDCTL} get /k8s/a
  +
</PRE>
  +
* Дальше переключиться на пользователя kubeapiserver
  +
<PRE>
  +
ETCDCTL="etcdctl \
  +
--endpoints="${ENDPOINT}" \
  +
--cert=${P}/kubeapiserver.pem \
  +
--key=${P}/kubeapiserver.key "
  +
  +
</PRE>
  +
* Проверить запись и чтение
  +
<PRE>
  +
${ETCDCTL} get /k8s/a
  +
  +
${ETCDCTL} put /k8s/a c
  +
  +
${ETCDCTL} get /k8s/a
  +
</PRE>
  +
=Обновление сертификатов=
  +
Можно использовать скрипт или consul-template, но это пока отложено на будущее

Версия 19:36, 13 октября 2022

ETCD

Вторая версия статьи, максимально подробная (первая версия тут - https://noname.com.ua/mediawiki/index.php/Etcd)


Требования к окружению

  • 3 ноды raspberry pi установленные и настроенные, имеющие коннективити друг с другом
  • для работы etcd выделен отдельный VLAN с отдельным адресным пространством
  • установленный и настроенный PKI на основе Hashicorp Vault (в примере - по адресу http://vault.home)
  • Настроенный DNS и созданы записи для всех доменов в примере (в моем случае DNS поднят на MikroTik)

DNS

Подчеркну что все взаимоджействие происходит исключительно по доменным именам
Создаем три записи DNS (для трех мастер-нод каждая из которых находится в своей "Availability Zone" (В кавычках по тому что в лабе это все очень условно)

/ip/dns/static/add name=etcd.master.az1.k8s.cluster.home address=10.0.11.1<br>
/ip/dns/static/add name=etcd.master.az2.k8s.cluster.home address=10.0.21.1<br>
/ip/dns/static/add name=etcd.master.az3.k8s.cluster.home address=10.0.31.1<br>

Описание параметров ETCd

Общие параметры

  • --debug
  • --name=etcd-az-1 Имя ноды кластера - должно быть одним из содержащихся в параметре --initial-cluster На каждой ноде это имя отличается
  • --data-dir =/var/lib/etcd
  • --listen-peer-urls адрес для peer-to-peer коммуникации
  • --listen-client-urls адрес для клиентов (https допустим только при наличии сертификатов)
  • --advertise-client-urls адрес который будет анонсирован для клиентов, тут должно быть доменное имя и оно же должно быть в CN/AltNames что бы можно было валидировать сертификат

Параметры кластера

  • --initial-advertise-peer-urlsАдрес который будет анонсирован для peer-to-peer соединений, тоже домен
  • --initial-cluster-token начальный токен, ЭТОТ ТОКЕН ОБЩИЙ ДЛЯ ВСЕХ НОД иначе вместо одного кластера из 3 нод будет создано три неполных кластера из одной ноды каждый
  • --initial-clusterсписок нод кластера вместе с именами, этот список общий для всех нод и должен быть одинаковый
  • --initial-cluster-state должно быть new для нового кластера

Параметры SSL для peer-to-peer

  • --peer-client-cert-auth требовать SSL (сертификаты всех нод должны быть подписаны одним СА)
  • --peer-cert-file файл сертификата
  • --peer-key-file файл ключа
  • --peer-trusted-ca-fileСА которым подписаны сертификаты для peer-to-peer взаимодействия

Параметры SSL для клиентских подключений

  • --trusted-ca-fileСА которым подписаны клиентские сертификаты
  • --cert-file файл сертификата
  • --key-file файл ключа
  • --client-cert-auth требовать SSL от клиентов (и не разрешать подключения без сертификата)

Установка из пакетов (на всех трех нодах)

Собирать код самой последней версии под архитектуру АРМ откровенно лениво

apt -y \
  install \
    etcd \
    etcd-client \
    etcd-server \
    etcd-discovery
dpkg -l | grep etcd
ii  etcd                            3.3.25+dfsg-7                           all          Transitional package for etcd-client and etcd-server
ii  etcd-client                     3.3.25+dfsg-7                           arm64        highly-available key value store -- client
ii  etcd-discovery                  2.0.0+git2019.04.19.git.78fb45d3c9-4    arm64        etcd discovery service
ii  etcd-server                     3.3.25+dfsg-7                           arm64        highly-available key value store -- daemon

Остановить сервис (запускается после установки)
systemctl stop etcd


Переместить юнит (свой вариант юнита создается ниже)
mv /usr/lib/systemd/system/etcd.service /root/etcd.service.original

Подготовка SSL сертификатов

Согласно документации (https://etcd.io/docs/v3.5/op-guide/security/) etcd сертификаты используются в двух независимых настройках:

  • Коммуникация между нодами кластера
  • Коммуникация между кластером и клиентом

Соответственно есть ТРИ типа сертификатов

  • Серверные, которые используются для коммуникации по порту из настройки --listen-peer-urls=https://127.0.0.1:2380 \ (127.0.0.1 для примера),

Этот сертификат должен отвечать следующим требованиям:

  1. Должен быть подписан правильным СА, т.е. вся цепочка доверия должна быть проверяем. Корневой СА для этой цепочки указывается в настройке --peer-trusted-ca-file
  2. Должен соответствовать домену
  3. Должен иметь разрешения как для клиентского так и серверного использования ext_key_usage="ServerAuth,ClientAuth"


  • Серверные, которые используются для коммуникации с клиентами (условно назову их "Серверные-Клиентские" )
  • Клиентские, которые используются клиентами (например etcdctl) для подключения (условно назову их Клиентские-Клиентские)

Конфигурация PKI для etcd

Для получения сертификатов требуется отдельная конфигурация Vault PKI что вынесено в отдельную статью
Сначала разобрать настройку PKI: Пример настройки PKI с подробными пояснениями
А так же тестовый пользователь и домен Roles and Permissions
Основываясь на примере - настроить следующую конфигурацию

  • 3 отдельных ендпоинта, каждый для своего домена
  • три отдельных пользователя с разделением прав


Получение сертификатов для peer-to-peer SSL

Шаги отдельно описаны в документе ETCD PKI но без отдельно разбора каждого шага - эти шаги разобраны для тестового случая.

  • на этом шаге можно запустить etcd с peer-to-peer SSL

Peer-to-Peer SSL

Получить на всех трех нодах корневой сертификат

#!/bin/bash


CERT_NAME=" /etc/etcd/certs/k8s_root_certificate.pem"

echo "-----BEGIN CERTIFICATE-----"                            >  ${CERT_NAME} && \
curl "http://vault.home:8200/v1/k8s_pki_root_ca/ca" | base64  >> ${CERT_NAME} && \
echo "-----END CERTIFICATE-----"                              >> ${CERT_NAME}

Стртовый скрипт

Тут оставлены только значимые на данный момент переменные

  • Сертификаты ETCD_PEER_CERT_FILE (разные на всех нодах) выписаны через Vault
  • ETCD_PEER_TRUSTED_CA_FILE - корневой СА (не промежуточный СА!)
  • Промежуточный СА содержится в сертификате (для того что бы создать цепочку доверия)

master1

#!/bin/bash

export ETCD_UNSUPPORTED_ARCH=arm
ETCD_NAME="etcd-az1"
ETCD_LISTEN_PEER_URLS="https://10.0.11.1:2380"
ETCD_LISTEN_CLIENT_URLS="http://10.0.11.1:2379,http://127.0.0.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://etcd.master.az1.k8s.cluster.home:2380"
ETCD_INITIAL_CLUSTER="etcd-az1=https://etcd.master.az1.k8s.cluster.home:2380,etcd-az2=https://etcd.master.az2.k8s.cluster.home:2380,etcd-az3=https://etcd.master.az3.k8s.cluster.home:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd.k8s.cluster.home"
ETCD_ADVERTISE_CLIENT_URLS="http://etcd.master.az1.k8s.cluster.home:2379"
ETCD_PROXY="off"
ETCD_PEER_CERT_FILE="/etc/etcd/certs/server/etcd-server-crt.pem"
ETCD_PEER_KEY_FILE="/etc/etcd/certs/server/etcd-server-key.pem"
ETCD_PEER_TRUSTED_CA_FILE="/etc/etcd/certs/k8s_root_certificate.pem"

/usr/bin/etcd \
  --debug \
  --name="${ETCD_NAME}" \
  --listen-peer-urls="${ETCD_LISTEN_PEER_URLS}" \
  --listen-client-urls="${ETCD_LISTEN_CLIENT_URLS}" \
  --advertise-client-urls="${ETCD_ADVERTISE_CLIENT_URLS}" \
  --initial-advertise-peer-urls="${ETCD_INITIAL_ADVERTISE_PEER_URLS}" \
  --initial-cluster-token="${ETCD_INITIAL_CLUSTER_TOKEN}" \
  --initial-cluster="${ETCD_INITIAL_CLUSTER}" \
  --initial-cluster-state="${ETCD_INITIAL_CLUSTER_STATE}" \
  --data-dir="${ETCD_DATA_DIR}" \
  --peer-client-cert-auth \
  --peer-cert-file="${ETCD_PEER_CERT_FILE}" \
  --peer-key-file="${ETCD_PEER_KEY_FILE}" \
  --peer-trusted-ca-file="${ETCD_PEER_TRUSTED_CA_FILE}"

master2

#!/bin/bash

export ETCD_UNSUPPORTED_ARCH=arm
ETCD_NAME="etcd-az2"
ETCD_LISTEN_PEER_URLS="https://10.0.21.1:2380"
ETCD_LISTEN_CLIENT_URLS="http://10.0.21.1:2379,http://127.0.0.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://etcd.master.az2.k8s.cluster.home:2380"
ETCD_INITIAL_CLUSTER="etcd-az1=https://etcd.master.az1.k8s.cluster.home:2380,etcd-az2=https://etcd.master.az2.k8s.cluster.home:2380,etcd-az3=https://etcd.master.az3.k8s.cluster.home:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd.k8s.cluster.home"
ETCD_ADVERTISE_CLIENT_URLS="http://etcd.master.az2.k8s.cluster.home:2379"
ETCD_PROXY="off"
ETCD_PEER_CERT_FILE="/etc/etcd/certs/server/etcd-server-crt.pem"
ETCD_PEER_KEY_FILE="/etc/etcd/certs/server/etcd-server-key.pem"
ETCD_PEER_TRUSTED_CA_FILE="/etc/etcd/certs/k8s_root_certificate.pem"

/usr/bin/etcd \
  --debug \
  --name="${ETCD_NAME}" \
  --listen-peer-urls="${ETCD_LISTEN_PEER_URLS}" \
  --listen-client-urls="${ETCD_LISTEN_CLIENT_URLS}" \
  --advertise-client-urls="${ETCD_ADVERTISE_CLIENT_URLS}" \
  --initial-advertise-peer-urls="${ETCD_INITIAL_ADVERTISE_PEER_URLS}" \
  --initial-cluster-token="${ETCD_INITIAL_CLUSTER_TOKEN}" \
  --initial-cluster="${ETCD_INITIAL_CLUSTER}" \
  --initial-cluster-state="${ETCD_INITIAL_CLUSTER_STATE}" \
  --data-dir="${ETCD_DATA_DIR}" \
  --peer-client-cert-auth \
  --peer-cert-file="${ETCD_PEER_CERT_FILE}" \
  --peer-key-file="${ETCD_PEER_KEY_FILE}" \
  --peer-trusted-ca-file="${ETCD_PEER_TRUSTED_CA_FILE}"

master3

#!/bin/bash

export ETCD_UNSUPPORTED_ARCH=arm
ETCD_NAME="etcd-az3"
ETCD_LISTEN_PEER_URLS="https://10.0.31.1:2380"
ETCD_LISTEN_CLIENT_URLS="http://10.0.31.1:2379,http://127.0.0.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://etcd.master.az3.k8s.cluster.home:2380"
ETCD_INITIAL_CLUSTER="etcd-az1=https://etcd.master.az1.k8s.cluster.home:2380,etcd-az2=https://etcd.master.az2.k8s.cluster.home:2380,etcd-az3=https://etcd.master.az3.k8s.cluster.home:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd.k8s.cluster.home"
ETCD_ADVERTISE_CLIENT_URLS="http://etcd.master.az3.k8s.cluster.home:2379"
ETCD_PROXY="off"
ETCD_PEER_CERT_FILE="/etc/etcd/certs/server/etcd-server-crt.pem"
ETCD_PEER_KEY_FILE="/etc/etcd/certs/server/etcd-server-key.pem"
ETCD_PEER_TRUSTED_CA_FILE="/etc/etcd/certs/k8s_root_certificate.pem"

/usr/bin/etcd \
  --debug \
  --name="${ETCD_NAME}" \
  --listen-peer-urls="${ETCD_LISTEN_PEER_URLS}" \
  --listen-client-urls="${ETCD_LISTEN_CLIENT_URLS}" \
  --advertise-client-urls="${ETCD_ADVERTISE_CLIENT_URLS}" \
  --initial-advertise-peer-urls="${ETCD_INITIAL_ADVERTISE_PEER_URLS}" \
  --initial-cluster-token="${ETCD_INITIAL_CLUSTER_TOKEN}" \
  --initial-cluster="${ETCD_INITIAL_CLUSTER}" \
  --initial-cluster-state="${ETCD_INITIAL_CLUSTER_STATE}" \
  --data-dir="${ETCD_DATA_DIR}" \
  --peer-client-cert-auth \
  --peer-cert-file="${ETCD_PEER_CERT_FILE}" \
  --peer-key-file="${ETCD_PEER_KEY_FILE}" \
  --peer-trusted-ca-file="${ETCD_PEER_TRUSTED_CA_FILE}"

Проверка подключения без SSL

ETCDCTL_API=3 etcdctl --debug --endpoints=http://etcd.master.az1.k8s.cluster.home:2379 member list


Вывод разделен на 2 части - дебаг и собственно вывод команды

  • http - подключение ПОКА без шифрования
ETCDCTL_CACERT=
ETCDCTL_CERT=
ETCDCTL_COMMAND_TIMEOUT=5s
ETCDCTL_DEBUG=true
ETCDCTL_DIAL_TIMEOUT=2s
ETCDCTL_DISCOVERY_SRV=
ETCDCTL_ENDPOINTS=[http://etcd.master.az1.k8s.cluster.home:2379]
ETCDCTL_HEX=false
ETCDCTL_INSECURE_DISCOVERY=true
ETCDCTL_INSECURE_SKIP_TLS_VERIFY=false
ETCDCTL_INSECURE_TRANSPORT=true
ETCDCTL_KEEPALIVE_TIME=2s
ETCDCTL_KEEPALIVE_TIMEOUT=6s
ETCDCTL_KEY=
ETCDCTL_USER=
ETCDCTL_WRITE_OUT=simple
WARNING: 2022/10/12 12:51:18 Adjusting keepalive ping interval to minimum period of 10s
WARNING: 2022/10/12 12:51:18 Adjusting keepalive ping interval to minimum period of 10s
INFO: 2022/10/12 12:51:18 parsed scheme: "endpoint"
INFO: 2022/10/12 12:51:18 ccResolverWrapper: sending new addresses to cc: [{http://etcd.master.az1.k8s.cluster.home:2379  <nil> 0 <nil>}]
INFO: 2022/10/12 12:51:18 Subchannel Connectivity change to CONNECTING
INFO: 2022/10/12 12:51:18 Subchannel picks a new address "http://etcd.master.az1.k8s.cluster.home:2379" to connect
INFO: 2022/10/12 12:51:18 Channel Connectivity change to CONNECTING
INFO: 2022/10/12 12:51:18 Subchannel Connectivity change to READY
INFO: 2022/10/12 12:51:18 Channel Connectivity change to READY
54d484c9a805fd2, started, etcd-az1, https://etcd.master.az1.k8s.cluster.home:2380, http://etcd.master.az1.k8s.cluster.home:2379
c19d34eeefb6ae25, started, etcd-az2, https://etcd.master.az2.k8s.cluster.home:2380, http://etcd.master.az2.k8s.cluster.home:2379
e354bb9691207bf1, started, etcd-az3, https://etcd.master.az3.k8s.cluster.home:2380, http://etcd.master.az3.k8s.cluster.home:2379

Получение сертификатов для "Клиентского" SSL

Шаги отдельно описаны в документе [PKI] но без отдельно разбора каждого шага - эти шаги разобраны для тестового случая.

  • на этом шаге можно запустить etcd с client-server SSL

Настройка "клиентского" SSL

Следующий шаг - добавить шифрование клиентских соединений
Тут может возникнуть некоторая путаница - есть 2 "клиентских" сертификата

  • "клиентский-серверный" - тот что устанавливается на сервере ETCD для того что бы обеспечить SSL клиентам
  • "совсем клиентский" - тот с которым авторизуются клиенты

В этом разделе идет речь про установку "клиентского-серверного" сертификата

Стартовый скрипт

master1

#!/bin/bash

export ETCD_UNSUPPORTED_ARCH=arm
export ETCDCTL_API=3
ETCD_NAME="etcd-az1"
ETCD_LISTEN_PEER_URLS="https://10.0.11.1:2380"
ETCD_LISTEN_CLIENT_URLS="https://10.0.11.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://etcd.master.az1.k8s.cluster.home:2380"
ETCD_INITIAL_CLUSTER="etcd-az1=https://etcd.master.az1.k8s.cluster.home:2380,etcd-az2=https://etcd.master.az2.k8s.cluster.home:2380,etcd-az3=https://etcd.master.az3.k8s.cluster.home:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd.k8s.cluster.home"
ETCD_ADVERTISE_CLIENT_URLS="https://etcd.master.az1.k8s.cluster.home:2379"
ETCD_PROXY="off"
ETCD_CERT_FILE="/etc/etcd/certs/server-to-client/etcd-server-to-client-crt.pem"
ETCD_KEY_FILE="/etc/etcd/certs/server-to-client/etcd-server-to-client-key.pem"
ETCD_TRUSTED_CA_FILE="/etc/etcd/certs/k8s_root_certificate.pem"
ETCD_PEER_CERT_FILE="/etc/etcd/certs/server/etcd-server-crt.pem"
ETCD_PEER_KEY_FILE="/etc/etcd/certs/server/etcd-server-key.pem"
ETCD_PEER_TRUSTED_CA_FILE="/etc/etcd/certs/k8s_root_certificate.pem"

/usr/bin/etcd \
  --debug \
  --name="${ETCD_NAME}" \
  --listen-peer-urls="${ETCD_LISTEN_PEER_URLS}" \
  --listen-client-urls="${ETCD_LISTEN_CLIENT_URLS}" \
  --advertise-client-urls="${ETCD_ADVERTISE_CLIENT_URLS}" \
  --initial-advertise-peer-urls="${ETCD_INITIAL_ADVERTISE_PEER_URLS}" \
  --initial-cluster-token="${ETCD_INITIAL_CLUSTER_TOKEN}" \
  --initial-cluster="${ETCD_INITIAL_CLUSTER}" \
  --initial-cluster-state="${ETCD_INITIAL_CLUSTER_STATE}" \
  --data-dir="${ETCD_DATA_DIR}" \
  --peer-client-cert-auth \
  --peer-cert-file="${ETCD_PEER_CERT_FILE}" \
  --peer-key-file="${ETCD_PEER_KEY_FILE}" \
  --peer-trusted-ca-file="${ETCD_PEER_TRUSTED_CA_FILE}" \
  --cert-file=${ETCD_CERT_FILE} \
  --key-file=${ETCD_KEY_FILE} \
  --trusted-ca-file=${ETCD_TRUSTED_CA_FILE} \
  --client-cert-auth

master2

#!/bin/bash

export ETCD_UNSUPPORTED_ARCH=arm
export ETCDCTL_API=3
ETCD_NAME="etcd-az2"
ETCD_LISTEN_PEER_URLS="https://10.0.21.1:2380"
ETCD_LISTEN_CLIENT_URLS="https://10.0.21.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://etcd.master.az2.k8s.cluster.home:2380"
ETCD_INITIAL_CLUSTER="etcd-az1=https://etcd.master.az1.k8s.cluster.home:2380,etcd-az2=https://etcd.master.az2.k8s.cluster.home:2380,etcd-az3=https://etcd.master.az3.k8s.cluster.home:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd.k8s.cluster.home"
ETCD_ADVERTISE_CLIENT_URLS="https://etcd.master.az2.k8s.cluster.home:2379"
ETCD_PROXY="off"
ETCD_CERT_FILE="/etc/etcd/certs/server-to-client/etcd-server-to-client-crt.pem"
ETCD_KEY_FILE="/etc/etcd/certs/server-to-client/etcd-server-to-client-key.pem"
ETCD_TRUSTED_CA_FILE="/etc/etcd/certs/k8s_root_certificate.pem"
ETCD_PEER_CERT_FILE="/etc/etcd/certs/server/etcd-server-crt.pem"
ETCD_PEER_KEY_FILE="/etc/etcd/certs/server/etcd-server-key.pem"
ETCD_PEER_TRUSTED_CA_FILE="/etc/etcd/certs/k8s_root_certificate.pem"

/usr/bin/etcd \
  --debug \
  --name="${ETCD_NAME}" \
  --listen-peer-urls="${ETCD_LISTEN_PEER_URLS}" \
  --listen-client-urls="${ETCD_LISTEN_CLIENT_URLS}" \
  --advertise-client-urls="${ETCD_ADVERTISE_CLIENT_URLS}" \
  --initial-advertise-peer-urls="${ETCD_INITIAL_ADVERTISE_PEER_URLS}" \
  --initial-cluster-token="${ETCD_INITIAL_CLUSTER_TOKEN}" \
  --initial-cluster="${ETCD_INITIAL_CLUSTER}" \
  --initial-cluster-state="${ETCD_INITIAL_CLUSTER_STATE}" \
  --data-dir="${ETCD_DATA_DIR}" \
  --peer-client-cert-auth \
  --peer-cert-file="${ETCD_PEER_CERT_FILE}" \
  --peer-key-file="${ETCD_PEER_KEY_FILE}" \
  --peer-trusted-ca-file="${ETCD_PEER_TRUSTED_CA_FILE}" \
  --cert-file=${ETCD_CERT_FILE} \
  --key-file=${ETCD_KEY_FILE} \
  --trusted-ca-file=${ETCD_TRUSTED_CA_FILE} \
  --client-cert-auth

master3

#!/bin/bash

export ETCD_UNSUPPORTED_ARCH=arm
export ETCDCTL_API=3
ETCD_NAME="etcd-az3"
ETCD_LISTEN_PEER_URLS="https://10.0.31.1:2380"
ETCD_LISTEN_CLIENT_URLS="https://10.0.31.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://etcd.master.az3.k8s.cluster.home:2380"
ETCD_INITIAL_CLUSTER="etcd-az1=https://etcd.master.az1.k8s.cluster.home:2380,etcd-az2=https://etcd.master.az2.k8s.cluster.home:2380,etcd-az3=https://etcd.master.az3.k8s.cluster.home:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd.k8s.cluster.home"
ETCD_ADVERTISE_CLIENT_URLS="https://etcd.master.az3.k8s.cluster.home:2379"
ETCD_PROXY="off"
ETCD_CERT_FILE="/etc/etcd/certs/server-to-client/etcd-server-to-client-crt.pem"
ETCD_KEY_FILE="/etc/etcd/certs/server-to-client/etcd-server-to-client-key.pem"
ETCD_TRUSTED_CA_FILE="/etc/etcd/certs/k8s_root_certificate.pem"
ETCD_PEER_CERT_FILE="/etc/etcd/certs/server/etcd-server-crt.pem"
ETCD_PEER_KEY_FILE="/etc/etcd/certs/server/etcd-server-key.pem"
ETCD_PEER_TRUSTED_CA_FILE="/etc/etcd/certs/k8s_root_certificate.pem"

/usr/bin/etcd \
  --debug \
  --name="${ETCD_NAME}" \
  --listen-peer-urls="${ETCD_LISTEN_PEER_URLS}" \
  --listen-client-urls="${ETCD_LISTEN_CLIENT_URLS}" \
  --advertise-client-urls="${ETCD_ADVERTISE_CLIENT_URLS}" \
  --initial-advertise-peer-urls="${ETCD_INITIAL_ADVERTISE_PEER_URLS}" \
  --initial-cluster-token="${ETCD_INITIAL_CLUSTER_TOKEN}" \
  --initial-cluster="${ETCD_INITIAL_CLUSTER}" \
  --initial-cluster-state="${ETCD_INITIAL_CLUSTER_STATE}" \
  --data-dir="${ETCD_DATA_DIR}" \
  --peer-client-cert-auth \
  --peer-cert-file="${ETCD_PEER_CERT_FILE}" \
  --peer-key-file="${ETCD_PEER_KEY_FILE}" \
  --peer-trusted-ca-file="${ETCD_PEER_TRUSTED_CA_FILE}" \
  --cert-file=${ETCD_CERT_FILE} \
  --key-file=${ETCD_KEY_FILE} \
  --trusted-ca-file=${ETCD_TRUSTED_CA_FILE} \
  --client-cert-auth

Проверка подключения с SSL

Без клиентского сертификата

ETCDCTL_API=3 etcdctl --debug --endpoints=https://etcd.master.az1.k8s.cluster.home:2379 member list

Ожидаемо не работает

WARNING: 2022/10/12 17:55:21 grpc: addrConn.createTransport failed to connect to {https://etcd.master.az1.k8s.cluster.home:2379  <nil> 0 <nil>}. Err: connection error: desc = "transport: authentication handshake failed: remote error: tls: bad certificate". Reconnecting...

Получения сертификата для клиентов

Получение сертификатов является частью настройки PKI и вынесено в отдельный документ

После получения клиентского сертификата можно проверить работу:

#!/bin/bash


export ETCDCTL_API=3

P="/etc/etcd/certs/client"
ENDPOINT="https://etcd.master.az1.k8s.cluster.home:2379"

etcdctl \
    --debug \
    --endpoints="${ENDPOINT}" \
    --cert=${P}/etcd-client-crt.pem \
    --key=${P}/etcd-client-key.pem \
    member list
ETCDCTL_CACERT=
ETCDCTL_CERT=/etc/etcd/certs/client/etcd-client-crt.pem
ETCDCTL_COMMAND_TIMEOUT=5s
ETCDCTL_DEBUG=true
ETCDCTL_DIAL_TIMEOUT=2s
ETCDCTL_DISCOVERY_SRV=
ETCDCTL_ENDPOINTS=[https://etcd.master.az1.k8s.cluster.home:2379]
ETCDCTL_HEX=false
ETCDCTL_INSECURE_DISCOVERY=true
ETCDCTL_INSECURE_SKIP_TLS_VERIFY=false
ETCDCTL_INSECURE_TRANSPORT=true
ETCDCTL_KEEPALIVE_TIME=2s
ETCDCTL_KEEPALIVE_TIMEOUT=6s
ETCDCTL_KEY=/etc/etcd/certs/client/etcd-client-key.pem
ETCDCTL_USER=
ETCDCTL_WRITE_OUT=simple
WARNING: 2022/10/12 19:22:28 Adjusting keepalive ping interval to minimum period of 10s
WARNING: 2022/10/12 19:22:28 Adjusting keepalive ping interval to minimum period of 10s
INFO: 2022/10/12 19:22:28 parsed scheme: "endpoint"
INFO: 2022/10/12 19:22:28 ccResolverWrapper: sending new addresses to cc: [{https://etcd.master.az1.k8s.cluster.home:2379  <nil> 0 <nil>}]
INFO: 2022/10/12 19:22:28 Subchannel Connectivity change to CONNECTING
INFO: 2022/10/12 19:22:28 Subchannel picks a new address "https://etcd.master.az1.k8s.cluster.home:2379" to connect
INFO: 2022/10/12 19:22:28 Channel Connectivity change to CONNECTING
INFO: 2022/10/12 19:22:29 Subchannel Connectivity change to READY
INFO: 2022/10/12 19:22:29 Channel Connectivity change to READY
54d484c9a805fd2, started, etcd-az1, https://etcd.master.az1.k8s.cluster.home:2380, https://etcd.master.az1.k8s.cluster.home:2379
c19d34eeefb6ae25, started, etcd-az2, https://etcd.master.az2.k8s.cluster.home:2380, https://etcd.master.az2.k8s.cluster.home:2379
e354bb9691207bf1, started, etcd-az3, https://etcd.master.az3.k8s.cluster.home:2380, https://etcd.master.az3.k8s.cluster.home:2379

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

ETCd позволяет использовать CN в качестве имени пользователя а сам сертификат - вместо пароля

предварительная настройка

export ETCDCTL_API=3

P="/etc/etcd/certs/client"
ENDPOINT="https://etcd.master.az1.k8s.cluster.home:2379"

ETCDCTL="etcdctl \
    --endpoints="${ENDPOINT}" \
    --cert=${P}/etcd-client-crt.pem \
    --key=${P}/etcd-client-key.pem \
    member list "

Шаги по настройке

  • Создать пользователя root (c паролем, тут ввожу руками)
${ETCDCTL} user add root
  • Включить авторизацию
${ETCDCTL}  auth enable
  • настроить PKI для возможности выписывания сертификатов с произвольным CN (по умолчанию разрешены только валидные хостнеймы)

Это часть настройки ETCd и вынесено в отдельную секцию

  • проверить авторизацию с сертификатом для root (БЕЗ пароля!) Все дальнейшие действия - от рута, с сертификатом
ETCDCTL="etcdctl \
    --endpoints="${ENDPOINT}" \
    --cert=${P}/root.pem \
    --key=${P}/root.key "



echo "---ROLES---"
${ETCDCTL} role list

(ролей еще нет)

  • Создать 2 пользователей (для того что бы проверить разделение прав, один из них зарезервирован под аписервер)
echo testuser | ${ETCDCTL} --interactive=false  user add testuser
echo kubeapiserver | ${ETCDCTL} --interactive=false  user add kubeapiserver
  • 2 роли
${ETCDCTL} role add testrole
${ETCDCTL} role add k8s
  • дать права для ролей
${ETCDCTL} role grant-permission testrole --prefix=true readwrite /testprefix/
${ETCDCTL} role grant-permission k8s --prefix=true readwrite /k8s
  • дать роли пользователям
${ETCDCTL} user grant-role kubeapiserver  k8s
${ETCDCTL} user grant-role testuser       testrole
  • Записать ключ-значение
{ETCDCTL} put /k8s/a c
{ETCDCTL} get /k8s/a
  • Дальше переключиться на пользователя kubeapiserver
ETCDCTL="etcdctl \
    --endpoints="${ENDPOINT}" \
    --cert=${P}/kubeapiserver.pem \
    --key=${P}/kubeapiserver.key "

  • Проверить запись и чтение
${ETCDCTL}  get  /k8s/a

${ETCDCTL} put /k8s/a c

${ETCDCTL}  get  /k8s/a

Обновление сертификатов

Можно использовать скрипт или consul-template, но это пока отложено на будущее