Skip to main content

7.1. Security - Authentication and TLS Certificates

Mục lục


1. Giới thiệu phần Security

Phần này bàn về security trong Kubernetes. Bắt đầu với việc tìm hiểu các nguyên lý bảo mật (security primitives) của Kubernetes — làm sao ai đó truy cập được vào Kubernetes cluster? Và các hành động của họ được kiểm soát ra sao? Ở mức tổng quan, sẽ bắt đầu với các cơ chế authentication khác nhau. Sẽ xem các cấu hình mặc định trong cluster, và thực hành xem cấu hình của một cluster hiện có.

Sẽ bàn về TLS certificates và cách các component khác nhau trong cluster được bảo mật bằng TLS certificates. Nếu là một Kubernetes administrator, tự thiết lập một cluster, chắc chắn sẽ gặp các thử thách liên quan tới certificate — đó là lý do phần này bàn từ những kiến thức nền tảng nhất. Đây là một trong những phần được đầu tư nhiều thời gian nhất, với mục tiêu đơn giản hoá một số khái niệm cốt lõi xoay quanh certificate, nên có thêm một số bài giảng tiền đề (prerequisite lectures) dành cho người mới với chủ đề này.

Sau đó chuyển sang authorization, nơi xem xét các cơ chế authorization khác nhau, tập trung cụ thể vào Role-Based Access Controls. Tiếp theo bàn về cách bảo mật image trong môi trường, sau đó là Security Contexts, và cuối cùng là Network Policies.


2. Các nguyên lý bảo mật (Security Primitives) trong Kubernetes

Kubernetes là nền tảng hàng đầu để host các application production, nên bảo mật là mối quan tâm hàng đầu. Bắt đầu với các host tạo nên chính cluster. Tất nhiên, mọi truy cập vào các host này phải được bảo mật — tắt root access, tắt password-based authentication, chỉ cho phép SSH key-based authentication, cùng bất kỳ biện pháp nào khác cần thiết để bảo mật hạ tầng vật lý hoặc ảo host Kubernetes. Nếu hạ tầng đó bị xâm phạm, mọi thứ đều bị xâm phạm. Trọng tâm ở đây là các vấn đề bảo mật liên quan tới Kubernetes.

Đã biết kube-apiserver là trung tâm của mọi hoạt động trong Kubernetes — tương tác với nó qua utility kubectl, hoặc truy cập trực tiếp API. Qua đó có thể thực hiện gần như mọi thao tác trên cluster. Vậy đó là tuyến phòng thủ đầu tiên: kiểm soát truy cập vào chính kube-apiserver. Cần đưa ra hai loại quyết định: ai có thể truy cập cluster? Và họ có thể làm gì?

Ai có thể truy cập API server được xác định bởi các cơ chế authentication. Có nhiều cách khác nhau để authenticate tới API server: certificates, hoặc thậm chí tích hợp với các external authentication provider như LDAP. Cuối cùng, với máy móc (machines), tạo service accounts — sẽ xem chi tiết hơn ở các phần tiếp theo.

Một khi đã có quyền truy cập vào cluster, họ có thể làm gì được xác định bởi các cơ chế authorization. Authorization được triển khai dùng role-based access controls, nơi user được liên kết với group có các quyền cụ thể. Ngoài ra còn có các authorization module khác như Attribute-Based Access Control, Node Authorizer, Webhook, v.v. — sẽ xem chi tiết hơn ở phần sau.

Mọi giao tiếp trong cluster giữa các component khác nhau như etcd cluster, kube-controller-manager, scheduler, kube-apiserver, cũng như các component chạy trên worker node như kubelet và kube-proxy, đều được bảo mật bằng TLS encryption. Có hẳn một phần dành riêng cho việc này, nơi sẽ bàn và thực hành cách thiết lập certificate giữa các component khác nhau.

Còn giao tiếp giữa các application bên trong cluster thì sao? Mặc định, mọi pod đều có thể truy cập mọi pod khác trong cluster. Có thể hạn chế truy cập giữa chúng bằng Network Policies — sẽ xem chi tiết cách thực hiện ở phần Network Policies.


3. Authentication trong Kubernetes

Đã biết Kubernetes cluster gồm nhiều node, vật lý hoặc ảo, và nhiều component phối hợp cùng nhau. Có các user như administrator truy cập cluster để thực hiện tác vụ quản trị, các developer truy cập cluster để test hoặc deploy application, và có end user truy cập các application được deploy trên cluster. Và có các third-party application truy cập cluster cho mục đích tích hợp.

Xuyên suốt phần này sẽ bàn cách bảo mật cluster bằng cách bảo mật giao tiếp giữa các component nội bộ và bảo mật quyền truy cập quản trị vào cluster thông qua các cơ chế authentication và authorization. Trọng tâm ở đây là bảo mật quyền truy cập vào Kubernetes cluster bằng các cơ chế authentication.

Bảo mật cho end user truy cập application được deploy trên cluster do chính application tự quản lý nội bộ, nên sẽ không bàn tới ở đây. Trọng tâm là quyền truy cập của user vào Kubernetes cluster cho mục đích quản trị. Vậy còn lại hai loại user: con người, như administrator và developer, và robot, như các process, service hoặc application khác cần truy cập cluster.

Kubernetes không quản lý user account một cách native. Nó dựa vào nguồn bên ngoài, như một file chứa thông tin user, hoặc certificate, hoặc một identity service bên thứ ba như LDAP, để quản lý các user này. Vậy nên không thể tạo user trong một Kubernetes cluster, hay xem danh sách user như vậy. Tuy nhiên, với service account, Kubernetes có thể quản lý chúng — có thể tạo và quản lý service account bằng Kubernetes API (có hẳn một phần riêng dành cho service account).

Mọi truy cập user được quản lý bởi kube-apiserver. Dù truy cập cluster qua công cụ kubectl hay trực tiếp qua API, mọi request đều đi qua kube-apiserver, và kube-apiserver authenticate request trước khi xử lý nó. Vậy kube-apiserver authenticate như thế nào? Có nhiều cơ chế authentication có thể cấu hình. Có thể dùng username và token trong một static token file, hoặc authenticate bằng certificate. Một lựa chọn khác là kết nối tới các giao thức authentication bên thứ ba, như LDAP, Kerberos, v.v.

Về mặt lý thuyết, cách dễ hiểu nhất để bắt đầu là static password file hoặc static token file — trong file CSV chứa thông tin user, có thể tuỳ chọn thêm một cột thứ tư với thông tin group để gán user vào group cụ thể; tương tự, thay vì password, static token file chỉ định một token. Tuy nhiên, static password file (basic-auth-file) đã bị gỡ hoàn toàn khỏi Kubernetes từ v1.19 — không còn là tuỳ chọn khả dụng nữa, dù cách hiểu concept CSV file vẫn hữu ích để nắm ý tưởng chung. Riêng static token file vẫn còn tồn tại: truyền file token vào như một option --token-auth-file cho kube-apiserver, và khi authenticate, chỉ định token như một Authorization Bearer Token trong request.

Nhớ rằng, cơ chế authentication lưu token dưới dạng clear text trong một static file không phải cách tiếp cận được khuyến nghị, vì không an toàn. Nhưng đây là cách dễ nhất để hiểu những kiến thức cơ bản về authentication trong Kubernetes. Nếu đang thử điều này trong một setup kubeadm, cũng cần cân nhắc volume mount để truyền vào auth file. Chi tiết về việc này có trong bài viết đi kèm (xem mục Nguồn tham khảo), và nhớ thiết lập authentication cho user mới. Authorization sẽ được bàn sau trong khoá học này.


4. Kiến thức nền về TLS Certificates

Bảo mật cluster bằng TLS và troubleshoot các vấn đề liên quan tới TLS có thể đặc biệt khó khăn nếu chưa quen với kiến thức nền tảng của TLS certificate. Nếu đã quen với khái niệm này, có thể bỏ qua các bài giảng tiền đề (prerequisite lectures) này và chuyển thẳng tới các phần liên quan tới Kubernetes.

Một certificate được dùng để đảm bảo sự tin cậy (trust) giữa hai bên trong một giao dịch. Ví dụ, khi một user cố truy cập một web server, TLS certificate đảm bảo giao tiếp giữa user và server được mã hoá và server đúng là bên mà nó tự nhận.

Xét một kịch bản: nếu không có kết nối an toàn, khi một user truy cập ứng dụng ngân hàng trực tuyến, các thông tin đăng nhập họ gõ vào sẽ được gửi dưới dạng plain text. Hacker sniffing network traffic có thể dễ dàng lấy được thông tin đăng nhập này và dùng để hack tài khoản ngân hàng của user. Rõ ràng không an toàn. Vậy phải encrypt dữ liệu được truyền đi bằng encryption key.

