티스토리 뷰

Kubernetes the hard way의 목적

Kubernetes the hard way의 핵심은 "자동화 도구(Managed Services나 Installer)를 전혀 사용하지 않고,
모든 구성 요소를 밑바닥부터 직접 설치하고 설정하는 것. kubeadm 도구조차 사용하지 않고 설치하는 것이 특징이며 각각의 구성요소들을 직접 한땀한땀 설치하므로써 kubernetes의 내부 구조를 이해하고 분석할 수 있는 능력을 키우기 위함

본 자료는 Cloud@net 스터디 자료로 실제 교육 내용을 토대로 현재 프로덕션 환경에 적용하기 위한 목적이어서 실제 물리서버로 설치하는 방식으로 실습을 진행하였음

 

 

▶ 사전 준비물 

☞ 하이퍼바이저 물리 서버 1식 (VM 4식)

    - 하이퍼바이저 : Proxmox 

    - 서버 모델 : HP Gen G7 (CPU : 4 core,  MEM : 250G. HDD : 2T)

    - VM : 총 4식 (운영체제 : Debian 12)

NAME Description CPU MEM NIC HOSTNAME
jumpbox Administration host 2 1536 MB 192.168.7.245 jumpbox
server Kubernetes server 2 2GB 192.168.7.246 server.kubernetes.local server
node-0 Kubernetes worker 2 2GB 192.168.7.247 node-0.kubernetes.local node-0
node-1 Kubernetes worker 2 2GB 192.168.7.248 node-1.kubernetes.local node-1

 

☞ 스터디 수업에서는 NIC 이 외부와 내부로 분리하여 구성하고 있으나

     실제 프로덕션 환경에서 구축하는 방식으로 실습을 진행하였기 때문에

     VirtualBox와 Vegrant를 사용하지 않고 베어메탈 서버의 단일 네트워크

     환경으로 구축하였음

 

 

▶ 실습 구성도

 

☞  우분투 로컬 서버 (KIND 설치) 노드 - 1식

 

우분투 노드 1식은 kubernetes the hardway 의 설치 및 구성 정보를  KIND를 이용하여 서로 비교하기 위해 필요하며 본인은 테스트를 위한 베어메탈 서버 자원이 이미 확보된 상황이어서 실습할 때  WSL을 사용할 필요가 없음. 우분투가 설치된 프러덕션 환경을 이용하여 실습할 경우 스터디 내용 처럼 VirtualBox와 baygrant 그리고 WSL 관련 내용이 불필요하므로 제외시켰음

 

▶ 우분투 가상화 노드에 KIND 설치

더보기

# 도커 설치

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh ./get-docker.sh
...

# 설치 확인
docker info
docker ps
sudo systemctl status docker
cat /etc/group | grep docker

 

# KIND 및 관리 툴 설치

# 기본 사용자 디렉터리 이동
cd $PWD
pwd

#
sudo systemctl stop apparmor && sudo systemctl disable apparmor

# 
sudo apt update && sudo apt-get install bridge-utils net-tools jq tree unzip kubectx kubecolor -y

# Install Kind
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.31.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
kind --version

# Install kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv ./kubectl /usr/bin
sudo kubectl version --client=true

# Install Helm
curl -s https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
helm version

# Source the completion
source <(kubectl completion bash)
echo 'source <(kubectl completion bash)' >> ~/.bashrc

# Alias kubectl to k
echo 'alias k=kubectl' >> ~/.bashrc
echo 'complete -o default -F __start_kubectl k' >> ~/.bashrc

# Install Kubeps & Setting PS1
git clone https://github.com/jonmosco/kube-ps1.git
echo -e "source $PWD/kube-ps1/kube-ps1.sh" >> ~/.bashrc
cat <<"EOT" >> ~/.bashrc
KUBE_PS1_SYMBOL_ENABLE=true
function get_cluster_short() {
  echo "$1" | cut -d . -f1
}
KUBE_PS1_CLUSTER_FUNCTION=get_cluster_short
KUBE_PS1_SUFFIX=') '
PS1='$(kube_ps1)'$PS1
EOT

# .bashrc 적용을 위해서 logout 후 터미널 다시 접속 하자
exit

 

 

# KIND로 K8S 배포

# 클러스터 배포 전 확인
docker ps

# Create a cluster with kind
kind create cluster --name myk8s --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
- role: worker
EOF

# 확인
kind get nodes --name myk8s
kubens default

# kind 는 별도 도커 네트워크 생성 후 사용 : 기본값 172.18.0.0/16
docker network ls
docker inspect kind | jq

# k8s api 주소 확인 : 어떻게 로컬에서 접속이 되는 걸까?
kubectl cluster-info

# 노드 정보 확인 : CRI 는 containerd 사용
kubectl get node -o wide

# 파드 정보 확인 : CNI 는 kindnet 사용
kubectl get pod -A -o wide

# 네임스페이스 확인 >> 도커 컨테이너에서 배운 네임스페이스와 다릅니다!
kubectl get namespaces

# 컨트롤플레인/워커 노드(컨테이너) 확인 : 도커 컨테이너 이름은 myk8s-control-plane , myk8s-worker 임을 확인
docker ps
docker images
docker exec -it myk8s-control-plane ss -tnlp

# 디버그용 내용 출력에 ~/.kube/config 권한 인증 로드
kubectl get pod -v6

# kube config 파일 확인 : "server: https://127.0.0.1:YYYYY" 127.0.0.1:Port로 접속 가능을 확인!
cat ~/.kube/config
ls -l ~/.kube/config

 

 

(참고) 클러스터 삭제

# 클러스터 삭제
kind delete cluster --name myk8s
docker ps
cat ~/.kube/config

 

 

 

K8S the hard way 클러스터 설치

 

1. 노드 공통

#!/usr/bin/env bash

echo ">>>> Proxmox VM Initial Config Start <<<<"

# [TASK 1] 사용자 설정 및 시간대
# Cloud-init 기본 사용자인 'debian' 기준 (vagrant 대신 debian 사용)
echo "alias vi=vim" >> /etc/profile
ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

# [TASK 2] AppArmor 비활성화 (K8s 호환성)
systemctl stop apparmor && systemctl disable apparmor >/dev/null 2>&1

# [TASK 3] SWAP 비활성화 (K8s 필수 설정)
swapoff -a && sed -i '/swap/s/^/#/' /etc/fstab

# [TASK 4] 필수 패키지 설치
apt update -qq
apt install tree git jq yq unzip vim sshpass -y -qq

# [TASK 5] Root 및 Debian 사용자 패스워드 설정
echo "root:qwe123" | chpasswd
echo "debian:qwe123" | chpasswd

# [TASK 6] SSH 설정 수정 (Root 접속 허용)
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
systemctl restart sshd

# [TASK 7] 로컬 DNS 설정 (/etc/hosts) - 요청하신 IP 반영
sed -i '/^127\.0\.\(1\|2\)\.1/d' /etc/hosts
cat << EOF >> /etc/hosts
192.168.7.245 jumpbox
192.168.7.246 server.kubernetes.local server
192.168.7.247 node-0.kubernetes.local node-0
192.168.7.248 node-1.kubernetes.local node-1
EOF

echo ">>>> Initial Config End <<<<"

 

 

2. jumpbox 가상머신

# 사용자 확인
whoami
pwd

# OS version 확인
cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian

# AppArmor 상태 확인
aa-status
systemctl is-active apparmor
inactive
     
# /etc/hosts 파일 내용 확인
# https://www.debian.org/doc/manuals/debian-reference/ch05.en.html#_the_hostname_resolution
cat /etc/hosts

 

 

Set Up The Jumpbox

설치에 필요한 파일 등 준비 - Docs

설치 항목버전

설치 항목 버전
k8s 관련 (kube-apiserver, kubelet 등) 1.32.2
etcd 3.6.0
containerd 2.1.0
runc 1.3.0

 

# 툴 설치 : 이미 적용되어 있음
apt-get update && apt install tree git jq yq unzip vim sshpass -y

# Sync GitHub Repository
pwd
git clone --depth 1 https://github.com/kelseyhightower/kubernetes-the-hard-way.git
cd kubernetes-the-hard-way
tree
pwd


(확인)
debian@jumpbox:~$ pwd
git clone --depth 1 https://github.com/kelseyhightower/kubernetes-the-hard-way.git
cd kubernetes-the-hard-way
tree
pwd
/home/debian
Cloning into 'kubernetes-the-hard-way'...
remote: Enumerating objects: 41, done.
remote: Counting objects: 100% (41/41), done.
remote: Compressing objects: 100% (40/40), done.
remote: Total 41 (delta 3), reused 14 (delta 1), pack-reused 0 (from 0)
Receiving objects: 100% (41/41), 29.27 KiB | 3.66 MiB/s, done.
Resolving deltas: 100% (3/3), done.
.
├── CONTRIBUTING.md
├── COPYRIGHT.md
├── LICENSE
├── README.md
├── ca.conf
├── configs
│   ├── 10-bridge.conf
│   ├── 99-loopback.conf
│   ├── containerd-config.toml
│   ├── encryption-config.yaml
│   ├── kube-apiserver-to-kubelet.yaml
│   ├── kube-proxy-config.yaml
│   ├── kube-scheduler.yaml
│   └── kubelet-config.yaml
├── docs
│   ├── 01-prerequisites.md
│   ├── 02-jumpbox.md
│   ├── 03-compute-resources.md
│   ├── 04-certificate-authority.md
│   ├── 05-kubernetes-configuration-files.md
│   ├── 06-data-encryption-keys.md
│   ├── 07-bootstrapping-etcd.md
│   ├── 08-bootstrapping-kubernetes-controllers.md
│   ├── 09-bootstrapping-kubernetes-workers.md
│   ├── 10-configuring-kubectl.md
│   ├── 11-pod-network-routes.md
│   ├── 12-smoke-test.md
│   └── 13-cleanup.md
├── downloads-amd64.txt
├── downloads-arm64.txt
└── units
    ├── containerd.service
    ├── etcd.service
    ├── kube-apiserver.service
    ├── kube-controller-manager.service
    ├── kube-proxy.service
    ├── kube-scheduler.service
    └── kubelet.service

4 directories, 35 files
/home/debian/kubernetes-the-hard-way
debian@jumpbox:~/kubernetes-the-hard-way$ pwd
/home/debian/kubernetes-the-hard-way





# Download Binaries : k8s 구성을 위한 컴포넌트 다운로드

# CPU 아키텍처 확인
dpkg --print-architecture
arm64   # macOS 사용자
amd64   # Windows 사용자

debian@jumpbox:~/kubernetes-the-hard-way$ dpkg --print-architecture
amd64


# CPU 아키텍처 별 다운로드 목록 정보 다름
ls -l downloads-*
-rw-r--r-- 1 root root 839 Jan  4 10:30 downloads-amd64.txt
-rw-r--r-- 1 root root 839 Jan  4 10:30 downloads-arm64.txt

# https://kubernetes.io/releases/download/
cat downloads-$(dpkg --print-architecture).txt
https://dl.k8s.io/v1.32.3/bin/linux/amd64/kubectl
https://dl.k8s.io/v1.32.3/bin/linux/amd64/kube-apiserver
https://dl.k8s.io/v1.32.3/bin/linux/amd64/kube-controller-manager
https://dl.k8s.io/v1.32.3/bin/linux/amd64/kube-scheduler
https://dl.k8s.io/v1.32.3/bin/linux/amd64/kube-proxy
https://dl.k8s.io/v1.32.3/bin/linux/amd64/kubelet
https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.32.0/crictl-v1.32.0-linux-amd64.tar.gz
https://github.com/opencontainers/runc/releases/download/v1.3.0-rc.1/runc.amd64
https://github.com/containernetworking/plugins/releases/download/v1.6.2/cni-plugins-linux-amd64-v1.6.2.tgz
https://github.com/containerd/containerd/releases/download/v2.1.0-beta.0/containerd-2.1.0-beta.0-linux-amd64.tar.gz
https://github.com/etcd-io/etcd/releases/download/v3.6.0-rc.3/etcd-v3.6.0-rc.3-linux-amd64.tar.gz

# wget 으로 다운로드 실행 : 500MB Size 정도
wget -q --show-progress \
  --https-only \
  --timestamping \
  -P downloads \
  -i downloads-$(dpkg --print-architecture).txt


kubectl                                             100%[=================================================================================================================>]  54.67M  4.27MB/s    in 13s
kube-apiserver                                      100%[=================================================================================================================>]  88.94M  4.13MB/s    in 21s
kube-controller-manager                             100%[=================================================================================================================>]  82.00M  3.98MB/s    in 21s
kube-scheduler                                      100%[=================================================================================================================>]  62.79M  3.61MB/s    in 16s
kube-proxy                                          100%[=================================================================================================================>]  63.75M  4.02MB/s    in 15s
kubelet                                             100%[=================================================================================================================>]  73.82M  3.85MB/s    in 19s
crictl-v1.32.0-linux-amd64.tar.gz                   100%[=================================================================================================================>]  18.21M  4.18MB/s    in 4.4s
runc.amd64                                          100%[=================================================================================================================>]  11.30M  4.53MB/s    in 2.5s
cni-plugins-linux-amd64-v1.6.2.tgz                  100%[=================================================================================================================>]  50.35M  3.55MB/s    in 13s
containerd-2.1.0-beta.0-linux-amd64.tar.gz          100%[=================================================================================================================>]  37.01M  3.38MB/s    in 10s
etcd-v3.6.0-rc.3-linux-amd64.tar.gz                 100%[=================================================================================================================>]  22.48M  3.84MB/s    in 5.9s



# 확인
ls -oh downloads
total 566M
-rw-r--r-- 1 debian 51M Jan  7  2025 cni-plugins-linux-amd64-v1.6.2.tgz
-rw-r--r-- 1 debian 38M Mar 18  2025 containerd-2.1.0-beta.0-linux-amd64.tar.gz
-rw-r--r-- 1 debian 19M Dec  9  2024 crictl-v1.32.0-linux-amd64.tar.gz
-rw-r--r-- 1 debian 23M Mar 28  2025 etcd-v3.6.0-rc.3-linux-amd64.tar.gz
-rw-r--r-- 1 debian 89M Mar 12  2025 kube-apiserver
-rw-r--r-- 1 debian 83M Mar 12  2025 kube-controller-manager
-rw-r--r-- 1 debian 64M Mar 12  2025 kube-proxy
-rw-r--r-- 1 debian 63M Mar 12  2025 kube-scheduler
-rw-r--r-- 1 debian 55M Mar 12  2025 kubectl
-rw-r--r-- 1 debian 74M Mar 12  2025 kubelet
-rw-r--r-- 1 debian 12M Mar  4  2025 runc.amd64


