Vault PKI Intermediate CAs for ALL SERVICES Kubernetes the hard way v2: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
Строка 98: Строка 98:
 
* <code>--tls-cert-file</code>
 
* <code>--tls-cert-file</code>
 
* <code>--tls-private-key-file</code>
 
* <code>--tls-private-key-file</code>
Этот сертификат выпускается <code>k8s_pki_intermediate_ca_for_service_kube_apiserver_tls/<code>
+
Этот сертификат выпускается <code>k8s_pki_intermediate_ca_for_service_kube_apiserver_tls/</code>
  +
  +
<PRE>
  +
netstat -ntpl| grep kube-api
  +
tcp 0 0 10.0.12.1:6443 0.0.0.0:* LISTEN 85224/kube-apiserve
  +
<PRE>
  +
<PRE>
  +
openssl s_client -connect 10.0.12.1:6443
  +
  +
...
  +
  +
depth=2 C = Ukraine, L = Kharkov, street = app. 131 + street = Lui Pastera St. 322, postalCode = 61172, O = Home Network, OU = IT, CN = Root Certificate Authority for Home Network v2
  +
verify return:1
  +
depth=1 C = Ukraine, L = Kharkov, street = Lui Pastera st. 322 app. 131, O = K8s The Hardest Way Labs, OU = IT, CN = Intermediate CA for service kube-apiserver TLS
  +
verify return:1
  +
depth=0 C = Ukraine, L = Kharkov, street = Lui Pastera st. 322 app. 131, O = K8s The Hardest Way Labs, OU = IT, CN = kube-apiserver.az1.k8s.cluster.home
  +
verify return:1
  +
</code>
   
 
==<code>kube-controller-manager</code> TLS CA==
 
==<code>kube-controller-manager</code> TLS CA==

Версия 11:56, 15 ноября 2022


Эта страница - часть большой статьи про CA используемые в k8s: Vault_PKI_Kubernetes_the_hard_way_v2


Некоторые термины

  • CA: certificate authority или certification authority ( на русском это звучит как Центр Сертефикации)

В контексте документа может иметь несколько возможных значений - как собственно центр выпуска сертификатов, так и сам корневой (или промежуточный сертификат) этого центра. По сути, сертификат СА, который используется для подписания клиентских и серверных сертификатом не только не является секретным, но наоборот должен быть доступен для доступа так как именно он используется для проверки валидности выпущенных сертификатов

В случае с PKI на основе Vault СA доступны для скачивания без авторизации.



Есть 2 типа сертификатов (конечно их больше но в K8s используется 2 типа). Потому в целом (кроме etcd) есть разделение СА в том числе и по типу выпускаемых сертификатов

  • client_auth - этот суффикс у СА используется в значении "сертификаты используются для авторизации" (другими словами - не используются для организации http)
  • tls - этот суффикс у СА используется в значении "сертификаты используются для организации https/TLS"

Создание СА для работы кластера K8s

K8s использует СА для выписывания сертификатов 2 типов

  • "Обычные" серверные сертификаты (CN = domain)
  • Сертификаты используемые для авторизации - клиентские (CN=username, O=groupname)


Всего в Vault настроены такие СА:

k8s_pki_intermediate_ca_for_service_etcd/                           pki          pki_13a87e77          PKI Intermediate CA for ETCd service
k8s_pki_intermediate_ca_for_service_kube_apiserver_client_auth/     pki          pki_622072da          PKI Intermediate CA for K8S: kube-apiserver CLIENT_AUTH
k8s_pki_intermediate_ca_for_service_kube_apiserver_tls/             pki          pki_d8737474          PKI Intermediate CA for K8S: kube-apiserver TLS
k8s_pki_intermediate_ca_for_service_kube_controller_manager_tls/    pki          pki_34a63553          PKI Intermediate CA for K8S: kube-controller-manager TLS
k8s_pki_intermediate_ca_for_service_kube_scheduler_tls/             pki          pki_5b5f53f5          PKI Intermediate CA for K8S: kube-scheduler TLS
k8s_pki_intermediate_ca_for_service_kubelet_client_auth/            pki          pki_4f1df8fd          PKI Intermediate CA for K8S: kubelet CLIENT_AUTH
k8s_pki_intermediate_ca_for_service_kubelet_tls/                    pki          pki_47e7182a          PKI Intermediate CA for K8S: kubelet TLS
k8s_pki_root_ca/                                                    pki          pki_8b6cae1e          PKI k8s Root CA