Dữ liệu được encrypt bằng một key — về cơ bản là một tập hợp số và chữ cái ngẫu nhiên. Thêm số ngẫu nhiên vào dữ liệu, encrypt nó thành một định dạng không thể nhận diện được. Dữ liệu sau đó được gửi tới server. Hacker sniffing network nhận được dữ liệu, nhưng không thể làm gì với nó. Tương tự, server nhận dữ liệu cũng không thể decrypt nếu không có key. Vậy một bản copy của key cũng phải được gửi tới server để server có thể decrypt và đọc message. Vì key cũng được gửi qua cùng network, kẻ tấn công có thể sniff được luôn và decrypt dữ liệu bằng nó. Đây gọi là symmetric encryption. Đây là một cách encryption an toàn, nhưng vì nó dùng cùng một key để encrypt và decrypt dữ liệu, và vì key phải được trao đổi giữa sender và receiver, có rủi ro hacker chiếm được key và decrypt dữ liệu.

Đó là lúc asymmetric encryption xuất hiện. Thay vì dùng một key duy nhất để encrypt và decrypt dữ liệu, asymmetric encryption dùng một cặp key: một private key và một public lock (thực chất là private key và public key, nhưng để dễ hình dung, sẽ gọi là private key và public lock — một key chỉ mình mình có nên nó private; một lock ai cũng truy cập được nên nó public). Điểm mấu chốt: nếu encrypt hoặc lock dữ liệu bằng lock của mình, chỉ có thể mở nó bằng key tương ứng. Vậy key phải luôn được giữ an toàn và không chia sẻ với ai khác — nó private. Còn lock thì public, có thể chia sẻ với người khác, nhưng họ chỉ có thể lock thứ gì đó bằng nó. Bất kể thứ gì được lock bằng public lock, chỉ có thể unlock bằng private key tương ứng.

💡 Hình dung: private key giống chiếc chìa khóa nhà chỉ riêng chủ nhà giữ — không đưa cho ai. Public key giống ổ khóa gắn sẵn trên cửa, ai cũng lấy được để khóa (encrypt) một gói đồ gửi tới, nhưng chỉ đúng chìa của chủ nhà (private key) mới mở (decrypt) được gói đó. Chiều ngược lại cũng đúng: khóa bằng chìa riêng thì ai cầm ổ khóa công khai cũng mở được — đó chính là cách CA "ký" certificate, để bất kỳ ai cũng verify được bằng public key của CA.

Ví dụ đơn giản hơn — bảo mật SSH access bằng key pair. Có một server trong môi trường cần truy cập. Không muốn dùng password vì quá rủi ro, nên quyết định dùng key pair. Generate một cặp public và private key bằng lệnh ssh-keygen. Lệnh này tạo hai file: id_rsa là private key và id_rsa.pub là public key (thực chất là public lock). Sau đó bảo mật server bằng cách khoá mọi truy cập trừ qua một "cửa" được khoá bằng public lock — thường thực hiện bằng cách thêm một entry với public key vào file authorized_keys của SSH trên server. Vậy lock là public và ai cũng có thể thử phá, nhưng chừng nào không ai có được private key (vốn an toàn trên laptop), không ai truy cập được server. Khi SSH, chỉ định vị trí private key trong lệnh SSH.

Nếu có nhiều server khác trong môi trường? Có thể tạo bản copy của public lock và đặt lên bất kỳ server nào muốn. Có thể dùng cùng private key để SSH vào tất cả server một cách an toàn. Nếu user khác cần truy cập server? Họ có thể làm tương tự — generate cặp public/private key riêng, và người quản lý server có thể tạo thêm một "cửa" khác, khoá bằng public lock của họ, copy sang tất cả server, và giờ user khác cũng truy cập được bằng private key của họ.

Quay lại ví dụ web server. Vấn đề với symmetric encryption trước đó là key dùng để encrypt dữ liệu phải được gửi tới server qua network cùng với dữ liệu đã encrypt, nên có rủi ro hacker lấy được key để decrypt dữ liệu. Nếu có cách nào đó đưa key tới server một cách an toàn? Một khi key được đưa tới server an toàn, server và client có thể tiếp tục giao tiếp an toàn bằng symmetric encryption. Để truyền symmetric key từ client sang server an toàn, dùng asymmetric encryption — generate một cặp public/private key trên server. Lệnh ssh-keygen dùng để tạo key pair cho SSH trước đó, còn ở đây dùng lệnh OpenSSL để generate cặp private/public key cho web server.

Khi user lần đầu truy cập web server qua HTTPS, họ nhận được public key từ server. Giả sử hacker sniffing traffic cũng lấy được bản copy public key này. User (hay chính xác là browser của user) sau đó encrypt symmetric key bằng public key server cung cấp — symmetric key giờ đã được bảo mật. User gửi cái này tới server, hacker cũng nhận được một bản copy. Server dùng private key để decrypt message và lấy lại symmetric key. Tuy nhiên, hacker không có private key để decrypt và lấy symmetric key từ message nhận được — hacker chỉ có public key, chỉ có thể lock/encrypt message chứ không decrypt được. Symmetric key giờ chỉ an toàn với user và server. Họ có thể dùng symmetric key để encrypt dữ liệu gửi cho nhau, và bên nhận dùng cùng symmetric key để decrypt và lấy thông tin. Hacker chỉ còn lại các message đã encrypt và public key, không decrypt được gì. Với asymmetric encryption, đã truyền thành công symmetric key từ user sang server, và với symmetric encryption, đã bảo mật mọi giao tiếp tiếp theo giữa họ.

Asymmetric key exchange: trao symmetric key an toànClient (Browser)Server1. Certificate + public key2. Tạo symmetric key3. Symmetric key (encrypt bằng public key)4. Decrypt bằng private key5. Giao tiếp qua lại bằng symmetric keyAsymmetric chỉ để trao symmetric key an toàn — giao tiếp thật dùng symmetric (nhanh hơn)

Kịch bản hacker giả mạo. Hacker tìm cách mới để hack tài khoản — nhận ra cách duy nhất lấy được credential là khiến user gõ vào một form do hacker tạo ra. Vậy hacker tạo một website trông y hệt website ngân hàng, host trên server riêng, và cũng muốn user nghĩ nó an toàn, nên tự generate cặp public/private key riêng và cấu hình trên web server của mình. Cuối cùng, hacker tìm cách tweak môi trường hoặc network để route request đáng lẽ tới website ngân hàng sang server của mình. User mở browser, gõ địa chỉ website, thấy trang login quen thuộc, gõ username/password, chắc chắn dùng HTTPS để đảm bảo giao tiếp mã hoá — browser nhận key, gửi symmetric key đã encrypt, rồi gửi credential đã encrypt bằng cùng key, và bên nhận decrypt credential bằng cùng symmetric key. Đã giao tiếp an toàn theo đúng nghĩa mã hoá — nhưng với server của hacker.

Vậy làm sao biết key nhận từ server có hợp lệ (từ đúng ngân hàng thật) hay không? Khi server gửi key, nó không gửi key trơn — nó gửi kèm một certificate có chứa key đó. Certificate có thông tin về ai được cấp certificate, public key của server đó, vị trí server, v.v. Mọi certificate đều có tên trên đó — subject mà certificate được cấp cho. Đây là trường quan trọng để xác thực danh tính — nếu là web server, tên này phải khớp với những gì user gõ trên URL trong browser. Nếu ngân hàng được biết tới với các tên khác, và muốn user truy cập application bằng các tên đó, tất cả các tên đó nên được chỉ định trong certificate dưới mục Subject Alternative Names. Nhưng bất kỳ ai cũng có thể generate một certificate như vậy — có thể generate một certificate nói mình là Google. Đó là điều hacker đã làm trong trường hợp này — generate một certificate nói mình là website ngân hàng.

Vậy làm sao xem một certificate và xác thực nó hợp lệ? Đó là lúc phần quan trọng nhất của certificate phát huy tác dụng: ai đã ký và cấp certificate? Nếu tự generate một certificate, phải tự ký nó — gọi là self-signed certificate. Bất kỳ ai xem certificate tự tạo sẽ ngay lập tức biết đó không phải certificate an toàn vì được ký bởi chính chủ. Nếu xem kỹ certificate nhận từ hacker, sẽ thấy đó là certificate giả được ký bởi chính hacker. Trên thực tế, browser tự làm việc này — mọi web browser đều có sẵn cơ chế xác thực certificate, browser kiểm tra certificate nhận từ server và xác thực để đảm bảo nó hợp lệ. Nếu nhận diện đó là certificate giả, nó sẽ cảnh báo.

