Danh mục:
Bài viết này cung cấp cái nhìn tổng quát về mTLS (Mutual TLS), lý do tại sao nó quan trọng trong kiến trúc Microservices và các chiến lược triển khai hiệu quả.
So sánh TLS vs mTLS

Luồng giao tiếp mTLS
- Client Hello: Client bắt đầu kết nối.
- Server Hello & Certificate: Server gửi chứng chỉ của mình.
- Client Certificate Request: Server yêu cầu chứng chỉ từ Client.
- Client Certificate & Verification: Client gửi chứng chỉ và Server kiểm tra.
- Key Exchange: Thiết lập khóa mã hóa chung sau khi cả hai đã tin tưởng nhau.
Tại sao nên sử dụng mTLS?
Tăng cường bảo mật
- Đảm bảo rằng chỉ những Client được cấp phép mới có thể truy cập vào Server.
- Ngăn chặn các cuộc tấn công giả mạo (Impersonation).
Bảo mật Microservices (Service Mesh)
- Trong mô hình Zero Trust, không có mạng nào là an toàn tuyệt đối. mTLS giúp xác thực danh tính của từng Service trong Cluster.
API Tài chính / Fintech
- Đáp ứng các tiêu chuẩn bảo mật khắt khe khi truyền tải dữ liệu nhạy cảm giữa các tổ chức.
Ví dụ thực tế
1. Kích hoạt mTLS trong Istio
- Istio giúp việc triển khai mTLS trở nên dễ dàng thông qua các cấu hình khai báo.
- Chế độ PERMISSIVE: Chấp nhận cả lưu lượng có mTLS và không có mTLS (Dùng khi đang chuyển đổi).
- Chế độ STRICT: Bắt buộc mọi kết nối phải có mTLS.
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: my-service
spec:
mtls:
mode: STRICT
Ép buộc sử dụng mTLS cho thông tin liên lạc giữa các dịch vụ trong Namespace tương ứng.
Ví dụ cấu hình mTLS cho Spring WebClient
MtlsHttpClientConfig (Cấu hình HttpClient cho mTLS)
import io.netty.handler.ssl.SslContextBuilder import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import reactor.netty.http.client.HttpClient import java.io.FileInputStream import java.security.KeyStore import javax.net.ssl.KeyManagerFactory import javax.net.ssl.SSLContext import javax.net.ssl.TrustManagerFactory import java.security.SecureRandom @Configuration class MtlsHttpClientConfig { @Bean fun mtlsHttpClient(): HttpClient { val keyStorePath = "client.p12" // Đường dẫn tới chứng chỉ client val keyStorePassword = "changeit".toCharArray() // Mật khẩu kho khóa // Tải chứng chỉ Client (KeyStore) val keyStore = KeyStore.getInstance("PKCS12") FileInputStream(keyStorePath).use { keyStore.load(it, keyStorePassword) } // Khởi tạo KeyManagerFactory (Dùng để xác thực Client với Server) val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()) kmf.init(keyStore, keyStorePassword) // Khởi tạo TrustManagerFactory (Dùng để xác thực chứng chỉ của Server) val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) tmf.init(keyStore) // Cấu hình SSLContext với TLS val sslContext = SSLContext.getInstance("TLS") sslContext.init(kmf.keyManagers, tmf.trustManagers, SecureRandom()) // Tạo HttpClient bảo mật với SSLContext vừa cấu hình return HttpClient.create().secure { spec -> spec.sslContext(sslContext) } } }
WebClientConfig (Cấu hình WebClient)
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.client.reactive.ReactorClientHttpConnector import org.springframework.web.reactive.function.client.WebClient import reactor.netty.http.client.HttpClient @Configuration class WebClientConfig { @Bean fun mtlsWebClient(mtlsHttpClient: HttpClient): WebClient { // Xây dựng WebClient sử dụng HttpClient đã cấu hình mTLS return WebClient.builder() .baseUrl("https://secure.api.example.com") .clientConnector(ReactorClientHttpConnector(mtlsHttpClient)) .build() } }
- KeyStore (client.p12): Đây là file chứa chứng chỉ cá nhân của dịch vụ của bạn để gửi cho phía đối tác xác thực.
- TrustStore: Trong ví dụ này, keyStore được dùng làm cả TrustManagerFactory. Trong thực tế, bạn thường có một file riêng (như truststore.jks) chứa các chứng chỉ CA đáng tin cậy để xác thực server phía đối tác.
Ví dụ sử dụng WebClient
MtlsSecureService
import org.springframework.stereotype.Service import org.springframework.web.reactive.function.client.WebClient import reactor.core.publisher.Mono import java.time.Duration @Service class MtlsSecureService( private val mtlsWebClient: WebClient // WebClient đã được cấu hình mTLS ) { fun fetchSecureData(): Mono<String> { return mtlsWebClient.get() .uri("/secure-data") .retrieve() .bodyToMono(String::class.java) .timeout(Duration.ofSeconds(5)) // Giới hạn thời gian phản hồi là 5 giây } }
Ví dụ sử dụng WebClient (Phiên bản Coroutine)
Dependencies (Khai báo phụ thuộc)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
}
Cách sử dụng
import kotlinx.coroutines.reactor.awaitSingle import org.springframework.stereotype.Service import org.springframework.web.reactive.function.client.WebClient @Service class MtlsSecureService( private val mtlsWebClient: WebClient ) { suspend fun fetchSecureData(): String { return mtlsWebClient.get() .uri("/secure-data") .retrieve() .bodyToMono(String::class.java) .awaitSingle() // Chuyển đổi từ Mono sang Coroutine } }
Ví dụ cấu hình mTLS cho Client Node.js
const fs = require('fs'); const https = require('https'); const options = { hostname: 'secure.api.example', port: 443, path: '/', method: 'GET', key: fs.readFileSync('client-key.pem'), // Khóa riêng (Private Key) của client cert: fs.readFileSync('client-cert.pem'), // Chứng chỉ (Certificate) của client ca: fs.readFileSync('ca-cert.pem'), // Chứng chỉ CA để xác thực phía Server }; const req = https.request(options, res => { console.log('Trạng thái (status):', res.statusCode); res.on('data', d => { process.stdout.write(d); }); }); req.on('error', e => { console.error('Lỗi kết nối:', e); }); req.end();
Lưu ý khi triển khai

Các công cụ liên quan

Tóm tắt
- mTLS là phương thức xác thực hai chiều dựa trên TLS, trong đó cả Client và Server đều phải tự chứng minh danh tính thì mới có thể giao tiếp được.
- Hiệu quả vượt trội trong việc tăng cường bảo mật cho môi trường Microservices, Fintech và API xác thực.
- Điểm mấu chốt nằm ở việc tự động hóa quản lý chứng chỉ và sự ổn định trong vận hành.
Sử dụng mTLS trong Kubernetes và ảnh hưởng đến hiệu năng
Việc có sử dụng mTLS cho thông tin liên lạc giữa các dịch vụ trong cụm Kubernetes hay không cần được quyết định dựa trên sự cân bằng giữa tính bảo mật và hiệu năng.
1. Có tổn hao hiệu năng khi triển khai mTLS không?
Có. Các nguyên nhân chính bao gồm:

📌 Trong môi trường K8s thông thường, độ trễ (latency) sẽ tăng thêm khoảng 5~15%. Mức sử dụng CPU có thể tăng lên đến 30% khi sử dụng mTLS (tùy thuộc vào từng dịch vụ).
2. Vậy gọi qua DNS nội bộ có an toàn mà không cần mTLS không?
Không hẳn. Lý do như sau:

Tóm lại, giả định "An toàn vì ở trong cùng một cụm (cluster)" là một giả định rất nguy hiểm.
3. Thông thường sẽ thiết kế như thế nào?

Ví dụ cấu hình dựa trên Istio
PERMISSIVE (Cho phép mTLS tùy chọn)/ Chế độ này cho phép cả lưu lượng mã hóa mTLS và văn bản thuần (plaintext), thường dùng trong giai đoạn chuyển đổi.
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: internal-namespace
spec:
mtls:
mode: PERMISSIVE
STRICT (Bắt buộc mTLS) Chế độ nghiêm ngặt, chỉ chấp nhận lưu lượng có mTLS.
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: secure-services
namespace: payment
spec:
mtls:
mode: STRICT
Tóm tắt kết luận
- Khi dùng mTLS: Bảo mật mạnh mẽ hơn nhưng có tổn hao hiệu năng (tăng CPU/Độ trễ)
- Chỉ gọi DNS nội bộ: Dễ bị tấn công DNS Spoofing hoặc xâm nhập Pod
- Chiến lược đề xuất: Chỉ áp dụng mTLS cho dịch vụ quan trọng + Kết hợp NetworkPolicy
- Công nghệ thay thế: Cân nhắc Cilium dựa trên eBPF, SPIRE, mTLS offloading, v.v.
Hướng dẫn cấu hình mTLS Offloading (Kubernetes + Service Mesh)
mTLS Offloading là kiến trúc thực hiện việc mã hóa/giải mã và xác thực mTLS tại một lớp riêng biệt (Proxy/Sidecar/Gateway) thay vì tại ứng dụng. Cấu hình này giúp đáp ứng đồng thời việc tối ưu hóa hiệu năng và quản lý bảo mật.
mTLS Offloading là gì?
Đây là cấu trúc xử lý việc kiểm tra chứng chỉ, bắt tay TLS và mã hóa/giải mã bên ngoài ứng dụng.
[Client] ⇄ [Sidecar / Proxy (Xử lý mTLS)] ⇄ [Application (HTTP/gRPC thuần)]Các phương thức cấu hình Offloading
1️⃣ Dựa trên Istio + Envoy (Mô hình Sidecar) Envoy Sidecar sẽ xử lý mTLS. Ứng dụng giao tiếp nội bộ với Envoy bằng HTTP văn bản thuần thông qua localhost.
[Pod A]
├── [App Container] ←→ localhost HTTP
└── [Envoy Sidecar] ⇄⇄ mTLS ⇄⇄ [Envoy Sidecar]
↑
[Pod B]
2️⃣ Chấm dứt TLS tại Ingress Gateway + mTLS nội bộ (Bán Offloading)
[External Client]
⇄ TLS
[Ingress Gateway (Envoy)] ⇄ mTLS ⇄ [Dịch vụ nội bộ]
3️⃣ Proxy ngoài hoặc Node Local Sidecar Các Service Mesh như Linkerd, Consul Connect, Cilium sẽ đảm nhận mTLS. Ứng dụng chỉ sử dụng HTTP thông thường.
Ví dụ thực tế dựa trên Istio
DestinationRule (Thiết lập đối tượng áp dụng mTLS)
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: ratings
spec:
host: ratings.default.svc.cluster.local
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
PeerAuthentication (Bắt buộc mTLS giữa các dịch vụ)
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: default
spec:
mtls:
mode: STRICT
Ưu điểm của phương thức Offloading
- Tăng hiệu năng: Giảm gánh nặng bắt tay TLS và mã hóa/giải mã cho ứng dụng
- Đơn giản hóa code: Không cần viết code tải hoặc gia hạn chứng chỉ trong ứng dụng
- Tiêu chuẩn hóa: Quản lý tập trung các chính sách bảo mật (theo đơn vị Mesh)
- Tự động vận hành: Tự động xoay vòng chứng chỉ (ví dụ: SDS, cert-manager)
Các điểm cần lưu ý
- Vector tấn công Proxy: Sidecar Proxy có thể trở thành mục tiêu tấn công
- Khó gỡ lỗi: Nguyên nhân lỗi TLS có thể nằm ở lớp Proxy, gây khó khăn khi truy vết
- Sử dụng tài nguyên: Proxy xử lý toàn bộ lưu lượng nên sẽ làm tăng mức tiêu thụ CPU/RAM
- Thiết kế hệ thống xác thực: Cần làm rõ hệ thống tin cậy, vòng đời chứng chỉ và CA
Tóm tắt
- Dịch vụ thông thường : Xử lý mTLS dựa trên Istio Sidecar
- Liên kết bên ngoài: Chấm dứt TLS tại Ingress Gateway + dùng mTLS nội bộ
- Môi trường hiệu năng cao: Kết hợp tái sử dụng phiên TLS (Session reuse) và tinh chỉnh Envoy
- Cần quản lý CA: Cân nhắc áp dụng Vault, cert-manager hoặc SPIFFE
Nguồn bài viết ryukato.github.io