Полный список СА (промежуточных СА!)

Всего существует 8 СА которые используются в этой инсталляции (один из них - корневой СА).
Если верить документации, то это не предел - каждый файл с CA в настройках сервисов может содержать
более одного сертификата, другими словами 2 процесса kube-apiserver вполне могут использовать разные CA

В частных случаях можно упростить настройку, и вообще использовать 1 СА
Эта инсталляция подразумевает настойку PKI средней сложности, что бы не переусложнять.

k8s_pki_intermediate_ca_for_service_etcd/

k8s_pki_intermediate_ca_for_service_etcd/ - используется для клиентских и серверных сертификатов etcd. Строго говоря, не является частью k8s и настраивается отдельно (Настройка PKI для etcd)

  • для шифрования endpoints
  • для авторизации клиентов

k8s_pki_intermediate_ca_for_service_kube_apiserver_client_auth/ k8s_pki_intermediate_ca_for_service_kube_apiserver_tls/

  • k8s_pki_intermediate_ca_for_service_kube_apiserver_client_auth/ - используется для клиентских сертефикатов kube-apiserver, по которым API проверяет права пользователей.
  • k8s_pki_intermediate_ca_for_service_kube_apiserver_tls/ Используется для обеспечения https при подключении к kube-apiserver. При этом происходит двухсторонняя проверка
    • Все клиенты (как сервисы, часть k8s, например kube-controller-manager, kube-scheduler так и kubectl для администрирования) должны обладать CA (который как и прочие СА не является секретным), для того что бы иметь возможность проверить кластер, другими словами быть уверенным в том что подключаются туда куда ожидают.

Часть kubeconfig отвечающая за этот сертификат:

clusters:
- cluster:
    certificate-authority: /etc/k8s/shared/certs/CA/k8s_pki_intermediate_ca_for_service_kube_apiserver_tls.pem
    server: https://kube-apiserver.k8s.cluster.home:443
    • Со своей стороны сервер проверяет как то что сертефикат клиента подписан правильным СА (k8s_pki_intermediate_ca_for_service_kube_apiserver_client_auth/), так и поля CN O в сертификате, которые используются как имя пользователя и группа. Имена групп выбраны не случайно - для них уже есть (или можно создать свои!) ClusterRoleBindings

k8s_pki_intermediate_ca_for_service_kube_controller_manager_tls/

  • k8s_pki_intermediate_ca_for_service_kube_controller_manager_tls/ - используется для обеспечения https, серверные сетефикаты

k8s_pki_intermediate_ca_for_service_kube_scheduler_tls/

  • k8s_pki_intermediate_ca_for_service_kube_scheduler_tls/ - используется для обеспечения https, серверные сетефикаты

k8s_pki_intermediate_ca_for_service_kubelet_client_auth/ k8s_pki_intermediate_ca_for_service_kubelet_tls/

  • k8s_pki_intermediate_ca_for_service_kubelet_client_auth/ kubelet в целом устроен аналогично kube-api серверу, и использует 2 СА - один для авторизации клиентов (в случае с kubelet клиентом выступает kube-apiserver), а второй используется для обеспечения https
    • У kube-apiserver есть настройка --kubelet-certificate-authority - это файлс СА для k8s_pki_intermediate_ca_for_service_kubelet_tls/, таким образом kube-apiserver может точно знать что он обращается к нужному kubelet, так как его серверный сертефикат подписан этим СА
    • --kubelet-client-certificate--kubelet-client-key содрежат сертификат, выписанный помощью СА k8s_pki_intermediate_ca_for_service_kubelet_client_auth/ и содержат имя пользователя и группу с которыми kube-apiserver авторизуется у kubelet


