Lỗi Gặp Phải
Bạn chạy docker pull registry.internal:5000/myapp:latest và nhận được thông báo:
Error response from daemon: Get "https://registry.internal:5000/v2/": x509: certificate signed by unknown authority
Docker xác minh chứng chỉ TLS với kho CA tin cậy của nó trước khi chấp nhận bất kỳ kết nối nào. Registry nội bộ của bạn đang dùng cert tự ký — hoặc cert được ký bởi CA nội bộ mà Docker chưa biết — nên Docker từ chối kết nối.
Nguyên Nhân
Việc xác minh TLS của Docker rất nghiêm ngặt. Không có cảnh báo click-through như trình duyệt. Nếu cert của registry rơi vào bất kỳ trường hợp nào dưới đây, Docker sẽ từ chối ngay:
- Chứng chỉ tự ký (self-signed certificate)
- Được ký bởi CA nội bộ/doanh nghiệp không có trong system trust store
- Thiếu intermediate CA certificates trong chuỗi chứng chỉ
Cách khắc phục tùy thuộc vào việc bạn muốn tin cậy cert đúng cách hay chỉ cần unblock nhanh trong môi trường dev.
Cách 1: Thêm CA Certificate của Registry vào Docker (Khuyến Nghị)
Đây là cách đúng cho môi trường production. Bạn đang yêu cầu Docker tin cậy CA của registry cụ thể — chứ không phải bỏ qua hoàn toàn bảo mật.
Bước 1: Lấy CA certificate từ registry của bạn
# Nếu bạn có shell access vào registry server:
scp user@registry.internal:/etc/docker/certs/ca.crt /tmp/registry-ca.crt
# Hoặc lấy trực tiếp qua mạng bằng openssl:
openssl s_client -connect registry.internal:5000 -showcerts < /dev/null 2>/dev/null \
| openssl x509 -outform PEM > /tmp/registry-ca.crt
Bước 2: Cài cert cho Docker
# Tạo thư mục certs riêng cho registry
sudo mkdir -p /etc/docker/certs.d/registry.internal:5000
# Đặt CA cert vào đúng vị trí
sudo cp /tmp/registry-ca.crt /etc/docker/certs.d/registry.internal:5000/ca.crt
Không cần restart Docker. Docker quét /etc/docker/certs.d/ mỗi lần pull — cert có hiệu lực ngay lập tức.
Dành cho macOS/Windows Docker Desktop
Thêm CA vào system keychain và Docker Desktop sẽ tự nhận:
# macOS
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /tmp/registry-ca.crt
# Sau đó restart Docker Desktop
Trên Windows, import cert vào Windows Certificate Store mục "Trusted Root Certification Authorities", rồi restart Docker Desktop.
Cách 2: Thêm CA vào System Trust Store (Linux)
Muốn cert được tin cậy trên toàn hệ thống — không chỉ riêng Docker? Cài ở cấp độ OS thay thế.
# Ubuntu/Debian
sudo cp /tmp/registry-ca.crt /usr/local/share/ca-certificates/registry-internal.crt
sudo update-ca-certificates
# RHEL/CentOS/Fedora
sudo cp /tmp/registry-ca.crt /etc/pki/ca-trust/source/anchors/registry-internal.crt
sudo update-ca-trust
Sau đó restart Docker để nhận cập nhật từ system trust store:
sudo systemctl restart docker
Cách 3: Đánh Dấu Registry là Insecure (Chỉ Dùng cho Dev/Test)
Chỉ cần chạy được trong năm phút trên máy dev local? Hãy báo cho Docker bỏ qua xác minh TLS cho registry đó.
Chỉnh sửa (hoặc tạo) /etc/docker/daemon.json:
{
"insecure-registries": ["registry.internal:5000"]
}
Restart Docker:
sudo systemctl restart docker
Sau đó thử lại:
docker pull registry.internal:5000/myapp:latest
Cảnh báo: Cách này vô hiệu hóa hoàn toàn xác minh TLS cho registry đó. Bất kỳ ai có thể chặn traffic mạng của bạn đều có thể gửi cho bạn image độc hại. Tuyệt đối không dùng trong môi trường production.
Cách 4: Sửa Chứng Chỉ của Registry
Nếu bạn quản lý registry, sửa cert một lần sẽ gọn hơn là vá từng máy client. Hãy tạo cert tự ký đúng chuẩn với Subject Alternative Name (SAN) — Docker và trình duyệt hiện đại đều yêu cầu điều này:
# Tạo CA key và cert
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 1826 -key ca.key -out ca.crt \
-subj "/C=US/O=Internal/CN=Internal CA"
# Tạo registry key và CSR
openssl genrsa -out registry.key 4096
openssl req -new -key registry.key -out registry.csr \
-subj "/CN=registry.internal"
# Ký với SAN extension
cat > san.ext <<EOF
[SAN]
subjectAltName=DNS:registry.internal,IP:192.168.1.100
EOF
openssl x509 -req -days 730 -in registry.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out registry.crt -extfile san.ext -extensions SAN
Cấu hình registry sử dụng registry.crt và registry.key, sau đó phân phối ca.crt đến tất cả Docker clients theo Cách 1.
Kiểm Tra Sau Khi Sửa
Sau khi áp dụng bất kỳ cách nào, hãy xác nhận TLS thực sự hoạt động trước khi kết luận xong:
# Kiểm tra TLS handshake trực tiếp
curl -v --cacert /tmp/registry-ca.crt https://registry.internal:5000/v2/
# Kỳ vọng: HTTP 200 và body JSON rỗng: {}
# Kiểm tra docker pull từ đầu đến cuối
docker pull registry.internal:5000/myapp:latest
# Xem chính xác cert mà registry đang phục vụ
openssl s_client -connect registry.internal:5000 -showcerts
Nếu docker pull hoàn thành mà không gặp lỗi x509, bạn đã xử lý xong.
Vẫn Lỗi Sau Khi Thực Hiện Cách 1?
- Copy nhầm cert: Bạn cần cert của root CA, không phải cert của server. Kiểm tra bằng
openssl x509 -in /etc/docker/certs.d/registry.internal:5000/ca.crt -text -noout— tìmCA:TRUEdưới mục Basic Constraints. - Hostname không khớp: Hostname trong lệnh
docker pullphải khớp chính xác với CN hoặc SAN trong cert. Kiểm tra bằngopenssl x509 -in registry.crt -text | grep -A1 "Subject Alternative". - Chuỗi cert không đầy đủ: Có intermediate CA không? Ghép toàn bộ chuỗi vào một file:
cat intermediate.crt root-ca.crt > /etc/docker/certs.d/registry.internal:5000/ca.crt. - Cache của Docker Desktop: Trên macOS hoặc Windows, cần restart hoàn toàn Docker Desktop (không chỉ daemon) sau khi thêm cert.
Phòng Ngừa
- Phân phối cert của internal CA như một phần trong quá trình cấu hình máy — Ansible, Chef, hoặc startup script. Máy mới sẽ tự động tin cậy registry của bạn ngay từ đầu.
- Thêm vị trí CA cert vào tài liệu onboarding của team. Chỉ mất năm phút để fix, nhưng phải biết cần tìm gì ngay từ ngày đầu tiên.
- Với các registry có thể truy cập qua DNS công khai, Let's Encrypt giải quyết hoàn toàn vấn đề self-signed cert — miễn phí, tự động gia hạn, được tin cậy toàn cầu.

