https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/04-certificate-authority.md


인증서를 생성하도록 하자


인증서는 만들것도 많고, 햇갈릴수 있는 부분이니 꼼꼼히 작업해야한다.



### Certificate Authority 


# ca-config.json 파일 생성

cat > ca-config.json <<EOF

{

  "signing": {

    "default": {

      "expiry": "8760h"

    },

    "profiles": {

      "kubernetes": {

        "usages": ["signing", "key encipherment", "server auth", "client auth"],

        "expiry": "8760h"

      }

    }

  }

}

EOF


# ca-csr.json 파일 생성

cat > ca-csr.json <<EOF

{

  "CN": "Kubernetes",

  "key": {

    "algo": "rsa",

    "size": 2048

  },

  "names": [

    {

      "C": "US",

      "L": "Portland",

      "O": "Kubernetes",

      "OU": "CA",

      "ST": "Oregon"

    }

  ]

}

EOF


# ca 인증서 생성

cfssl gencert -initca ca-csr.json | cfssljson -bare ca



[root@master01 ~]# ll ca*

-rw-r--r--. 1 root root  232 Nov 23 10:51 ca-config.json

-rw-r--r--. 1 root root 1005 Nov 23 10:51 ca.csr

-rw-r--r--. 1 root root  211 Nov 23 10:51 ca-csr.json

-rw-------. 1 root root 1679 Nov 23 13:26 ca-key.pem

-rw-r--r--. 1 root root 1318 Nov 23 13:26 ca.pem

[root@master01 ~]#


ca-config.json, ca-csr.json (EOF 로 파일 직접생성), ca.csr, ca.pem, ca-key.pem 파일이 있어야 하며, 위의 파일중 ca.pem, ca-key.pem 파일을 사용한다. 


[root@master01 ~]# cat 001_create_ca.sh 

#!/bin/bash


### CA Create


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


이렇게 간단하게 스크립트로 생성하였다. 



### Client and Server Certificates


# admin-csr.json 파일 생성

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


# admin 인증서 생성

cfssl gencert \

  -ca=ca.pem \

  -ca-key=ca-key.pem \

  -config=ca-config.json \

  -profile=kubernetes \

  admin-csr.json | cfssljson -bare admin


# 결과

# ll admin* | awk {'print $9'}

admin.csr

admin-csr.json

admin-key.pem

admin.pem


admin-csr.json (EOF 로 파일 직접생성), admin.csr, admin.pem, admin-key.pem 파일이 있어야 하며, 위의 파일중 admin.pem, admin-key.pem 파일을 사용한다. 



[root@master01 ~]# cat 002_admin_certificate.sh 

#!/bin/bash


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


이렇게 간단하게 스크립트로 생성하였다. 



### The Kubelet Client Certificates


kubelet 에서 사용할 인증서로, 몇가지 IP(hostname) 정보가 필요하다.

External_IP 는 Master 의 외부노출(haproxy 구성예정) IP 이다. 

INTERNAL_IP 는 Worker Node 의 자기자신 IP 이다. 

instance 는 worker node 의 hostname 정보 이다. 


[root@master01 ~]# cat 003_kubelet_client_certificate.sh 

#!/bin/bash


EXTERNAL_IP=192.168.1.47 

INTERNAL_IP=("192.168.1.57" "192.168.1.58" "192.168.1.60")

instance=("worker01" "worker02" "worker03")


for ((i=0; i<3; i++)); do

cat > ${instance[i]}-csr.json <<EOF