Vậy làm sao tạo một certificate hợp lệ cho web server mà browser sẽ tin tưởng? Làm sao để certificate được ký bởi ai đó có thẩm quyền? Đó là lúc certificate authority (CA) xuất hiện — các tổ chức uy tín có thể ký và xác thực certificate. Một số cái phổ biến: Symantec, DigiCert, Comodo, GlobalSign, v.v. Cách hoạt động: generate một Certificate Signing Request (CSR) bằng key đã generate trước đó và tên domain website, cũng dùng lệnh OpenSSL — thao tác này tạo ra file my-bank.csr, chính là Certificate Signing Request cần gửi tới CA để ký. CA xác thực thông tin, và một khi hợp lệ, họ ký certificate rồi gửi lại. Giờ có một certificate được CA ký mà browser tin tưởng. Nếu hacker cố ký certificate theo cách tương tự, sẽ fail ở giai đoạn xác thực, và certificate của họ sẽ bị CA từ chối — website họ host sẽ không có certificate hợp lệ. CA dùng nhiều kỹ thuật khác nhau để đảm bảo đúng là chủ sở hữu domain đó.

CA trust chain: từ CSR tới certificate được browser tin tưởngServer: generatekey pair + CSRGửi CSRtới CACA ký bằngCA private keyCertificateđã kýBrowser verifybằng CA public keyCA public key đã có sẵn (built-in) trong browser — không cần trao đổi lại

Nhưng làm sao browser biết chính CA đó là hợp lệ? Ví dụ, nếu certificate được ký bởi một CA giả? Trong trường hợp này, certificate được ký bởi Symantec — làm sao browser biết Symantec là một CA hợp lệ, và certificate thực sự được Symantec ký, chứ không phải bởi ai đó tự xưng là Symantec? Các CA có sẵn cặp public/private key riêng. CA dùng private key để ký certificate. Public key của mọi CA được tích hợp sẵn (built-in) vào các browser. Browser dùng public key của CA để xác thực certificate thực sự được CA đó ký. Có thể xem chúng trong phần cài đặt của web browser, dưới mục Certificates, tab Trusted CAs.

Đây là các public CA giúp đảm bảo các website công khai như ngân hàng, email... là hợp lệ. Tuy nhiên, chúng không giúp xác thực các site host riêng tư, ví dụ nội bộ trong tổ chức, như để truy cập ứng dụng payroll hay email nội bộ. Với trường hợp đó, có thể host private CA riêng. Hầu hết các công ty kể trên đều có dịch vụ private offering — một CA server có thể deploy nội bộ trong công ty. Sau đó có thể cài public key của internal CA server lên browser của toàn bộ nhân viên và thiết lập kết nối an toàn trong tổ chức.

Tóm tắt nhanh: Đã thấy vì sao cần encrypt message gửi qua network. Để encrypt message, dùng asymmetric encryption với một cặp public và private key. Admin dùng một cặp key để bảo mật kết nối SSH tới server. Server dùng một cặp key để bảo mật HTTPS traffic. Nhưng để làm được điều đó, server trước tiên gửi một certificate signing request tới CA. CA dùng private key để ký CSR. Nhớ rằng, mọi user có một bản copy public key của CA. Certificate đã ký sau đó được gửi lại cho server. Server cấu hình web application với certificate đã ký. Khi một user truy cập web application, server trước tiên gửi certificate kèm public key của nó. User (hay browser của user) đọc certificate và dùng public key của CA để xác thực và lấy public key của server. Sau đó nó generate một symmetric key muốn dùng cho toàn bộ giao tiếp tiếp theo. Symmetric key được encrypt bằng public key của server và gửi lại cho server. Server dùng private key để decrypt message và lấy lại symmetric key. Symmetric key sau đó được dùng cho giao tiếp tiếp theo.

Vậy administrator generate một key pair để bảo mật SSH. Web server generate một key pair để bảo mật website bằng HTTPS. Certificate authority generate bộ key pair riêng để ký certificate. End user, tuy nhiên, chỉ generate duy nhất một cặp asymmetric key. Một khi thiết lập được trust với website, họ dùng username và password để authenticate tới web server. Với key pair của server, client đã có thể xác thực server đúng là bên nó tự nhận. Nhưng server không chắc chắn client có đúng là họ tự nhận hay không — có thể là hacker giả mạo user bằng cách nào đó chiếm được credential (không phải qua network, vì đã bảo mật bằng TLS — có thể bằng cách khác). Vậy server có thể làm gì để xác thực client đúng là họ tự nhận? Như một phần của quá trình xây dựng trust ban đầu, server có thể yêu cầu một certificate từ client. Client phải generate một cặp key và lấy một certificate đã ký từ một CA hợp lệ. Client sau đó gửi certificate tới server để server xác thực client đúng là họ tự nhận.

Có thể đang nghĩ chưa bao giờ tự generate client certificate để truy cập một website — đó là vì TLS client certificate thường không được triển khai trên web server. Kể cả nếu có, tất cả đều được triển khai ngầm — user thông thường không phải tự generate và quản lý certificate thủ công. Đó là mảnh ghép cuối cùng về client certificate.

Toàn bộ hạ tầng bao gồm CA, các server, con người, và quy trình generate, phân phối, và duy trì digital certificate được gọi là Public Key Infrastructure (PKI).

Lưu ý cuối cùng về naming convention: thường thì certificate với public key được đặt tên với đuôi .crt hoặc .pem. Ví dụ server.crt, server.pem cho server certificate, hoặc client.crt, client.pem cho client certificate. Private key thường có đuôi .key hoặc -key.pem, ví dụ server.key hoặc server-key.pem. Vậy hãy nhớ, private key thường có chữ "key" trong tên, dù dưới dạng đuôi file hay trong tên certificate. Cái nào không có chữ "key" trong tên thường là public key hoặc certificate.

Cũng cần làm rõ: đã dùng ẩn dụ key và lock cho private và public key, tạo cảm giác chỉ lock (public key) mới encrypt được dữ liệu — điều đó không đúng. Thực chất đây là hai key liên quan hoặc bắt cặp — có thể encrypt dữ liệu bằng bất kỳ cái nào trong hai, và chỉ decrypt được bằng cái còn lại. Không thể encrypt bằng một cái rồi decrypt bằng chính nó. Vậy phải cẩn thận encrypt dữ liệu bằng key nào — nếu encrypt dữ liệu bằng private key, bất kỳ ai có public key (thực ra có thể là bất kỳ ai) đều decrypt và đọc được message.


5. TLS Certificates trong Kubernetes

Đã thấy public và private key là gì, cách server dùng chúng để bảo mật kết nối (gọi là server certificate), thế nào là certificate authority (có cặp public/private key riêng dùng để ký server certificate, gọi là root certificate), và cách server có thể yêu cầu client tự xác thực bằng client certificate. Vậy có ba loại certificate: server certificate cấu hình trên server, root certificate cấu hình trên CA server, và client certificate cấu hình trên client.

Kubernetes cluster gồm một tập hợp master và worker node. Tất nhiên, mọi giao tiếp giữa các node này cần được bảo mật và encrypt. Mọi tương tác giữa các service và client của chúng cần được bảo mật. Ví dụ, một administrator tương tác với Kubernetes cluster qua kubectl hoặc truy cập trực tiếp Kubernetes API phải thiết lập kết nối TLS an toàn. Giao tiếp giữa mọi component trong Kubernetes cluster cũng cần được bảo mật. Vậy hai yêu cầu chính: mọi service trong cluster dùng server certificate, và mọi client dùng client certificate để xác thực danh tính.

💡 Hình dung: kube-apiserver giống tổng đài trung tâm của một tòa nhà văn phòng — mọi phòng ban (scheduler, controller-manager, kube-proxy, admin) đều có đường dây riêng nối về tổng đài, nhưng không phòng ban nào gọi thẳng cho nhau. Mỗi đường dây cần đúng "thẻ ra vào" (client certificate) để tổng đài xác nhận đúng người trước khi kết nối. Thú vị là, chính tổng đài đó lại là "khách gọi điện" khi cần liên lạc với hai bộ phận khác — etcd (kho lưu trữ hồ sơ) và kubelet (quản lý từng tầng nhà) — nên cũng phải mang theo thẻ ra vào riêng khi gọi tới đó.

Xét từng component trong Kubernetes cluster và xác định server, client, và ai nói chuyện với ai:

Kube-apiserver. API server expose một HTTPS service mà các component khác cũng như external user dùng để quản lý Kubernetes cluster. Vậy nó là server và cần certificate để bảo mật giao tiếp với client. Generate một cặp certificate và key — gọi là apiserver.crtapiserver.key. Nhớ rằng, tên certificate có thể khác nhau tuỳ setup Kubernetes, tuỳ ai và cách cluster được thiết lập.

Etcd server. Lưu mọi thông tin về cluster, nên cần một cặp certificate và key riêng — gọi là etcdserver.crtetcdserver.key.

Kubelet (trên worker node). Cũng expose một HTTPS API endpoint mà kube-apiserver dùng để tương tác với worker node — cần một cặp certificate và key, gọi là kubelet.crtkubelet.key.

Đó là các server component. Giờ tới các client component:

Admin user — truy cập kube-apiserver qua kubectl hoặc REST API. Cần một cặp certificate và key để authenticate — gọi là admin.crtadmin.key.

Scheduler — nói chuyện với kube-apiserver để tìm pod cần lập lịch rồi yêu cầu API server lập lịch pod lên đúng worker node. Với kube-apiserver, scheduler chỉ là một client khác, như admin user, nên cần xác thực bằng client TLS certificate — cần cặp certificate và key riêng, gọi là scheduler.crtscheduler.key.

Kube-controller-manager — cũng là một client truy cập kube-apiserver, nên cũng cần certificate để authenticate với kube-apiserver.

Kube-proxy — cần client certificate để authenticate tới kube-apiserver, cũng cần cặp certificate và key riêng, gọi là kube-proxy.crtkube-proxy.key.

Các server cũng giao tiếp với nhau. Ví dụ, kube-apiserver giao tiếp với etcd server. Thực ra, trong tất cả các component, kube-apiserver là component duy nhất nói chuyện với etcd server. Vậy với etcd server, kube-apiserver là một client, nên cần authenticate — kube-apiserver có thể dùng lại cặp key đã dùng để serve API của chính nó (apiserver.crtapiserver.key), hoặc generate một cặp certificate mới riêng cho việc authenticate tới etcd server.

Kube API server cũng nói chuyện với kubelet server trên từng node — đó là cách nó giám sát worker node. Với việc này, cũng có thể dùng lại certificate gốc hoặc generate cái mới riêng cho mục đích này.

Vậy là quá nhiều certificate. Thử nhóm lại: có một tập client certificate mà phần lớn client dùng để kết nối tới kube-apiserver. Có một tập server-side certificate mà kube-apiserver, etcd server, và kubelet dùng để authenticate client của chúng.

Ai là client, ai là server trong cluster?Admin / Scheduler /Controller-manager / Kube-proxykube-apiserver(server cho mọi client)etcd(server)kubelet(mỗi node)client certapiserver LÀ client ở đâykube-apiserver vừa là server cho phần lớn component, vừa là client của etcd và kubelet

Như đã biết, cần một certificate authority để ký tất cả các certificate này. Kubernetes yêu cầu ít nhất một certificate authority cho cluster — thực tế có thể có nhiều hơn một: một cho tất cả component trong cluster, và một riêng cho etcd. Trong trường hợp đó, certificate của etcd server và client certificate của etcd server (trong trường hợp này là client certificate của API server) sẽ đều được ký bởi CA của etcd server. Hiện tại, sẽ dùng một CA duy nhất cho cluster. CA, như đã biết, có cặp certificate và key riêng — gọi là ca.crtca.key. Đó là tổng hợp mọi certificate dùng trong cluster.


6. Tạo Certificates cho Cluster bằng OpenSSL

Để generate certificate, có nhiều tool khác nhau như EasyRSA, OpenSSL, hay CFSSL, v.v. Ở đây dùng tool OpenSSL để generate certificate.

CA certificates. Trước tiên tạo một private key dùng lệnh OpenSSL:

openssl genrsa -out ca.key 2048

Sau đó dùng lệnh openssl req cùng key vừa tạo để generate một certificate signing request. CertificateSigningRequest giống như certificate, có đầy đủ thông tin, nhưng chưa có chữ ký. Trong CertificateSigningRequest, chỉ định tên component certificate này dành cho trong trường Common Name (CN). Trong trường hợp này, vì đang tạo certificate cho Kubernetes CA, đặt tên là Kubernetes-CA:

openssl req -new -key ca.key -subj "/CN=KUBERNETES-CA" -out ca.csr

Cuối cùng, ký certificate bằng lệnh openssl x509, chỉ định certificate signing request vừa generate ở lệnh trước:

openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt

Vì đây là cho chính CA, nó tự ký (self-signed) bởi CA bằng private key nó vừa generate ở bước đầu. Từ giờ trở đi, với mọi certificate khác, sẽ dùng cặp key CA này để ký chúng. CA giờ đã có private key và root certificate file.

Client certificates. Bắt đầu với admin user — theo cùng quy trình, tạo private key cho admin user bằng lệnh OpenSSL, rồi generate một CSR. Đây là nơi chỉ định tên admin user, là kube-admin — tên này không nhất thiết phải là kube-admin, có thể là bất cứ gì, nhưng nhớ đây là tên mà kubectl client authenticate với — khi chạy lệnh kubectl, đây sẽ là tên xuất hiện trong audit log và các nơi khác. Nên chọn một tên phù hợp cho trường này. Cuối cùng, generate một signed certificate bằng lệnh openssl x509, nhưng lần này chỉ định CA certificate và CA key — đang ký certificate của mình bằng cặp key CA, khiến nó thành một certificate hợp lệ trong cluster. Signed certificate được output ra file admin.crt — đó là certificate admin user sẽ dùng để authenticate tới Kubernetes cluster.

Nếu để ý, toàn bộ quy trình generate một key và certificate pair tương tự việc tạo một user account cho user mới. Certificate là user ID đã xác thực, và key giống như password — chỉ là an toàn hơn nhiều so với username/password đơn giản.

Vậy làm sao phân biệt user này với các user khác? User account cần được nhận diện là admin user, không chỉ là một basic user thông thường. Làm điều đó bằng cách thêm thông tin group cho user trong certificate. Trong trường hợp này, có một group tên system:masters tồn tại sẵn trên Kubernetes với quyền quản trị. Cần chỉ định thông tin này trong certificate signing request, bằng cách thêm chi tiết group với tham số OU khi generate certificate signing request. Một khi đã ký, có certificate cho admin user với quyền admin.

Theo cùng quy trình để generate client certificate cho các component khác truy cập kube-apiserver: kube-scheduler — vì là system component thuộc control plane Kubernetes, tên phải được prefix bằng từ khoá system:. Tương tự với kube-controller-manager, cũng là system component nên tên cũng phải prefix system:. Và cuối cùng, kube-proxy.

Vậy đã tạo CA certificate, rồi tới toàn bộ client certificate gồm admin user, scheduler, controller manager, và kube-proxy. Sẽ theo cùng quy trình để tạo ba client certificate còn lại cho kube-apiserver và kubelet khi tạo server certificate cho chúng — nên tạm gác lại.

Dùng những certificate này thế nào? Lấy certificate admin làm ví dụ, để quản lý cluster, có thể dùng certificate này thay vì username/password trong một REST API call gửi tới kube-apiserver — chỉ định key, certificate, và CA certificate như các option. Đó là một cách đơn giản. Cách khác là chuyển toàn bộ các tham số này vào một configuration file gọi là kubeconfig. Trong đó, chỉ định chi tiết API server endpoint, certificate cần dùng, v.v. Đó là cách hầu hết các Kubernetes client dùng — sẽ xem kubeconfig chi tiết hơn ở phần sau.

Trước khi chuyển sang server-side certificate, một điều nữa: nhớ ở bài giảng tiền đề đã nói, để client xác thực certificate gửi từ server, và ngược lại, tất cả đều cần một bản copy public certificate của certificate authority — cái đã được cài sẵn trong browser của user trong trường hợp web application. Tương tự, trong Kubernetes, để các component khác nhau này xác thực lẫn nhau, tất cả đều cần một bản copy root certificate của CA. Vậy bất cứ khi nào cấu hình một server hay client với certificate, cũng cần chỉ định root certificate của CA.

Server-side certificates. Bắt đầu với etcd server — theo cùng quy trình như trước để generate certificate cho etcd, đặt tên etcd-server. Etcd server có thể được deploy dưới dạng cluster trên nhiều server, như trong môi trường high availability. Trong trường hợp đó, để bảo mật giao tiếp giữa các member khác nhau trong cluster, phải generate thêm peer certificate. Sau khi certificate được generate, chỉ định chúng khi khởi động etcd server — có option --key-file--cert-file để chỉ định etcd server key. Có các option khác để chỉ định peer certificate. Và cuối cùng, như đã bàn, nó cần CA root certificate để xác thực các client kết nối tới etcd server là hợp lệ.

