Büyük ihtimalle yazı dizisinin en uzun makalesi bu olacak. Uzun sebebi fazla komut olması değil aslında, sertifikaları oluştururken kullanığımız json konfigürasyon dosyalarını biraz uzun olmasından kaynaklarnıyor.
Daha önce CFSSL kurulumunu yaptığımız bölümde de bahsetmiştim ancak tekrarda fayda vardır diyerek hatırlatmak istiyorum. Eğer PKI ve TLS hakkında yetersiz olduğunuzu düşünüyorsanız Gökhan Şengün'ün "Pratik Kriptogafi ve Güvenlik Konseptleri" başlıklı sunumunu izlemenizi kesinlikle tavsiye ederim.
Sırasıyla şu işlemleri gerçekleştiriyor olacağız.
- CA (Certificate Authoirty) oluşturacağız.
- Daha sonra her bir bileşen ve makina için CSR (Certificate Signing Request) oluşturacağız.
- Ve son olarak CSR kullanak TLS sertifikalarımızı CA ile imzalayıp oluşturuyor olacağız.
Sertifikaları oluştururken kullanılan bazı kısaltmalar ve anlamları.
- Country (countryName, C),
- Organization (organizationName, O),
- Organizational unit (organizationalUnitName, OU),
- Distinguished name qualifier (dnQualifier),
- State or province name (stateOrProvinceName, ST),
- Common name (commonName, CN) and
- Serial number (serialNumber)
Kubernetes resmi sayfasından sertifikaların kullanımı ve best practice'ler hakkında bilgi almak için Kubernetes resm isayafasını ziyaret edebilirsiniz.
Örneğin Kubernetes API servisine ulaşmak için kullanılan kubectl veya bir client library kimlik doğrulamasından sonra API'yi kullanılabilecektir. Bu süreç için de sertifikaya ihtiyaç duyulacaktır. Aşağıdaki şekilde bu süreç gösterilmiştir.
Daha fazla bilgi için şu sayfayı ziyeret ediniz.
Setifikaları host makinamızda oluşturduktan sonra makinalarımıza taşıyacağız.
Windows kullanıcıları
- Ya CFSSL kurulumunda bahsettiğim gibi lb-01 makinası üzerinden sertifikaları oluşturabilirler. Altta unix tabanlı sistemler için yazılan komutları doğrudan kullanabilirsiniz.
- Windows'la devam edecekseniz powershell için burada örneğini vereceğim şekilde sertifikaları oluşturabilirsiniz. Komutlar powershell core 7.2 versiyonunda test edilmiştir.
Linux ve Mac için
mkdir ~/kubernetes && cd ~/kubernetes
cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"kubernetes": {
"usages": ["signing", "key encipherment", "server auth", "client auth"],
"expiry": "8760h"
}
}
}
}
EOF
cat > ca-csr.json <<EOF
{
"CN": "Kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "Kubernetes",
"OU": "CA",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
Windows için
mkdir ~/kubernetes
cd ~/kubernetes
@'
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"kubernetes": {
"usages": ["signing", "key encipherment", "server auth", "client auth"],
"expiry": "8760h"
}
}
}
}
'@ | tee ca-config.json
@'
{
"CN": "Kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "Kubernetes",
"OU": "CA",
"ST": "Oregon"
}
]
}
'@ | tee ca-csr.json
.\cfssl_windows-amd64.exe gencert -initca ca-csr.json | .\cfssljson_windows-amd64.exe -bare ca
Sonuç olarak 2 adet pem dosyası oluşmuş olmalıdır.
- ca-key.pem
- ca.pem
Linux ve Mac için
cat > admin-csr.json <<EOF
{
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:masters",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
admin-csr.json | cfssljson -bare admin
Windows İçin
@'
{
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:masters",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
'@ | tee admin-csr.json
.\cfssl_windows-amd64.exe gencert `
-ca="ca.pem" `
-ca-key="ca-key.pem" `
-config="ca-config.json" `
-profile="kubernetes" `
admin-csr.json | .\cfssljson_windows-amd64.exe -bare admin
Sonuç olarak 2 adet pem dosyası oluşmuş olmalıdır.
- admin-key.pem
- admin.pem
Kubernetes, Kubelets tarafından yapılan API isteklerini özel olarak yetkilendiren "Node Authorizer" adlı özel amaçlı bir yetkilendirme modu kullanır. Node Authorizer tarafından yetkilendirilmek için Kubelets'ler, system:nodes grubunda olduklarını gösteren ve kullanıcı adı system:node: olan bir kullanıcı adıyla kullanılmalıdır.
Bu bölümde, "Node Authorizer" gereksinimlerini karşılayan her Kubernetes worker nodu için sertifika oluşturuyor olacağız.
Bizde makinaların external ip adresleri olamadığı için sertifikaları sadece internal domain ve makina adları için oluşturyoruz.
Linux LXC için Ip adreslerini otomatik almak isterseniz
for instance in worker-01 worker-02 worker-03; do
cat > ${instance}-csr.json <<EOF
{
"CN": "system:node:${instance}",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:nodes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
INTERNAL_IP=$(lxc info ${instance} | grep eth0 | head -1 | awk '{print $3}')
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-hostname=${instance},${INTERNAL_IP} \
-profile=kubernetes \
${instance}-csr.json | cfssljson -bare ${instance}
done
SSH ile bağlanıldığında ip listesi ile
INTERNAL_IP=
WORKER=
WORKERS=(worker-01,10.240.10.7 worker-02,10.240.10.8 worker-03,10.240.10.9)
for i in "${WORKERS[@]}" ; do
KEY=${i%,*};
VAL=${i#*,};
INTERNAL_IP=$VAL;
WORKER=$KEY;
cat > ${WORKER}-csr.json <<EOF
{
"CN": "system:node:${WORKER}",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:nodes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-hostname=${instance},${INTERNAL_IP} \
-profile=kubernetes \
${WORKER}-csr.json | cfssljson -bare ${WORKER}
done
Windows için
$instances = @{"worker-01"="10.240.10.7"; "worker-02"="10.240.10.8";"worker-03"="10.240.10.9"}
foreach ($key in $instances.keys)
{
$instance=$key
$internal_ip=$instances[$key]
#Write-Host $internal_ip
#Write-Host $instance
@'
{
"CN": "system:node:$instance",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:nodes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
'@ | tee $instance-csr.json
.\cfssl_windows-amd64.exe gencert `
-ca="ca.pem" `
-ca-key="ca-key.pem" `
-config="ca-config.json" `
-hostname="$instance ,$internal_ip" `
-profile="kubernetes" `
$instance-csr.json | .\cfssljson_windows-amd64.exe -bare $instance
}
sonuçta 6 adet pem dosyası oluşmuş olmalıdır.
- worker-01-key.pem
- worker-01.pem
- worker-02-key.pem
- worker-02.pem
- worker-03-key.pem
- worker-03.pem
Linux ve Mac için
cat > kube-controller-manager-csr.json <<EOF
{
"CN": "system:kube-controller-manager",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:kube-controller-manager",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
Windows için
@'
{
"CN": "system:kube-controller-manager",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:kube-controller-manager",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
'@ | tee kube-controller-manager-csr.json
.\cfssl_windows-amd64.exe gencert `
-ca="ca.pem" `
-ca-key="ca-key.pem" `
-config="ca-config.json" `
-profile="kubernetes" `
kube-controller-manager-csr.json | .\cfssljson_windows-amd64.exe -bare kube-controller-manager
Sonuçta 2 adet pem dosyası oluşmuş olmalıdır.
- kube-controller-manager-key.pem
- kube-controller-manager.pem
Linux ve Mac için
cat > kube-proxy-csr.json <<EOF
{
"CN": "system:kube-proxy",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:node-proxier",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
kube-proxy-csr.json | cfssljson -bare kube-proxy
Windows için
@'
{
"CN": "system:kube-proxy",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:node-proxier",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
'@ | tee kube-proxy-csr.json
.\cfssl_windows-amd64.exe gencert `
-ca="ca.pem" `
-ca-"key=ca-key.pem" `
-config="ca-config.json" `
-profile="kubernetes" `
kube-proxy-csr.json | .\cfssljson_windows-amd64.exe -bare kube-proxy
Sonuçta 2 adet pem dosyası oluşmuş olmalıdır.
- kube-proxy-key.pem
- kube-proxy.pem
Linux ve Mac için
cat > kube-scheduler-csr.json <<EOF
{
"CN": "system:kube-scheduler",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:kube-scheduler",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
kube-scheduler-csr.json | cfssljson -bare kube-scheduler
Windows için
@'
{
"CN": "system:kube-scheduler",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:kube-scheduler",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
'@ | tee kube-scheduler-csr.json
.\cfssl_windows-amd64.exe gencert `
-ca="ca.pem" `
-ca-key="ca-key.pem" `
-config="ca-config.json" `
-profile="kubernetes" `
kube-scheduler-csr.json | .\cfssljson_windows-amd64.exe -bare kube-scheduler
Sonuçta 2 adet pem dosyası oluşmuş olmalıdır.
- kube-scheduler-key.pem
- kube-scheduler.pem
Bu kısımda belirttiğimiz ip adresleri ve domain name'ler biaz kafa karıştırıcı olabiliyor. Aslında çok basit bir mantığı var. Şöyleki Kubernetes API'sine ulaşabilecek tüm istemcilerin bilgisini sertifikaya belirtiyoruz. Çünkü örneğin load balancer'lar üzerinden kubernetes API'si çağrıldığında sertifikanın load balancer hostname'i veya ip'si üzerinden cevap verebilmesi gerekiyor. Detaylar için şu sayfayı ziyaret ediniz.
KUBERNETES_PUBLIC_ADDRESS değişkeni ile load balancer ip adreslerimizi veriyoruz. aslında bizim kurgumuzda bu ip adresleri iç ip aralığında ancak mantığın oluşması adına kaynaklarda geçtiği üzere public ip olarak ekledik. Çünki gerçek ortamlarda bu makinaların yada load balancer cihazının iç sunuculardan olmama ihtimali daha büyük. Ayrıca VIP (10.240.10.10) adresimizi de ekliyoruz.
Diğer dikkat edilmesi gereken bir husus da "kubernetes" domain adının API'ye atanması ve ileride "Control Pane" oluşturulurken vereceğimiz servis ip aralığındaki ilk ip olan 10.32.0.1 ip'si ile bağlanmasıdır. Bu nedenle sertifika hostname'ine bu ip'yi de ekliyoruz.
Linux ve Mac için
KUBERNETES_PUBLIC_ADDRESS=10.240.10.2,lb-01,10.240.10.3,lb-02,10.240.10.10
KUBERNETES_HOSTNAMES=kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster,kubernetes.svc.cluster.local
CONTROLLER_ADDRESS=10.240.10.4,controller-01,10.240.10.5,controller-02,10.240.10.6,controller-03
cat > kubernetes-csr.json <<EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "Kubernetes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-hostname=10.32.0.1,${CONTROLLER_ADDRESS},${KUBERNETES_PUBLIC_ADDRESS},127.0.0.1,${KUBERNETES_HOSTNAMES} \
-profile=kubernetes \
kubernetes-csr.json | cfssljson -bare kubernetes
Windows için
$KUBERNETES_PUBLIC_ADDRESS="10.240.10.2,lb-01,10.240.10.3,lb-02,10.240.10.10"
KUBERNETES_HOSTNAMES="kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster,kubernetes.svc.cluster.local"
$CONTROLLER_ADDRESS="10.240.10.4,controller-01,10.240.10.5,controller-02,10.240.10.6,controller-03"
@'
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "Kubernetes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
'@ | tee kubernetes-csr.json
.\cfssl_windows-amd64.exe gencert `
-ca="ca.pem" `
-ca-key="ca-key.pem" `
-config="ca-config.json" `
-hostname="10.32.0.1,$CONTROLLER_ADDRESS,$KUBERNETES_PUBLIC_ADDRESS,127.0.0.1,$KUBERNETES_HOSTNAMES" `
-profile="kubernetes" `
kubernetes-csr.json | .\cfssljson_windows-amd64.exe -bare kubernetes
Sonuçta 2 adet pem dosyası oluşmuş olmalıdır.
- kubernetes-key.pem
- kubernetes.pem
Controller manager hizmet hesabı oluşturmak ve imzalamak için key pair'e ihtiyaç duyar. Bunun için sertifika oluşturmamız gerekiyor. Detaylar için şu sayfayı ziyaret ediniz.
cat > service-account-csr.json <<EOF
{
"CN": "service-accounts",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "Kubernetes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
service-account-csr.json | cfssljson -bare service-account
Windows için
@'
{
"CN": "service-accounts",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "Kubernetes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
'@ | tee service-account-csr.json
.\cfssl_windows-amd64.exe gencert `
-ca="ca.pem" `
-ca-key="ca-key.pem" `
-config="ca-config.json" `
-profile="kubernetes" `
service-account-csr.json | .\cfssljson_windows-amd64.exe -bare service-account
Sonuçta 2 adet pem dosyası oluşmuş olmalıdır.
- service-account-key.pem
- service-account.pem
LXC kullananlar için
Uygun sertifika ve private key'leri worker makinalarımıza kopyalıyoruz.
for instance in worker-01 worker-02 worker-03; do
lxc file push ca.pem ${instance}-key.pem ${instance}.pem ${instance}/home/ubuntu/
done
Uygun sertifika ve private key'leri controller makinalarımıza kopyalıyoruz.
for instance in controller-01 controller-02 controller-03; do
lxc file push ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
service-account-key.pem service-account.pem ${instance}/home/ubuntu/
done
(Linux ve Mac) SSH kullananlar için Uygun sertifika ve private key'leri worker makinalarımıza kopyalıyoruz.
INTERNAL_IP=
WORKER=
WORKERS=(worker-01,10.240.10.7 worker-02,10.240.10.8 worker-03,10.240.10.9)
for i in "${WORKERS[@]}" ; do
KEY=${i%,*};
VAL=${i#*,};
INTERNAL_IP=$VAL;
WORKER=$KEY;
scp ca.pem ${WORKER}-key.pem ${WORKER}.pem ${VAL}:~/kubernetes
done
Uygun sertifika ve private key'leri controller makinalarımıza kopyalıyoruz.
for instance in (10.240.10.4, 10.240.10.5, 10.240.10.6); do
scp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
service-account-key.pem service-account.pem ${instance}:~/kubernetes
done
Windows kullananlar için
Uygun sertifika ve private key'leri worker makinalarımıza kopyalıyoruz.
$instances = @{"worker-01"="10.240.10.7"; "worker-02"="10.240.10.8";"worker-03"="10.240.10.9"}
foreach ($key in $instances.keys)
{
$instance=$key
$internal_ip=$instances[$key]
scp ca.pem $instance-key.pem $instance.pem $internal_ip:~/kubernetes
}
Uygun sertifika ve private key'leri controller makinalarımıza kopyalıyoruz.
$instances = @{"controller-01"="10.240.10.4"; "controller-02"="10.240.10.5";"controller-03"="10.240.10.6"}
foreach ($key in $instances.keys)
{
$instance=$key
$internal_ip=$instances[$key]
scp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem `
service-account-key.pem service-account.pem $internal_ip:~/kubernetes
}
kube-proxy, kube-controller-manager, kube-scheduler, ve kubelet istemci sertifikalarını sonraki bölümde istemci authentication konfigürasyon dosyalarını oluşturmak için kullanacağız.
- Giriş ve Lab Ortamının Kurulması
- İstemci Araçlarının Kurulumu
- Harici Yük Dengeleyici Kurulumu
- Certificate Authority ve TLS Sertifikalarının Oluşturulması
- Kubeconfig Dosyalarının Oluşturulması
- Data Encryption Config ve Key Oluşturulması
- Etcd Cluster Kurulumu
- Control Plane'nin Kurulumu ve Konfigürasyonu
- Worker Node'ların Kurulumu ve Konfigürasyonu
- Uzak Bağlantı için Kubectl Konfigürasyonu
- Pod Network Route'larının Ayarlanması
- DNS'in Kurulumu ve Konfigürasyonu
- Smoke Test