{

  "CN": "system:node:${instance[i]}",

  "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[i]},${INTERNAL_IP[i]},${EXTERNAL_IP} \

  -profile=kubernetes \

  ${instance[i]}-csr.json | cfssljson -bare ${instance[i]}

done



위의 내용을 스크립트로 작성하여 sh 003_kubelet_client_certificate.sh 로 수행하였으며, 아래와 같은 인증서가 있어야 한다. 


[root@master01 ~]# ll worker* | awk {'print $9'}

worker01.csr

worker01-csr.json

worker01-key.pem

worker01.pem

worker02.csr

worker02-csr.json

worker02-key.pem

worker02.pem

worker03.csr

worker03-csr.json

worker03-key.pem

worker03.pem



### The Controller Manager Client Certificate

[root@master01 ~]# cat 004_controller-manager-certificate.sh 

#!/bin/bash


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


# 스크립트 생성 후 실행

sh 004_controller-manager-certificate.sh 


# 확인

[root@master01 ~]# ll kube-controller* | awk {'print $9'}

kube-controller-manager.csr

kube-controller-manager-csr.json

kube-controller-manager-key.pem

kube-controller-manager.pem


### The Kube Proxy Client Certificate


[root@master01 ~]# cat 005_kube-proxy_client_certificate.sh 

#!/bin/bash


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


# 스크립트 생성 후 실행

sh 005_kube-proxy_client_certificate.sh 


# 확인

[root@master01 ~]# ll kube-proxy* | awk {'print $9'}

kube-proxy.csr

kube-proxy-csr.json

kube-proxy-key.pem

kube-proxy.pem



### The Scheduler Client Certificate


[root@master01 ~]# cat 006_kube-scheduler_client_certificate.sh 

#!/bin/bash


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



# 스크립트 생성 후 실행

sh 006_kube-scheduler_client_certificate.sh 


# 확인

[root@master01 ~]# ll kube-scheduler* | awk {'print $9'}

kube-scheduler.csr

kube-scheduler-csr.json

kube-scheduler-key.pem

kube-scheduler.pem



### The Kubernetes API Server Certificate


EXTERNAL_IP 는 master 의 외부노출 IP 이다. (haproxy)

MASTER_IP 는 master node 의 각각의 IP 이다. 


[root@master01 ~]# cat 007_apiserver_certificate.sh 

#!/bin/bash


EXTERNAL_IP=192.168.1.47 

MASTER_IP=192.168.1.21,192.168.1.55,192.168.1.56

KUBERNETES_HOSTNAMES=kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster,kubernetes.svc.cluster.local


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,${MASTER_IP},127.0.0.1,${KUBERNETES_HOSTNAMES},${EXTERNAL_IP} \

  -profile=kubernetes \

  kubernetes-csr.json | cfssljson -bare kubernetes



# 스크립트 생성 후 실행

sh apiserver_certificate.sh 

# 확인
[root@master01 ~]# ll kubernetes* | awk {'print $9'}
kubernetes.csr
kubernetes-csr.json
kubernetes-key.pem
kubernetes.pem


### The Service Account Key Pair


[root@master01 ~]# cat 008_service-account_certificate.sh 

#!/bin/bash


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


# 스크립트 생성 후 실행

sh 008_service-account_certificate.sh 

# 확인
[root@master01 ~]# ll service* | awk {'print $9'}
service-account.csr
service-account-csr.json
service-account-key.pem
service-account.pem


### Distribute the Client and Server Certificates (인증서 배포)


[root@master01 ~]# cat 009_certificate_file_copy.sh 

#!/bin/bash


WORKER=("worker01" "worker02" "worker03")

MASTER=("master01" "master02" "master03")


for ((i=0; i<3; i++)); do

  scp ca.pem ${WORKER[i]}-key.pem ${WORKER[i]}.pem ${WORKER[i]}:~/

  

  sleep 2


done




for ((i=0; i<3; i++)); do

  scp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \

    service-account-key.pem service-account.pem ${MASTER[i]}:~/


  sleep 2


done


# 스크립트 생성 후 실행

sh 009_certificate_file_copy.sh 

# 확인
master01, 02, 03 서버의 $home:~/ 에 "ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem service-account-key.pem service-account.pem" 파일이 있어야 한다. 

worker01, 02, 03 서버의 $home:~/ 에 "worker01-key.pem, worker01.pem" 파일이 01, 02, 03 의 이름을 가지고 있어야 한다. 













### 서버 전체적으로 필요한 기본 구성


### 방화벽 끄기

service firewalld stop

systemctl disable firewalld

iptables -L 


### dns 관련 utils 구성

yum install -y bind-utils


### selinux 끄기
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
setenforce 0



https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/03-compute-resources.md



Local PC 를 이용해서 구성진행이라, "https://dangerzo.tistory.com/entry/HARDWAY-0-Architecture?category=919304" 해당 내용에서 구성한 Hardward 구성을 참조해서 진행하면 된다. 


Master 및 Worker 의 IP 를 고정으로 가져가면 편리하지만, DHCP 로 구성이 안되는것은 아니니 걱정하지말고 구성하자

DHCP 는 테스트 Lab 일경우 추천하며, 운영상황에서는 IP 가 변경되면 변경되는 IP 에 따라서 인증서 및 Kubeconfig 파일의 변경 및 etcd 등등 여러가지에 영향을 끼치니 Static IP 를 가지고 구성하는것을 추천한다. 


VM 은 한번 구성 후 삭제만하지 않는다면 기존의 IP를 왠만하면 (95% 이상) 가지고 올라오기때문에 테스트에 전혀 문제는 없다. 


작업 후 Master01 서버 (kubectl 및 hardway 서버구성 진행할 서버) 에서 인증서를 발행하여, 각 서버에 비밀번호 없이 ssh 통신이 될수 있도록 세팅해주자.


### SSH Keygen 을 이용한 인증서 발급 및 인증서 복사 작업


ssh-keygen 을 이용해서 key 생성시 질문에 대해서는 전부 enter(빈공란)를 입력 해도 인증서 생성에는 전혀 문제가 없다. 


# ssh-keygen -t rsa

Generating public/private rsa key pair.

Enter file in which to save the key (/root/.ssh/id_rsa): 

Enter passphrase (empty for no passphrase): 

Enter same passphrase again: 

Your identification has been saved in /root/.ssh/id_rsa.

Your public key has been saved in /root/.ssh/id_rsa.pub.

The key fingerprint is:

SHA256:RUuebgSuNX4lxe+pPcVeAZd8afQwH0Q7arNMXQJ6xpk root@haproxy

The key's randomart image is:

+---[RSA 2048]----+

|        . o.o B=o|

|       . = *.= X=|

|        + O E.=o=|

|       + = =  +oo|

|      . S +  * +.|

|         o  + = +|

|             = o.|

|            . o .|

|               . |

+----[SHA256]-----+


# ll .ssh/

total 12

-rw-------  1 root root 1679 Dec  1 15:19 id_rsa

-rw-r--r--  1 root root  394 Dec  1 15:19 id_rsa.pub



### Public 인증서 작업대상 서버에 복사 (Haproxy, Master01, 02, 03, Worker01, 02, 03)

ssh 키 복사작업을할때 서버에서 scp 명령어를 이용해서 비밀번호를 한땀한땀 입력해가며 key 를 복사해두 된다. 

1. 작업대상서버에 $HOME/.ssh/ Directory 생성하기
작업대상 서버 접속 후 (master01~03, worker01~03, haproxy)
mkdir .ssh

2. 키 복사하기
scp .ssh/id_rsa.pub root@작업대상서버:~/.ssh/authorized_keys
ex) scp .ssh/id_rsa.pub root@192.168.1.55:~/.ssh/authorized_keys