Kube-apiserver. Generate certificate cho kube-apiserver tương tự như trước. Nhưng API server là component phổ biến nhất trong tất cả các component — mọi thứ đều nói chuyện với kube-apiserver, mọi thao tác đều đi qua kube-apiserver, bất cứ gì di chuyển trong cluster, kube-apiserver đều biết tới, cần thông tin gì, nói chuyện với kube-apiserver. Vậy nó có nhiều tên và alias khác nhau trong cluster. Tên thật của nó là kube-apiserver. Nhưng có người gọi nó là kubernetes, vì với nhiều người không thực sự biết bên dưới Kubernetes hoạt động ra sao, kube-apiserver chính là Kubernetes. Người khác gọi nó là kubernetes.default. Có người gọi nó là kubernetes.default.svc, và có người gọi bằng tên đầy đủ kubernetes.default.svc.cluster.local. Cuối cùng, ở một số nơi nó cũng được tham chiếu đơn giản bằng địa chỉ IP của nó — IP của host chạy kube-apiserver hoặc pod chạy nó. Vậy tất cả các tên này phải xuất hiện trong certificate được generate cho kube-apiserver — chỉ khi đó những ai tham chiếu tới kube-apiserver bằng các tên này mới thiết lập được kết nối hợp lệ.

Dùng cùng tập lệnh như trước để generate key. Trong certificate signing request, chỉ định tên kube-apiserver. Nhưng làm sao chỉ định tất cả alternate name? Với việc đó, phải tạo một file openssl.cnf, chỉ định các alternate name trong section alt_names của file. Bao gồm mọi DNS name mà API server được biết tới, cũng như địa chỉ IP. Truyền config file này như một option khi generate Certificate Signing Request. Cuối cùng, ký certificate bằng CA certificate và key. Giờ đã có kube-apiserver certificate.

Đến lúc xem chỉ định các key này ở đâu. Nhớ tới các client certificate mà API server dùng khi giao tiếp như một client tới etcd và kubelet server. Vị trí của các certificate này được truyền vào executable của kube-apiserver hoặc file cấu hình service. Trước tiên, cần truyền vào file CA — nhớ rằng, mọi component đều cần CA certificate để xác thực client của chúng. Sau đó cung cấp kube-apiserver certificate dưới các option TLS cert. Rồi chỉ định client certificate mà kube-apiserver dùng để kết nối tới etcd server, cũng kèm CA file. Và cuối cùng, kube-apiserver client certificate để kết nối tới kubelet.

Kubelet server. Kubelet server là một HTTPS API server chạy trên mỗi node, chịu trách nhiệm quản lý node. Đó là bên API server nói chuyện tới để giám sát node cũng như gửi thông tin về pod nào cần lập lịch lên node này. Vậy cần một cặp key/certificate cho mỗi node trong cluster. Đặt tên những certificate này ra sao? Không phải tất cả đều đặt tên kubelet — chúng sẽ được đặt tên theo node: node01, node02, và node03. Sau khi certificate được tạo, dùng chúng trong file cấu hình kubelet — như thường lệ, chỉ định root CA certificate rồi cung cấp kubelet node certificate. Phải làm điều này cho từng node trong cluster.

Cũng đã bàn về một tập client certificate mà kubelet dùng để giao tiếp với kube-apiserver — dùng để kubelet authenticate tới kube-apiserver, cũng cần được generate. Đặt tên những certificate này ra sao? Kube-apiserver cần biết node nào đã authenticate và cấp đúng bộ quyền cho nó. Vậy nó yêu cầu node phải có đúng tên theo đúng format. Vì các node là system component giống kube-scheduler và controller-manager đã bàn trước đó, format bắt đầu bằng từ khoá system:, theo sau là node rồi tên node, trong trường hợp này là node01 tới node03. Và làm sao API server cấp đúng bộ quyền? Nhớ đã chỉ định group name cho admin user để có quyền admin — tương tự, các node phải được thêm vào một group tên system:nodes. Sau khi certificate được generate, chúng đi vào các kubeconfig file như đã bàn trước đó.


7. Xem Certificates trong Cluster hiện có

Giả sử vừa gia nhập một team mới để giúp họ quản lý môi trường Kubernetes — một administrator mới với team này. Được thông báo có nhiều vấn đề liên quan tới certificate trong môi trường, nên được yêu cầu thực hiện một health check toàn bộ certificate trong cluster. Làm gì đầu tiên?

Trước tiên, quan trọng là biết cluster được thiết lập như thế nào. Có nhiều giải pháp khác nhau để deploy Kubernetes cluster, và mỗi giải pháp dùng phương pháp khác nhau để generate và quản lý certificate. Nếu tự deploy một Kubernetes cluster from scratch, tự generate tất cả certificate như đã làm ở phần trước. Hoặc nếu dựa vào một automated provisioning tool như kubeadm, nó sẽ tự động lo việc generate và cấu hình cluster. Trong khi tự deploy các component dưới dạng native service trên node phần cứng, tool kubeadm deploy chúng dưới dạng pod. Vậy quan trọng là biết nên nhìn vào đâu để xem đúng thông tin.

Ở đây xem xét một cluster được provision bởi kubeadm làm ví dụ. Để thực hiện health check, bắt đầu bằng việc xác định tất cả certificate dùng trong hệ thống. Có một mẫu Excel spreadsheet cho việc này (xem mục Nguồn tham khảo). Ý tưởng là tạo một danh sách các certificate file đang dùng, đường dẫn của chúng, tên được cấu hình trên chúng, alternate name được cấu hình (nếu có), tổ chức mà certificate account thuộc về, người cấp certificate (issuer), và ngày hết hạn trên certificate.

Làm sao lấy được các thông tin này? Bắt đầu với các certificate file đang dùng. Với môi trường được thiết lập bởi kubeadm, tìm file definition của kube-apiserver dưới thư mục /etc/kubernetes/manifests. Lệnh dùng để khởi động kube-apiserver có thông tin về tất cả certificate nó dùng. Xác định certificate file dùng cho từng mục đích và ghi lại.

Tiếp theo, lấy từng certificate và xem bên trong để tìm thêm chi tiết. Ví dụ, bắt đầu với certificate file của API server. Chạy lệnh openssl x509 và cung cấp certificate file làm input để decode certificate và xem chi tiết. Bắt đầu với tên trên certificate, dưới mục subject — trong trường hợp này là kube-apiserver. Rồi tới alternate name — kube-apiserver có nhiều alternate name, nên phải đảm bảo tất cả đều có mặt. Sau đó kiểm tra mục validity của certificate để xác định ngày hết hạn. Rồi tới issuer của certificate — đây nên là CA đã cấp certificate. kubeadm đặt tên Kubernetes CA là kubernetes.

Theo cùng quy trình để xác định thông tin về mọi certificate khác. Những điều cần kiểm tra: đảm bảo có đúng tên, đúng alternate name, đảm bảo certificate thuộc đúng tổ chức. Và quan trọng nhất, chúng được cấp bởi đúng issuer và certificate chưa hết hạn. Các yêu cầu về certificate được liệt kê chi tiết trong trang tài liệu Kubernetes (xem mục Nguồn tham khảo).

Nếu gặp vấn đề, cần bắt đầu xem log. Nếu tự thiết lập cluster from scratch, và các service được cấu hình dưới dạng native service trong OS, cần xem service log bằng chức năng logging của hệ điều hành. Nếu thiết lập cluster bằng kubeadm, các component được deploy dưới dạng pod, nên có thể xem log bằng lệnh kubectl logs theo sau là tên pod. Đôi khi, nếu các core component như kube-apiserver hoặc etcd server bị down, các lệnh kubectl sẽ không hoạt động — lúc đó phải xuống một cấp thấp hơn, tới Docker để lấy log. Liệt kê tất cả container bằng lệnh crictl ps -a, rồi xem log bằng lệnh crictl logs theo sau là container ID.


8. Lab: Xem chi tiết Certificate và Troubleshooting

Xác định certificate file dùng cho kube-apiserver. Xem manifest file của kube-apiserver, biết dưới /etc/kubernetes/manifests. Xem file này, tìm certificate file dùng cho kube-apiserver: certificate là /etc/kubernetes/pki/apiserver.crt và key tương ứng.

