Vault PKI Intermediate CAs for ALL SERVICES Kubernetes the hard way v2

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


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

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



Задача - настроить промежуточные СА для всех сервисов k8s

Забегая вперед, отмечу что

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

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

Всего в 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/ - используется для клиентских и серверных сертификатов etcd. Строго говоря, не является частью k8s и настраивается отдельно (Настройка PKI для etcd)
    • для шифрования endpoints
    • для авторизации клиентов
  • 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/ - используется для обеспечения https, серверные сетефикаты
  • k8s_pki_intermediate_ca_for_service_kube_scheduler_tls/ - используется для обеспечения https, серверные сетефикаты
  • 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/

TLS CA

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

kube-apiserver TLS CA

--tls-cert-fil --tls-private-key-file

kube-controller-manager TLS CA

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

kube-schedulerTLS CA

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

kubelet TLS CA

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

This parameter should be set via the config file specified by the Kubelet's --config

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