Golang 使用 Docker SDK 生成自签名的 SSL 证书
以下是使用 Golang 调用 Docker SDK 生成自签名的 SSL 证书的示例代码:
package main
import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"net"
"os"
"path/filepath"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/certificates"
"github.com/docker/docker/client"
)
func main() {
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
// 生成私钥
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
// 生成自签名证书
cert, err := generateSelfSignedCert(key)
if err != nil {
panic(err)
}
// 创建一个新的证书包
bundle := &certificates.Bundle{
Certificate: cert,
PrivateKey: key,
}
// 将证书包保存到磁盘
err = saveCertificateBundle(bundle)
if err != nil {
panic(err)
}
// 从磁盘加载证书包
bundle, err = loadCertificateBundle()
if err != nil {
panic(err)
}
// 创建一个新的 CA
ca, err := generateCACert()
if err != nil {
panic(err)
}
// 创建一个由 CA 签名的新的客户端证书
clientCert, err := generateClientCert(ca, key)
if err != nil {
panic(err)
}
// 创建一个由 CA 签名的新的服务器证书
serverCert, err := generateServerCert(ca, key)
if err != nil {
panic(err)
}
// 使用客户端和服务器证书创建一个新的 TLS 配置
tlsConfig, err := createTLSConfig(clientCert, serverCert)
if err != nil {
panic(err)
}
// 使用 TLS 配置连接到 Docker 守护进程
cli, err = client.NewClientWithOpts(client.WithTLSClientConfig(tlsConfig))
if err != nil {
panic(err)
}
// 列出 Docker 镜像
images, err := cli.ImageList(context.Background(), types.ImageListOptions{})
if err != nil {
panic(err)
}
// 打印 Docker 镜像
for _, image := range images {
fmt.Println(image.ID)
}
}
func generateSelfSignedCert(key *rsa.PrivateKey) ([]byte, error) {
// 生成自签名证书
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: "localhost"},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(1, 0, 0),
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
IsCA: true,
}
cert, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
if err != nil {
return nil, err
}
// 以 PEM 格式编码证书
pemCert := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: cert,
})
return pemCert, nil
}
func generateCACert() ([]byte, error) {
// 生成私钥
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, err
}
// 生成自签名证书
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: "docker-ca"},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
IsCA: true,
}
cert, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
if err != nil {
return nil, err
}
// 以 PEM 格式编码证书
pemCert := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: cert,
})
return pemCert, nil
}
func generateClientCert(caCert, clientKey []byte) ([]byte, error) {
// 解码 CA 证书
caCertBlock, _ := pem.Decode(caCert)
if caCertBlock == nil {
return nil, fmt.Errorf("failed to decode CA certificate")
}
// 解析 CA 证书
caCert, err := x509.ParseCertificate(caCertBlock.Bytes)
if err != nil {
return nil, err
}
// 生成私钥
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, err
}
// 生成证书签名请求 (CSR)
csrTemplate := x509.CertificateRequest{
Subject: pkix.Name{CommonName: "client"},
}
csr, err := x509.CreateCertificateRequest(rand.Reader, &csrTemplate, key)
if err != nil {
return nil, err
}
// 使用 CA 证书签名 CSR
cert, err := x509.CreateCertificate(rand.Reader, &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: "client"},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(1, 0, 0),
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
BasicConstraintsValid: true,
}, caCert, key.Public(), key)
if err != nil {
return nil, err
}
// 以 PEM 格式编码证书
pemCert := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: cert,
})
return pemCert, nil
}
func generateServerCert(caCert, serverKey []byte) ([]byte, error) {
// 解码 CA 证书
caCertBlock, _ := pem.Decode(caCert)
if caCertBlock == nil {
return nil, fmt.Errorf("failed to decode CA certificate")
}
// 解析 CA 证书
caCert, err := x509.ParseCertificate(caCertBlock.Bytes)
if err != nil {
return nil, err
}
// 生成私钥
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, err
}
// 生成证书签名请求 (CSR)
csrTemplate := x509.CertificateRequest{
Subject: pkix.Name{CommonName: "localhost"},
DNSNames: []string{
"localhost",
"127.0.0.1",
"::1",
},
IPAddresses: []net.IP{
net.IPv4(127, 0, 0, 1),
net.IPv6loopback,
},
}
csr, err := x509.CreateCertificateRequest(rand.Reader, &csrTemplate, key)
if err != nil {
return nil, err
}
// 使用 CA 证书签名 CSR
cert, err := x509.CreateCertificate(rand.Reader, &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: "localhost"},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(1, 0, 0),
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}, caCert, key.Public(), serverKey)
if err != nil {
return nil, err
}
// 以 PEM 格式编码证书
pemCert := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: cert,
})
return pemCert, nil
}
func createTLSConfig(clientCert, serverCert []byte) (*tls.Config, error) {
// 加载客户端证书和密钥
clientCertBlock, _ := pem.Decode(clientCert)
if clientCertBlock == nil {
return nil, fmt.Errorf("failed to decode client certificate")
}
clientKey, err := x509.ParsePKCS1PrivateKey(clientCertBlock.Bytes)
if err != nil {
return nil, err
}
// 加载服务器证书和密钥
serverCertBlock, _ := pem.Decode(serverCert)
if serverCertBlock == nil {
return nil, fmt.Errorf("failed to decode server certificate")
}
serverCert, err := x509.ParseCertificate(serverCertBlock.Bytes)
if err != nil {
return nil, err
}
// 加载 CA 证书
caCertBlock, _ := pem.Decode([]byte(os.Getenv("DOCKER_CERT_PATH") + "/ca.pem"))
if caCertBlock == nil {
return nil, fmt.Errorf("failed to decode CA certificate")
}
caCert, err := x509.ParseCertificate(caCertBlock.Bytes)
if err != nil {
return nil, err
}
// 创建一个新的 TLS 配置
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{
tls.Certificate{
Certificate: [][]byte{clientCert},
PrivateKey: clientKey,
},
},
RootCAs: x509.NewCertPool(),
}
tlsConfig.RootCAs.AddCert(caCert)
tlsConfig.ServerName = serverCert.Subject.CommonName
return tlsConfig, nil
}
func saveCertificateBundle(bundle *certificates.Bundle) error {
// 如果证书目录不存在,则创建它
err := os.MkdirAll(filepath.Dir(os.Getenv("DOCKER_CERT_PATH")+"/cert.pem"), 0700)
if err != nil {
return err
}
// 将证书包保存到磁盘
certFile, err := os.Create(os.Getenv("DOCKER_CERT_PATH") + "/cert.pem")
if err != nil {
return err
}
defer certFile.Close()
err = pem.Encode(certFile, &pem.Block{
Type: "CERTIFICATE",
Bytes: bundle.Certificate,
})
if err != nil {
return err
}
keyFile, err := os.Create(os.Getenv("DOCKER_CERT_PATH") + "/key.pem")
if err != nil {
return err
}
defer keyFile.Close()
err = pem.Encode(keyFile, &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(bundle.PrivateKey.(*rsa.PrivateKey)),
})
if err != nil {
return err
}
return nil
}
func loadCertificateBundle() (*certificates.Bundle, error) {
// 从磁盘加载证书包
certFile, err := os.Open(os.Getenv("DOCKER_CERT_PATH") + "/cert.pem")
if err != nil {
return nil, err
}
defer certFile.Close()
certPEM, err := pem.Decode(certFile)
if err != nil {
return nil, err
}
keyFile, err := os.Open(os.Getenv("DOCKER_CERT_PATH") + "/key.pem")
if err != nil {
return nil, err
}
defer keyFile.Close()
keyPEM, err := pem.Decode(keyFile)
if err != nil {
return nil, err
}
key, err := x509.ParsePKCS1PrivateKey(keyPEM.Bytes)
if err != nil {
return nil, err
}
bundle := &certificates.Bundle{
Certificate: certPEM.Bytes,
PrivateKey: key,
}
return bundle, nil
}
在这个示例中,我们使用了 Docker SDK 连接到 Docker 守护进程,并使用 TLS 连接。我们使用了自签名的 SSL 证书来保护连接。我们使用了 Golang 的标准库来生成证书,并使用 Docker SDK 将证书保存到 Docker 守护进程的证书路径中。我们还使用了 Docker SDK 列出 Docker 镜像。
这个示例代码可以帮助你了解如何使用 Golang 调用 Docker SDK 生成自签名的 SSL 证书。
原文地址: https://www.cveoy.top/t/topic/j6s4 著作权归作者所有。请勿转载和采集!