Xác định certificate file dùng để authenticate kube-apiserver như một client tới etcd server. Đây là cấu hình kube-apiserver, và kube-apiserver kết nối tới etcd server như một client — chỉ định địa chỉ etcd server, rồi CA file, certificate file, key. Cert file là /etc/kubernetes/pki/apiserver-etcd-client.crt.

Xác định key dùng để authenticate kube-apiserver tới kubelet server. Có certificate file và key liên quan tới kubelet — key là /etc/kubernetes/pki/apiserver-kubelet-client.key.

Tóm tắt: các file dùng bởi chính API server để host chính nó nằm dưới /etc/kubernetes/pki — certificate và key của API server. Còn mọi thứ để kết nối tới etcd server, CA file nằm dưới etcd, nhưng các file client của API server vẫn nằm dưới thư mục PKI. Tương tự, file client cho kubelet cũng nằm dưới thư mục PKI. Vậy bất cứ gì liên quan tới kube-apiserver — dù là certificate/key của chính nó, hay các file client để kết nối tới etcd/kubelet — đều nằm dưới /etc/kubernetes/pki.

Xác định etcd server certificate dùng để host chính etcd server. Xem manifest file của etcd server — certificate file nằm dưới thư mục etcd, key cũng dưới thư mục etcd, và CA file cũng dưới thư mục etcd. Vậy bất cứ gì liên quan tới chính etcd server nằm dưới /etc/kubernetes/pki/etcd. Certificate là /etc/kubernetes/pki/etcd/server.crt.

Xác định etcd server CA root/certificate dùng để serve etcd server. CA file (trusted CA file) nằm dưới /etc/kubernetes/pki/etcd. Như đã bàn, etcd server có CA file riêng (trusted CA root file) nằm dưới thư mục /etc/kubernetes/pki/etcd, còn kube-apiserver có CA file riêng nằm ở thư mục khác. Đó là /etc/kubernetes/pki/etcd/ca.crt.

Common Name (CN) cấu hình trên kube-apiserver certificate là gì? Chạy certificate qua lệnh:

openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout

Xem thông tin — issuer là kubernetes, nhưng subject (certificate được cấp cho ai) có common name là kube-apiserver.

Tên của CA đã cấp kube-apiserver certificate là gì? Xem mục issuer — tên là kubernetes.

Alternate name nào dưới đây KHÔNG được cấu hình trên kube-apiserver? Như đã bàn, kube-apiserver có nhiều tên: control plane, kubernetes, kubernetes.default, kubernetes.default.svc, kubernetes.default.svc.cluster.local, và cả địa chỉ IP. kube-master không có trong danh sách này — đó là đáp án.

Common Name cấu hình trên etcd server certificate là gì? Chạy cùng lệnh cho etcd server certificate — issuer là etcd-ca (etcd có CA riêng, khác với CA kubernetes của kube-apiserver). Common name cho etcd server certificate là control plane — nhưng đây không phải control plane của Kubernetes, mà đang tham chiếu tới control plane của etcd.

Certificate kube-apiserver có hiệu lực bao lâu kể từ ngày cấp? Xem mục validity: Not Before là April 17, 2022, và hiệu lực tới April 17, 2023 — khoảng một năm.

Root CA certificate có hiệu lực bao lâu kể từ ngày cấp? Chạy cùng lệnh cho root CA certificate — validity từ April 17, 2022 tới April 14, 2032 — khoảng 10 năm.

Kịch bản troubleshoot 1 — kubectl đột nhiên ngừng phản hồi sau một change window. Có người vừa sửa một file nào đó. Chạy kubectl get pods — sau một lúc, báo lỗi connection to the server was refused, did you specify the right host or port?. Nghĩa là kubectl không thể giao tiếp với kube-apiserver. Không thể dùng lệnh kubectl để kiểm tra trạng thái kube-apiserver vì chính kubectl không giao tiếp được — phải dùng Docker, vì các pod thực chất chạy dưới dạng container trên host Docker. Chạy docker ps | grep kube-apiserver — thấy một container kube-apiserver vừa exited 27 giây trước, và một container kube-apiserver mới. Xem log container này — thấy lỗi: Error while dialing TCP 127.0.0.1:2379. Đã biết 2379 là port của etcd server — vậy kube-apiserver không kết nối được tới etcd server.

Xem etcd server — kiểm tra thư mục certificate, thấy có server.crt, nhưng không có server-certificate.crt. Xem manifest file của etcd server, /etc/kubernetes/manifests/etcd.yaml — nơi cấu hình etc/kubernetes/pki/etcd/server.crt — có người đã set sai đường dẫn certificate ở đây (dùng server-certificate.crt thay vì server.crt). Sửa lại đường dẫn thành server.crt, lưu file, chờ pod etcd khởi động lại, rồi chờ kube-apiserver pick up thay đổi — kiểm tra lại, kubectl đã hoạt động trở lại và node đã Ready.

Kịch bản troubleshoot 2 — kube-apiserver dừng lần nữa sau vài giờ. Xem log kube-apiserver — lần này báo unable to connect to the server: TLS handshake timeout. Kiểm tra docker ps -a | grep apiserver — container này đã thành công (không crash), xem log — authentication handshake failed, certificate signed by unknown authority, kèm thông tin không kết nối được tới 127.0.0.1:2379 (etcd server). Vậy kube-apiserver không kết nối được tới etcd server vì handshake issue — certificate bị ký bởi unknown authority.

Xem etcd pod — container etcd đã chạy 4 phút, xem log — khởi động bình thường, không lỗi, nhưng sau đó thấy các connection bị reject từ một remote, báo bad certificate. Vậy etcd đang reject connection từ kube-apiserver vì nó gửi một bad certificate. Xem certificate cấu hình trên API server, tập trung vào phần liên quan tới etcd: có etcd-CA file set thành /etc/kubernetes/pki/ca.crt, và apiserver-etcd-client.crt (client certificate của API server) được set đúng, key file cũng đúng, URL etcd server cũng đúng. Nhưng như đã bàn trước đó, Kubernetes có CA file riêng, và etcd cũng có CA file riêng nằm dưới /etc/kubernetes/pki/etcd — vậy đáng lẽ phải chỉ định CA file của etcd (chứ không phải CA file của Kubernetes) ở đây. Sửa lại thành đúng CA file của etcd, lưu lại — kube-apiserver khởi động lại, không còn lỗi, và API server đã hoạt động trở lại.


9. Certificates API (CertificateSigningRequest)

Đã setup một CA server và một loạt certificate cho các component khác nhau, khởi động các service với đúng certificate, và mọi thứ đã hoạt động. Là administrator duy nhất và user của cluster, có admin certificate và key của riêng mình. Một admin mới gia nhập team, cần quyền truy cập cluster — cần một cặp certificate và key cho họ để truy cập cluster. Họ tạo private key riêng, generate một certificate signing request, và gửi cho mình. Vì là admin duy nhất, lấy certificate signing request đó tới CA server, ký nó bằng private key và root certificate của CA server, qua đó tạo ra một certificate, rồi gửi certificate lại cho họ. Giờ họ có cặp certificate và key hợp lệ để truy cập cluster.

Certificate có một khoảng thời gian hiệu lực (validity period), hết hạn sau một khoảng thời gian. Mỗi lần hết hạn, lặp lại đúng quy trình generate CSR mới và ký bởi CA — cứ xoay vòng (rotate) certificate file như vậy.

CA server là gì, nằm ở đâu trong setup Kubernetes? CA thực chất chỉ là cặp key và certificate file đã generate. Ai chiếm được cặp file này có thể ký bất kỳ certificate nào cho môi trường Kubernetes, tạo bao nhiêu user tuỳ ý với bất kỳ quyền nào họ muốn. Vậy các file này cần được bảo vệ và lưu trữ trong môi trường an toàn — đặt chúng trên một server hoàn toàn bảo mật. Server đó trở thành CA server. Certificate key file được lưu an toàn trên server đó, chỉ trên server đó. Mỗi lần muốn ký một certificate, chỉ có thể làm được bằng cách login vào server đó. Hiện tại, các certificate đang đặt ngay trên Kubernetes master node — vậy master node cũng chính là CA server. Tool kubeadm cũng làm điều tương tự — nó tạo một cặp file CA và lưu ngay trên master node.

Từ trước tới giờ đã ký request thủ công. Nhưng khi số lượng user tăng lên và team lớn dần, cần một cách quản lý certificate, signing request, và xoay vòng certificate khi hết hạn tự động hơn. Kubernetes có sẵn một Certificates API built-in để làm việc này. Với Certificates API, giờ có thể gửi một CertificateSigningRequest trực tiếp tới Kubernetes qua một API call. Lần này, khi administrator nhận một certificate signing request, thay vì login vào master node và tự ký certificate, họ tạo một Kubernetes API object gọi là CertificateSigningRequest. Một khi object được tạo, tất cả certificate signing request có thể được xem bởi các administrator của cluster. Các request có thể được review và approve dễ dàng bằng lệnh kubectl. Certificate này sau đó có thể được trích xuất và chia sẻ với user.

