1. Yêu cầu phần cứng và phiên bản phần mềm
Để triển khai hệ thống PKI tự động ổn định, bạn cần chuẩn bị môi trường Kubernetes với cấu hình tối thiểu sau.
Phiên bản Kubernetes: 1.25 trở lên (Khuyên dùng 1.28+ để hỗ trợ tốt nhất các tính năng mới của Vault Agent).
Phiên bản HashiCorp Vault: 1.14 trở lên (Bắt buộc để sử dụng Secrets Engine v2 và tính năng Kubernetes Auth mới).
Phiên bản Caddy: 2.6 trở lên (Hỗ trợ tốt cho ACME v2 và tích hợp với Vault).
Phiên bản Terraform: 1.5 trở lên (Để quản lý state và module Kubernetes hiện đại).
Yêu cầu phần cứng tối thiểu cho cluster:
- 3 Node (1 Control Plane, 2 Worker) để đảm bảo tính sẵn sàng cao (High Availability).
- CPU: Tối thiểu 4 vCPU tổng cộng cho toàn cluster.
- RAM: Tối thiểu 8GB RAM tổng cộng.
- Disk: Tối thiểu 50GB SSD (Vault cần IOPS cao để ghi logs và state).
Verify: Chạy lệnh dưới để kiểm tra phiên bản hiện có trên node của bạn.
kubectl version --short && terraform version && vault version
Kết quả mong đợi: Đầu ra hiển thị phiên bản của kubectl, terraform và vault đều lớn hơn hoặc bằng các giá trị yêu cầu trên. Nếu thiếu, hãy tiến hành cài đặt trước khi tiếp tục.
2. Kiến trúc luồng hoạt động tổng quan
Trước khi viết code, bạn cần hiểu rõ luồng dữ liệu giữa các thành phần để cấu hình đúng quyền hạn.
Luồng hoạt động cơ bản như sau: Ứng dụng (App) chạy trong Kubernetes sẽ khởi động một sidecar hoặc agent để liên hệ với HashiCorp Vault.
Vault đóng vai trò là Certificate Authority (CA) chính, lưu trữ Private Key và cấp phát các chứng chỉ ngắn hạn (Short-lived certificates).
Caddy đóng vai trò là Reverse Proxy, nó sẽ yêu cầu chứng chỉ từ Vault thông qua API, sau đó cấu hình server HTTPS để phục vụ traffic từ bên ngoài vào App.
Quá trình xác thực: App trong K8s sử dụng ServiceAccount Token để xác thực vào Vault (thông qua Kubernetes Auth Method).
Vault xác thực thành công -> Cấp phát chứng chỉ -> Caddy nhận chứng chỉ -> Caddy lắng nghe cổng 443 và bảo vệ App.
Verify: Vẽ sơ đồ luồng trên giấy hoặc công cụ vẽ để đảm bảo bạn đã nắm rõ vai trò của từng component trước khi triển khai.
3. Cài đặt và cấu hình Terraform
Terraform sẽ là công cụ chính để triển khai hạ tầng (Infrastructure as Code) cho Vault và các resource Kubernetes cần thiết.
Bước đầu tiên là tạo thư mục dự án và file cấu hình chính.
mkdir -p ~/pkiauto/terraform && cd ~/pkiauto/terraform
Trong thư mục này, tạo file main.tf để khai báo provider Kubernetes và Vault.
File: ~/pkiauto/terraform/main.tf
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.20"
}
vault = {
source = "hashicorp/vault"
version = "~> 3.0"
}
}
}
provider "kubernetes" {
config_path = "~/.kube/config"
}
# Provider Vault sẽ được cấu hình sau khi Vault đã chạy
# Ở đây ta khai báo placeholder để Terraform nhận diện
provider "vault" {
address = "https://vault.default.svc.cluster.local:8200"
# Các tham số xác thực sẽ được thêm ở phần cấu hình sau
skip_tls_verify = true
}
Kết quả mong đợi: File main.tf được tạo thành công, chứa khai báo provider cho Kubernetes và Vault. Lệnh `terraform fmt` sẽ không báo lỗi.
Tiếp theo, tạo file variables.tf để tham số hóa các biến quan trọng như tên cluster, namespace.
File: ~/pkiauto/terraform/variables.tf
variable "cluster_name" {
description = "Tên của cluster Kubernetes"
type = string
default = "k8s-pki-cluster"
}
variable "vault_namespace" {
description = "Namespace để triển khai Vault"
type = string
default = "vault-system"
}
variable "caddy_namespace" {
description = "Namespace để triển khai Caddy"
type = string
default = "caddy-system"
}
Kết quả mong đợi: File variables.tf được tạo, giúp bạn dễ dàng thay đổi tên cluster và namespace mà không cần sửa code logic.
Để quản lý state file an toàn, ta cần tạo file backend.tf để chỉ định nơi lưu state. Ở đây ta dùng local backend cho phần 1, sau này có thể chuyển sang S3 hoặc Vault.
File: ~/pkiauto/terraform/backend.tf
terraform {
backend "local" {
path = "terraform.tfstate"
}
}
Verify: Chạy lệnh dưới để kiểm tra cú pháp Terraform.
terraform init
Kết quả mong đợi: Terraform download provider kubernetes và vault, xuất hiện dòng "Terraform has been successfully initialized!".
4. Thiết lập Namespace và ServiceAccount trong Kubernetes
Trước khi deploy Vault, ta cần tạo các namespace và ServiceAccount để Vault và Caddy hoạt động đúng nguyên tắc phân vùng (Isolation).
Tạo file resources.tf để định nghĩa Namespace cho Vault và Caddy.
File: ~/pkiauto/terraform/resources.tf
resource "kubernetes_namespace" "vault" {
metadata {
name = var.vault_namespace
labels = {
"name" = var.vault_namespace
}
}
}
resource "kubernetes_namespace" "caddy" {
metadata {
name = var.caddy_namespace
labels = {
"name" = var.caddy_namespace
}
}
}
Kết quả mong đợi: File resources.tf được tạo, chứa định nghĩa resource namespace cho cả Vault và Caddy.
Tiếp theo, tạo ServiceAccount riêng cho Vault. ServiceAccount này sẽ được Vault sử dụng để tự xác thực (bootstrap) hoặc để các pod khác liên hệ.
File: ~/pkiauto/terraform/vault_sa.tf
resource "kubernetes_service_account" "vault_server" {
metadata {
name = "vault-server"
namespace = kubernetes_namespace.vault.metadata[0].name
}
}
resource "kubernetes_secret" "vault_sa_token" {
depends_on = [kubernetes_service_account.vault_server]
metadata {
name = "vault-server-token"
namespace = kubernetes_namespace.vault.metadata[0].name
}
type = "kubernetes.io/service-account-token"
data = {
"kubernetes.io/service-account.name" = kubernetes_service_account.vault_server.metadata[0].name
}
}
Kết quả mong đợi: File vault_sa.tf được tạo, tự động tạo secret chứa token cho service account vault-server.
Tương tự, tạo ServiceAccount cho Caddy. Caddy cần quyền này để có thể liên hệ với Vault và lấy chứng chỉ.
File: ~/pkiauto/terraform/caddy_sa.tf
resource "kubernetes_service_account" "caddy" {
metadata {
name = "caddy-pki"
namespace = kubernetes_namespace.caddy.metadata[0].name
}
}
resource "kubernetes_secret" "caddy_sa_token" {
depends_on = [kubernetes_service_account.caddy]
metadata {
name = "caddy-pki-token"
namespace = kubernetes_namespace.caddy.metadata[0].name
}
type = "kubernetes.io/service-account-token"
data = {
"kubernetes.io/service-account.name" = kubernetes_service_account.caddy.metadata[0].name
}
}
Kết quả mong đợi: File caddy_sa.tf được tạo, chuẩn bị sẵn service account cho Caddy.
Để áp dụng các cấu hình này vào Kubernetes cluster, ta cần chạy lệnh apply.
terraform apply -auto-approve
Kết quả mong đợi: Terraform tạo 2 namespace (vault-system, caddy-system) và các ServiceAccount tương ứng. Dòng "Apply complete! Resources: 6 added..." xuất hiện.
Verify: Kiểm tra xem namespace và service account đã được tạo chưa trên cluster.
kubectl get namespaces | grep -E "vault-system|caddy-system" && kubectl get serviceaccount -n vault-system && kubectl get serviceaccount -n caddy-system
Kết quả mong đợi: Đầu ra liệt kê 2 namespace và 2 service account (vault-server, caddy-pki) tương ứng.
Điều hướng series:
Mục lục: Series: Series: Xây dựng hệ thống quản lý mật mã và chứng chỉ số tự động (Automated PKI & Certificate Management) với HashiCorp Vault, Caddy và Kubernetes
Phần 2: Triển khai và cấu hình HashiCorp Vault trong Kubernetes »