위의 작업이 불편하다면 아래의 expect scripts 를 참조하여 자동화를 해도 된다. (선택사항)

### expect 설치(선택사항)
yum install -y expect

### 스크립트 구성(선택사항)

#!/bin/bash

THOST=("192.168.1.55" "192.168.1.56" "192.168.1.57" "192.168.1.58" "192.168.1.60")

for ((i=0; i<6; i++)); do

echo "Create directory ${THOST[i]} Server START"

expect <<EOF
spawn ssh root@${THOST[i]} mkdir /root/.ssh/
expect (yes/no)?
send "yes\n"
expect password:
send "비밀번호\n"
expect eof
EOF

echo "Create directory ${THOST[i]} Server END" 

sleep 2

done


for ((i=0; i<6; i++)); do

echo "Copy Public Key ${THOST[i]} Server START"

expect <<EOF
spawn scp .ssh/id_rsa.pub root@${THOST[i]}:~/.ssh/authorized_keys
expect pssword:
send "비밀번호\n"
expect eof
EOF

echo "Copy Public Key ${THOST[i]} Server END"

sleep 2

done


3. 각 서버마다 hostname 을 정확하게 지정해주고, /etc/hosts 파일에 정보를 기입하자. 


### 각 서버에서 작업

sudo hostnamectl set-hostname master01

sudo hostnamectl set-hostname master02

sudo hostnamectl set-hostname master03

sudo hostnamectl set-hostname worker01

sudo hostnamectl set-hostname worker02

sudo hostnamectl set-hostname worker03

sudo hostnamectl set-hostname haproxy


### Hosts 파일 구성


cat << EOF > /etc/hosts

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4

::1         localhost localhost.localdomain localhost6 localhost6.localdomain6



192.168.1.21    master01

192.168.1.55    master02

192.168.1.56    master03

192.168.1.57    worker01

192.168.1.58    worker02

192.168.1.60    worker03

192.168.1.47    haproxy


EOF


위의 IP 는 각 서버구성시 확인 후 변경해 주도록 하자



+ Recent posts