Cách hoạt động: user trước tiên tạo một key, rồi generate một certificate signing request dùng key với tên của họ trên đó, rồi gửi request cho administrator. Administrator lấy certificate signing request và tạo một object CertificateSigningRequest. Object CertificateSigningRequest được tạo giống các Kubernetes object khác, dùng manifest file với các field thông thường. kindCertificateSigningRequest. Trong spec section, usages định nghĩa certificate sẽ được dùng như thế nào. expirationSeconds kiểm soát validity của certificate. signerName cho Kubernetes biết ai được phép ký certificate signing request và loại certificate nào đang được yêu cầu. Field request là nơi chỉ định certificate signing request gửi bởi user — nhưng không chỉ định dưới dạng plain text, mà phải encode bằng lệnh base64. Sau đó đưa text đã encode vào field request rồi submit request.

Một khi object được tạo, tất cả certificate signing request có thể được xem bởi administrator bằng lệnh kubectl get csr.

kubectl get csr

# Output minh họa
NAME AGE SIGNERNAME REQUESTOR CONDITION
akshay 2m kubernetes.io/kube-apiserver-client kubernetes-admin Pending

(Output minh họa — cấu trúc và tên cột đúng theo lệnh thật, số liệu cụ thể chỉ mang tính ví dụ.) Cột CONDITION là nơi thấy ngay trạng thái request — Pending nghĩa là chưa ai approve/deny, sau khi xử lý sẽ chuyển thành Approved,Issued hoặc Denied.

Xác định request mới và approve request bằng lệnh kubectl certificate approve. Kubernetes ký certificate bằng cặp key CA và generate một certificate cho user. Certificate này sau đó có thể được trích xuất và chia sẻ với user. Xem certificate bằng cách xem nó ở định dạng YAML — generated certificate signing request là một phần của output, nhưng như trước, nó ở dạng base64 encode. Để decode, lấy text và dùng option decode của utility base64. Việc này cho ra certificate ở dạng plain text, có thể chia sẻ với end user.

Giờ đã thấy cách hoạt động, ai là bên thực hiện tất cả các thao tác này? Xem Kubernetes control plane, có kube-apiserver, scheduler, controller manager, v.v. — component nào thực sự chịu trách nhiệm cho các thao tác liên quan tới certificate? Toàn bộ các thao tác liên quan tới certificate được thực hiện bởi controller manager. Nếu xem kỹ controller manager, sẽ thấy nó có các controller tên CSR approving, CSR signing, v.v. — chúng chịu trách nhiệm thực hiện các tác vụ cụ thể này. Đã biết nếu ai đó cần ký certificate, họ cần root certificate và private key của CA server. Cấu hình service của controller-manager có hai option để chỉ định điều này.


10. Lab: Thực hành Certificates API

Một thành viên mới, Akshay, gia nhập team, cần quyền truy cập cluster. Certificate signing request nằm ở thư mục root — có Akshay.csrAkshay.key.

Tạo một object CertificateSigningRequest tên Akshay với nội dung file Akshay.csr. Không có lệnh imperative để làm việc này. Vào trang tài liệu Kubernetes, phần tạo CertificateSigningRequest, lấy template (bỏ dòng đầu và cuối vì cần chỉnh sửa request, kể cả expiration date vì không cần cho lúc này). Tạo file akshay.yaml, dán template vào. Cần đưa nội dung Akshay.csr vào field request, nhưng phải ở định dạng base64-encoded trước:

cat Akshay.csr | base64 -w 0

Option -w 0 để in ra dưới dạng một dòng duy nhất (mặc định base64 in ra kèm newline, không phù hợp vì field này cần một dòng duy nhất). Copy kết quả này, dán vào field request trong akshay.yaml, đổi tên trong metadata thành akshay. signerName nên là kubernetes.io/kube-apiserver-client (mặc định đã đúng).

Tạo — báo lỗi illegal base64 data at input byte 100 — thiếu một dấu bằng (=) khi copy. Copy lại request cho đúng, lưu lại thành akshay.yaml, tạo lại — thành công. kubectl get csr — thấy request tên akshay, trạng thái Pending.

Trạng thái của object CertificateSigningRequest vừa tạo là gì? Pending.

Approve CSR.

kubectl certificate approve akshay

Hiện có bao nhiêu CSR request trên cluster? Có hai request.

Trong quá trình kiểm tra định kỳ, phát hiện có một CSR request mới. Tên request này là gì? agent-smith.

Request này đang yêu cầu quyền truy cập vào group nào? Xem chi tiết bằng:

kubectl get csr agent-smith -o yaml

Dưới spec, mục groups, thấy nó đang request system:masterssystem:authenticated. system:masters là group nó đang request truy cập.

Điều này không ổn, vì không muốn cấp system:masters — group có rất nhiều quyền lực. Vậy từ chối request:

kubectl certificate deny agent-smith

Xoá object CSR mới. Kiểm tra trạng thái — đã Denied. Xoá nó:

kubectl delete csr agent-smith

Kiểm tra lại — đã bị xoá thành công.


11. Kubeconfig

Đã thấy cách generate certificate cho một user, và cách client dùng certificate file và key để query Kubernetes REST API xin danh sách Pod bằng curl. Ví dụ, cluster tên my-kube-playground. Gửi một curl request tới địa chỉ kube-apiserver, kèm cặp file cùng CA certificate như các option. Việc này được kube-apiserver validate để authenticate user.

Làm sao thực hiện điều này bằng lệnh kubectl? Có thể chỉ định cùng thông tin bằng các option --server, --client-key, --client-certificate, và --certificate-authority với utility kubectl. Tất nhiên, gõ những cái này mỗi lần rất mất công. Vậy chuyển thông tin này vào một configuration file gọi là kubeconfig, rồi chỉ định file này như option --kubeconfig trong lệnh. Mặc định, tool kubectl tìm một file tên config dưới thư mục .kube trong home directory của user. Nếu tạo kubeconfig file ở đó, không cần chỉ định đường dẫn tường minh trong lệnh kubectl — đó là lý do từ trước tới giờ chưa cần chỉ định option nào cho lệnh kubectl.

Kubeconfig file có định dạng cụ thể. Config file có ba section: clusters, users, và contexts. Clusters là các Kubernetes cluster khác nhau cần truy cập — có thể có nhiều cluster cho môi trường dev, test, prod, hay cho các tổ chức khác nhau, hoặc trên các cloud provider khác nhau. Users là các user account dùng để truy cập những cluster này — ví dụ admin user, dev user, prod user, v.v. Các user này có thể có quyền khác nhau trên các cluster khác nhau. Cuối cùng, contexts gắn kết hai cái lại — context định nghĩa user account nào dùng để truy cập cluster nào. Ví dụ, có thể tạo một context tên admin@production dùng account admin để truy cập production cluster. Hay muốn truy cập cluster đã setup trên Google bằng credential dev user để test deploy application đã build.

Nhớ rằng, không phải đang tạo user mới hay cấu hình bất kỳ loại user access hay authorization nào trong cluster. Với quy trình này, đang dùng user hiện có với quyền hiện có, và định nghĩa user nào sẽ dùng để truy cập cluster nào. Nhờ vậy không cần chỉ định user certificate và server address trong mỗi lệnh kubectl.

Vậy fit vào ví dụ như thế nào? Thông tin server và certificate authority trong lệnh đi vào section clusters, key và certificate của admin user đi vào section users. Sau đó tạo một context chỉ định dùng user my-kube-admin để truy cập cluster my-kube-playground.

Kubeconfig file ở định dạng YAML. Có apiVersion set là v1, kindConfig, và có ba section như đã bàn — mỗi cái ở dạng array, nên có thể chỉ định nhiều cluster, user, hoặc context trong cùng một file. Dưới clusters, thêm một item mới cho cluster kube-playground, đặt tên my-kube-playground, chỉ định server address dưới field server. Cũng cần certificate của Certificate Authority. Rồi thêm một entry dưới section user để chỉ định chi tiết user my-kube-admin, cung cấp vị trí client certificate và key pair. Giờ đã định nghĩa cluster và user để truy cập cluster. Tiếp theo, tạo một entry dưới section contexts để liên kết hai cái lại — sẽ đặt tên context là my-kube-admin@my-kube-playground, chỉ định cùng tên đã dùng cho cluster và user. Theo cùng quy trình để thêm tất cả cluster cần truy cập hàng ngày, user credential dùng để truy cập chúng, cũng như context.