Например: O = system:masters, OU = system, CN = kube-apiserver-to-kubelet

При этом по-умолчанию соответствующие ClustetRoleBinding отсутствуют, и перед подключением kubele их требуется создать дополнительно. (эта часть настройки выполняется при конфигурировании kube-apiserver


  • k8s_pki_intermediate_ca_for_service_kubelet_tls/ - используется для обеспечения https, серверные сетефикаты

k8s_pki_root_ca/

  • k8s_pki_root_ca/ - это корневой СА которым подписаны все промежуточные СА, и его сертификат СА обязательно требуется распространить по всем хостам так как он является полностью доверенным (в пределах этой инсталляции, конечно)

TLS CA

Для того что бы предоставлять API по https нужны следующие СА

kube-apiserver TLS CA

Для обеспечения https доступа к API используются 2 параметра - файл сертефиката и файл ключа

  • --tls-cert-file
  • --tls-private-key-file

Этот сертификат выпускается k8s_pki_intermediate_ca_for_service_kube_apiserver_tls/

netstat  -ntpl| grep kube-api
tcp        0      0 10.0.12.1:6443          0.0.0.0:*               LISTEN      85224/kube-apiserve
<PRE>
<PRE>
openssl s_client -connect  10.0.12.1:6443

...

depth=2 C = Ukraine, L = Kharkov, street = app. 131 + street = Lui Pastera St. 322, postalCode = 61172, O = Home Network, OU = IT, CN = Root Certificate Authority for Home Network v2
verify return:1
depth=1 C = Ukraine, L = Kharkov, street = Lui Pastera st. 322 app. 131, O = K8s The Hardest Way Labs, OU = IT, CN = Intermediate CA for service kube-apiserver TLS
verify return:1
depth=0 C = Ukraine, L = Kharkov, street = Lui Pastera st. 322 app. 131, O = K8s The Hardest Way Labs, OU = IT, CN = kube-apiserver.az1.k8s.cluster.home
verify return:1
</code>

==<code>kube-controller-manager</code> TLS CA==
* <code>--tls-cert-file</code>
* <code>--tls-private-key-file</code>

==<code>kube-scheduler</code>TLS CA==
--tls-cert-file
--tls-private-key-file

==<code>kubelet</code> TLS CA==
* <code>tlsCertFile</code>
* <code>tlsPrivateKeyFile</code>


This parameter should be set via the config file specified by the Kubelet's --config
<PRE>
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
...
tlsCertFile: "/etc/k8s/kubelet/tls/kubelet.az1.k8s.home.pem"
tlsPrivateKeyFile: "/etc/k8s/kubelet/tls/kubelet.az1.k8s.home.key"
authorizationMode: Node,RBAC

Client CA

СА для TLS

Отдельный СА (промежуточный СА!)
Переменные вынесены в отдельный файл

env
export VAULT_ADDR=http://127.0.0.1:8200
export VAULT_TOKEN="s.Yb1J2VamFyYoav3VVE2YQQ88"
export PKI_PATH="k8s_pki_intermediate_ca_for_service_kube_apiserver_tls"
export N='kube-apiserver'

Настройка СА

#!/bin/bash

source ../env

vault \
  secrets \
    enable \
      -path=${PKI_PATH} \
      -description="PKI Intermediate CA for K8S kube-apiserver API endpoints" \
      -max-lease-ttl="175200h" \
    pki
#!/bin/bash

source ../env

vault \
  write \
    -format=json \
     ${PKI_PATH}/intermediate/generate/exported \
     common_name="Intermediate CA for service kube-api-server API endpoints" \
     country="Ukraine" \
     locality="Kharkov" \
     street_address="Lui Pastera st. 322 app. 131" \
     postal_code="61172" \
     organization="K8s The Hardest Way Labs" \
     ou="IT" \
     ttl="175200h" > ${PKI_PATH}.json


cat ${PKI_PATH}.json | jq -r '.data.csr' > ${PKI_PATH}_intermediate_ca.csr
cat ${PKI_PATH}.json | jq -r '.data.private_key' > ${PKI_PATH}_intermediate_ca.key
#!/bin/bash

source ../env

vault \
  write \
    -format=json \
    k8s_pki_root_ca/root/sign-intermediate \
    csr=@${PKI_PATH}_intermediate_ca.csr \
    country="Ukraine" \
    locality="Kharkov" \
    street_address="Lui Pastera st. 322 app. 131" \
    postal_code="61172" \
    organization="K8s The Hardest Way Labs" \
    ou="IT" \
    format=pem_bundle \
    ttl="175200h" > ${PKI_PATH}_intermediate_ca_pem_bundle.json


cat ${PKI_PATH}_intermediate_ca_pem_bundle.json | jq -r '.data.certificate' > ${PKI_PATH}_intermediate_ca_pem.crt
cat ${PKI_PATH}_intermediate_ca_pem_bundle.json | jq -r '.data.issuing_ca'  > k8s_root_certificate.pem
#!/bin/bash

source ../env

openssl \
    verify \
    -verbose \
     -CAfile k8s_root_certificate.pem \
    ${PKI_PATH}_intermediate_ca_pem.crt
#!/bin/bash

source ../env

vault \
    write \
    ${PKI_PATH}/intermediate/set-signed \
    certificate=@${PKI_PATH}_intermediate_ca_pem.crt \
    key=@${PKI_PATH}_intermediate_ca.key

Права, пользователи, роли

Далее назначить права на пользователей для каждого экземпляра сервера

#!/bin/bash

source ../env

N='kube-apiserver'
for AZ in $(seq 1 3);
do
    DOMAIN="${N}.az${AZ}.k8s.cluster.home"
    BALANCER_DOMAIN="${N}.k8s.cluster.home"
    NAME_SERVER="${DOMAIN}-server"
    NAME_CLIENT="${DOMAIN}-client"


    vault \
        write \
            ${PKI_PATH}/roles/${NAME_SERVER}-role \
            country="Ukraine" \
            locality="Kharkov" \
            street_address="Lui Pastera st 322 app. 311"\
            postal_code="61172" \
            organization="Home Network" \
            ou="IT" \
            allowed_domains="${DOMAIN},${BALANCER_DOMAIN}" \
            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" \
            require_cn=true

    vault \
        write \
            ${PKI_PATH}/roles/${NAME_CLIENT}-role \
            country="Ukraine" \
            locality="Kharkov" \
            street_address="Lui Pastera st 322 app. 311"\
            postal_code="61172" \
            organization="Home Network" \
            ou="IT" \
            allow_subdomains=false \
            max_ttl="87600h" \
            key_bits="2048" \
            key_type="rsa" \
            allow_any_name=true \
            allow_bare_domains=true \
            allow_glob_domain=false \
            allow_ip_sans=true \
            allow_localhost=false \
            client_flag=true \
            server_flag=false \
            enforce_hostnames=true \
            key_usage="DigitalSignature,KeyEncipherment" \
            ext_key_usage="ClientAuth" \
            require_cn=true
done
#!/bin/bash

source ../env

N='kube-apiserver'
for AZ in $(seq 1 3);
do
    DOMAIN="${N}.az${AZ}.k8s.cluster.home"
    NAME_SERVER="${DOMAIN}-server"
    NAME_CLIENT="${DOMAIN}-client"

    cat << EOF > ${NAME_SERVER}-policy.hlc
path "${PKI_PATH}/issue/${NAME_SERVER}-role"
{
  capabilities = ["read", "create", "list", "update"]
}
EOF

    vault \
        policy \
            write \
                ${NAME_SERVER}-policy \
                 ${NAME_SERVER}-policy.hlc
    vault \
        write \
            auth/userpass/users/${NAME_SERVER}-user \
            password=${NAME_SERVER}-password \
            policies=" ${NAME_SERVER}-policy,default"



    cat << EOF > ${NAME_CLIENT}-policy.hlc
path "${PKI_NAME}/issue/${NAME_CLIENT}-role"
{
  capabilities = ["read", "create", "list", "update"]
}
EOF

    vault \
        policy \
            write \
                ${NAME_CLIENT}-policy \
                 ${NAME_CLIENT}-policy.hlc
    vault \
        write \
            auth/userpass/users/${NAME_CLIENT}-user \
            password=${NAME_CLIENT}-password \
            policies=" ${NAME_CLIENT}-policy,default"


done
#!/bin/bash

source ../env

echo "---------ROLES---------------------"
vault \
    list \
        ${PKI_PATH}/roles
echo "---------USERS---------------------"
vault \
    list \
        auth/userpass/users
echo "------------------------------"


for AZ in $(seq 1 3);
do
    echo "------ AZ ${AZ} -----"
    DOMAIN="${N}.az${AZ}.k8s.cluster.home"
    NAME_SERVER="${DOMAIN}-server"
    NAME_CLIENT="${DOMAIN}-client"

    vault \
        policy \
            read \
                ${NAME_SERVER}-policy

    vault \
        policy \
            read \
                ${NAME_CLIENT}-policy

    vault \
        read \
            auth/userpass/users/${NAME_SERVER}-user
    vault \
        read \
            auth/userpass/users/${NAME_SERVER}-user

done

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

на конечных нодах используя имя пользователя и пароль а так же переменную AZ определнную на нодах индивидуально (Сертефикаты для kube-apiserver --tls-cert-file и --tls-private-key-file)

#!/bin/bash

set -eu${DEBUG:+x}

PKI_NAME="k8s_pki_intermediate_ca_for_service_kube_apiserver_tls"
CERTS_PATH="/etc/k8s/kube-apiserver/certs/tls"
mkdir -p ${CERTS_PATH}

N='kube-apiserver'
#AZ=1
DOMAIN="${N}.az${AZ}.k8s.cluster.home"
NAME_SERVER="${DOMAIN}-server"
NAME_CLIENT="${DOMAIN}-client"
BALANCER_DOMAIN="${N}.k8s.cluster.home"
IP="10.0.${AZ}2.1"
vault \
    login \
    -method=userpass \
    username="${NAME_SERVER}-user" \
    password="${NAME_SERVER}-password"


    DATE=$(date +%Y%m%dT%H%M)
    USERNAME="${N}-${AZ}-tls"

echo "========"
vault \
    write \
    -format=json \
    ${PKI_NAME}/issue/${NAME_SERVER}-role \
    common_name="${DOMAIN}" \
    alt_names="${DOMAIN},${BALANCER_DOMAIN}" \
    ip_sans="${IP}" \
    ca=false \
    ttl="43800h" \
    > ${CERTS_PATH}/${USERNAME}.crt.json

cat \
    ${CERTS_PATH}/${USERNAME}.crt.json \
    | jq -r '.data.private_key' > ${CERTS_PATH}/${USERNAME}-${DATE}.key

cat \
    ${CERTS_PATH}/${USERNAME}.crt.json \
    | jq -r '.data.certificate' > ${CERTS_PATH}/${USERNAME}-${DATE}.pem

cat \
    ${CERTS_PATH}/${USERNAME}.crt.json \
    | jq -r '.data.ca_chain[]' >> ${CERTS_PATH}/${USERNAME}-${DATE}.pem

ln -sf  ${CERTS_PATH}/${USERNAME}-${DATE}.key  ${CERTS_PATH}/${N}-tls.key
ln -sf  ${CERTS_PATH}/${USERNAME}-${DATE}.pem  ${CERTS_PATH}/${N}-tls.pem

СA для клиентов kube-apiserver