# Extract the component binaries from the release archives and organize them under the downloads directory.
ARCH=$(dpkg --print-architecture)
echo $ARCH

mkdir -p downloads/{client,cni-plugins,controller,worker}
tree -d downloads
downloads
├── client
├── cni-plugins
├── controller
└── worker

5 directories

# 압축 풀기
tar -xvf downloads/crictl-v1.32.0-linux-${ARCH}.tar.gz \
  -C downloads/worker/ && tree -ug downloads

(확인)  
crictl
[debian   debian  ]  downloads
├── [debian   debian  ]  client
├── [debian   debian  ]  cni-plugins
├── [debian   debian  ]  cni-plugins-linux-amd64-v1.6.2.tgz
├── [debian   debian  ]  containerd-2.1.0-beta.0-linux-amd64.tar.gz
├── [debian   debian  ]  controller
├── [debian   debian  ]  crictl-v1.32.0-linux-amd64.tar.gz
├── [debian   debian  ]  etcd-v3.6.0-rc.3-linux-amd64.tar.gz
├── [debian   debian  ]  kube-apiserver
├── [debian   debian  ]  kube-controller-manager
├── [debian   debian  ]  kube-proxy
├── [debian   debian  ]  kube-scheduler
├── [debian   debian  ]  kubectl
├── [debian   debian  ]  kubelet
├── [debian   debian  ]  runc.amd64
└── [debian   debian  ]  worker
    └── [debian   debian  ]  crictl

5 directories, 12 files
  
  
  

tar -xvf downloads/containerd-2.1.0-beta.0-linux-${ARCH}.tar.gz \
  --strip-components 1 \
  -C downloads/worker/ && tree -ug downloads


bin/containerd-shim-runc-v2
bin/containerd
bin/containerd-stress
bin/ctr
[debian   debian  ]  downloads
├── [debian   debian  ]  client
├── [debian   debian  ]  cni-plugins
├── [debian   debian  ]  cni-plugins-linux-amd64-v1.6.2.tgz
├── [debian   debian  ]  containerd-2.1.0-beta.0-linux-amd64.tar.gz
├── [debian   debian  ]  controller
├── [debian   debian  ]  crictl-v1.32.0-linux-amd64.tar.gz
├── [debian   debian  ]  etcd-v3.6.0-rc.3-linux-amd64.tar.gz
├── [debian   debian  ]  kube-apiserver
├── [debian   debian  ]  kube-controller-manager
├── [debian   debian  ]  kube-proxy
├── [debian   debian  ]  kube-scheduler
├── [debian   debian  ]  kubectl
├── [debian   debian  ]  kubelet
├── [debian   debian  ]  runc.amd64
└── [debian   debian  ]  worker
    ├── [debian   debian  ]  containerd
    ├── [debian   debian  ]  containerd-shim-runc-v2
    ├── [debian   debian  ]  containerd-stress
    ├── [debian   debian  ]  crictl
    └── [debian   debian  ]  ctr

5 directories, 16 files




tar -xvf downloads/cni-plugins-linux-${ARCH}-v1.6.2.tgz \
  -C downloads/cni-plugins/ && tree -ug downloads
  

./
./ipvlan
./tap
./loopback
./host-device
./README.md
./portmap
./ptp
./vlan
./bridge
./firewall
./LICENSE
./macvlan
./dummy
./bandwidth
./vrf
./tuning
./static
./dhcp
./host-local
./sbr
[debian   debian  ]  downloads
├── [debian   debian  ]  client
├── [debian   debian  ]  cni-plugins
│   ├── [debian   debian  ]  LICENSE
│   ├── [debian   debian  ]  README.md
│   ├── [debian   debian  ]  bandwidth
│   ├── [debian   debian  ]  bridge
│   ├── [debian   debian  ]  dhcp
│   ├── [debian   debian  ]  dummy
│   ├── [debian   debian  ]  firewall
│   ├── [debian   debian  ]  host-device
│   ├── [debian   debian  ]  host-local
│   ├── [debian   debian  ]  ipvlan
│   ├── [debian   debian  ]  loopback
│   ├── [debian   debian  ]  macvlan
│   ├── [debian   debian  ]  portmap
│   ├── [debian   debian  ]  ptp
│   ├── [debian   debian  ]  sbr
│   ├── [debian   debian  ]  static
│   ├── [debian   debian  ]  tap
│   ├── [debian   debian  ]  tuning
│   ├── [debian   debian  ]  vlan
│   └── [debian   debian  ]  vrf
├── [debian   debian  ]  cni-plugins-linux-amd64-v1.6.2.tgz
├── [debian   debian  ]  containerd-2.1.0-beta.0-linux-amd64.tar.gz
├── [debian   debian  ]  controller
├── [debian   debian  ]  crictl-v1.32.0-linux-amd64.tar.gz
├── [debian   debian  ]  etcd-v3.6.0-rc.3-linux-amd64.tar.gz
├── [debian   debian  ]  kube-apiserver
├── [debian   debian  ]  kube-controller-manager
├── [debian   debian  ]  kube-proxy
├── [debian   debian  ]  kube-scheduler
├── [debian   debian  ]  kubectl
├── [debian   debian  ]  kubelet
├── [debian   debian  ]  runc.amd64
└── [debian   debian  ]  worker
    ├── [debian   debian  ]  containerd
    ├── [debian   debian  ]  containerd-shim-runc-v2
    ├── [debian   debian  ]  containerd-stress
    ├── [debian   debian  ]  crictl
    └── [debian   debian  ]  ctr

5 directories, 36 files

  

## --strip-components 1 : etcd-v3.6.0-rc.3-linux-amd64/etcd 경로의 앞부분(디렉터리)을 제거
tar -xvf downloads/etcd-v3.6.0-rc.3-linux-${ARCH}.tar.gz \
  -C downloads/ \
  --strip-components 1 \
  etcd-v3.6.0-rc.3-linux-${ARCH}/etcdctl \
  etcd-v3.6.0-rc.3-linux-${ARCH}/etcd && tree -ug downloads





# 확인
tree downloads/worker/
tree downloads/cni-plugins
ls -l downloads/{etcd,etcdctl}

debian@jumpbox:~/kubernetes-the-hard-way$ tree downloads/worker/
downloads/worker/
├── containerd
├── containerd-shim-runc-v2
├── containerd-stress
├── crictl
└── ctr

1 directory, 5 files
debian@jumpbox:~/kubernetes-the-hard-way$
debian@jumpbox:~/kubernetes-the-hard-way$
debian@jumpbox:~/kubernetes-the-hard-way$ tree downloads/cni-plugins
downloads/cni-plugins
├── LICENSE
├── README.md
├── bandwidth
├── bridge
├── dhcp
├── dummy
├── firewall
├── host-device
├── host-local
├── ipvlan
├── loopback
├── macvlan
├── portmap
├── ptp
├── sbr
├── static
├── tap
├── tuning
├── vlan
└── vrf

1 directory, 20 files



debian@jumpbox:~/kubernetes-the-hard-way$ ls -l downloads/{etcd,etcdctl}
-rwxr-xr-x 1 debian debian 25219224 Mar 28  2025 downloads/etcd
-rwxr-xr-x 1 debian debian 16421016 Mar 28  2025 downloads/etcdctl




# 파일 이동 
mv downloads/{etcdctl,kubectl} downloads/client/
mv downloads/{etcd,kube-apiserver,kube-controller-manager,kube-scheduler} downloads/controller/
mv downloads/{kubelet,kube-proxy} downloads/worker/
mv downloads/runc.${ARCH} downloads/worker/runc

# 확인
tree downloads/client/
tree downloads/controller/
tree downloads/worker/


tree downloads/controller/
tree downloads/worker/
downloads/client/
├── etcdctl
└── kubectl

1 directory, 2 files
downloads/controller/
├── etcd
├── kube-apiserver
├── kube-controller-manager
└── kube-scheduler

1 directory, 4 files
downloads/worker/
├── containerd
├── containerd-shim-runc-v2
├── containerd-stress
├── crictl
├── ctr
├── kube-proxy
├── kubelet
└── runc

1 directory, 8 files