Một khi file đã sẵn sàng, nhớ rằng không cần tạo bất kỳ object nào như thường làm với các Kubernetes object khác. File được giữ nguyên như vậy, và được đọc bởi lệnh kubectl, các giá trị cần thiết được dùng.

Vậy kubectl biết chọn context nào? Đã định nghĩa ba context ở đây — nó nên bắt đầu với cái nào? Có thể chỉ định context mặc định để dùng bằng cách thêm field current-context vào kubeconfig file, chỉ định tên context cần dùng. Trong trường hợp này, kubectl sẽ luôn dùng context dev-user@google để truy cập cluster Google bằng credential của dev user.

Có các option command line trong kubectl để xem và sửa kubeconfig file. Để xem file hiện đang dùng, chạy lệnh kubectl config view — liệt kê cluster, context, và user, cũng như context hiện tại đang được set.

kubectl config view

# Output minh họa (rút gọn)
apiVersion: v1
clusters:
- cluster:
certificate-authority: /etc/kubernetes/pki/ca.crt
server: https://my-kube-playground:6443
name: my-kube-playground
contexts:
- context:
cluster: my-kube-playground
user: my-kube-admin
name: my-kube-admin@my-kube-playground
current-context: my-kube-admin@my-kube-playground
kind: Config
users:
- name: my-kube-admin
user:
client-certificate: /etc/kubernetes/pki/users/admin.crt
client-key: /etc/kubernetes/pki/users/admin.key

(Output minh họa — cấu trúc và tên field đúng theo lệnh thật, giá trị cụ thể chỉ mang tính ví dụ.) Trường current-context chính là context kubectl đang dùng mỗi khi chạy lệnh — đổi trường này (qua kubectl config use-context) là cách nhanh nhất để chuyển sang cluster/user khác mà không cần sửa gì trong clusters/users.

Kubeconfig: contexts liên kết clusters và usersclusters:- my-kube-playgroundserver: https://...:6443users:- my-kube-adminclient-cert + client-keycontexts:- my-kube-admin@my-kube-playground(current-context)chọn clusterchọn user

Như đã bàn, nếu không chỉ định kubeconfig file nào để dùng, nó dùng file mặc định nằm trong thư mục .kube của home directory user. Ngoài ra, có thể chỉ định một kubeconfig file bằng cách truyền option --kubeconfig trong command line.

Làm sao update current context? Đang dùng user my-kube-admin để truy cập my-kube-playground. Làm sao đổi context để dùng prod user truy cập production cluster? Chạy lệnh:

kubectl config use-context prod-user@production

để đổi current context thành context prod-user@production. Có thể thấy điều này trong field current-context của file. Vậy đúng, các thay đổi thực hiện bởi lệnh kubectl config thực sự phản ánh trong file. Có thể thực hiện các thay đổi khác trong file, update hoặc xoá item trong đó bằng các biến thể khác của lệnh kubectl config.

Còn namespace thì sao? Ví dụ, mỗi cluster có thể được cấu hình với nhiều namespace bên trong nó. Có thể cấu hình một context để chuyển tới một namespace cụ thể không? Có. Section contexts trong kubeconfig file có thể nhận thêm một field gọi là namespace, nơi chỉ định một namespace cụ thể. Nhờ vậy, khi chuyển sang context đó, sẽ tự động ở trong namespace cụ thể đó.

Một lưu ý về certificate. Đã thấy đường dẫn tới certificate file được chỉ định trong kubeconfig — tốt hơn nên dùng full path. Nhưng nhớ, cũng có cách khác để chỉ định certificate credential. Ví dụ, chỗ cấu hình đường dẫn tới certificate authority — thay vì dùng field certificate-authority và path tới file, có thể tuỳ chọn dùng field certificate-authority-data và cung cấp nội dung của chính certificate. Nhưng không phải file nguyên trạng — convert nội dung sang định dạng base64 encoded, rồi truyền vào. Tương tự, nếu thấy một file với certificate-data ở dạng encode, dùng option decode của base64 để decode certificate.


12. Lab: Thực hành Kubeconfig

File kubeconfig mặc định nằm ở đâu trong môi trường hiện tại? Tìm home directory hiện tại bằng biến môi trường HOME — set là root, thư mục hiện tại. Thường nằm dưới thư mục ẩn .kube — có thư mục .kube và file config bên trong. Vậy đó là root/.kube/config.

Có bao nhiêu cluster được định nghĩa trong file kubeconfig mặc định? Dưới clusters, chỉ có một cluster.

Có bao nhiêu user được định nghĩa trong file config mặc định? Chỉ có một user (kèm thông tin certificate).

Có bao nhiêu context được định nghĩa trong file config mặc định? Chỉ có một context.

User được cấu hình trong context hiện tại là gì? Current context tên là kubernetes-admin@kubernetes. Nhớ đây chỉ là tên — không nên giả định đây chính là user thực sự được cấu hình, dù trong trường hợp này naming convention đúng là user@cluster. Luôn phải xem field user thực tế — trong trường hợp này, user là kubernetes-admin.

Tên cluster được cấu hình trong file kubeconfig mặc định là gì? kubernetes.

Một kubeconfig file mới tên my-kube-config được tạo, nằm trong thư mục root.

Có bao nhiêu cluster được định nghĩa trong file này? 4 cluster.

Có bao nhiêu context được cấu hình trong file my-kube-config? 4 context.

User nào được cấu hình trong context research?dev-user.

Tên của client certificate file cấu hình cho user admin (aws-user) là gì? aws-user.crt.

Current context được set là gì trong file my-kube-config? test-user@development.

Muốn dùng dev user để truy cập test-cluster-1, set current context cho đúng. Xem các context có sẵn — có research@test-cluster-1 là context dùng dev-user để truy cập test-cluster-1. Dùng lệnh kubectl config use-context, và vì đây là file khác với file mặc định (root/.kube/config), phải chỉ định tên file:

kubectl config --kubeconfig=/root/my-kube-config use-context research

Kiểm tra lại — current-context trong file đã đổi thành research.

Không muốn phải chỉ định option kubeconfig mỗi lần chạy lệnh — làm file my-kube-config thành file kubeconfig mặc định. Di chuyển file này thành file mặc định (/root/.kube/config). Sau đó kubectl config view sẽ hiển thị file mới này.

Với current-context là research, thử truy cập cluster — có gì đó sai, xác định và fix. Chạy kubectl get nodes — thấy lỗi. Xem lại: dev-userclient-certificate set là dev-user.crt, nhưng file thực tế trong thư mục chứa certificate của tất cả user là dev-user.crt, dev-user.csr, dev-user.key — chứ không phải developer-user.crt như đang cấu hình sai trong file. Sửa lại đúng tên file dev-user.crt, thử lại — hoạt động.


Nguồn tham khảo

Nguồn gốc: Khóa "Certified Kubernetes Administrator (CKA)" — phần "Security" (Security Primitives; Authentication; TLS Certificates — kiến thức nền, TLS trong Kubernetes, tạo certificate bằng OpenSSL, xem certificate trong cluster hiện có, troubleshooting; Certificates API; Kubeconfig), nền tảng KodeKloud. Giảng viên: Mumshad Mannambeth.

Certificate Health Check Spreadsheet: kubernetes-the-hard-way/tools (mmumshad).

Repo ghi chú, link tài liệu, và đáp án các practice question của toàn bộ khóa học: kodekloudhub/certified-kubernetes-administrator-course.

Fact-check:

  • Static password file (basic-auth-file) đã bị gỡ hoàn toàn khỏi Kubernetes từ v1.19 — không còn được liệt kê trong tài liệu authentication chính thức. Static token file (--token-auth-file) vẫn còn tồn tại và hoạt động được, dù vẫn bị khuyến cáo không dùng cho production — 2026-09-13, Kubernetes: Authenticating.
  • kubernetes.io/kube-apiserver-client vẫn là 1 trong 3 well-known signer built-in cho CertificateSigningRequest; signer này không bao giờ được kube-controller-manager tự động approve — 2026-09-13, Kubernetes: Certificate Signing Requests.
  • Certificate do kubeadm tự sinh cho control-plane component (apiserver, admin, scheduler,...) mặc định có hiệu lực 1 năm, riêng CA gốc mặc định có hiệu lực 10 năm; kiểm tra hạn bằng kubeadm certs check-expiration, gia hạn bằng kubeadm certs renew — 2026-09-23, Kubernetes: Certificate Management with kubeadm.