Xác thực gRPC bằng SSL/TLS trong C++

Chuẩn bị môi trường

Môi trường thử nghiệm sử dụng:

  • Hệ điều hành: Ubuntu 24.04
  • CMake: 4.2.0
  • GCC: 13.3.0
  • OpenSSL: 3.0.13

Biên dịch và chạy ví dụ

Sau khi clone mã nguồn từ kho lưu trữ tùy chỉnh, tiến hành biên dịch bằng script:

./start_build.sh

Khởi động server hỗ trợ SSL:

./server_withssl

Và client tương ứng:

./client_withssl

Tổng quan về xác thực SSL/TLS

SSL/TLS cung cấp ba tính năng chính cho kết nối mạng:

  • Bảo mật: Mã hóa dữ liệu truyền đi.
  • Xác thực: Đảm bảo danh tính của các bên tham gia.
  • Toàn vẹn: Phát hiện nếu dữ liệu bị sửa đổi trong quá trình truyền.

Các tệp chứng chỉ

Trong thư mục credentials, có ba tệp quan trọng:

  • root.crt: Chứng chỉ gốc (self-signed), dùng làm "neo tin cậy" ở phía client.
  • localhost.crt: Chứng chỉ máy chủ, chứa thông tin định danh và khóa công khai của server.
  • localhost.key: Khóa riêng của máy chủ, phải được bảo vệ nghiêm ngặt.

Tạo chứng chỉ tự ký

Sử dụng OpenSSL để tạo CA riêng và cấp chứng chỉ cho server:

# Tạo khóa riêng cho CA
openssl genrsa -out root.key 2048

# Tạo chứng chỉ gốc tự ký
openssl req -x509 -new -nodes -key root.key -subj "/CN=MyTestCA" -days 3650 -out root.crt

# Tạo khóa riêng cho server
openssl genrsa -out localhost.key 2048

# Tạo yêu cầu ký chứng chỉ (CSR)
openssl req -new -key localhost.key -subj "/CN=localhost" -out localhost.csr

# Ký CSR bằng CA để tạo chứng chỉ server
openssl x509 -req -in localhost.csr -CA root.crt -CAkey root.key -CAcreateserial -out localhost.crt -days 365

Triển khai trong gRPC C++

Phía server

Server sử dụng SslServerCredentials thay vì InsecureServerCredentials:

grpc::SslServerCredentialsOptions ssl_opts;
ssl_opts.pem_root_certs = ""; // Không cần ở server
ssl_opts.pem_cert_chain = load_file("localhost.crt");
ssl_opts.pem_private_key = load_file("localhost.key");

builder.AddListeningPort("0.0.0.0:50051", grpc::SslServerCredentials(ssl_opts));

Phía client

Client cấu hình tin cậy CA gốc:

grpc::SslCredentialsOptions ssl_opts;
ssl_opts.pem_root_certs = load_file("root.crt");

auto channel = grpc::CreateChannel("localhost:50051", grpc::SslCredentials(ssl_opts));

Phân tích hiệu năng

Thử nghiệm với 1000 yêu cầu đơn luồng cho thấy:

  • Kết nối không mã hóa: ~805 QPS
  • Kết nối SSL/TLS: ~747 QPS

Chênh lệch hiệu năng khoảng 7.2%, chủ yếu do chi phí mã hóa/giải mã và thiết lập kết nối an toàn.

Phân tích bằng flame graph

Sử dụng perf và công cụ FlameGraph để thu thập và trực quan hóa chi phí CPU:

sudo perf record -F 99 -p $(pgrep server_withssl) -g -- sleep 30
perf script > out.perf
stackcollapse-perf.pl out.perf > out.folded
flamegraph.pl out.folded > grpc_ssl_flame.svg

Kết quả cho thấy các hàm liên quan đến OpenSSL chiếm tỷ trọng đáng kể trong tổng thời gian xử lý.

Định dạng mã nguồn

Sử dụng Clang-Format với cấu hình Google style, điều chỉnh một số tùy chọn:

IndentWidth: 4
BreakBeforeBraces: Allman
AllowShortIfStatementsOnASingleLine: false

Kích hoạt định dạng tự động khi lưu trong VS Code thông qua tiện ích mở rộng C/C++ và Clang-Format.

Thẻ: grpc C++ SSL/TLS openssl authentication

Đăng vào ngày 12 tháng 7 lúc 22:46