# 불필요한 압축 파일 제거
ls -l downloads/*gz
rm -rf downloads/*gz

-rw-r--r-- 1 debian debian 52794236 Jan  7  2025 downloads/cni-plugins-linux-amd64-v1.6.2.tgz
-rw-r--r-- 1 debian debian 38807044 Mar 18  2025 downloads/containerd-2.1.0-beta.0-linux-amd64.tar.gz
-rw-r--r-- 1 debian debian 19100418 Dec  9  2024 downloads/crictl-v1.32.0-linux-amd64.tar.gz
-rw-r--r-- 1 debian debian 23577153 Mar 28  2025 downloads/etcd-v3.6.0-rc.3-linux-amd64.tar.gz



# Make the binaries executable.
ls -l downloads/{client,cni-plugins,controller,worker}/*
sudo chmod +x downloads/{client,cni-plugins,controller,worker}/*
ls -l downloads/{client,cni-plugins,controller,worker}/*

# 일부 파일 소유자 변경
tree -ug downloads # cat /etc/passwd | grep vagrant && cat /etc/group | grep vagrant
sudo chown root:root downloads/client/etcdctl
sudo chown root:root downloads/controller/etcd
sudo chown root:root downloads/worker/crictl
tree -ug downloads


# kubernetes client 도구인 kubectl를 설치
ls -l downloads/client/kubectl
cp downloads/client/kubectl /usr/local/bin/

# can be verified by running the kubectl command:
kubectl version --client
Client Version: v1.32.3
Kustomize Version: v5.5.0

 

 

 

 

 

 

 

 

[K8S Docs] Release* : 1년에 3개의 마이너 버전 출시 → 최근 3개 버전 release branches(패치) 지원 (그이상 힘듬..) - Link

 

https://kubernetes.io/releases/patch-releases/

  • Download - Link
  • Release Cycle - Link
  • Patch Releases - Link
    • Kubernetes 1.32가 유지보수 모드로 전환되었습니다.2025년 12월 28일.
    • Kubernetes 1.32의 지원 종료일은 다음과 같습니다.2026년 2월 28일.
  • Release Managers - Link
  • Release Notes - Link
  • Version Skew Policy - Link*
    • kube-apiserver : HA apiserver 경우 newest 와 oldest 가 1개 마이너 버전 가능
      • newest kube-apiserver is at 1.32
      • other kube-apiserver instances are supported at 1.32 and 1.31
    • kubelet/kube-proxy : kubelet 는 apiserver 보다 높을수 없음. 추가로 apiserver 보다 3개 older 가능
      • kube-apiserver is at 1.32
      • kubelet is supported at 1.321.311.30, and 1.29
      • 만약 apiserver 가 HA로 1.32, 1.31 있다면 kubelet 는 1.32는 안되고, 1.31, 1.30, 1.29 가능
    • kube-controller-manager, kube-scheduler, and cloud-controller-manager : skip
    • kubectl : one minor version (older or newer) of kube-apiserver
      • kube-apiserver is at 1.32
      • kubectl is supported at 1.331.32, and 1.31

 

 

Provisioning Compute Resources

 

☞  To ssh jumpbox

# Machine Database (서버 속성 저장 파일) : IPV4_ADDRESS FQDN HOSTNAME POD_SUBNET
## 참고) server(controlplane)는 kubelet 동작하지 않아서, 파드 네트워크 대역 설정 필요 없음
cat <<EOF > machines.txt
192.168.7.246 server.kubernetes.local server
192.168.7.247 node-0.kubernetes.local node-0 10.200.0.0/24
192.168.7.248 node-1.kubernetes.local node-1 10.200.1.0/24
EOF
cat machines.txt

while read IP FQDN HOST SUBNET; do
  echo "${IP} ${FQDN} ${HOST} ${SUBNET}"
done < machines.txt

192.168.7.246 server.kubernetes.local server
192.168.7.247 node-0.kubernetes.local node-0 10.200.0.0/24
192.168.7.248 node-1.kubernetes.local node-1 10.200.1.0/24



# Configuring SSH Access 설정
 
# sshd config 설정 파일 확인 : 이미 암호 기반 인증 접속 설정 되어 있음
grep "^[^#]" /etc/ssh/sshd_config

PasswordAuthentication yes
KbdInteractiveAuthentication no
UsePAM yes
X11Forwarding yes
PrintMotd no
AcceptEnv LANG LC_*
Subsystem       sftp    /usr/lib/openssh/sftp-server
ClientAliveInterval 120
PermitRootLogin yes



...
PasswordAuthentication yes
PermitRootLogin yes

# Generate a new SSH key
ssh-keygen -t rsa -N "" -f /root/.ssh/id_rsa
debian@jumpbox:~/kubernetes-the-hard-way$ sudo ls -l /root/.ssh
total 16
-rw------- 1 root root    0 Jan  5 19:55 authorized_keys
-rw------- 1 root root 2602 Jan  8 16:20 id_rsa
-rw-r--r-- 1 root root  566 Jan  8 16:20 id_rsa.pub

# Copy the SSH public key to each machine
while read IP FQDN HOST SUBNET; do
  sshpass -p 'qwe123' ssh-copy-id -o StrictHostKeyChecking=no root@${IP}
done < machines.txt

  sshpass -p '1' ssh-copy-id -o StrictHostKeyChecking=no root@${IP}
done < machines.txt
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh -o 'StrictHostKeyChecking=no' 'root@192.168.7.246'"
and check to make sure that only the key(s) you wanted were added.

/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh -o 'StrictHostKeyChecking=no' 'root@192.168.7.247'"
and check to make sure that only the key(s) you wanted were added.

/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh -o 'StrictHostKeyChecking=no' 'root@192.168.7.248'"
and check to make sure that only the key(s) you wanted were added.



while read IP FQDN HOST SUBNET; do
  ssh -n root@${IP} cat /root/.ssh/authorized_keys
done < machines.txt

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCeZbf084vEL9Whhj7FWB6NGxTA7n1eHjTrxG6+gyof6ANcvfKEzTPwHOPZlkyQS+SxizkTz/QU0tNUbyEf0YthLO95VrtF/obB2Yh6TifECug6QNNlxn901hbttU8TQgffsY/Zwqnl7amdqN6/RNu5iRFmGLrE9hjmg8nuJ1uAxtAz2ifbWwgIuyRANbycFLQ7u/Hm+gfOcRPwlFRojcLq2HEPn8LiZkfRnQTTtsXfM7pmFmacHHdB/Xvx+8ZAQhBMMBFl5EPF6kdu56VHl/0cmJ4fwzsfEgKRUPMBW9Xns3BZ42W4UfTpPzoZS9klZxttHKiJNy00TBVRJW0UUVjUJUgNA4T1bstd8OlMvjqYmmKTgZQxbKkU5TLguZFYujS4bP4VqGO8lxBErUpZqPNVaYhQjIaJnLZjj9nbxjZzp2tv6ckYWDmjN94VV1Rpcq4USPI+Q9xQiJ0VW2Nye4Mip/vGqZvPmb4nFlO91LhLRJ3ZuATE4SVBffi1R5WUny0= root@jumpbox
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC0YRbcxtxXdfdGp6AL/pHNgu5WvGbqF+adax8VXfg/IJC/iPWHE2srBjb0TyEA2fqOX8Y97c67cpCFLmbEk7gDHzzo+gHc5zgA6cBg3DCg6q0oPpaxlhIm9uE7XzVevPSe6NbmCNPaDPefToJ9GAsOtGzcc8gz7X5C9YgvChstHbSuDW9EZJvKJkN3MO0cPy5LQempuRjpme2LEHTR+L4YPpnT/bil6hVglbx4JZOAetdgogUb4aczAFYGPYQIS8xn9J8u1GtC09Tjq8cIOBac4NDeiRHI5wT1xCPakc6o/faEpLDIduaVDKKrneBlYu5SfEEHwJDSoaTfY/dORk24PgNV2WflzuaNGb1zF+EicPopGmQMvU2p70fa4ZtX4wTdYsGXlUSd22aogqH3Qv7WINdN6SOjyKc9wIQL7p7rbcfxzbU9UWnGHPN/ze8N0hwlMoO1wMWaPXe7lXgrRJw88FDio67Vipu0lloAOdWS1zCDjzH2UAp4IZ/Vc7FMGYM= root@jumpbox
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCeZbf084vEL9Whhj7FWB6NGxTA7n1eHjTrxG6+gyof6ANcvfKEzTPwHOPZlkyQS+SxizkTz/QU0tNUbyEf0YthLO95VrtF/obB2Yh6TifECug6QNNlxn901hbttU8TQgffsY/Zwqnl7amdqN6/RNu5iRFmGLrE9hjmg8nuJ1uAxtAz2ifbWwgIuyRANbycFLQ7u/Hm+gfOcRPwlFRojcLq2HEPn8LiZkfRnQTTtsXfM7pmFmacHHdB/Xvx+8ZAQhBMMBFl5EPF6kdu56VHl/0cmJ4fwzsfEgKRUPMBW9Xns3BZ42W4UfTpPzoZS9klZxttHKiJNy00TBVRJW0UUVjUJUgNA4T1bstd8OlMvjqYmmKTgZQxbKkU5TLguZFYujS4bP4VqGO8lxBErUpZqPNVaYhQjIaJnLZjj9nbxjZzp2tv6ckYWDmjN94VV1Rpcq4USPI+Q9xQiJ0VW2Nye4Mip/vGqZvPmb4nFlO91LhLRJ3ZuATE4SVBffi1R5WUny0= root@jumpbox
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC0YRbcxtxXdfdGp6AL/pHNgu5WvGbqF+adax8VXfg/IJC/iPWHE2srBjb0TyEA2fqOX8Y97c67cpCFLmbEk7gDHzzo+gHc5zgA6cBg3DCg6q0oPpaxlhIm9uE7XzVevPSe6NbmCNPaDPefToJ9GAsOtGzcc8gz7X5C9YgvChstHbSuDW9EZJvKJkN3MO0cPy5LQempuRjpme2LEHTR+L4YPpnT/bil6hVglbx4JZOAetdgogUb4aczAFYGPYQIS8xn9J8u1GtC09Tjq8cIOBac4NDeiRHI5wT1xCPakc6o/faEpLDIduaVDKKrneBlYu5SfEEHwJDSoaTfY/dORk24PgNV2WflzuaNGb1zF+EicPopGmQMvU2p70fa4ZtX4wTdYsGXlUSd22aogqH3Qv7WINdN6SOjyKc9wIQL7p7rbcfxzbU9UWnGHPN/ze8N0hwlMoO1wMWaPXe7lXgrRJw88FDio67Vipu0lloAOdWS1zCDjzH2UAp4IZ/Vc7FMGYM= root@jumpbox
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCeZbf084vEL9Whhj7FWB6NGxTA7n1eHjTrxG6+gyof6ANcvfKEzTPwHOPZlkyQS+SxizkTz/QU0tNUbyEf0YthLO95VrtF/obB2Yh6TifECug6QNNlxn901hbttU8TQgffsY/Zwqnl7amdqN6/RNu5iRFmGLrE9hjmg8nuJ1uAxtAz2ifbWwgIuyRANbycFLQ7u/Hm+gfOcRPwlFRojcLq2HEPn8LiZkfRnQTTtsXfM7pmFmacHHdB/Xvx+8ZAQhBMMBFl5EPF6kdu56VHl/0cmJ4fwzsfEgKRUPMBW9Xns3BZ42W4UfTpPzoZS9klZxttHKiJNy00TBVRJW0UUVjUJUgNA4T1bstd8OlMvjqYmmKTgZQxbKkU5TLguZFYujS4bP4VqGO8lxBErUpZqPNVaYhQjIaJnLZjj9nbxjZzp2tv6ckYWDmjN94VV1Rpcq4USPI+Q9xQiJ0VW2Nye4Mip/vGqZvPmb4nFlO91LhLRJ3ZuATE4SVBffi1R5WUny0= root@jumpbox
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC0YRbcxtxXdfdGp6AL/pHNgu5WvGbqF+adax8VXfg/IJC/iPWHE2srBjb0TyEA2fqOX8Y97c67cpCFLmbEk7gDHzzo+gHc5zgA6cBg3DCg6q0oPpaxlhIm9uE7XzVevPSe6NbmCNPaDPefToJ9GAsOtGzcc8gz7X5C9YgvChstHbSuDW9EZJvKJkN3MO0cPy5LQempuRjpme2LEHTR+L4YPpnT/bil6hVglbx4JZOAetdgogUb4aczAFYGPYQIS8xn9J8u1GtC09Tjq8cIOBac4NDeiRHI5wT1xCPakc6o/faEpLDIduaVDKKrneBlYu5SfEEHwJDSoaTfY/dORk24PgNV2WflzuaNGb1zF+EicPopGmQMvU2p70fa4ZtX4wTdYsGXlUSd22aogqH3Qv7WINdN6SOjyKc9wIQL7p7rbcfxzbU9UWnGHPN/ze8N0hwlMoO1wMWaPXe7lXgrRJw88FDio67Vipu0lloAOdWS1zCDjzH2UAp4IZ/Vc7FMGYM= root@jumpbox





# Once each key is added, verify SSH public key access is working
# 아래는 IP 기반으로 접속 확인

while read IP FQDN HOST SUBNET; do
  ssh -n root@${IP} hostname
done < machines.txt


server
node-0
node-1



# Hostnames 설정

# 확인 : init_cfg.sh 로 이미 설정되어 있음
while read IP FQDN HOST SUBNET; do
  ssh -n root@${IP} cat /etc/hosts
done < machines.txt

while read IP FQDN HOST SUBNET; do
  ssh -n root@${IP} hostname --fqdn
done < machines.txt

# 아래는 hostname 으로 ssh 접속 확인
cat /etc/hosts
while read IP FQDN HOST SUBNET; do
  sshpass -p 'qwe123' ssh -n -o StrictHostKeyChecking=no root@${HOST} hostname
done < machines.txt

while read IP FQDN HOST SUBNET; do
  sshpass -p 'qwe123' ssh -n root@${HOST} uname -o -m -n
done < machines.txt

 

# Your system has configured 'manage_etc_hosts' as True.
# As a result, if you wish for changes to this file to persist
# then you will need to either
# a.) make changes to the master file in /etc/cloud/templates/hosts.debian.tmpl
# b.) change or remove the value of 'manage_etc_hosts' in
#     /etc/cloud/cloud.cfg or cloud-config from user-data
#
127.0.0.1 localhost

# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

192.168.7.245 jumpbox
192.168.7.246 server.kubernetes.local server
192.168.7.247 node-0.kubernetes.local node-0
192.168.7.248 node-1.kubernetes.local node-1

 

 

 

Provisioning a CA and Generating TLS Certificates

☞ CA 설정 및 TLS 인증서 생성 - Docs

  개인키 CSR   인증서 참고 정보
Root CA ca.key X ca.crt  
admin admin.key admin.csr admin.crt CN = admin, O = system:masters
node-0 node-0.key node-0.csr node-0.crt CN = system:node:node-0, O = system:nodes
node-1 node-1.key node-1.csr node-1.crt CN = system:node:node-1, O = system:nodes
kube-proxy kube-proxy.key kube-proxy.csr kube-proxy.crt CN = system:kube-proxy, O = system:node-proxier
kube-scheduler kube-scheduler.key kube-scheduler kube-scheduler.crt CN = system:kube-scheduler, O = system:kube-scheduler
kube-controller-manager kube-controller-manager.key kube-controller-manager.csr kube-controller-manager.crt CN = system:kube-controller-manager, O = system:kube-controller-manager
kube-api-server kube-api-server.key kube-api-server.csr kube-api-server.crt CN = kubernetes, SAN: IP(127.0.0.1, 10.32.0.1), DNS(kubernetes,..)
service-accounts service-accounts.key service-accounts.csr service-accounts.crt CN = service-accounts

 

항목 네트워크 대역 
clusterCIDR 10.200.0.0/16
→ node-0 PodCIDR 10.200.0.0/24
→ node-1 PodCIDR 10.200.1.0/24
ServiceCIDR 10.32.0.0/24
api clusterIP 10.32.0.1

 

 

(참고) kind k8s 에서 인증서 관련 파일 확인

더보기
# 툴 설치
docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree yq jq -y'

# Check certificates expiration for a Kubernetes cluster
docker exec -i myk8s-control-plane kubeadm certs check-expiration

[check-expiration] Reading configuration from the "kubeadm-config" ConfigMap in namespace "kube-system"...
[check-expiration] Use 'kubeadm init phase upload-config --config your-config.yaml' to re-upload it.

CERTIFICATE                EXPIRES                  RESIDUAL TIME   CERTIFICATE AUTHORITY   EXTERNALLY MANAGED
admin.conf                 Jan 06, 2027 06:59 UTC   363d            ca                      no
apiserver                  Jan 06, 2027 06:59 UTC   363d            ca                      no
apiserver-etcd-client      Jan 06, 2027 06:59 UTC   363d            etcd-ca                 no
apiserver-kubelet-client   Jan 06, 2027 06:59 UTC   363d            ca                      no
controller-manager.conf    Jan 06, 2027 06:59 UTC   363d            ca                      no
etcd-healthcheck-client    Jan 06, 2027 06:59 UTC   363d            etcd-ca                 no
etcd-peer                  Jan 06, 2027 06:59 UTC   363d            etcd-ca                 no
etcd-server                Jan 06, 2027 06:59 UTC   363d            etcd-ca                 no
front-proxy-client         Jan 06, 2027 06:59 UTC   363d            front-proxy-ca          no
scheduler.conf             Jan 06, 2027 06:59 UTC   363d            ca                      no
super-admin.conf           Jan 06, 2027 06:59 UTC   363d            ca                      no

CERTIFICATE AUTHORITY   EXPIRES                  RESIDUAL TIME   EXTERNALLY MANAGED
ca                      Jan 04, 2036 06:59 UTC   9y              no
etcd-ca                 Jan 04, 2036 06:59 UTC   9y              no
front-proxy-ca          Jan 04, 2036 06:59 UTC   9y              no


#
docker exec -it myk8s-control-plane tree /etc/kubernetes

/etc/kubernetes
|-- admin.conf
|-- controller-manager.conf
|-- kubelet.conf
|-- manifests
|   |-- etcd.yaml
|   |-- kube-apiserver.yaml
|   |-- kube-controller-manager.yaml
|   `-- kube-scheduler.yaml
|-- pki
|   |-- apiserver-etcd-client.crt
|   |-- apiserver-etcd-client.key
|   |-- apiserver-kubelet-client.crt
|   |-- apiserver-kubelet-client.key
|   |-- apiserver.crt
|   |-- apiserver.key
|   |-- ca.crt
|   |-- ca.key
|   |-- etcd
|   |   |-- ca.crt
|   |   |-- ca.key
|   |   |-- healthcheck-client.crt
|   |   |-- healthcheck-client.key
|   |   |-- peer.crt
|   |   |-- peer.key
|   |   |-- server.crt
|   |   `-- server.key
|   |-- front-proxy-ca.crt
|   |-- front-proxy-ca.key
|   |-- front-proxy-client.crt
|   |-- front-proxy-client.key
|   |-- sa.key
|   `-- sa.pub
|-- scheduler.conf
`-- super-admin.conf

4 directories, 31 files

 

☞ cat ca.conf 파일 내용 확인
구분 역할
[req] OpenSSL 요청 기본 동작
[ca_*] CA 인증서
[admin] 관리자 (kubectl)
[service-accounts] ServiceAccount 토큰 서명
[node-*] 워커 노드(kubelet)
[kube-proxy] kube-proxy
[kube-controller-manager] 컨트롤러
[kube-scheduler] 스케줄러
[kube-api-server] API Server
[default_req_extensions] 공통 CSR 옵션

 

[req]
distinguished_name = req_distinguished_name
prompt             = no                      # CSR 생성 시 대화형 입력 없음
x509_extensions    = ca_x509_extensions      # CA 인증서 생성 시 사용할 확장

[ca_x509_extensions]                         # CA 인증서 설정 (Root of Trust)
basicConstraints = CA:TRUE                   # CA 권한 인증서
keyUsage         = cRLSign, keyCertSign      # 다른 인증서를 서명 가능, Kubernetes 모든 인증의 신뢰 루트

[req_distinguished_name]
C   = US
ST  = Washington
L   = Seattle
CN  = CA                                     # 클러스터 CA

[admin]                                      # Admin 사용자 (kubectl)
distinguished_name = admin_distinguished_name
prompt             = no
req_extensions     = default_req_extensions

[admin_distinguished_name]
CN = admin                                   # [K8S] CN → user
O  = system:masters                          # [K8S] O → group , system:masters - Kubernetes 슈퍼유저 그룹, 모든 RBAC 인가 우회

# Service Accounts
#
# The Kubernetes Controller Manager leverages a key pair to generate
# and sign service account tokens as described in the
# [managing service accounts](https://kubernetes.io/docs/admin/service-accounts-admin/)
# documentation.

[service-accounts]                           # Service Account 서명자
distinguished_name = service-accounts_distinguished_name
prompt             = no
req_extensions     = default_req_extensions

[service-accounts_distinguished_name] 
CN = service-accounts                        # controller-manager가 사용하는 ServiceAccount 토큰 서명용 인증서 , apiserver에서 --service-account-key-file 로 사용

# Worker Nodes
#
# Kubernetes uses a [special-purpose authorization mode](https://kubernetes.io/docs/admin/authorization/node/)
# called Node Authorizer, that specifically authorizes API requests made
# by [Kubelets](https://kubernetes.io/docs/concepts/overview/components/#kubelet).
# In order to be authorized by the Node Authorizer, Kubelets must use a credential
# that identifies them as being in the `system:nodes` group, with a username
# of `system:node:<nodeName>`.

[node-0]                                    # Worker Node 인증서 (kubelet)
distinguished_name = node-0_distinguished_name
prompt             = no
req_extensions     = node-0_req_extensions

[node-0_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth, serverAuth  # clientAuth: apiserver → kubelet & serverAuth: kubelet HTTPS 서버(10250)
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = "Node-0 Certificate"
subjectAltName       = DNS:node-0, IP:127.0.0.1
subjectKeyIdentifier = hash

[node-0_distinguished_name]
CN = system:node:node-0                     # kubelet 사용자 , CN = system:node:<nodeName>
O  = system:nodes                           # Node Authorizer 그룹  ,O = system:nodes
C  = US
ST = Washington
L  = Seattle

[node-1]
distinguished_name = node-1_distinguished_name
prompt             = no
req_extensions     = node-1_req_extensions

[node-1_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth, serverAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = "Node-1 Certificate"
subjectAltName       = DNS:node-1, IP:127.0.0.1
subjectKeyIdentifier = hash

[node-1_distinguished_name]
CN = system:node:node-1
O  = system:nodes
C  = US
ST = Washington
L  = Seattle


# Kube Proxy Section
[kube-proxy]                                # kube-proxy
distinguished_name = kube-proxy_distinguished_name
prompt             = no
req_extensions     = kube-proxy_req_extensions

[kube-proxy_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth, serverAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = "Kube Proxy Certificate"
subjectAltName       = DNS:kube-proxy, IP:127.0.0.1
subjectKeyIdentifier = hash

[kube-proxy_distinguished_name]
CN = system:kube-proxy
O  = system:node-proxier                    # system:node-proxier ClusterRoleBinding 존재 , 서비스 네트워크 제어 가능
C  = US
ST = Washington
L  = Seattle


# Controller Manager
[kube-controller-manager]
distinguished_name = kube-controller-manager_distinguished_name
prompt             = no
req_extensions     = kube-controller-manager_req_extensions

[kube-controller-manager_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth, serverAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = "Kube Controller Manager Certificate"
subjectAltName       = DNS:kube-controller-manager, IP:127.0.0.1
subjectKeyIdentifier = hash

[kube-controller-manager_distinguished_name] # 클러스터 상태 관리, Node, ReplicaSet, SA 토큰 등 관리
CN = system:kube-controller-manager
O  = system:kube-controller-manager
C  = US
ST = Washington
L  = Seattle


# Scheduler
[kube-scheduler]
distinguished_name = kube-scheduler_distinguished_name
prompt             = no
req_extensions     = kube-scheduler_req_extensions

[kube-scheduler_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth, serverAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = "Kube Scheduler Certificate"
subjectAltName       = DNS:kube-scheduler, IP:127.0.0.1
subjectKeyIdentifier = hash

[kube-scheduler_distinguished_name]
CN = system:kube-scheduler
O  = system:kube-scheduler                  # Pod 스케줄링 전용 권한
C  = US
ST = Washington
L  = Seattle


# API Server
#
# The Kubernetes API server is automatically assigned the `kubernetes`
# internal dns name, which will be linked to the first IP address (`10.32.0.1`)
# from the address range (`10.32.0.0/24`) reserved for internal cluster
# services.

[kube-api-server]                           # API Server 인증서
distinguished_name = kube-api-server_distinguished_name
prompt             = no
req_extensions     = kube-api-server_req_extensions

[kube-api-server_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth, serverAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client, server
nsComment            = "Kube API Server Certificate"
subjectAltName       = @kube-api-server_alt_names
subjectKeyIdentifier = hash

[kube-api-server_alt_names]                 # SAN (Subject Alternative Name) : 모든 내부/외부 접근 주소
IP.0  = 127.0.0.1
IP.1  = 10.32.0.1
DNS.0 = kubernetes
DNS.1 = kubernetes.default
DNS.2 = kubernetes.default.svc
DNS.3 = kubernetes.default.svc.cluster
DNS.4 = kubernetes.svc.cluster.local
DNS.5 = server.kubernetes.local
DNS.6 = api-server.kubernetes.local

[kube-api-server_distinguished_name]
CN = kubernetes
C  = US
ST = Washington
L  = Seattle


[default_req_extensions]                    # 공통 CSR 확장 : 대부분 클라이언트 인증서 -> kubelet / apiserver만 serverAuth 추가
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = "Admin Client Certificate"
subjectKeyIdentifier = hash

 

 

 Certificate Authority (인증서 설치)

# Generate the CA configuration file, certificate, and private key

# Root CA 개인키 생성 : ca.key
openssl genrsa -out ca.key 4096
ls -l ca.key
-rw------- 1 root root 3272 Jan  8 16:34 ca.key


cat ca.key
openssl rsa -in ca.key -text -noout # 개인키 구조 확인





# Root CA 인증서 생성 : ca.crt
## -x509 : CSR을 만들지 않고 바로 인증서(X.509) 생성, 즉, Self-Signed Certificate
## -noenc : 개인키를 암호화하지 않음, 즉, CA 키(ca.key)에 패스프레이즈 없음
## -config ca.conf : 인증서 세부 정보는 설정 파일에서 읽음 , [req] 섹션 사용됨 - DN 정보 → [req_distinguished_name] , CA 확장 → [ca_x509_extensions]
openssl req -x509 -new -sha512 -noenc \
  -key ca.key -days 3653 \
  -config ca.conf \
  -out ca.crt
ls -l ca.crt
-rw-r--r-- 1 root root 1899 Jan  8 16:36 ca.crt

# ca.conf 관련 내용
cat ca.conf
-------------------------------------------
[req]
distinguished_name = req_distinguished_name
prompt             = no
x509_extensions    = ca_x509_extensions

[ca_x509_extensions]
basicConstraints = CA:TRUE                    # 이 인증서는 CA 역할 가능
keyUsage         = cRLSign, keyCertSign       # cRLSign: 인증서 폐기 목록(CRL) 서명 가능, keyCertSign: 다른 인증서를 서명할 수 있음

[req_distinguished_name]
C   = US
ST  = Washington
L   = Seattle
CN  = CA
-------------------------------------------

cat ca.crt
openssl x509 -in ca.crt -text -noout # 인증서 전체 내용 확인
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            56:fb:42:82:5e:2f:96:cf:f5:83:2e:78:46:98:6e:3f:08:ee:99:67
        Signature Algorithm: sha512WithRSAEncryption
        Issuer: C = US, ST = Washington, L = Seattle, CN = CA
        Validity
            Not Before: Jan  3 00:46:22 2026 GMT
            Not After : Jan  4 00:46:22 2036 GMT
        Subject: C = US, ST = Washington, L = Seattle, CN = CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    00:ae:ce:95:7e:db:50:a2:4a:71:8b:99:54:0d:b4:
                    ce:1e:6f:13:3c:a6:54:30:0f:5b:0a:76:56:8c:44:
                    75:98:58:a6:57:7d:d2:38:e8:05:3c:cc:a5:e9:86:
                    57:73:98:c5:17:52:7c:7e:c8:48:6c:6b:86:13:1c:
                    7a:72:5d:10:3a:15:72:8d:66:35:e3:55:06:3e:f7:
                    44:7f:1b:fc:9e:4a:2b:4a:28:dd:2c:34:63:8d:26:
                    cc:39:50:3b:44:e5:f8:fe:68:c8:c0:a5:94:ba:b1:
                    d5:e3:55:1d:d9:98:0c:03:23:3f:9d:d9:a0:79:2c:
                    e9:ce:c9:92:b8:1f:6e:83:cb:08:1e:e6:28:cf:55:
                    29:b3:f3:19:1b:fe:c2:d8:30:6e:ee:68:7e:80:c3:
                    9a:53:77:d1:ae:2a:21:ee:82:94:d7:b5:f3:8f:a3:
                    98:f8:85:c6:c9:94:72:f3:1e:61:45:84:97:e4:25:
                    69:c8:5e:11:2c:75:2a:85:a6:b4:75:50:5f:a1:6c:
                    0a:54:1e:78:ab:25:a3:2e:04:18:21:68:86:11:3d:
                    90:09:95:02:aa:fc:32:2c:c5:ed:ac:d1:14:3c:d7:
                    fc:c3:a3:9f:dd:52:07:eb:2f:a7:fc:22:5e:2c:23:
                    ad:f6:f5:1e:90:db:3f:32:eb:10:38:34:c3:f0:40:
                    5d:c9:0b:d0:01:fd:78:73:0b:80:92:75:0c:24:76:
                    c1:6d:93:42:86:4b:a0:6d:99:7b:72:46:b6:52:b1:
                    2f:47:90:a0:ed:d8:93:71:23:c4:20:c8:63:04:a1:
                    f6:b6:d8:6e:6b:20:1a:2b:56:43:02:47:5e:77:ae:
                    4e:00:d5:ec:05:f6:e8:a4:ab:aa:8b:14:8b:b9:da:
                    d4:a6:e6:c6:c2:35:5a:fd:24:51:7d:29:bb:3c:d3:
                    fd:a7:bf:a9:5b:77:5a:e1:b1:7b:51:ab:29:a4:15:
                    e7:ac:f6:2a:1e:38:68:bb:f6:6f:60:e4:26:34:cc:
                    45:08:2b:e0:71:9a:8e:67:e3:0d:d4:67:63:0b:76:
                    27:bd:ff:8d:9c:78:e5:b8:55:f0:ce:c1:35:b7:b6:
                    e7:44:60:60:25:ae:f1:0f:3d:c6:7e:25:03:a3:c8:
                    87:f8:3d:cd:4b:06:1b:d1:94:63:31:50:33:5b:3f:
                    3c:66:a8:4d:df:2a:b4:76:a4:fa:54:73:43:09:ac:
                    6c:21:0b:9c:35:e9:14:ca:25:cd:f1:72:c1:fe:0f:
                    aa:56:59:1d:ea:45:a7:ab:f5:41:a5:d1:50:3d:da:
                    f0:71:ff:8b:d2:3b:04:0a:d2:80:e9:17:d6:9a:a3:
                    1a:5f:19:9b:a0:ef:08:36:d4:88:65:2b:50:42:10:
                    14:e1:a9
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:TRUE
            X509v3 Key Usage: 
                Certificate Sign, CRL Sign
            X509v3 Subject Key Identifier: 
                B3:5D:82:13:B6:1C:44:59:8C:0A:4E:DB:2B:18:98:77:0D:7A:2F:5B

 

 

(참고) kind k8s ca.crt 정보

 

더보기
docker exec -i myk8s-control-plane cat /etc/kubernetes/pki/ca.crt | openssl x509 -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 2963297175414940201 (0x291fbf14b086a229)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = kubernetes
        Validity
            Not Before: Jan  8 04:37:34 2026 GMT
            Not After : Jan  6 04:42:34 2036 GMT
        Subject: CN = kubernetes
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:d2:b2:32:b5:5a:28:f4:fc:d4:0b:4a:f8:46:e8:
                    a5:cf:5a:55:56:aa:23:6b:f7:f5:12:0b:30:2e:3a:
                    b3:63:b6:1c:52:a6:2e:fa:01:12:bb:9c:8e:5f:55:
                    f1:e0:a3:25:d5:44:b7:ae:21:57:7c:a4:50:4d:8a:
                    22:d1:c3:8d:4a:03:89:5b:c2:5f:ba:f5:12:ce:b3:
                    60:43:e0:3b:ed:1f:45:89:c8:2a:e1:17:a7:06:9b:
                    dd:16:c2:61:78:c6:20:03:02:20:1f:f0:b7:46:a7:
                    c8:87:ce:6f:c1:ce:ff:93:22:cf:7d:77:c0:15:a4:
                    1e:8a:36:94:c0:34:5f:c0:aa:eb:9a:b2:07:97:b6:
                    89:c8:41:95:95:36:3c:7f:a4:97:6a:a0:3c:08:47:
                    3b:d7:75:f8:bd:3d:4d:70:ac:a6:81:2a:a4:9f:fb:
                    33:d3:84:a6:63:c7:92:1f:7a:d6:07:d8:b9:70:fa:
                    6d:b6:4e:15:17:33:4f:64:91:64:80:66:8f:37:e9:
                    87:45:b6:d3:18:06:98:f8:e3:94:e9:32:61:c8:ea:
                    3a:d4:5b:eb:b0:5c:20:9c:86:64:8a:39:08:cc:62:
                    c0:32:ed:49:5c:4d:56:08:85:e9:97:71:e0:01:78:
                    39:d5:a4:5d:66:95:e9:3f:e7:42:cf:52:34:55:8e:
                    6b:b5
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment, Certificate Sign
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Subject Key Identifier:
                C2:48:9F:C8:3A:EE:CC:BE:0E:A9:A8:AA:5E:1B:16:3F:78:76:7B:D0
            X509v3 Subject Alternative Name:
                DNS:kubernetes
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        b0:65:db:82:8f:e8:be:65:fd:5d:d2:e0:0f:fd:df:9d:fc:b9:
        01:66:21:01:66:12:56:fd:7b:a5:e7:c7:59:b1:ec:c2:9c:a9:
        ee:ac:ac:07:26:b9:b4:9a:0f:63:2f:07:a2:63:73:4c:cd:67:
        31:4d:da:98:bc:bf:51:0c:26:36:4e:9e:72:15:b0:5e:26:44:
        00:77:7f:2e:41:80:dc:92:32:30:92:7b:64:39:22:a3:b0:fd:
        9b:8b:8a:10:56:73:fa:1d:20:47:0e:31:54:93:23:70:4d:8b:
        3f:9f:9b:bb:2e:cc:69:eb:ea:04:c7:f1:14:db:8d:47:ba:c6:
        1e:2a:f1:b0:5a:9a:0b:f4:52:35:32:64:33:92:c4:02:cc:4c:
        fc:a9:a7:a2:a1:86:0a:da:f9:c9:17:f1:81:22:cf:0d:1e:0c:
        e4:78:ff:69:7d:ed:7b:d3:ab:7c:1c:50:07:e0:2a:57:15:aa:
        b5:e7:68:28:68:2e:59:13:fa:f0:39:1d:4c:ff:e6:69:4f:52:
        c6:b8:02:65:10:4a:20:af:e0:56:5d:01:03:b8:91:ab:76:aa:
        f7:31:b1:4a:73:36:41:54:d6:30:c8:79:54:86:f8:dc:7b:7d:
        65:52:80:78:0d:df:77:0e:a0:5e:22:37:47:46:80:f6:b0:67:
        4d:29:80:d0

 

  Create Client and Server Certificates : admin

# Create Client and Server Certificates : admin
openssl genrsa -out admin.key 4096
ls -l admin.key

# ca.conf 에 admin 섹션
cat ca.conf
-------------------------------------------
[admin]
distinguished_name = admin_distinguished_name
prompt             = no
req_extensions     = default_req_extensions

[admin_distinguished_name]
CN = admin
O  = system:masters

[default_req_extensions]                    # 공통 CSR 확장
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = "Admin Client Certificate"
subjectKeyIdentifier = hash
-------------------------------------------

# csr 파일 생성 : admin.key 개인키를 사용해 'CN=admin, O=system:masters'인 Kubernetes 관리자용 클라이언트 인증서 요청(admin.csr) 생성
openssl req -new -key admin.key -sha256 \
  -config ca.conf -section admin \
  -out admin.csr
ls -l admin.csr
openssl req -in admin.csr -text -noout # CSR 전체 내용 확인


# ca에 csr 요청을 통한 crt 파일 생성
## -req : CSR를 입력으로 받아 인증서를 생성, self-signed 아님, CA가 서명하는 방식
## -days 3653 : 인증서 유효기간 3653일 (약 10년)
## -copy_extensions copyall : CSR에 포함된 모든 X.509 extensions를 인증서로 복사
## -CAcreateserial : CA 시리얼 번호 파일 자동 생성, 다음 인증서 발급 시 재사용, 기본 생성 파일(ca.srl)
openssl x509 -req -days 3653 -in admin.csr \
  -copy_extensions copyall \
  -sha256 -CA ca.crt \
  -CAkey ca.key \
  -CAcreateserial \
  -out admin.crt
Certificate request self-signature ok
subject=CN = admin, O = system:masters

ls -l admin.crt
openssl x509 -in admin.crt -text -noout
...
        Issuer: C = US, ST = Washington, L = Seattle, CN = CA
        Validity
            Not Before: Jan  3 01:01:40 2026 GMT
            Not After : Jan  4 01:01:40 2036 GMT
        Subject: CN = admin, O = system:masters
        ...
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            Netscape Cert Type: 
                SSL Client
            Netscape Comment: 
                Admin Client Certificate
            ...

 

 

(참고) system:masters 그룹에 속한 사용자 특징 : 인증 후 → 인가 우회. 즉, 인증 시 바로 슈퍼유저 권한

더보기
  • RBAC 기반 권한검사(Role/ClusterRole)를 거치지 않음. 웹훅 기반 인가도 거치지 않음.
  • 즉, API 서버에서 모든 동작을 무조건 허용함. 실질적으로 클러스터 슈퍼유저(superuser) 권한
  • system:masters 그룹은 API 서버에 대한 무제한(superuser) 접근 권한을 부여하는 내장(built-in) 그룹.
  • 이 그룹에 속한 사용자는 모든 요청에 대해 RBAC이나 Webhook 같은 인가(authorization) 검사를 받지 않고 API 접근을 허용받음.
  • 따라서 일반적인 RBAC 정책(ClusterRole, ClusterRoleBinding)과 상관 없이 전체 클러스터에 대한 관리자 권한을 갖습니다 → 즉 인가 검증이 사실상 우회됨.
  • 공식 체크리스트에서도 이 그룹의 사용은 최소화하라고 권고. (부트스트랩 이후에는 사용자/컴포넌트에 system:masters 인증 정보로 접근하지 않아야 함) → AWS Root 계정과 유사하게 관리
    • 관리자 인증서가 탈취당하면 복구가 매우 어려움

 

  Create Client and Server Certificates : 나머지 전부

# ca.conf 수정
cat ca.conf | grep system:kube-scheduler
CN = system:kube-scheduler
O  = system:system:kube-scheduler
sed -i 's/system:system:kube-scheduler/system:kube-scheduler/' ca.conf
cat ca.conf | grep system:kube-scheduler
CN = system:kube-scheduler
O  = system:kube-scheduler


# 변수 지정
certs=(
  "node-0" "node-1"
  "kube-proxy" "kube-scheduler"
  "kube-controller-manager"
  "kube-api-server"
  "service-accounts"
)

# 확인
echo ${certs[*]}
node-0 node-1 kube-proxy kube-scheduler kube-controller-manager kube-api-server service-accounts

# 개인키 생성, csr 생성, 인증서 생성
for i in ${certs[*]}; do
  openssl genrsa -out "${i}.key" 4096

  openssl req -new -key "${i}.key" -sha256 \
    -config "ca.conf" -section ${i} \
    -out "${i}.csr"

  openssl x509 -req -days 3653 -in "${i}.csr" \
    -copy_extensions copyall \
    -sha256 -CA "ca.crt" \
    -CAkey "ca.key" \
    -CAcreateserial \
    -out "${i}.crt"
done
Certificate request self-signature ok
subject=CN = system:node:node-0, O = system:nodes, C = US, ST = Washington, L = Seattle
Certificate request self-signature ok
subject=CN = system:node:node-1, O = system:nodes, C = US, ST = Washington, L = Seattle
Certificate request self-signature ok
subject=CN = system:kube-proxy, O = system:node-proxier, C = US, ST = Washington, L = Seattle
Certificate request self-signature ok
subject=CN = system:kube-scheduler, O = system:kube-scheduler, C = US, ST = Washington, L = Seattle
Certificate request self-signature ok
subject=CN = system:kube-controller-manager, O = system:kube-controller-manager, C = US, ST = Washington, L = Seattle
Certificate request self-signature ok
subject=CN = kubernetes, C = US, ST = Washington, L = Seattle
Certificate request self-signature ok
subject=CN = service-accounts





ls -1 *.crt *.key *.csr
admin.crt
admin.csr
admin.key
ca.crt
ca.key
kube-api-server.crt
kube-api-server.csr
kube-api-server.key
kube-controller-manager.crt
kube-controller-manager.csr
kube-controller-manager.key
kube-proxy.crt
kube-proxy.csr
kube-proxy.key
kube-scheduler.crt
kube-scheduler.csr
kube-scheduler.key
node-0.crt
node-0.csr
node-0.key
node-1.crt
node-1.csr
node-1.key
service-accounts.crt
service-accounts.csr
service-accounts.key


# 인증서 정보 확인
openssl x509 -in node-0.crt -text -noout
        Issuer: C = US, ST = Washington, L = Seattle, CN = CA
        Validity
            Not Before: Jan  3 02:41:09 2026 GMT
            Not After : Jan  4 02:41:09 2036 GMT
        Subject: CN = system:node:node-0, O = system:nodes, C = US, ST = Washington, L = Seattle
        ...
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication, TLS Web Server Authentication
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            Netscape Cert Type: 
                SSL Client
            Netscape Comment: 
                Node-0 Certificate
            X509v3 Subject Alternative Name: 
                DNS:node-0, IP Address:127.0.0.1

openssl x509 -in node-1.crt -text -noout
        Subject: CN = system:node:node-1, O = system:nodes, C = US, ST = Washington, L = Seattle
            X509v3 Subject Alternative Name: 
                DNS:node-1, IP Address:127.0.0.1

openssl x509 -in kube-proxy.crt -text -noout
        Issuer: C = US, ST = Washington, L = Seattle, CN = CA
        Validity
            Not Before: Jan  3 02:41:13 2026 GMT
            Not After : Jan  4 02:41:13 2036 GMT
        Subject: CN = system:kube-proxy, O = system:node-proxier, C = US, ST = Washington, L = Seattle
        ...
        X509v3 extensions:
            Netscape Cert Type: 
                SSL Client
            Netscape Comment: 
                Kube Proxy Certificate
            X509v3 Subject Alternative Name: 
                DNS:kube-proxy, IP Address:127.0.0.1

openssl x509 -in kube-scheduler.crt -text -noout
        Issuer: C = US, ST = Washington, L = Seattle, CN = CA
        Validity
            Not Before: Jan  3 02:41:13 2026 GMT
            Not After : Jan  4 02:41:13 2036 GMT
        Subject: CN = system:kube-scheduler, O = system:kube-scheduler, C = US, ST = Washington, L = Seattle
            Netscape Cert Type: 
                SSL Client
            Netscape Comment: 
                Kube Scheduler Certificate
            X509v3 Subject Alternative Name: 
                DNS:kube-scheduler, IP Address:127.0.0.1

openssl x509 -in kube-controller-manager.crt -text -noout
        Validity
            Not Before: Jan  3 02:41:16 2026 GMT
            Not After : Jan  4 02:41:16 2036 GMT
        Subject: CN = system:kube-controller-manager, O = system:kube-controller-manager, C = US, ST = Washington, L = Seattle
            Netscape Cert Type: 
                SSL Client
            Netscape Comment: 
                Kube Controller Manager Certificate
            X509v3 Subject Alternative Name: 
                DNS:kube-controller-manager, IP Address:127.0.0.1

# api-server : SAN 정보에 10.32.0.1 은 kubernetes (Service) ClusterIP. 다른 인증서와 다르게 SSL Server 역할 추가 확인
openssl x509 -in kube-api-server.crt -text -noout
        Issuer: C = US, ST = Washington, L = Seattle, CN = CA
        Validity
            Not Before: Jan  3 02:41:17 2026 GMT
            Not After : Jan  4 02:41:17 2036 GMT
        Subject: CN = kubernetes, C = US, ST = Washington, L = Seattle
            Netscape Cert Type: 
                SSL Client, SSL Server
            Netscape Comment: 
                Kube API Server Certificate
            X509v3 Subject Alternative Name: 
                IP Address:127.0.0.1, IP Address:10.32.0.1, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster, DNS:kubernetes.svc.cluster.local, DNS:server.kubernetes.local, DNS:api-server.kubernetes.local

# service-accounts
openssl x509 -in service-accounts.crt -text -noout
        Issuer: C = US, ST = Washington, L = Seattle, CN = CA
        Validity
            Not Before: Jan  3 02:41:17 2026 GMT
            Not After : Jan  4 02:41:17 2036 GMT
        Subject: CN = service-accounts
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            Netscape Cert Type: 
                SSL Client
            Netscape Comment: 
                Admin Client Certificate

 

 

(참고) kind k8s 에 관련 정보 : 인증서 등

#
docker exec -it myk8s-control-plane tree /etc/kubernetes
docker exec -it myk8s-control-plane tree /var/lib/kubelet/pki


# node 인증서 정보
docker exec -it myk8s-control-plane tree /var/lib/kubelet/pki
/var/lib/kubelet/pki
|-- kubelet-client-2026-01-04-01-20-27.pem
|-- kubelet-client-current.pem -> /var/lib/kubelet/pki/kubelet-client-2026-01-04-01-20-27.pem
|-- kubelet.crt
`-- kubelet.key

docker exec -i myk8s-control-plane cat /var/lib/kubelet/pki/kubelet.crt | openssl x509 -text -noout
        Issuer: CN=myk8s-control-plane-ca@1767489627
        Validity
            Not Before: Jan  4 00:20:27 2026 GMT
            Not After : Jan  4 00:20:27 2027 GMT
        Subject: CN=myk8s-control-plane@1767489627
        ...
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Server Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Authority Key Identifier:
                5A:E4:1B:29:0F:79:7E:EB:5A:A2:BC:5B:B2:51:70:5F:90:D2:EC:9B
            X509v3 Subject Alternative Name:
                DNS:myk8s-control-plane

docker exec -i myk8s-worker cat /var/lib/kubelet/pki/kubelet.crt | openssl x509 -text -noout
        Subject: CN=myk8s-worker@1767489640
        ...
            X509v3 Subject Alternative Name:
                DNS:myk8s-worker


# kube-proxy 인증서 정보
kubectl get cm -n kube-system kube-proxy -o yaml
data:
  config.conf: |-
    apiVersion: kubeproxy.config.k8s.io/v1alpha1
    bindAddress: 0.0.0.0
    bindAddressHardFail: false
    clientConnection:
      acceptContentTypes: ""
      burst: 0
      contentType: ""
      kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
...
  kubeconfig.conf: |-
    apiVersion: v1
    kind: Config
    clusters:
    - cluster:
        certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        server: https://myk8s-control-plane:6443
      name: default
    contexts:
    - context:
        cluster: default
        namespace: default
        user: default
      name: default
    current-context: default
    users:
    - name: default
      user:
        tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token


# scheduler 인증서 정보
docker exec -i myk8s-control-plane cat /etc/kubernetes/scheduler.conf
docker exec -i myk8s-control-plane cat /etc/kubernetes/scheduler.conf | grep client-certificate-data | cut -d ':' -f 2 | base64 -d | openssl x509 -text -noout
docker exec -i myk8s-control-plane cat /etc/kubernetes/scheduler.conf | grep client-certificate-data | cut -d ':' -f 2 | tr -d ' ' | base64 -d | openssl x509 -text -noout
        Issuer: CN = kubernetes
        Validity
            Not Before: Jan  3 02:46:18 2026 GMT
            Not After : Jan  3 02:51:18 2027 GMT
        Subject: CN = system:kube-scheduler
        ...
            X509v3 Extended Key Usage:
                TLS Web Client Authentication

kubectl get pod -n kube-system -l component=kube-scheduler
kubectl describe pod -n kube-system -l component=kube-scheduler
kubectl rolesum -k User system:kube-scheduler
kubectl rbac-tool lookup system:kube-scheduler


# kcm 인증서 정보
docker exec -i myk8s-control-plane cat /etc/kubernetes/controller-manager.conf
docker exec -i myk8s-control-plane cat /etc/kubernetes/controller-manager.conf | grep client-certificate-data | cut -d ':' -f 2 | base64 -d | openssl x509 -text -noout
docker exec -i myk8s-control-plane cat /etc/kubernetes/controller-manager.conf | grep client-certificate-data | cut -d ':' -f 2 | tr -d ' ' | base64 -d | openssl x509 -text -noout
        Subject: CN=system:kube-controller-manager

kubectl rolesum -k User system:kube-controller-manager
kubectl rbac-tool lookup system:kube-controller-manager


# api-server 인증서 정보 : IP Address:10.96.0.1, IP Address:192.168.97.3, IP Address:127.0.0.1
docker exec -i myk8s-control-plane cat /etc/kubernetes/pki/apiserver.crt | openssl x509 -text -noout
        Issuer: CN=kubernetes
        Validity
            Not Before: Jan  3 03:31:30 2026 GMT
            Not After : Jan  3 03:36:30 2027 GMT
        Subject: CN=kube-apiserver
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Server Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Authority Key Identifier:
                3D:E2:06:BE:D3:96:A8:C6:46:48:DC:91:47:DB:54:0D:5B:12:91:01
            X509v3 Subject Alternative Name:
                DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:localhost, DNS:myk8s-control-plane, IP Address:10.96.0.1, IP Address:192.168.97.3, IP Address:127.0.0.1

kubectl get svc,ep
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   74m

NAME                   ENDPOINTS           AGE
endpoints/kubernetes   192.168.97.3:6443   74m

# apiserver 파드 args 정보
kubectl describe pod -n kube-system kube-apiserver-myk8s-control-plane
...
    Command:
      kube-apiserver
      --advertise-address=192.168.97.3                      # 클러스터 내 다른 컴포넌트가 접근할 API 서버 주소
      --allow-privileged=true                               # privileged: true 파드 허용, CNI, kube-proxy, CSI, Cilium 같은 시스템 파드 필수
      --authorization-mode=Node,RBAC                        # [인가] Node Authorizer(system:node:* , kubelet 전용 권한 검증) -> RBAC (사용자 / 그룹 기반 권한)
      --client-ca-file=/etc/kubernetes/pki/ca.crt           # [인증] X.509 클라이언트 인증 : kubectl, controller, scheduler 인증서 모두 여기로 검증
      --enable-admission-plugins=NodeRestriction            # Admission Controller : kubelet이 자기 노드/파드만 조작 가능하게 제한, Node Authorizer와 함께 작동
      --enable-bootstrap-token-auth=true                    # [인증] Bootstrap 토큰 인증 : 신규 노드 join 시 bootstrap.kubernetes.io/token 사용
      --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt                 # etcd 연동 : kube-apiserver → etcd mTLS , apiserver는 etcd의 클라이언트
      --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt # 상동
      --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key  # 상동
      --etcd-servers=https://127.0.0.1:2379                         # etcd 연동 : etcd 엔드포인트
      --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt  # kubelet 통신 : API 서버 → kubelet 호출 시 사용
      --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key          # kubelet 통신 : 로그, exec, metrics, stats 접근
      --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname               # kubelet 통신 : 노드 접근 주소 우선순위
      --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt   # Aggregated API / Front Proxy : API Aggregation Layer 인증
      --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key    # 상동
      --requestheader-allowed-names=front-proxy-client                      # 프록시 인증서 CN 제한
      --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt # 프록시가 전달한 사용자 정보 신뢰
      --requestheader-extra-headers-prefix=X-Remote-Extra-                  # metrics-server, aggregated apiserver 사용 시 필수
      --requestheader-group-headers=X-Remote-Group                          # 상동
      --requestheader-username-headers=X-Remote-User                        # 상동
      --runtime-config=                                     # 비어 있음 → 기본 API 활성화
      --secure-port=6443                                    # HTTPS API 포트 , HTTP(8080)는 기본 비활성화
      --service-account-issuer=https://kubernetes.default.svc.cluster.local  # ServiceAccount 토큰 관리 : SA 토큰 issuer (OIDC 호환), BoundServiceAccountTokenVolume 필수
      --service-account-key-file=/etc/kubernetes/pki/sa.pub                  # 상동 : 토큰 검증용 공개키
      --service-account-signing-key-file=/etc/kubernetes/pki/sa.key          # 상동 : 토큰 서명용 개인키
      --service-cluster-ip-range=10.96.0.0/16
      --tls-cert-file=/etc/kubernetes/pki/apiserver.crt         # kube-apiserver 서버 인증서(tls) : 클라이언트(kubectl, kubelet 등)가 이 인증서 검증
      --tls-private-key-file=/etc/kubernetes/pki/apiserver.key  # 상동

# (참고) api -> kubelet 호출 시 : api client crt 정보
docker exec -it myk8s-control-plane ls -l /etc/kubernetes/pki | grep apiserver
-rw-r--r-- 1 root root 1123 Jan  4 01:20 apiserver-etcd-client.crt
-rw------- 1 root root 1679 Jan  4 01:20 apiserver-etcd-client.key
-rw-r--r-- 1 root root 1176 Jan  4 01:20 apiserver-kubelet-client.crt
-rw------- 1 root root 1679 Jan  4 01:20 apiserver-kubelet-client.key
-rw-r--r-- 1 root root 1326 Jan  4 01:20 apiserver.crt
-rw------- 1 root root 1679 Jan  4 01:20 apiserver.key

docker exec -i myk8s-control-plane cat /etc/kubernetes/pki/apiserver-kubelet-client.crt | openssl x509 -text -noout
...

# ServiceAccount 토큰 검증용 공개키/개인키 확인 : api 파드 service-account-key-file, service-account-signing-key-file 에서 사용
docker exec -it myk8s-control-plane ls -l /etc/kubernetes/pki/sa.{key,pub}
-rw------- 1 root root 1679 Jan  4 01:20 /etc/kubernetes/pki/sa.key
-rw------- 1 root root  451 Jan  4 01:20 /etc/kubernetes/pki/sa.pub

 

 

 

Distribute the Client and Server Certificates

 

# Copy the appropriate certificates and private keys to the node-0 and node-1 machines
for host in node-0 node-1; do
  ssh root@${host} mkdir /var/lib/kubelet/

  scp ca.crt root@${host}:/var/lib/kubelet/

  scp ${host}.crt \
    root@${host}:/var/lib/kubelet/kubelet.crt

  scp ${host}.key \
    root@${host}:/var/lib/kubelet/kubelet.key
done

# 확인
ssh node-0 ls -l /var/lib/kubelet
ssh node-1 ls -l /var/lib/kubelet

ssh node-1 ls -l /var/lib/kubelet
total 60
-rw-r--r-- 1 root root  1899 Jan  8 16:42 ca.crt
drwx------ 2 root root  4096 Jan  6 16:34 checkpoints
-rw------- 1 root root    62 Jan  6 16:34 cpu_manager_state
drwxr-xr-x 2 root root  4096 Jan  6 16:34 device-plugins
-rw------- 1 root root 10161 Jan  6 16:16 kubeconfig
-rw-r--r-- 1 root root   610 Jan  6 16:31 kubelet-config.yaml
-rw-r--r-- 1 root root  2147 Jan  8 16:42 kubelet.crt
-rw------- 1 root root  3272 Jan  8 16:42 kubelet.key
-rw------- 1 root root    61 Jan  6 16:34 memory_manager_state
drwxr-x--- 2 root root  4096 Jan  6 16:34 plugins
drwxr-x--- 2 root root  4096 Jan  6 16:34 plugins_registry
drwxr-x--- 2 root root  4096 Jan  6 16:34 pod-resources
drwxr-x--- 3 root root  4096 Jan  6 16:44 pods
total 60
-rw-r--r-- 1 root root  1899 Jan  8 16:42 ca.crt
drwx------ 2 root root  4096 Jan  6 16:36 checkpoints
-rw------- 1 root root    62 Jan  6 16:36 cpu_manager_state
drwxr-xr-x 2 root root  4096 Jan  6 16:36 device-plugins
-rw------- 1 root root 10161 Jan  6 16:16 kubeconfig
-rw-r--r-- 1 root root   610 Jan  6 16:31 kubelet-config.yaml
-rw-r--r-- 1 root root  2147 Jan  8 16:42 kubelet.crt
-rw------- 1 root root  3268 Jan  8 16:42 kubelet.key
-rw------- 1 root root    61 Jan  6 16:36 memory_manager_state
drwxr-x--- 2 root root  4096 Jan  6 16:36 plugins
drwxr-x--- 2 root root  4096 Jan  6 16:36 plugins_registry
drwxr-x--- 2 root root  4096 Jan  6 16:36 pod-resources
drwxr-x--- 3 root root  4096 Jan  6 16:44 pods




# Copy the appropriate certificates and private keys to the server machine
scp \
  ca.key ca.crt \
  kube-api-server.key kube-api-server.crt \
  service-accounts.key service-accounts.crt \
  root@server:~/

ca.key                                                                                                                                                                      100% 3272     2.4MB/s   00:00
ca.crt                                                                                                                                                                      100% 1899     1.6MB/s   00:00
kube-api-server.key                                                                                                                                                         100% 3268     2.9MB/s   00:00
kube-api-server.crt                                                                                                                                                         100% 2354     2.0MB/s   00:00
service-accounts.key                                                                                                                                                        100% 3272     2.9MB/s   00:00
service-accounts.crt                                                                                                                                                        100% 2004     2.1MB/s   00:00


# 확인
ssh server ls -l /root

-rw------- 1 root root 3272 Jan  6 15:31 admin.key
-rw------- 1 root root 9953 Jan  6 16:16 admin.kubeconfig
-rw-r--r-- 1 root root 1899 Jan  8 16:42 ca.crt
-rw------- 1 root root 3272 Jan  8 16:42 ca.key
-rw-r--r-- 1 root root 2354 Jan  8 16:42 kube-api-server.crt
-rw------- 1 root root 3268 Jan  8 16:42 kube-api-server.key
-rw-r--r-- 1 root root  727 Jan  6 16:20 kube-apiserver-to-kubelet.yaml
-rw-r--r-- 1 root root 2004 Jan  8 16:42 service-accounts.crt
-rw------- 1 root root 3272 Jan  8 16:42 service-accounts.key

 

 

Generating Kubernetes Configuration Files for Authentication

 

목표 : API Server와 통신을 위한 Client 인증 설정 파일 작성 - Docs
Kubernetes client configuration files

 

The kubelet Kubernetes Configuration File

  • When generating kubeconfig files for Kubelets the client certificate matching the Kubelet's node name must be used.
  • This will ensure Kubelets are properly authorized by the Kubernetes Node Authorizer.
    • Node Authorization : Kubelet이 수행하는 API 요청에 대한 권한을 특별히 부여하는 특수 목적의 권한 부여 모드
# apiserver 파드 args 정보
kubectl describe pod -n kube-system kube-apiserver-myk8s-control-plane
    Command:
      kube-apiserver
      --authorization-mode=Node,RBAC  


# Generate a kubeconfig file for the node-0 and node-1 worker nodes

# config set-cluster
kubectl config set-cluster kubernetes-the-hard-way \
  --certificate-authority=ca.crt \
  --embed-certs=true \
  --server=https://server.kubernetes.local:6443 \
  --kubeconfig=node-0.kubeconfig && ls -l node-0.kubeconfig && cat node-0.kubeconfig

kubectl config set-cluster kubernetes-the-hard-way \
  --certificate-authority=ca.crt \
  --embed-certs=true \
  --server=https://server.kubernetes.local:6443 \
  --kubeconfig=node-1.kubeconfig && ls -l node-1.kubeconfig && cat node-1.kubeconfig

# config set-credentials
kubectl config set-credentials system:node:node-0 \
  --client-certificate=node-0.crt \
  --client-key=node-0.key \
  --embed-certs=true \
  --kubeconfig=node-0.kubeconfig && cat node-0.kubeconfig

kubectl config set-credentials system:node:node-1 \
  --client-certificate=node-1.crt \
  --client-key=node-1.key \
  --embed-certs=true \
  --kubeconfig=node-1.kubeconfig && cat node-1.kubeconfig
  
# set-context : default 추가
kubectl config set-context default \
  --cluster=kubernetes-the-hard-way \
  --user=system:node:node-0 \
  --kubeconfig=node-0.kubeconfig && cat node-0.kubeconfig

kubectl config set-context default \
  --cluster=kubernetes-the-hard-way \
  --user=system:node:node-1 \
  --kubeconfig=node-1.kubeconfig && cat node-1.kubeconfig
...
contexts:
- context:
    cluster: kubernetes-the-hard-way
    user: system:node:node-0
  name: default

# use-context : current-context 에 default 추가
kubectl config use-context default \
  --kubeconfig=node-0.kubeconfig

kubectl config use-context default \
  --kubeconfig=node-1.kubeconfig
...
current-context: default

#
ls -l *.kubeconfig
-rw------- 1 root root 10157 Jan  3 14:55 node-0.kubeconfig
-rw------- 1 root root 10068 Jan  3 14:50 node-1.kubeconfig

 

 

<실습 검증>

 ls -l *.kubeconfig

 

 

 

(참고) kind system:node 관련 정보

# 
kubectl describe clusterroles system:node
kubectl get clusterrolebindings.rbac.authorization.k8s.io system:node

# 일반적인 ClusterRoleBinding 다르게 subjects 필드가 없음
# system:node 는 특수한 bootstrap RBAC
# 노드 인증서의 O = system:nodes 가 이 ClusterRoleBinding 과 매칭됨 , 참고로 CN = system:node:<node명>
kubectl get clusterrolebindings.rbac.authorization.k8s.io system:node -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2026-01-03T03:36:37Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:node
  resourceVersion: "146"
  uid: a451c617-1577-499a-9b04-59af6789e3ee
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:node

#
docker exec -i myk8s-worker cat /etc/kubernetes/kubelet.conf
docker exec -i myk8s-worker cat /var/lib/kubelet/pki/kubelet-client-current.pem | openssl x509 -text -noout
        Subject: O=system:nodes, CN=system:node:myk8s-worker

 

 

☞ The kube-proxy Kubernetes Configuration File

# Generate a kubeconfig file for the kube-proxy service
kubectl config set-cluster kubernetes-the-hard-way \
  --certificate-authority=ca.crt \
  --embed-certs=true \
  --server=https://server.kubernetes.local:6443 \
  --kubeconfig=kube-proxy.kubeconfig

kubectl config set-credentials system:kube-proxy \
  --client-certificate=kube-proxy.crt \
  --client-key=kube-proxy.key \
  --embed-certs=true \
  --kubeconfig=kube-proxy.kubeconfig

kubectl config set-context default \
  --cluster=kubernetes-the-hard-way \
  --user=system:kube-proxy \
  --kubeconfig=kube-proxy.kubeconfig

kubectl config use-context default \
  --kubeconfig=kube-proxy.kubeconfig

# 확인
cat kube-proxy.kubeconfig

 

 

 

The kube-controller-manager Kubernetes Configuration File

# Generate a kubeconfig file for the kube-controller-manager service
kubectl config set-cluster kubernetes-the-hard-way \
  --certificate-authority=ca.crt \
  --embed-certs=true \
  --server=https://server.kubernetes.local:6443 \
  --kubeconfig=kube-controller-manager.kubeconfig

kubectl config set-credentials system:kube-controller-manager \
  --client-certificate=kube-controller-manager.crt \
  --client-key=kube-controller-manager.key \
  --embed-certs=true \
  --kubeconfig=kube-controller-manager.kubeconfig

kubectl config set-context default \
  --cluster=kubernetes-the-hard-way \
  --user=system:kube-controller-manager \
  --kubeconfig=kube-controller-manager.kubeconfig

kubectl config use-context default \
  --kubeconfig=kube-controller-manager.kubeconfig

# 확인
cat kube-controller-manager.kubeconfig

 

☞ The admin Kubernetes Configuration File

# Generate a kubeconfig file for the admin user
kubectl config set-cluster kubernetes-the-hard-way \
  --certificate-authority=ca.crt \
  --embed-certs=true \
  --server=https://127.0.0.1:6443 \
  --kubeconfig=admin.kubeconfig

kubectl config set-credentials admin \
  --client-certificate=admin.crt \
  --client-key=admin.key \
  --embed-certs=true \
  --kubeconfig=admin.kubeconfig

kubectl config set-context default \
  --cluster=kubernetes-the-hard-way \
  --user=admin \
  --kubeconfig=admin.kubeconfig

kubectl config use-context default \
  --kubeconfig=admin.kubeconfig

# 확인
cat admin.kubeconfig

 

 

Distribute the Kubernetes Configuration Files

#
ls -l *.kubeconfig
-rw------- 1 root root  9949 Jan  3 15:00 admin.kubeconfig
-rw------- 1 root root 10305 Jan  3 14:59 kube-controller-manager.kubeconfig
-rw------- 1 root root 10187 Jan  3 14:58 kube-proxy.kubeconfig
-rw------- 1 root root 10231 Jan  3 14:59 kube-scheduler.kubeconfig
-rw------- 1 root root 10157 Jan  3 14:55 node-0.kubeconfig
-rw------- 1 root root 10068 Jan  3 14:50 node-1.kubeconfig

# Copy the kubelet and kube-proxy kubeconfig files to the node-0 and node-1 machines
for host in node-0 node-1; do
  ssh root@${host} "mkdir -p /var/lib/{kube-proxy,kubelet}"

  scp kube-proxy.kubeconfig \
    root@${host}:/var/lib/kube-proxy/kubeconfig \

  scp ${host}.kubeconfig \
    root@${host}:/var/lib/kubelet/kubeconfig
done

# 확인
ssh node-0 ls -l /var/lib/*/kubeconfig
ssh node-1 ls -l /var/lib/*/kubeconfig


# Copy the kube-controller-manager and kube-scheduler kubeconfig files to the server machine
scp admin.kubeconfig \
  kube-controller-manager.kubeconfig \
  kube-scheduler.kubeconfig \
  root@server:~/

# 확인
ssh server ls -l /root/*.kubeconfig

 

 

 

Generating the Data Encryption Config and Key

목표 : ETCD 에 Secret 저장 시, 암호화 저장 설정 - Docs , Encrypting Confidential Data at Rest

# The Encryption Key

# Generate an encryption key
export ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)
echo $ENCRYPTION_KEY
JMnUP1PUUORZE9iadPdzYifnvPVIniSzOW6NUoMofVc=


# The Encryption Config File

# Create the encryption-config.yaml encryption config file
# (참고) 실제 etcd 값에 기록되는 헤더 : k8s:enc:aescbc:v1:key1:<ciphertext>
cat configs/encryption-config.yaml
kind: EncryptionConfiguration           # kube-apiserver가 etcd에 저장할 리소스를 어떻게 암호화할지 정의
apiVersion: apiserver.config.k8s.io/v1  # --encryption-provider-config 플래그로 참조
resources:
  - resources:
      - secrets                         # 암호화 대상 Kubernetes 리소스 : 여기서는 Secret 리소스만 암호화
    providers:                          # 지원 providers(위 부터 적용됨) : identity, aescbc, aesgcm, kms v2, secretbox
      - aescbc:                         # etcd에 저장될 Secret을 AES-CBC 방식으로 암호화
          keys:
            - name: key1                # 키 식별자 (etcd 데이터에 기록됨)
              secret: ${ENCRYPTION_KEY}
      - identity: {}                    # 암호화하지 않음 (Plaintext), 주로 하위 호환성 / 점진적 암호화 목적
      
envsubst < configs/encryption-config.yaml > encryption-config.yaml
cat encryption-config.yaml

# Copy the encryption-config.yaml encryption config file to each controller instance:
scp encryption-config.yaml root@server:~/
ssh server ls -l /root/encryption-config.yaml

 

 

 Bootstrapping the etcd Cluster

목표 : server 노드에 etcd 서비스 기동

# Prerequisites

# hostname 변경 : controller -> server
# http 평문 통신!
# Each etcd member must have a unique name within an etcd cluster. 
# Set the etcd name to match the hostname of the current compute instance:
cat units/etcd.service | grep controller

ETCD_NAME=server
cat > units/etcd.service <<EOF
[Unit]
Description=etcd
Documentation=https://github.com/etcd-io/etcd

[Service]
Type=notify
ExecStart=/usr/local/bin/etcd \\
  --name ${ETCD_NAME} \\
  --initial-advertise-peer-urls http://127.0.0.1:2380 \\
  --listen-peer-urls http://127.0.0.1:2380 \\
  --listen-client-urls http://127.0.0.1:2379 \\
  --advertise-client-urls http://127.0.0.1:2379 \\
  --initial-cluster-token etcd-cluster-0 \\
  --initial-cluster ${ETCD_NAME}=http://127.0.0.1:2380 \\
  --initial-cluster-state new \\
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
cat units/etcd.service | grep server

# Copy etcd binaries and systemd unit files to the server machine
scp \
  downloads/controller/etcd \
  downloads/client/etcdctl \
  units/etcd.service \
  root@server:~/


# 아래는 server 가상머신 접속 후 명령 실행
# The commands in this lab must be run on the server machine. Login to the server machine using the ssh command. Example:
ssh root@server
-------------------------------------------------------------------
# Bootstrapping an etcd Cluster

# Install the etcd Binaries
# Extract and install the etcd server and the etcdctl command line utility
pwd
mv etcd etcdctl /usr/local/bin/

# Configure the etcd Server
mkdir -p /etc/etcd /var/lib/etcd
chmod 700 /var/lib/etcd
cp ca.crt kube-api-server.key kube-api-server.crt /etc/etcd/

# Create the etcd.service systemd unit file:
mv etcd.service /etc/systemd/system/
tree /etc/systemd/system/

# Start the etcd Server
systemctl daemon-reload
systemctl enable etcd
systemctl start etcd

# 확인
systemctl status etcd --no-pager
ss -tnlp | grep etcd
LISTEN 0      4096       127.0.0.1:2380      0.0.0.0:*    users:(("etcd",pid=2829,fd=3))                          
LISTEN 0      4096       127.0.0.1:2379      0.0.0.0:*    users:(("etcd",pid=2829,fd=6)) 

# List the etcd cluster members
etcdctl member list
702b0a34e2cfd39, started, server, http://127.0.0.1:2380, http://127.0.0.1:2379, false

etcdctl member list -w table
etcdctl endpoint status -w table

exit
-------------------------------------------------------------------

 

 

 

(참고) kind k8s etcd 관련 인증서 정보

# https 암호 통신 설정 정보 확인
kubectl describe pod -n kube-system etcd-myk8s-control-plane
...
    Command:
      etcd
      --advertise-client-urls=https://192.168.97.3:2379
      --cert-file=/etc/kubernetes/pki/etcd/server.crt
      --client-cert-auth=true
      --data-dir=/var/lib/etcd
      --experimental-initial-corrupt-check=true
      --experimental-watch-progress-notify-interval=5s
      --initial-advertise-peer-urls=https://192.168.97.3:2380
      --initial-cluster=myk8s-control-plane=https://192.168.97.3:2380
      --key-file=/etc/kubernetes/pki/etcd/server.key
      --listen-client-urls=https://127.0.0.1:2379,https://192.168.97.3:2379
      --listen-metrics-urls=http://127.0.0.1:2381
      --listen-peer-urls=https://192.168.97.3:2380
      --name=myk8s-control-plane
      --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
      --peer-client-cert-auth=true
      --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
      --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
      --snapshot-count=10000
      --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt

#
docker exec -it myk8s-control-plane tree /etc/kubernetes/pki/etcd
/etc/kubernetes/pki/etcd
|-- ca.crt
|-- ca.key
|-- healthcheck-client.crt
|-- healthcheck-client.key
|-- peer.crt
|-- peer.key
|-- server.crt
`-- server.key

# etcd 별도 CA 확인
docker exec -i myk8s-control-plane cat /etc/kubernetes/pki/etcd/ca.crt | openssl x509 -text -noout
        Issuer: CN=etcd-ca
        Validity
            Not Before: Jan  4 01:15:25 2026 GMT
            Not After : Jan  2 01:20:25 2036 GMT
        Subject: CN=etcd-ca
        ...
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment, Certificate Sign
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Subject Key Identifier:
                8C:D1:86:C6:90:7E:1E:9F:16:2B:FE:7C:6F:3F:3F:1A:6A:5F:B9:AD
            X509v3 Subject Alternative Name:
                DNS:etcd-ca

# kubeadm 에 인증서 정보 확인
docker exec -i myk8s-control-plane kubeadm certs check-expiration
CERTIFICATE                EXPIRES                  RESIDUAL TIME   CERTIFICATE AUTHORITY   EXTERNALLY MANAGED
apiserver-etcd-client      Jan 04, 2027 01:20 UTC   364d            etcd-ca                 no
etcd-healthcheck-client    Jan 04, 2027 01:20 UTC   364d            etcd-ca                 no
etcd-peer                  Jan 04, 2027 01:20 UTC   364d            etcd-ca                 no
etcd-server                Jan 04, 2027 01:20 UTC   364d            etcd-ca                 no
...

CERTIFICATE AUTHORITY   EXPIRES                  RESIDUAL TIME   EXTERNALLY MANAGED
ca                      Jan 02, 2036 01:20 UTC   9y              no
etcd-ca                 Jan 02, 2036 01:20 UTC   9y              no
front-proxy-ca          Jan 02, 2036 01:20 UTC   9y              no

# apiserver(client) -> etcd(server) 호출 시 사용하는 클라이언트 인증서 정보 확인
docker exec -i myk8s-control-plane cat /etc/kubernetes/pki/apiserver-etcd-client.crt | openssl x509 -text -noout
        Issuer: CN=etcd-ca
        Validity
            Not Before: Jan  4 01:15:25 2026 GMT
            Not After : Jan  4 01:20:25 2027 GMT
        Subject: CN=kube-apiserver-etcd-client
        ...
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE

 

 

  Bootstrapping the Kubernetes Control Plane

Server 노드에 ‘api server, scheduler, kcm’ 서비스 기동 - Docs

항목 네트워크 대역 or IP
clusterCIDR 10.200.0.0/16
→ node-0 PodCIDR 10.200.0.0/24
→ node-1 PodCIDR 10.200.1.0/24
ServiceCIDR 10.32.0.0/24
→ api clusterIP 10.32.0.1

 

 

설정 파일 작성 후 server 에 전달

# Prerequisites

# kube-apiserver.service 수정 : service-cluster-ip-range 추가
# https://github.com/kelseyhightower/kubernetes-the-hard-way/issues/905
# service-cluster-ip 값은 ca.conf 에 설정한 [kube-api-server_alt_names] 항목의 Service IP 범위
cat ca.conf | grep '\[kube-api-server_alt_names' -A2
[kube-api-server_alt_names]
IP.0  = 127.0.0.1
IP.1  = 10.32.0.1

cat units/kube-apiserver.service
cat << EOF > units/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
  --allow-privileged=true \\
  --apiserver-count=1 \\
  --audit-log-maxage=30 \\
  --audit-log-maxbackup=3 \\
  --audit-log-maxsize=100 \\
  --audit-log-path=/var/log/audit.log \\
  --authorization-mode=Node,RBAC \\
  --bind-address=0.0.0.0 \\
  --client-ca-file=/var/lib/kubernetes/ca.crt \\
  --enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\
  --etcd-servers=http://127.0.0.1:2379 \\
  --event-ttl=1h \\
  --encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \\
  --kubelet-certificate-authority=/var/lib/kubernetes/ca.crt \\
  --kubelet-client-certificate=/var/lib/kubernetes/kube-api-server.crt \\
  --kubelet-client-key=/var/lib/kubernetes/kube-api-server.key \\
  --runtime-config='api/all=true' \\
  --service-account-key-file=/var/lib/kubernetes/service-accounts.crt \\
  --service-account-signing-key-file=/var/lib/kubernetes/service-accounts.key \\
  --service-account-issuer=https://server.kubernetes.local:6443 \\
  --service-cluster-ip-range=10.32.0.0/24 \\
  --service-node-port-range=30000-32767 \\
  --tls-cert-file=/var/lib/kubernetes/kube-api-server.crt \\
  --tls-private-key-file=/var/lib/kubernetes/kube-api-server.key \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
cat units/kube-apiserver.service


# kube-apiserver가 kubelet(Node)에 접근할 수 있도록 허용하는 '시스템 내부용 RBAC' 설정
cat configs/kube-apiserver-to-kubelet.yaml ; echo
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"  # Kubernetes가 업그레이드 시 자동 관리
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-apiserver-to-kubelet
rules:
  - apiGroups:
      - ""                                               # Core API group (v1) : Node 관련 서브리소스는 core group에 속함
    resources:                                           # 아래 처럼, kubelet API 대부분을 포괄
      - nodes/proxy                                      ## apiserver → kubelet 프록시 통신
      - nodes/stats                                      ## 노드/파드 리소스 통계 (cAdvisor)
      - nodes/log                                        ## metrics-server / top 명령
      - nodes/spec                                       ## kubectl logs
      - nodes/metrics                                    ## metrics-server / top 명령
    verbs:
      - "*"                                              # 대상은 “nodes 하위 리소스”로 한정 + 모든 동작 허용 (get, list, watch, create, proxy 등)
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: system:kube-apiserver                            # 누가 이 권한을 쓰는가? → kube-apiserver 자신
  namespace: ""
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:kube-apiserver-to-kubelet
subjects:
  - apiGroup: rbac.authorization.k8s.io
    kind: User
    name: kubernetes                         # 사용자 kubernetes ,이 사용자는 kube-apiserver가 사용하는 클라이언트 인증서의 CN

# api-server : Subject CN 확인
openssl x509 -in kube-api-server.crt -text -noout
        Subject: CN = kubernetes,

# api -> kubelet 호출 시 Flow
kube-apiserver (client)
  |
  | (TLS client cert, CN=kubernetes)
  ↓
kubelet API Server 역할 (/stats, /log, /metrics)
  |
  ↓
RBAC 평가:
  User = kubernetes
  → ClusterRoleBinding system:kube-apiserver 매칭
  → ClusterRole system:kube-apiserver-to-kubelet 권한 부여


# kube-scheduler
cat units/kube-scheduler.service ; echo
cat configs/kube-scheduler.yaml ; echo


# kube-controller-manager : cluster-cidr 는 POD CIDR 포함하는 대역, service-cluster-ip-range 는 apiserver 설정 값 동일 설정.
cat units/kube-controller-manager.service ; echo
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-controller-manager \
  --bind-address=0.0.0.0 \
  --cluster-cidr=10.200.0.0/16 \
  --cluster-name=kubernetes \
  --cluster-signing-cert-file=/var/lib/kubernetes/ca.crt \
  --cluster-signing-key-file=/var/lib/kubernetes/ca.key \
  --kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \
  --root-ca-file=/var/lib/kubernetes/ca.crt \
  --service-account-private-key-file=/var/lib/kubernetes/service-accounts.key \
  --service-cluster-ip-range=10.32.0.0/24 \
  --use-service-account-credentials=true \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target


# Connect to the jumpbox and copy Kubernetes binaries and systemd unit files to the server machine
scp \
  downloads/controller/kube-apiserver \
  downloads/controller/kube-controller-manager \
  downloads/controller/kube-scheduler \
  downloads/client/kubectl \
  units/kube-apiserver.service \
  units/kube-controller-manager.service \
  units/kube-scheduler.service \
  configs/kube-scheduler.yaml \
  configs/kube-apiserver-to-kubelet.yaml \
  root@server:~/

# 확인
ssh server ls -l /root

 

Provision the Kubernetes Control Plane : kubectl 확인

ssh root@server
---------------------------------------------------------------
# Create the Kubernetes configuration directory:
pwd
mkdir -p /etc/kubernetes/config


# Install the Kubernetes binaries:
mv kube-apiserver \
  kube-controller-manager \
  kube-scheduler kubectl \
  /usr/local/bin/
ls -l /usr/local/bin/kube-*


# Configure the Kubernetes API Server
mkdir -p /var/lib/kubernetes/
mv ca.crt ca.key \
  kube-api-server.key kube-api-server.crt \
  service-accounts.key service-accounts.crt \
  encryption-config.yaml \
  /var/lib/kubernetes/
ls -l /var/lib/kubernetes/

## Create the kube-apiserver.service systemd unit file:
mv kube-apiserver.service \
  /etc/systemd/system/kube-apiserver.service
tree /etc/systemd/system


# Configure the Kubernetes Controller Manager

## Move the kube-controller-manager kubeconfig into place:
mv kube-controller-manager.kubeconfig /var/lib/kubernetes/

## Create the kube-controller-manager.service systemd unit file:
mv kube-controller-manager.service /etc/systemd/system/


# Configure the Kubernetes Scheduler

## Move the kube-scheduler kubeconfig into place:
mv kube-scheduler.kubeconfig /var/lib/kubernetes/

## Create the kube-scheduler.yaml configuration file:
mv kube-scheduler.yaml /etc/kubernetes/config/

## Create the kube-scheduler.service systemd unit file:
mv kube-scheduler.service /etc/systemd/system/


# Start the Controller Services : Allow up to 10 seconds for the Kubernetes API Server to fully initialize.
systemctl daemon-reload
systemctl enable kube-apiserver kube-controller-manager kube-scheduler
systemctl start  kube-apiserver kube-controller-manager kube-scheduler

# 확인
ss -tlp | grep kube
LISTEN 0      4096               *:6443              *:*    users:(("kube-apiserver",pid=3071,fd=3))                
LISTEN 0      4096               *:10257             *:*    users:(("kube-controller",pid=3072,fd=3))               
LISTEN 0      4096               *:10259             *:*    users:(("kube-scheduler",pid=3073,fd=3))  

systemctl is-active kube-apiserver
systemctl status kube-apiserver --no-pager
journalctl -u kube-apiserver --no-pager

systemctl status kube-scheduler --no-pager
systemctl status kube-controller-manager --no-pager

# Verify this using the kubectl command line tool:
kubectl cluster-info dump --kubeconfig admin.kubeconfig
kubectl cluster-info --kubeconfig admin.kubeconfig
Kubernetes control plane is running at https://127.0.0.1:6443

kubectl get node --kubeconfig admin.kubeconfig
kubectl get pod -A --kubeconfig admin.kubeconfig

kubectl get service,ep --kubeconfig admin.kubeconfig
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.32.0.1    <none>        443/TCP   110m

NAME                   ENDPOINTS        AGE
endpoints/kubernetes   10.0.2.15:6443   110m

# clusterroles 확인
kubectl get clusterroles --kubeconfig admin.kubeconfig
NAME                                                                   CREATED AT
admin                                                                  2026-01-03T08:42:54Z
cluster-admin                                                          2026-01-03T08:42:54Z
edit                                                                   2026-01-03T08:42:54Z
system:aggregate-to-admin                                              2026-01-03T08:42:54Z
system:aggregate-to-edit                                               2026-01-03T08:42:54Z
system:aggregate-to-view                                               2026-01-03T08:42:54Z
system:auth-delegator                                                  2026-01-03T08:42:54Z
system:basic-user                                                      2026-01-03T08:42:54Z
system:certificates.k8s.io:certificatesigningrequests:nodeclient       2026-01-03T08:42:54Z
system:certificates.k8s.io:certificatesigningrequests:selfnodeclient   2026-01-03T08:42:54Z
system:certificates.k8s.io:kube-apiserver-client-approver              2026-01-03T08:42:54Z
system:certificates.k8s.io:kube-apiserver-client-kubelet-approver      2026-01-03T08:42:54Z
system:certificates.k8s.io:kubelet-serving-approver                    2026-01-03T08:42:54Z
system:certificates.k8s.io:legacy-unknown-approver                     2026-01-03T08:42:54Z
system:controller:attachdetach-controller                              2026-01-03T08:42:54Z
system:controller:certificate-controller                               2026-01-03T08:42:54Z
system:controller:clusterrole-aggregation-controller                   2026-01-03T08:42:54Z
system:controller:cronjob-controller                                   2026-01-03T08:42:54Z
system:controller:daemon-set-controller                                2026-01-03T08:42:54Z
system:controller:deployment-controller                                2026-01-03T08:42:54Z
system:controller:disruption-controller                                2026-01-03T08:42:54Z
system:controller:endpoint-controller                                  2026-01-03T08:42:54Z
system:controller:endpointslice-controller                             2026-01-03T08:42:54Z
system:controller:endpointslicemirroring-controller                    2026-01-03T08:42:54Z
system:controller:ephemeral-volume-controller                          2026-01-03T08:42:54Z
system:controller:expand-controller                                    2026-01-03T08:42:54Z
system:controller:generic-garbage-collector                            2026-01-03T08:42:54Z
system:controller:horizontal-pod-autoscaler                            2026-01-03T08:42:54Z
system:controller:job-controller                                       2026-01-03T08:42:54Z
system:controller:legacy-service-account-token-cleaner                 2026-01-03T08:42:54Z
system:controller:namespace-controller                                 2026-01-03T08:42:54Z
system:controller:node-controller                                      2026-01-03T08:42:54Z
system:controller:persistent-volume-binder                             2026-01-03T08:42:54Z
system:controller:pod-garbage-collector                                2026-01-03T08:42:54Z
system:controller:pv-protection-controller                             2026-01-03T08:42:54Z
system:controller:pvc-protection-controller                            2026-01-03T08:42:54Z
system:controller:replicaset-controller                                2026-01-03T08:42:54Z
system:controller:replication-controller                               2026-01-03T08:42:54Z
system:controller:resourcequota-controller                             2026-01-03T08:42:54Z
system:controller:root-ca-cert-publisher                               2026-01-03T08:42:54Z
system:controller:route-controller                                     2026-01-03T08:42:54Z
system:controller:service-account-controller                           2026-01-03T08:42:54Z
system:controller:service-controller                                   2026-01-03T08:42:54Z
system:controller:statefulset-controller                               2026-01-03T08:42:54Z
system:controller:ttl-after-finished-controller                        2026-01-03T08:42:54Z
system:controller:ttl-controller                                       2026-01-03T08:42:54Z
system:controller:validatingadmissionpolicy-status-controller          2026-01-03T08:42:54Z
system:discovery                                                       2026-01-03T08:42:54Z
system:heapster                                                        2026-01-03T08:42:54Z
system:kube-aggregator                                                 2026-01-03T08:42:54Z
system:kube-controller-manager                                         2026-01-03T08:42:54Z
system:kube-dns                                                        2026-01-03T08:42:54Z
system:kube-scheduler                                                  2026-01-03T08:42:54Z
system:kubelet-api-admin                                               2026-01-03T08:42:54Z
system:monitoring                                                      2026-01-03T08:42:54Z
system:node                                                            2026-01-03T08:42:54Z
system:node-bootstrapper                                               2026-01-03T08:42:54Z
system:node-problem-detector                                           2026-01-03T08:42:54Z
system:node-proxier                                                    2026-01-03T08:42:54Z
system:persistent-volume-provisioner                                   2026-01-03T08:42:54Z
system:public-info-viewer                                              2026-01-03T08:42:54Z
system:service-account-issuer-discovery                                2026-01-03T08:42:54Z
system:volume-scheduler                                                2026-01-03T08:42:54Z
view                                                                   2026-01-03T08:42:54Z

kubectl describe clusterroles system:kube-scheduler --kubeconfig admin.kubeconfig


# kube-scheduler subject 확인
kubectl get clusterrolebindings --kubeconfig admin.kubeconfig
kubectl describe clusterrolebindings system:kube-scheduler --kubeconfig admin.kubeconfig
Role:
  Kind:  ClusterRole
  Name:  system:kube-scheduler
Subjects:
  Kind  Name                   Namespace
  ----  ----                   ---------
  User  system:kube-scheduler 

---------------------------------------------------------------

 

 

 

▶ RBAC for Kubelet Authorization

이 섹션에서는 Kubernetes API 서버가 각 작업자 노드에서 Kubelet API에 액세스할 수 있도록 RBAC 권한을 구성합니다. Kubelet API에 대한 액세스 권한은 메트릭, 로그를 검색하고 포드에서 명령을 실행하는 데 필요합니다. 이 튜토리얼에서는 Kubelet --authorization-mode 플래그를 Webhook으로 설정합니다. Webhook 모드에서는 SubjectAccessReview API를 사용하여 권한을 결정합니다.

 

ssh root@server # 이미 server 에 ssh 접속 상태
---------------------------------------------------------------
# api -> kubelet 접속을 위한 RBAC 설정
# Create the system:kube-apiserver-to-kubelet ClusterRole with permissions to access the Kubelet API and perform most common tasks associated with managing pods:
cat kube-apiserver-to-kubelet.yaml
kubectl apply -f kube-apiserver-to-kubelet.yaml --kubeconfig admin.kubeconfig
clusterrole.rbac.authorization.k8s.io/system:kube-apiserver-to-kubelet created
clusterrolebinding.rbac.authorization.k8s.io/system:kube-apiserver created

# 확인
kubectl get clusterroles system:kube-apiserver-to-kubelet --kubeconfig admin.kubeconfig
kubectl get clusterrolebindings system:kube-apiserver --kubeconfig admin.kubeconfig

---------------------------------------------------------------

 

(참고) kind k8s 에서 kubelet config 설정

ssh root@server # 이미 server 에 ssh 접속 상태
---------------------------------------------------------------
# api -> kubelet 접속을 위한 RBAC 설정
# Create the system:kube-apiserver-to-kubelet ClusterRole with permissions to access the Kubelet API and perform most common tasks associated with managing pods:
cat kube-apiserver-to-kubelet.yaml
kubectl apply -f kube-apiserver-to-kubelet.yaml --kubeconfig admin.kubeconfig
clusterrole.rbac.authorization.k8s.io/system:kube-apiserver-to-kubelet created
clusterrolebinding.rbac.authorization.k8s.io/system:kube-apiserver created

# 확인
kubectl get clusterroles system:kube-apiserver-to-kubelet --kubeconfig admin.kubeconfig
kubectl get clusterrolebindings system:kube-apiserver --kubeconfig admin.kubeconfig

---------------------------------------------------------------

 

 

jumpbox 서버에서 k8s controlplane 정상 동작 확인

curl -s -k --cacert ca.crt https://server.kubernetes.local:6443/version | jq
{
  "major": "1",
  "minor": "32",
  "gitVersion": "v1.32.3",
  "gitCommit": "32cc146f75aad04beaaa245a7157eb35063a9f99",
  "gitTreeState": "clean",
  "buildDate": "2025-03-11T19:52:21Z",
  "goVersion": "go1.23.6",
  "compiler": "gc",
  "platform": "linux/arm64"
}

 

 

 

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함