Kubernetes the hard way etcd setup

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску

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
/ip/dns/static/add name=etcd.master.az2.k8s.cluster.home address=10.0.21.1
/ip/dns/static/add name=etcd.master.az3.k8s.cluster.home address=10.0.31.1

Описание параметров 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

Свой systemd-unit

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

  • изменить права - почти наверняка после тестовых запусков от рута права будут неправильные
chown etcd:etcd /var/lib/etcd/
  • лишний симлинк
rm /etc/systemd/system/etcd2.service
  • отключить ненужный сервис
systemctl disable etcd-discovery.service
systemctl stop  etcd-discovery.service




/etc/systemd/system/etcd.service

[Unit]
Description=etcd - highly-available key value store
Documentation=https://etcd.io/docs
Documentation=man:etcd
After=network.target
Wants=network-online.target

[Service]
LimitNOFILE=65536
Environment=ETCD_UNSUPPORTED_ARCH=arm
Environment=ETCDCTL_API=3
EnvironmentFile=-/etc/default/etcd
Type=notify
User=etcd
PermissionsStartOnly=true

ExecStart=/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

Restart=on-failure
RestartSec=60

[Install]
WantedBy=multi-user.target
Alias=etcd-server.service
systemctl daemon-reload
systemctl restart etcd
systemctl enable etcd
systemctl status etcd
● etcd.service - etcd - highly-available key value store
     Loaded: loaded (/etc/systemd/system/etcd.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2022-10-13 20:26:46 EEST; 2min 33s ago
       Docs: https://etcd.io/docs
             man:etcd
   Main PID: 6972 (etcd)
      Tasks: 10 (limit: 9237)
     Memory: 25.7M
        CPU: 10.563s
     CGroup: /system.slice/etcd.service
             └─6972 /usr/bin/etcd --debug --name=etcd-az3 --listen-peer-urls=https://10.0.31.1:2380 --listen-client-urls=https://10.0.31.1:2379 --advertise-client-urls=https://etcd.master.az3.k8s.cluster.home:2379 --initial-advertise-peer-urls=https://etcd.master.az3.k8s.cluster.home:2380 >

Oct 13 20:26:46 master-az3 etcd[6972]: INFO: 2022/10/13 20:26:46 Subchannel Connectivity change to CONNECTING
Oct 13 20:26:46 master-az3 etcd[6972]: INFO: 2022/10/13 20:26:46 Subchannel picks a new address "10.0.31.1:2379" to connect
Oct 13 20:26:46 master-az3 etcd[6972]: serving client requests on 10.0.31.1:2379
Oct 13 20:26:46 master-az3 etcd[6972]: INFO: 2022/10/13 20:26:46 Channel Connectivity change to CONNECTING
Oct 13 20:26:47 master-az3 etcd[6972]: INFO: 2022/10/13 20:26:47 Subchannel Connectivity change to READY
Oct 13 20:26:47 master-az3 etcd[6972]: INFO: 2022/10/13 20:26:47 Channel Connectivity change to READY
Oct 13 20:26:49 master-az3 etcd[6972]: established a TCP streaming connection with peer 54d484c9a805fd2 (stream Message writer)
Oct 13 20:26:49 master-az3 etcd[6972]: updated the cluster version from 3.0 to 3.3
Oct 13 20:26:49 master-az3 etcd[6972]: enabled capabilities for version 3.3
Oct 13 20:26:49 master-az3 etcd[6972]: established a TCP streaming connection with peer 54d484c9a805fd2 (stream MsgApp v2 writer)

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

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