CertificateSigningRequest và kubeconfig
Mục tiêu bài học
Nhắc lại nhanh bài trước: Kubernetes có hai loại "danh tính". ServiceAccount là danh tính cho workload chạy trong cluster, còn user thường (như dev-anna, ci-bot) không có object nào trong API, nó chỉ tồn tại thông qua client certificate do cluster ký. Bài trước mình đã siết pod bằng SecurityContext và PSA, bài này mình đi vào phía con người: cấp cert cho user và đóng gói thành kubeconfig.
Sau bài này, bạn phải làm được:
- Tạo private key, CSR bằng
opensslvà submit thành objectCertificateSigningRequest. - Phê duyệt CSR và export certificate đã ký ra file.
- Dựng file kubeconfig hoàn chỉnh (cluster, user, context) bằng
kubectl config. - Kiểm chứng: phân biệt lỗi 401 (sai cert) và 403 (thiếu RBAC).
- Nhận diện các bẫy khiến bài CSR trong đề thi bị mất điểm oan.
Đây là dạng bài gần như chắc chắn xuất hiện trong đề CKA, và nó cũng là dạng bài mà thí sinh hay mất điểm vì gõ sai một cờ.
Ví dụ mẫu: cấp cert cho user dev-anna và dựng kubeconfig
Đề bài kiểu thi: "User dev-anna thuộc group dev-team cần một kubeconfig tại /root/dev-anna.kubeconfig, dùng cluster hiện tại, context tên dev-anna@kubernetes. Chứng chỉ phải do cluster ký."
Luồng tổng quát:
flowchart LR
A["🔑<br/>openssl genrsa"] --> B["📝<br/>openssl req -new"]
B --> C["📦<br/>base64 CSR"]
C --> D["📄<br/>CertificateSigningRequest"]
D --> E["✅<br/>certificate approve"]
E --> F["📜<br/>status.certificate"]
F --> G["⚙️<br/>kubectl config set-credentials"]
G --> H["🚀<br/>kubectl --kubeconfig"]
Bước 1: Tạo key và file CSR
openssl genrsa -out dev-anna.key 2048
openssl req -new -key dev-anna.key -out dev-anna.csr -subj "/CN=dev-anna/O=dev-team"
CN là username, O là group. Không có O thì mọi RoleBinding gắn với Group sẽ vô tác dụng, đây là lỗi rất hay gặp.
Bước 2: Mã hóa base64 nội dung CSR
cat dev-anna.csr | base64 | tr -d '\n'
Phải bỏ newline, nếu không API server sẽ từ chối. Cách nhanh hơn: base64 -w0 dev-anna.csr.
Bước 3: Tạo object CertificateSigningRequest
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: dev-anna
spec:
request: <DÁN_CHUỖI_BASE64_Ở_BƯỚC_2>
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
[!TIP] Trong phòng thi, đừng copy paste hai lần. Dùng heredoc để vừa encode vừa apply trong một lệnh:
cat <<EOF | kubectl apply -f - apiVersion: certificates.k8s.io/v1 kind: CertificateSigningRequest metadata: name: dev-anna spec: request: $(cat dev-anna.csr | base64 | tr -d '\n') signerName: kubernetes.io/kube-apiserver-client usages: - client auth EOF
Bước 4: Phê duyệt và lấy certificate
kubectl get csr
kubectl certificate approve dev-anna
kubectl get csr dev-anna -o jsonpath='{.status.certificate}' | base64 -d > dev-anna.crt
Kiểm tra nội dung cert vừa nhận:
openssl x509 -in dev-anna.crt -noout -subject
# subject=O = dev-team, CN = dev-anna
Bước 5: Dựng kubeconfig
Lấy thông tin cluster đang dùng:
kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'
Rồi tạo kubeconfig từng phần:
kubectl config set-cluster kubernetes \
--server=https://<API_SERVER>:6443 \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--kubeconfig=/root/dev-anna.kubeconfig
kubectl config set-credentials dev-anna \
--client-certificate=dev-anna.crt \
--client-key=dev-anna.key \
--embed-certs=true \
--kubeconfig=/root/dev-anna.kubeconfig
kubectl config set-context dev-anna@kubernetes \
--cluster=kubernetes \
--user=dev-anna \
--kubeconfig=/root/dev-anna.kubeconfig
kubectl config use-context dev-anna@kubernetes --kubeconfig=/root/dev-anna.kubeconfig
[!WARNING] Thiếu
--embed-certs=truethì kubeconfig chỉ lưu đường dẫn file. Copy sang máy khác hoặc chấm bài trên thư mục khác là hỏng ngay. Đề CKA gần như luôn yêu cầu kubeconfig "self-contained", nên mặc định hãy thêm cờ này.
Bước 6: Kiểm chứng
kubectl config view --kubeconfig=/root/dev-anna.kubeconfig
kubectl --kubeconfig=/root/dev-anna.kubeconfig auth can-i get pods -n dev
kubectl --kubeconfig=/root/dev-anna.kubeconfig get pods -n dev
Nếu kết quả là Forbidden (403) thì tin tốt: cert và kubeconfig đã đúng, chỉ còn thiếu RBAC (bài trước đã làm RoleBinding cho user hoặc group). Nếu là Unauthorized (401) thì cert hoặc CA đang sai.
Luyện tập có hướng dẫn
Làm lần lượt ba bài dưới đây trên cluster lab. Đừng mở đáp án trước khi thử ít nhất một lần.
Bài 1: CSR cơ bản, kiểm tra subject
Tạo key và CSR cho user ci-bot, group ci, submit với signer phù hợp, approve, export ra /root/ci-bot.crt và chứng minh subject đúng.
Xem đáp án bài 1
cd /root
openssl genrsa -out ci-bot.key 2048
openssl req -new -key ci-bot.key -out ci-bot.csr -subj "/CN=ci-bot/O=ci"
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: ci-bot
spec:
request: $(cat ci-bot.csr | base64 | tr -d '\n')
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
EOF
kubectl certificate approve ci-bot
kubectl get csr ci-bot -o jsonpath='{.status.certificate}' | base64 -d > /root/ci-bot.crt
openssl x509 -in /root/ci-bot.crt -noout -subject
Kết quả mong đợi: subject=O = ci, CN = ci-bot.
Bài 2: Dựng kubeconfig đầy đủ
Từ cert ở bài 1, tạo /root/ci-bot.kubeconfig với cluster kubernetes, user ci-bot, context ci-bot@kubernetes, namespace mặc định là ci. Sau đó chạy kubectl --kubeconfig=/root/ci-bot.kubeconfig get pods và giải thích kết quả nhận được.
Xem đáp án bài 2
kubectl config set-cluster kubernetes \
--server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}') \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--kubeconfig=/root/ci-bot.kubeconfig
kubectl config set-credentials ci-bot \
--client-certificate=/root/ci-bot.crt \
--client-key=/root/ci-bot.key \
--embed-certs=true \
--kubeconfig=/root/ci-bot.kubeconfig
kubectl config set-context ci-bot@kubernetes \
--cluster=kubernetes \
--user=ci-bot \
--namespace=ci \
--kubeconfig=/root/ci-bot.kubeconfig
kubectl config use-context ci-bot@kubernetes --kubeconfig=/root/ci-bot.kubeconfig
kubectl --kubeconfig=/root/ci-bot.kubeconfig get pods
Kết quả điển hình: Error from server (Forbidden). Như vậy là phần authentication đã xong, chỉ còn thiếu Role/RoleBinding trong namespace ci. Nếu bạn thấy Unauthorized thì quay lại kiểm tra cert và CA.
Kiểm tra nhanh namespace mặc định đã ăn chưa:
kubectl --kubeconfig=/root/ci-bot.kubeconfig config view --minify -o jsonpath='{.contexts[0].context.namespace}'
Bài 3: Sửa một kubeconfig bị hỏng
Cho file /root/broken.kubeconfig:
apiVersion: v1
kind: Config
clusters:
- name: k8s-lab
cluster:
server: https://127.0.0.1:8443
certificate-authority-data: <CA_DATA>
users:
- name: ci-bot
user:
client-certificate-data: <CERT_DATA>
client-key-data: <KEY_DATA>
contexts:
- name: ci-bot@kubernetes
context:
cluster: kubernetes
user: ci-bot
current-context: ci-bot@kubernetes
Lệnh kubectl --kubeconfig=/root/broken.kubeconfig get ns báo lỗi kết nối. Tìm và sửa hai lỗi.
Xem đáp án bài 3
Lỗi 1: port sai. API server mặc định là 6443, không phải 8443.
Lỗi 2: tên cluster không khớp. Khối clusters đặt tên k8s-lab nhưng contexts lại trỏ tới kubernetes, nên context không tìm thấy cluster.
Sửa bằng lệnh thay vì sửa tay file YAML:
kubectl config set-cluster k8s-lab \
--server=https://127.0.0.1:6443 \
--kubeconfig=/root/broken.kubeconfig
kubectl config set-context ci-bot@kubernetes \
--cluster=k8s-lab \
--user=ci-bot \
--kubeconfig=/root/broken.kubeconfig
kubectl --kubeconfig=/root/broken.kubeconfig get ns
Bài học: tên cluster trong contexts là con trỏ tới tên, không phải tên miền tự do. Sai một ký tự là kubeconfig chết.
Lỗi thường gặp và cách xử lý
| Triệu chứng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
error decoding certificate request khi apply CSR |
Chuỗi base64 còn newline hoặc dán thiếu | Encode lại bằng base64 -w0, dùng heredoc $(...) |
| CSR tạo được nhưng không có cert | Chưa approve, hoặc đã deny |
kubectl get csr, rồi kubectl certificate approve <tên> |
| Không approve được, báo forbidden | Thiếu quyền trên certificatesigningrequests/approval |
Trong thi bạn là admin nên hiếm gặp, kiểm tra đang dùng đúng kubeconfig chưa |
Unauthorized (401) khi test kubeconfig |
Cert hết hạn, sai CA, hoặc client-key không khớp cert | So lại --certificate-authority, kiểm tra subject bằng openssl x509 |
Forbidden (403) |
Cert đúng nhưng thiếu RBAC | Tạo Role/RoleBinding cho user hoặc group tương ứng |
| Kubeconfig chỉ chạy trên máy hiện tại | Quên --embed-certs=true |
Tạo lại với --embed-certs=true |
context ... does not exist |
Tên cluster trong context không khớp khối clusters |
kubectl config get-clusters rồi set-context lại |
| Sửa CSR báo lỗi | CSR là immutable | kubectl delete csr <tên> rồi tạo lại từ đầu |
Một lưu ý về signer: kubernetes.io/kube-apiserver-client cần approve thủ công. Còn kubernetes.io/kube-apiserver-client-kubelet thì controller-manager tự approve cho kubelet, nên đừng thắc mắc vì sao CSR của kubelet đã Approved sẵn.
Góc kinh nghiệm thi
- Đọc kỹ yêu cầu về vị trí file và tên context. Đề cho
/root/dev-anna.kubeconfigvàdev-anna@kubernetesthì phải đúng từng ký tự. Sai tên context là mất điểm dù cert đúng. - Đừng đoán API server URL. Luôn lấy từ kubeconfig hiện tại:
kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'. Trên cluster thi thường làhttps://<node-ip>:6443. --embed-certs=truelà mặc định của bạn, trừ khi đề nói rõ là dùng đường dẫn file.- Kiểm chứng bằng
kubectl auth can-i --asthay vì đoán:kubectl auth can-i get pods -n dev --as=dev-anna --as-group=dev-team. - Phân biệt 401 và 403 là kỹ năng chẩn đoán nhanh nhất trong bài này. 401 = vấn đề danh tính, 403 = vấn đề quyền.
- Đừng quên
O=trong subject. Nếu đề nói "user thuộc group X" thì group đó phải nằm trong CSR, không thể thêm vào sau. - Cert do CSR ký có thời hạn (mặc định khoảng 1 năm với signer client). Nếu cert cũ không dùng được, xóa CSR cũ và làm lại từ bước 1.
- Nếu đề bắt đầu bằng "user đã tồn tại", hãy kiểm tra xem cert đã có sẵn ở
/rootchưa trước khi sinh key mới, tiết kiệm được vài phút.
[!IMPORTANT] Quy tắc một dòng để nhớ: CSR lo phần danh tính (bạn là ai), RBAC lo phần quyền (bạn được làm gì), kubeconfig chỉ là cách đóng gói cả hai để kubectl dùng. Ba thứ độc lập, hỏng cái nào sửa cái đó.
Tóm tắt và bước tiếp theo
Tóm gọn bài này trong sáu dòng:
openssl genrsatạo key,openssl req -new -subj "/CN=user/O=group"tạo CSR.- Base64 nội dung CSR (bỏ newline) và đặt vào
spec.requestcủa objectCertificateSigningRequest. signerName: kubernetes.io/kube-apiserver-clientvớiusages: [client auth]cho user thường.kubectl certificate approverồi lấy cert từstatus.certificate.- Dựng kubeconfig bằng bốn lệnh
kubectl config set-cluster,set-credentials,set-context,use-context, luôn kèm--embed-certs=true. - Test bằng
auth can-i; 401 là lỗi danh tính, 403 là lỗi RBAC.
Ôn nhanh bằng cách điền vào chỗ trống:
- Signer dùng để ký client certificate cho user thường là {{c1::kubernetes.io/kube-apiserver-client}}.
- Nội dung file
.csrsau khi mã hóa base64 được đặt vào trường {{c2::spec.request}}. - Certificate đã ký nằm ở {{c3::status.certificate}} dưới dạng base64.
- Trong subject, giá trị {{c4::CN}} trở thành username và giá trị {{c5::O}} trở thành group.
- Lệnh phê duyệt CSR là {{c6::kubectl certificate approve}} theo sau là tên CSR.
- Kubeconfig mặc định nằm ở
~/.kube/configvà có thể ghi đè bằng biến môi trường {{c7::KUBECONFIG}}.
Deck ôn tập cho bài này:
[
{ "front": "signerName nào dùng để cấp client certificate cho user thường?", "back": "kubernetes.io/kube-apiserver-client" },
{ "front": "Trường nào trong CSR chứa nội dung file .csr?", "back": "spec.request, chứa PEM CSR đã mã hóa base64 và đã bỏ newline." },
{ "front": "Lệnh phê duyệt một CSR?", "back": "kubectl certificate approve <tên-csr>" },
{ "front": "Lấy certificate đã ký từ CSR ra file?", "back": "kubectl get csr <tên> -o jsonpath='{.status.certificate}' | base64 -d > user.crt" },
{ "front": "Với subject /CN=alice/O=dev, CN và O map thành gì trong Kubernetes?", "back": "CN là username, O là group dùng để gán RBAC." },
{ "front": "Tạo private key 2048 bit bằng openssl?", "back": "openssl genrsa -out user.key 2048" },
{ "front": "Tạo file CSR bằng openssl với user và group cho trước?", "back": "openssl req -new -key user.key -out user.csr -subj \"/CN=user/O=group\"" },
{ "front": "Cờ nào nhúng certificate trực tiếp vào kubeconfig thay vì trỏ đường dẫn file?", "back": "--embed-certs=true" },
{ "front": "Một context trong kubeconfig gồm những thành phần nào?", "back": "cluster, user và namespace (tùy chọn)." },
{ "front": "Kubeconfig mặc định nằm ở đâu và biến môi trường nào ghi đè nó?", "back": "~/.kube/config, ghi đè bằng biến KUBECONFIG." },
{ "front": "Kiểm tra user alice có quyền get pods không?", "back": "kubectl auth can-i get pods --as=alice" },
{ "front": "Có sửa được một CSR đã tạo không?", "back": "Không, CSR là immutable, phải delete rồi tạo lại." },
{ "front": "usages nào bắt buộc phải có với signer kube-apiserver-client?", "back": "client auth" },
{ "front": "Lỗi 403 khác lỗi 401 thế nào khi test kubeconfig?", "back": "403 là đã xác thực nhưng thiếu RBAC, 401 là certificate hoặc danh tính sai." }
]
Bài tiếp theo: Checkpoint của Module 7. Bạn sẽ gặp một đề tổng hợp ngắn trộn cả ba mảng: tạo Role/RoleBinding đúng phạm vi, gán ServiceAccount cho workload, và bài CSR kèm kubeconfig như vừa luyện. Hãy chuẩn bị sẵn alias k và thói quen chạy kubectl auth can-i --as để tự kiểm tra trước khi nộp.