Etcd: различия между версиями
Sirmax (обсуждение | вклад) |
Sirmax (обсуждение | вклад) |
||
| (не показаны 24 промежуточные версии этого же участника) | |||
| Строка 13: | Строка 13: | ||
* установленный и настроенный PKI на основе Hashicorp Vault (в примере - по адресу http://vault.home) |
* установленный и настроенный PKI на основе Hashicorp Vault (в примере - по адресу http://vault.home) |
||
* Настроенный DNS и созданы записи для всех доменов в примере (в моем случае DNS поднят на MikroTik) |
* Настроенный DNS и созданы записи для всех доменов в примере (в моем случае DNS поднят на MikroTik) |
||
| + | |||
| + | =Замечания к тестовому окружению= |
||
| + | |||
| + | * для Vault используется корневой токен вместо отдельной авторизации по каждой роли |
||
| + | * для Vault используется http вместо https |
||
| + | |||
| + | * ??? |
||
=Установка= |
=Установка= |
||
| Строка 19: | Строка 26: | ||
<PRE> |
<PRE> |
||
apt -y install etcd-server etcd-client etcd |
apt -y install etcd-server etcd-client etcd |
||
| + | </PRE> |
||
| + | Удалить юнит (свой создается ниже) |
||
| + | <PRE> |
||
| + | rm /usr/lib/systemd/system/etcd.service |
||
</PRE> |
</PRE> |
||
<PRE> |
<PRE> |
||
| Строка 36: | Строка 47: | ||
=Peer-to-peer SSL= |
=Peer-to-peer SSL= |
||
| − | Для того что бы настроить SSL потребуются сертификаты для соответствующих доменов. Так как сертификаты во взаимодействии нод кластера используются как клиентские и как серверные, то нужна соответствующая настройка |
+ | Для того что бы настроить SSL потребуются сертификаты для соответствующих доменов. Так как сертификаты во взаимодействии нод кластера используются как клиентские и как серверные, то нужна соответствующая настройка PKI |
==настройка PKI для peer-to-peer SSL== |
==настройка PKI для peer-to-peer SSL== |
||
* Нужен клиент Vault |
* Нужен клиент Vault |
||
| Строка 69: | Строка 80: | ||
ext_key_usage="ServerAuth,ClientAuth" \ |
ext_key_usage="ServerAuth,ClientAuth" \ |
||
require_cn=true |
require_cn=true |
||
| + | </PRE> |
||
| + | В скрипте выще важно следующее |
||
| + | * <B>etc-az-k8s-home-server-crt</B> имя роли - по сути произвольная строка которая просто определяет endpoint (используется ниже) |
||
| + | * <B>allowed_domains</B>="etcd1.home,etcd2.home,etcd3.home,etcd.home,etcd.az1.k8s.home,etcd.az2.k8s.home,etcd.az3.k8s.home" - список доменов для которых можно выписывать сертефикаты используя этот endpoint. В моем случае изначально планировалось использовать домены etcdX.home но так как настройка "а-ля мультизонный кластер" то домер решил изменить <BR> |
||
| + | ВАЖНО: Домены пречислять через запятую без пробелов иначе не работает (как минимум в моей версии Vault) |
||
| + | * <B>allow_subdomains</B>=false - не разрешать создавать сабдомены |
||
| + | * <B>client_flag</B>=true - сертификат может использоваться как клиентский |
||
| + | * <B>server_flag</B>=true - сертификат может использоваться как серверный |
||
| + | * <B>ext_key_usage</B>="ServerAuth,ClientAuth" - расширения |
||
| + | |||
| + | |||
| + | Если попробовать создать только серверный сертификат то возникает ошибка SSL которая в общем-то об этом и говорит и ничего не работает |
||
| + | |||
| + | |||
| + | ==Создание сертификатов для peer-to-peer== |
||
| + | Пример для одного домена, для остальных аналогично |
||
| + | |||
| + | |||
| + | <PRE> |
||
| + | export VAULT_ADDR=http://vault.home:8200 |
||
| + | export VAULT_TOKEN=<some-token-here> |
||
| + | |||
| + | |||
| + | domain="etcd.az1.k8s.home" |
||
| + | vault \ |
||
| + | write \ |
||
| + | -format=json pki_intermediate_ca/issue/etc-az-k8s-home-server-crt \ |
||
| + | common_name="${domain}" \ |
||
| + | ttl="43800h" > ${domain}.crt.json |
||
| + | </PRE> |
||
| + | |||
| + | * <B>issue/etc-az-k8s-home-server-crt</B> - имя роли которое указано на предыдущем шаге |
||
| + | * используется рутовый токен который имеет все права (но это только для примера что бы пропустить "лишние" шаги) |
||
| + | |||
| + | Полученный файл <B>etcd.az1.k8s.home.crt.json</B>: |
||
| + | <PRE> |
||
| + | { |
||
| + | "request_id": "0454e996-7bbc-d3ca-8830-cc2d544b2763", |
||
| + | "lease_id": "", |
||
| + | "lease_duration": 0, |
||
| + | "renewable": false, |
||
| + | "data": { |
||
| + | "ca_chain": [ |
||
| + | "-----BEGIN CERTIFICATE----- пропущено -----END CERTIFICATE-----" |
||
| + | ], |
||
| + | "certificate": "-----BEGIN CERTIFICATE----- пропущено -----END CERTIFICATE-----", |
||
| + | "expiration": 1792583899, |
||
| + | "issuing_ca": "-----BEGIN CERTIFICATE----- пропущено -----END CERTIFICATE-----", |
||
| + | "private_key": "-----BEGIN RSA PRIVATE KEY----- пропущено -----END RSA PRIVATE KEY-----", |
||
| + | "private_key_type": "rsa", |
||
| + | "serial_number": "3b:f4:6d:6d:b8:47:38:9f:7b:4d:dc:11:89:d9:63:ff:74:e6:fd:ed" |
||
| + | }, |
||
| + | "warnings": null |
||
| + | } |
||
| + | </PRE> |
||
| + | Из полученного файла подготовить отдельно файлы сертификатов: |
||
| + | <PRE> |
||
| + | #!/bin/bash |
||
| + | |||
| + | domain="etcd.az1.k8s.home" |
||
| + | |||
| + | mkdir -p /etc/etcd/certs/server |
||
| + | |||
| + | cat \ |
||
| + | ${domain}.crt.json \ |
||
| + | | jq -r '.data.private_key' > /etc/etcd/certs/server/${domain}.key |
||
| + | |||
| + | cat \ |
||
| + | ${domain}.crt.json \ |
||
| + | | jq -r '.data.certificate' > /etc/etcd/certs/server/${domain}.pem |
||
| + | |||
| + | cat \ |
||
| + | ${domain}.crt.json \ |
||
| + | | jq -r '.data.ca_chain[]' >> /etc/etcd/certs/server/${domain}.pem |
||
| + | |||
| + | </PRE> |
||
| + | <B>Обратить внимание:</B> так как сертефикат подписан НЕ корневым а промежуточным центром сертефикации то в файл сертификата требуется добавить промежуточный сертефикат (поле '.data.ca_chain[]' в json) |
||
| + | |||
| + | |||
| + | ==Тестовый запуск c peer-to-peer SSL== |
||
| + | В целом этого достаточно что бы запустить etcd (но клиентские соединения будут нешифрованными и без авторизации) |
||
| + | <BR> |
||
| + | Скрипт запуска (на всех трех нодах отличаются домены и адреса): |
||
| + | <PRE> |
||
| + | export ETCD_UNSUPPORTED_ARCH=arm |
||
| + | |||
| + | /usr/bin/etcd \ |
||
| + | --debug \ |
||
| + | --name=etcd-az-1 \ |
||
| + | --listen-peer-urls=https://10.240.1.2:2380 \ |
||
| + | --listen-client-urls=http://10.240.1.2:2379,http://127.0.0.1:2379 \ |
||
| + | --advertise-client-urls=http://etcd.az1.k8s.home:2379 \ |
||
| + | --initial-advertise-peer-urls=https://etcd.az1.k8s.home:2380 \ |
||
| + | --initial-cluster-token=etcd.az1.k8s.home \ |
||
| + | --initial-cluster etcd-az-1=https://etcd.az1.k8s.home:2380,etcd-az-2=https://etcd.az2.k8s.home:2380,etcd-az-3=https://etcd.az3.k8s.home:2380 \ |
||
| + | --initial-cluster-state=new \ |
||
| + | --data-dir=/var/lib/etcd \ |
||
| + | --peer-client-cert-auth \ |
||
| + | --peer-cert-file=/etc/etcd/certs/server/etcd.az1.k8s.home.pem \ |
||
| + | --peer-key-file=/etc/etcd/certs/server/etcd.az1.k8s.home.key \ |
||
| + | --peer-trusted-ca-file=/etc/etcd/certs/rootCA.pem |
||
| + | </PRE> |
||
| + | |||
| + | Запускать на всех трех нодах! |
||
| + | |||
| + | ==Проверка подключения клиента без SSL== |
||
| + | <PRE> |
||
| + | ETCDCTL_API=3 etcdctl --debug --endpoints=http://etcd.az1.k8s.home:2379 member list |
||
| + | </PRE> |
||
| + | Вывод команды разбит на 2 части - дебаг и собственно вывод |
||
| + | <BR>из вывода команды видно что все три ноды в кластере |
||
| + | <PRE> |
||
| + | INFO: 2021/10/22 15:50:14 parsed scheme: "" |
||
| + | INFO: 2021/10/22 15:50:14 scheme "" not registered, fallback to default scheme |
||
| + | INFO: 2021/10/22 15:50:14 ccResolverWrapper: sending new addresses to cc: [{etcd.az1.k8s.home:2379 0 <nil>}] |
||
| + | INFO: 2021/10/22 15:50:14 balancerWrapper: got update addr from Notify: [{etcd.az1.k8s.home:2379 <nil>}] |
||
| + | INFO: 2021/10/22 15:50:14 clientv3/balancer: pin "etcd.az1.k8s.home:2379" |
||
| + | INFO: 2021/10/22 15:50:14 balancerWrapper: got update addr from Notify: [{etcd.az1.k8s.home:2379 <nil>}] |
||
| + | </PRE> |
||
| + | <PRE> |
||
| + | b7a875ba8d83c06, started, etcd-az-3, https://etcd.az3.k8s.home:2380, http://etcd.az3.k8s.home:2379 |
||
| + | 489c4054ed342d1a, started, etcd-az-2, https://etcd.az2.k8s.home:2380, http://etcd.az2.k8s.home:2379 |
||
| + | db4ea93d7a019672, started, etcd-az-1, https://etcd.az1.k8s.home:2380, http://etcd.az1.k8s.home:2379 |
||
</PRE> |
</PRE> |
||
=Client SSL= |
=Client SSL= |
||
| + | Следующий шаг - добавить шифрование клиентских соединений |
||
| + | <BR> |
||
| + | Тут есть путаница - "клиентский-серверный" и "совсем клиентский" сертефикаты |
||
| + | * "клиентский-серверный" - тот что устанавливается на сервере ETCD для того что бы обеспечить SSL клиентам |
||
| + | * "совсем клиентский" - тот с которым авторизуются клиенты |
||
| + | ==настройка PKI для Client SSL== |
||
| + | Со стороны ETCD сетрефикаты - "серверные", со стороны клиентов - "клиентские", по тому требуется создать в Vault PKI два дополнительных endpoint |
||
| + | |||
| + | |||
| + | * Для сертефиката который будет "клиентский-серверный": |
||
| + | <PRE> |
||
| + | vault write pki_intermediate_ca/roles/etc-az-k8s-home-server-only-crt \ |
||
| + | country="Ukraine" \ |
||
| + | locality="Kharkov" \ |
||
| + | street_address="Lui Pastera st 322 app. 311"\ |
||
| + | postal_code="61172" \ |
||
| + | organization="Home Network" \ |
||
| + | ou="IT" \ |
||
| + | allowed_domains="etcd1.home,etcd2.home,etcd3.home,etcd.home,etcd.az1.k8s.home,etcd.az2.k8s.home,etcd.az3.k8s.home" \ |
||
| + | allow_subdomains=false \ |
||
| + | max_ttl="87600h" \ |
||
| + | key_bits="2048" \ |
||
| + | key_type="rsa" \ |
||
| + | allow_any_name=false \ |
||
| + | allow_bare_domains=true \ |
||
| + | allow_glob_domain=false \ |
||
| + | allow_ip_sans=true \ |
||
| + | allow_localhost=false \ |
||
| + | client_flag=false \ |
||
| + | server_flag=true \ |
||
| + | enforce_hostnames=true \ |
||
| + | key_usage="DigitalSignature,KeyEncipherment" \ |
||
| + | ext_key_usage="ServerAuth" \ |
||
| + | require_cn=true |
||
| + | </PRE> |
||
| + | Обратить внимаене что это чисто серверный сертефикат: |
||
| + | * client_flag=false |
||
| + | * ext_key_usage="ServerAuth" |
||
| + | |||
| + | |||
| + | "совсем клиентский": |
||
| + | <PRE> |
||
| + | vault write pki_intermediate_ca/roles/etc-az-k8s-home-client-only-crt \ |
||
| + | country="Ukraine" \ |
||
| + | locality="Kharkov" \ |
||
| + | street_address="Lui Pastera st 322 app. 311"\ |
||
| + | postal_code="61172" \ |
||
| + | organization="Home Network" \ |
||
| + | ou="IT" \ |
||
| + | allowed_domains="etcd1.home,etcd2.home,etcd3.home,etcd.home,etcd.az1.k8s.home,etcd.az2.k8s.home,etcd.az3.k8s.home" \ |
||
| + | allow_subdomains=false \ |
||
| + | max_ttl="87600h" \ |
||
| + | key_bits="2048" \ |
||
| + | key_type="rsa" \ |
||
| + | allow_any_name=true \ |
||
| + | allow_bare_domains=false \ |
||
| + | allow_glob_domain=false \ |
||
| + | allow_ip_sans=false \ |
||
| + | allow_localhost=false \ |
||
| + | client_flag=true \ |
||
| + | server_flag=false \ |
||
| + | enforce_hostnames=false \ |
||
| + | key_usage="DigitalSignature" \ |
||
| + | ext_key_usage="ClientAuth" \ |
||
| + | require_cn=true |
||
| + | </PRE> |
||
| + | Тут - только клиентский сертефикат |
||
| + | * client_flag=true |
||
| + | * server_flag=false |
||
| + | * ext_key_usage="ClientAuth" |
||
| + | |||
| + | ==Создание сертификатов для Client SSL== |
||
| + | В целом полностью аналогично созданию для peer-to-peer за исключением использования других endpoint естественно |
||
| + | |||
| + | <PRE> |
||
| + | export VAULT_ADDR=http://vault.home:8200 |
||
| + | export VAULT_TOKEN=... |
||
| + | domain="etcd.az1.k8s.home" |
||
| + | mkdir -p ./client_crt |
||
| + | vault \ |
||
| + | write \ |
||
| + | -format=json pki_intermediate_ca/issue/etc-az-k8s-home-server-only-crt \ |
||
| + | common_name="${domain}" \ |
||
| + | ttl="43800h" > ./client_crt/${domain}.crt.json |
||
| + | </PRE> |
||
| + | <PRE> |
||
| + | mkdir -p ./client_only_crt |
||
| + | vault \ |
||
| + | write \ |
||
| + | -format=json pki_intermediate_ca/issue/etc-az-k8s-home-client-only-crt \ |
||
| + | common_name="${domain}" \ |
||
| + | ttl="43800h" > ./client_only_crt/${domain}.crt.json |
||
| + | </PRE> |
||
| + | и аналогично с помощью jq достать сами сертификаты и ключи |
||
| + | |||
| + | ==Тестовый запуск c Client SSL== |
||
| + | ===Systemd Unit File=== |
||
| + | Юнит файлы требуют доработки - вынести в конфиги весь хардкод |
||
| + | |||
| + | * /etc/systemd/system/etcd.service |
||
| + | |||
| + | <PRE> |
||
| + | [Unit] |
||
| + | Description=etcd |
||
| + | Documentation=https://github.com/coreos |
||
| + | |||
| + | [Service] |
||
| + | Type=notify |
||
| + | LimitNOFILE=65536 |
||
| + | Environment=ETCD_UNSUPPORTED_ARCH=arm |
||
| + | ExecStart=/usr/bin/etcd \ |
||
| + | --debug \ |
||
| + | --name=etcd-az-1 \ |
||
| + | --listen-peer-urls=https://10.240.1.2:2380 \ |
||
| + | --listen-client-urls=https://10.240.1.2:2379,https://127.0.0.1:2379 \ |
||
| + | --advertise-client-urls=https://etcd.az1.k8s.home:2379 \ |
||
| + | --initial-advertise-peer-urls=https://etcd.az1.k8s.home:2380 \ |
||
| + | --initial-cluster-token=etcd.az1.k8s.home \ |
||
| + | --initial-cluster etcd-az-1=https://etcd.az1.k8s.home:2380,etcd-az-2=https://etcd.az2.k8s.home:2380,etcd-az-3=https://etcd.az3.k8s.home:2380 \ |
||
| + | --initial-cluster-state=new \ |
||
| + | --data-dir=/var/lib/etcd \ |
||
| + | --peer-client-cert-auth \ |
||
| + | --peer-cert-file=/etc/etcd/certs/server/etcd.az1.k8s.home.pem \ |
||
| + | --peer-key-file=/etc/etcd/certs/server/etcd.az1.k8s.home.key \ |
||
| + | --peer-trusted-ca-file=/etc/etcd/certs/rootCA.pem \ |
||
| + | --trusted-ca-file=/etc/etcd/certs/rootCA.pem \ |
||
| + | --cert-file=/etc/etcd/certs/client/etcd.az1.k8s.home.pem \ |
||
| + | --key-file=/etc/etcd/certs/client/etcd.az1.k8s.home.key \ |
||
| + | --client-cert-auth |
||
| + | |||
| + | Restart=on-failure |
||
| + | RestartSec=60 |
||
| + | |||
| + | [Install] |
||
| + | WantedBy=multi-user.target |
||
| + | Alias=etcd-server.service |
||
| + | </PRE> |
||
| + | ===Общие параметры=== |
||
| + | * <B> --debug </B> |
||
| + | * <B> --name</B>=etcd-az-1 Имя ноды кластера - должно быть одним из содержащихся в параметре <B> --initial-cluster</B> На каждой ноде это имя отличается |
||
| + | * <B> --data-dir</B> =/var/lib/etcd |
||
| + | |||
| + | * <B> --listen-peer-urls</B>=https://10.240.1.2:2380 адрес для peer-to-peer коммуникации |
||
| + | * <B> --listen-client-urls</B>=https://10.240.1.2:2379,https://127.0.0.1:2379 - адрес для клиентов (https допустим только при наличии сертификатов) |
||
| + | * <B> --advertise-client-urls</B>=https://etcd.az1.k8s.home:2379 |
||
| + | |||
| + | ===Параметры кластера=== |
||
| + | * <B> --initial-advertise-peer-urls</B> =https://etcd.az1.k8s.home:2380 |
||
| + | * <B> --initial-cluster-token</B>=etcd.az1.k8s.home - начальный токен, ЭТОТ ТОКЕН ОБЩИЙ ДЛЯ ВСЕХ НОД иначе вместо одного кластера из 3 нод будет создано три неполных кластера из одной ноды каждый |
||
| + | * <B> --initial-cluster</B>etcd-az-1=https://etcd.az1.k8s.home:2380,etcd-az-2=https://etcd.az2.k8s.home:2380,etcd-az-3=https://etcd.az3.k8s.home:2380 список нод кластера вместе с именами, этот список общий для всех нод |
||
| + | * <B> --initial-cluster-state</B>=new |
||
| + | |||
| + | ===Параметры SSL для peer-to-peer=== |
||
| + | * <B> --peer-client-cert-auth</B> |
||
| + | * <B> --peer-cert-file</B> =/etc/etcd/certs/server/etcd.az1.k8s.home.pem |
||
| + | * <B> --peer-key-file</B> =/etc/etcd/certs/server/etcd.az1.k8s.home.key |
||
| + | * <B> --peer-trusted-ca-file</B> =/etc/etcd/certs/rootCA.pem |
||
| + | |||
| + | ===Параметры SSL для клиентских подключений=== |
||
| + | * <B> --trusted-ca-file</B>=/etc/etcd/certs/rootCA.pem |
||
| + | * <B> --cert-file</B>=/etc/etcd/certs/client/etcd.az1.k8s.home.pem |
||
| + | * <B> --key-file</B>=/etc/etcd/certs/client/etcd.az1.k8s.home.key |
||
| + | * <B> --client-cert-auth </B> |
||
| + | |||
| + | ==Проверка подключения клиента с использованием SSL== |
||
| + | <PRE> |
||
| + | #!/bin/bash |
||
| + | |||
| + | |||
| + | export ETCDCTL_API=3\ |
||
| + | |||
| + | etcdctl \ |
||
| + | --debug \ |
||
| + | --endpoints=https://etcd.az1.k8s.home:2379 \ |
||
| + | --cert=/root/k8s/etcd/client_only_crt/etcd.az1.k8s.home.pem \ |
||
| + | --key=/root/k8s/etcd/client_only_crt/etcd.az1.k8s.home.key \ |
||
| + | member list |
||
| + | </PRE> |
||
| + | <PRE> |
||
| + | INFO: 2021/10/23 14:16:04 parsed scheme: "" |
||
| + | INFO: 2021/10/23 14:16:04 scheme "" not registered, fallback to default scheme |
||
| + | INFO: 2021/10/23 14:16:04 ccResolverWrapper: sending new addresses to cc: [{etcd.az1.k8s.home:2379 0 <nil>}] |
||
| + | INFO: 2021/10/23 14:16:04 balancerWrapper: got update addr from Notify: [{etcd.az1.k8s.home:2379 <nil>}] |
||
| + | INFO: 2021/10/23 14:16:04 clientv3/balancer: pin "etcd.az1.k8s.home:2379" |
||
| + | INFO: 2021/10/23 14:16:04 balancerWrapper: got update addr from Notify: [{etcd.az1.k8s.home:2379 <nil>}] |
||
| + | </PRE> |
||
| + | <PRE> |
||
| + | b7a875ba8d83c06, started, etcd-az-3, https://etcd.az3.k8s.home:2380, https://etcd.az3.k8s.home:2379 |
||
| + | 489c4054ed342d1a, started, etcd-az-2, https://etcd.az2.k8s.home:2380, https://etcd.az2.k8s.home:2379 |
||
| + | db4ea93d7a019672, started, etcd-az-1, https://etcd.az1.k8s.home:2380, https://etcd.az1.k8s.home:2379 |
||
| + | </PRE> |
||
| + | |||
| + | В целом можно сказать что авьторизация возможна |
||
| + | * с клиентским сертификатом |
||
| + | * c сертификатом сервера для peer-to-peer (кстати эту возможность вероятно надо отключить как-то) |
||
| + | С сертификатом для клиентских подключения, который используется со стороны сервера, клиент подключиться не сможет |
||
| + | <PRE> |
||
| + | WARNING: 2021/10/23 14:15:46 grpc: addrConn.createTransport failed to connect to {etcd.az2.k8s.home:2379 0 <nil>}. Err :connection error: desc = "transport: authentication handshake failed: x509: certificate specifies an incompatible key usage". Reconnecting... |
||
| + | </PRE> |
||
| + | |||
| + | =Разграничение прав, роли пользователи и авторизация по сертефикатам= |
||
| + | TBD |
||
Текущая версия на 11:43, 30 сентября 2022
Etcd
Это часть моего изучения k8s the hard way
но может использоваться и отдельно
Требования
- 3 ноды raspberry pi установленные и настроенные, имеющие коннективити друг с другом
- установленный и настроенный PKI на основе Hashicorp Vault (в примере - по адресу http://vault.home)
- Настроенный DNS и созданы записи для всех доменов в примере (в моем случае DNS поднят на MikroTik)
Замечания к тестовому окружению
- для Vault используется корневой токен вместо отдельной авторизации по каждой роли
- для Vault используется http вместо https
- ???
Установка
- мне НЕ удалось ни найти ни собрать более свежую версию чем была доступна в пакетах дистрибутива
- установить на всех трех нодах
apt -y install etcd-server etcd-client etcd
Удалить юнит (свой создается ниже)
rm /usr/lib/systemd/system/etcd.service
dpkg -l | grep etcd iU etcd 3.2.26+dfsg-3 all Transitional package for etcd-client and etcd-server ii etcd-client 3.2.26+dfsg-3 armhf highly-available key value store -- client iF etcd-server 3.2.26+dfsg-3 armhf highly-available key value store -- daemon
- TODO: проверить кросс-компиляцию для ARM
Подготовка SSL сертификатов
Согласно документации (https://etcd.io/docs/v3.5/op-guide/security/) etcd сертификаты используются в двух независимых настройках:
- Коммуникация между нодами кластера
- Коммуникация между кластером и клиентом
Peer-to-peer SSL
Для того что бы настроить SSL потребуются сертификаты для соответствующих доменов. Так как сертификаты во взаимодействии нод кластера используются как клиентские и как серверные, то нужна соответствующая настройка PKI
настройка PKI для peer-to-peer SSL
- Нужен клиент Vault
- В примере используется рутовый токен (нужен ТОЛЬКО для создания "роли", но используется везде в примерах)
Для обновления сертификатов будет добавлен пользователь или другой способ авторизации и права будут ограничены
export VAULT_ADDR=http://vault.home:8200
export VAULT_TOKEN=<some-token-here>
vault write pki_intermediate_ca/roles/etc-az-k8s-home-server-crt \
country="Ukraine" \
locality="Kharkov" \
street_address="Lui Pastera st 322 app. 311"\
postal_code="61172" \
organization="Home Network" \
ou="IT" \
allowed_domains="etcd1.home,etcd2.home,etcd3.home,etcd.home,etcd.az1.k8s.home,etcd.az2.k8s.home,etcd.az3.k8s.home" \
allow_subdomains=false \
max_ttl="87600h" \
key_bits="2048" \
key_type="rsa" \
allow_any_name=false \
allow_bare_domains=true \
allow_glob_domain=false \
allow_ip_sans=true \
allow_localhost=false \
client_flag=true \
server_flag=true \
enforce_hostnames=true \
key_usage="DigitalSignature,KeyEncipherment" \
ext_key_usage="ServerAuth,ClientAuth" \
require_cn=true
В скрипте выще важно следующее
- etc-az-k8s-home-server-crt имя роли - по сути произвольная строка которая просто определяет endpoint (используется ниже)
- allowed_domains="etcd1.home,etcd2.home,etcd3.home,etcd.home,etcd.az1.k8s.home,etcd.az2.k8s.home,etcd.az3.k8s.home" - список доменов для которых можно выписывать сертефикаты используя этот endpoint. В моем случае изначально планировалось использовать домены etcdX.home но так как настройка "а-ля мультизонный кластер" то домер решил изменить
ВАЖНО: Домены пречислять через запятую без пробелов иначе не работает (как минимум в моей версии Vault)
- allow_subdomains=false - не разрешать создавать сабдомены
- client_flag=true - сертификат может использоваться как клиентский
- server_flag=true - сертификат может использоваться как серверный
- ext_key_usage="ServerAuth,ClientAuth" - расширения
Если попробовать создать только серверный сертификат то возникает ошибка SSL которая в общем-то об этом и говорит и ничего не работает
Создание сертификатов для peer-to-peer
Пример для одного домена, для остальных аналогично
export VAULT_ADDR=http://vault.home:8200
export VAULT_TOKEN=<some-token-here>
domain="etcd.az1.k8s.home"
vault \
write \
-format=json pki_intermediate_ca/issue/etc-az-k8s-home-server-crt \
common_name="${domain}" \
ttl="43800h" > ${domain}.crt.json
- issue/etc-az-k8s-home-server-crt - имя роли которое указано на предыдущем шаге
- используется рутовый токен который имеет все права (но это только для примера что бы пропустить "лишние" шаги)
Полученный файл etcd.az1.k8s.home.crt.json:
{
"request_id": "0454e996-7bbc-d3ca-8830-cc2d544b2763",
"lease_id": "",
"lease_duration": 0,
"renewable": false,
"data": {
"ca_chain": [
"-----BEGIN CERTIFICATE----- пропущено -----END CERTIFICATE-----"
],
"certificate": "-----BEGIN CERTIFICATE----- пропущено -----END CERTIFICATE-----",
"expiration": 1792583899,
"issuing_ca": "-----BEGIN CERTIFICATE----- пропущено -----END CERTIFICATE-----",
"private_key": "-----BEGIN RSA PRIVATE KEY----- пропущено -----END RSA PRIVATE KEY-----",
"private_key_type": "rsa",
"serial_number": "3b:f4:6d:6d:b8:47:38:9f:7b:4d:dc:11:89:d9:63:ff:74:e6:fd:ed"
},
"warnings": null
}
Из полученного файла подготовить отдельно файлы сертификатов:
#!/bin/bash
domain="etcd.az1.k8s.home"
mkdir -p /etc/etcd/certs/server
cat \
${domain}.crt.json \
| jq -r '.data.private_key' > /etc/etcd/certs/server/${domain}.key
cat \
${domain}.crt.json \
| jq -r '.data.certificate' > /etc/etcd/certs/server/${domain}.pem
cat \
${domain}.crt.json \
| jq -r '.data.ca_chain[]' >> /etc/etcd/certs/server/${domain}.pem
Обратить внимание: так как сертефикат подписан НЕ корневым а промежуточным центром сертефикации то в файл сертификата требуется добавить промежуточный сертефикат (поле '.data.ca_chain[]' в json)
Тестовый запуск c peer-to-peer SSL
В целом этого достаточно что бы запустить etcd (но клиентские соединения будут нешифрованными и без авторизации)
Скрипт запуска (на всех трех нодах отличаются домены и адреса):
export ETCD_UNSUPPORTED_ARCH=arm /usr/bin/etcd \ --debug \ --name=etcd-az-1 \ --listen-peer-urls=https://10.240.1.2:2380 \ --listen-client-urls=http://10.240.1.2:2379,http://127.0.0.1:2379 \ --advertise-client-urls=http://etcd.az1.k8s.home:2379 \ --initial-advertise-peer-urls=https://etcd.az1.k8s.home:2380 \ --initial-cluster-token=etcd.az1.k8s.home \ --initial-cluster etcd-az-1=https://etcd.az1.k8s.home:2380,etcd-az-2=https://etcd.az2.k8s.home:2380,etcd-az-3=https://etcd.az3.k8s.home:2380 \ --initial-cluster-state=new \ --data-dir=/var/lib/etcd \ --peer-client-cert-auth \ --peer-cert-file=/etc/etcd/certs/server/etcd.az1.k8s.home.pem \ --peer-key-file=/etc/etcd/certs/server/etcd.az1.k8s.home.key \ --peer-trusted-ca-file=/etc/etcd/certs/rootCA.pem
Запускать на всех трех нодах!
Проверка подключения клиента без SSL
ETCDCTL_API=3 etcdctl --debug --endpoints=http://etcd.az1.k8s.home:2379 member list
Вывод команды разбит на 2 части - дебаг и собственно вывод
из вывода команды видно что все три ноды в кластере
INFO: 2021/10/22 15:50:14 parsed scheme: ""
INFO: 2021/10/22 15:50:14 scheme "" not registered, fallback to default scheme
INFO: 2021/10/22 15:50:14 ccResolverWrapper: sending new addresses to cc: [{etcd.az1.k8s.home:2379 0 <nil>}]
INFO: 2021/10/22 15:50:14 balancerWrapper: got update addr from Notify: [{etcd.az1.k8s.home:2379 <nil>}]
INFO: 2021/10/22 15:50:14 clientv3/balancer: pin "etcd.az1.k8s.home:2379"
INFO: 2021/10/22 15:50:14 balancerWrapper: got update addr from Notify: [{etcd.az1.k8s.home:2379 <nil>}]
b7a875ba8d83c06, started, etcd-az-3, https://etcd.az3.k8s.home:2380, http://etcd.az3.k8s.home:2379 489c4054ed342d1a, started, etcd-az-2, https://etcd.az2.k8s.home:2380, http://etcd.az2.k8s.home:2379 db4ea93d7a019672, started, etcd-az-1, https://etcd.az1.k8s.home:2380, http://etcd.az1.k8s.home:2379
Client SSL
Следующий шаг - добавить шифрование клиентских соединений
Тут есть путаница - "клиентский-серверный" и "совсем клиентский" сертефикаты
- "клиентский-серверный" - тот что устанавливается на сервере ETCD для того что бы обеспечить SSL клиентам
- "совсем клиентский" - тот с которым авторизуются клиенты
настройка PKI для Client SSL
Со стороны ETCD сетрефикаты - "серверные", со стороны клиентов - "клиентские", по тому требуется создать в Vault PKI два дополнительных endpoint
- Для сертефиката который будет "клиентский-серверный":
vault write pki_intermediate_ca/roles/etc-az-k8s-home-server-only-crt \
country="Ukraine" \
locality="Kharkov" \
street_address="Lui Pastera st 322 app. 311"\
postal_code="61172" \
organization="Home Network" \
ou="IT" \
allowed_domains="etcd1.home,etcd2.home,etcd3.home,etcd.home,etcd.az1.k8s.home,etcd.az2.k8s.home,etcd.az3.k8s.home" \
allow_subdomains=false \
max_ttl="87600h" \
key_bits="2048" \
key_type="rsa" \
allow_any_name=false \
allow_bare_domains=true \
allow_glob_domain=false \
allow_ip_sans=true \
allow_localhost=false \
client_flag=false \
server_flag=true \
enforce_hostnames=true \
key_usage="DigitalSignature,KeyEncipherment" \
ext_key_usage="ServerAuth" \
require_cn=true
Обратить внимаене что это чисто серверный сертефикат:
- client_flag=false
- ext_key_usage="ServerAuth"
"совсем клиентский":
vault write pki_intermediate_ca/roles/etc-az-k8s-home-client-only-crt \
country="Ukraine" \
locality="Kharkov" \
street_address="Lui Pastera st 322 app. 311"\
postal_code="61172" \
organization="Home Network" \
ou="IT" \
allowed_domains="etcd1.home,etcd2.home,etcd3.home,etcd.home,etcd.az1.k8s.home,etcd.az2.k8s.home,etcd.az3.k8s.home" \
allow_subdomains=false \
max_ttl="87600h" \
key_bits="2048" \
key_type="rsa" \
allow_any_name=true \
allow_bare_domains=false \
allow_glob_domain=false \
allow_ip_sans=false \
allow_localhost=false \
client_flag=true \
server_flag=false \
enforce_hostnames=false \
key_usage="DigitalSignature" \
ext_key_usage="ClientAuth" \
require_cn=true
Тут - только клиентский сертефикат
- client_flag=true
- server_flag=false
- ext_key_usage="ClientAuth"
Создание сертификатов для Client SSL
В целом полностью аналогично созданию для peer-to-peer за исключением использования других endpoint естественно
export VAULT_ADDR=http://vault.home:8200
export VAULT_TOKEN=...
domain="etcd.az1.k8s.home"
mkdir -p ./client_crt
vault \
write \
-format=json pki_intermediate_ca/issue/etc-az-k8s-home-server-only-crt \
common_name="${domain}" \
ttl="43800h" > ./client_crt/${domain}.crt.json
mkdir -p ./client_only_crt
vault \
write \
-format=json pki_intermediate_ca/issue/etc-az-k8s-home-client-only-crt \
common_name="${domain}" \
ttl="43800h" > ./client_only_crt/${domain}.crt.json
и аналогично с помощью jq достать сами сертификаты и ключи
Тестовый запуск c Client SSL
Systemd Unit File
Юнит файлы требуют доработки - вынести в конфиги весь хардкод
- /etc/systemd/system/etcd.service
[Unit]
Description=etcd
Documentation=https://github.com/coreos
[Service]
Type=notify
LimitNOFILE=65536
Environment=ETCD_UNSUPPORTED_ARCH=arm
ExecStart=/usr/bin/etcd \
--debug \
--name=etcd-az-1 \
--listen-peer-urls=https://10.240.1.2:2380 \
--listen-client-urls=https://10.240.1.2:2379,https://127.0.0.1:2379 \
--advertise-client-urls=https://etcd.az1.k8s.home:2379 \
--initial-advertise-peer-urls=https://etcd.az1.k8s.home:2380 \
--initial-cluster-token=etcd.az1.k8s.home \
--initial-cluster etcd-az-1=https://etcd.az1.k8s.home:2380,etcd-az-2=https://etcd.az2.k8s.home:2380,etcd-az-3=https://etcd.az3.k8s.home:2380 \
--initial-cluster-state=new \
--data-dir=/var/lib/etcd \
--peer-client-cert-auth \
--peer-cert-file=/etc/etcd/certs/server/etcd.az1.k8s.home.pem \
--peer-key-file=/etc/etcd/certs/server/etcd.az1.k8s.home.key \
--peer-trusted-ca-file=/etc/etcd/certs/rootCA.pem \
--trusted-ca-file=/etc/etcd/certs/rootCA.pem \
--cert-file=/etc/etcd/certs/client/etcd.az1.k8s.home.pem \
--key-file=/etc/etcd/certs/client/etcd.az1.k8s.home.key \
--client-cert-auth
Restart=on-failure
RestartSec=60
[Install]
WantedBy=multi-user.target
Alias=etcd-server.service
Общие параметры
- --debug
- --name=etcd-az-1 Имя ноды кластера - должно быть одним из содержащихся в параметре --initial-cluster На каждой ноде это имя отличается
- --data-dir =/var/lib/etcd
- --listen-peer-urls=https://10.240.1.2:2380 адрес для peer-to-peer коммуникации
- --listen-client-urls=https://10.240.1.2:2379,https://127.0.0.1:2379 - адрес для клиентов (https допустим только при наличии сертификатов)
- --advertise-client-urls=https://etcd.az1.k8s.home:2379
Параметры кластера
- --initial-advertise-peer-urls =https://etcd.az1.k8s.home:2380
- --initial-cluster-token=etcd.az1.k8s.home - начальный токен, ЭТОТ ТОКЕН ОБЩИЙ ДЛЯ ВСЕХ НОД иначе вместо одного кластера из 3 нод будет создано три неполных кластера из одной ноды каждый
- --initial-clusteretcd-az-1=https://etcd.az1.k8s.home:2380,etcd-az-2=https://etcd.az2.k8s.home:2380,etcd-az-3=https://etcd.az3.k8s.home:2380 список нод кластера вместе с именами, этот список общий для всех нод
- --initial-cluster-state=new
Параметры SSL для peer-to-peer
- --peer-client-cert-auth
- --peer-cert-file =/etc/etcd/certs/server/etcd.az1.k8s.home.pem
- --peer-key-file =/etc/etcd/certs/server/etcd.az1.k8s.home.key
- --peer-trusted-ca-file =/etc/etcd/certs/rootCA.pem
Параметры SSL для клиентских подключений
- --trusted-ca-file=/etc/etcd/certs/rootCA.pem
- --cert-file=/etc/etcd/certs/client/etcd.az1.k8s.home.pem
- --key-file=/etc/etcd/certs/client/etcd.az1.k8s.home.key
- --client-cert-auth
Проверка подключения клиента с использованием SSL
#!/bin/bash
export ETCDCTL_API=3\
etcdctl \
--debug \
--endpoints=https://etcd.az1.k8s.home:2379 \
--cert=/root/k8s/etcd/client_only_crt/etcd.az1.k8s.home.pem \
--key=/root/k8s/etcd/client_only_crt/etcd.az1.k8s.home.key \
member list
INFO: 2021/10/23 14:16:04 parsed scheme: ""
INFO: 2021/10/23 14:16:04 scheme "" not registered, fallback to default scheme
INFO: 2021/10/23 14:16:04 ccResolverWrapper: sending new addresses to cc: [{etcd.az1.k8s.home:2379 0 <nil>}]
INFO: 2021/10/23 14:16:04 balancerWrapper: got update addr from Notify: [{etcd.az1.k8s.home:2379 <nil>}]
INFO: 2021/10/23 14:16:04 clientv3/balancer: pin "etcd.az1.k8s.home:2379"
INFO: 2021/10/23 14:16:04 balancerWrapper: got update addr from Notify: [{etcd.az1.k8s.home:2379 <nil>}]
b7a875ba8d83c06, started, etcd-az-3, https://etcd.az3.k8s.home:2380, https://etcd.az3.k8s.home:2379 489c4054ed342d1a, started, etcd-az-2, https://etcd.az2.k8s.home:2380, https://etcd.az2.k8s.home:2379 db4ea93d7a019672, started, etcd-az-1, https://etcd.az1.k8s.home:2380, https://etcd.az1.k8s.home:2379
В целом можно сказать что авьторизация возможна
- с клиентским сертификатом
- c сертификатом сервера для peer-to-peer (кстати эту возможность вероятно надо отключить как-то)
С сертификатом для клиентских подключения, который используется со стороны сервера, клиент подключиться не сможет
WARNING: 2021/10/23 14:15:46 grpc: addrConn.createTransport failed to connect to {etcd.az2.k8s.home:2379 0 <nil>}. Err :connection error: desc = "transport: authentication handshake failed: x509: certificate specifies an incompatible key usage". Reconnecting...
Разграничение прав, роли пользователи и авторизация по сертефикатам
TBD