You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在GoLang/Docker环境下建立与AWS RDS MySQL的SSL/TLS连接?

在Docker部署的Go服务中建立AWS RDS MySQL SSL/TLS连接的问题

我正尝试在Docker部署的Go服务中建立与AWS RDS MySQL的SSL/TLS连接,但无法让服务正常使用AWS提供的证书包,遇到以下两类问题:

  • 本地Docker运行时:
    • 初始连接错误:2024/05/31 11:08:16 /app/internal/services/servicecontainer.go:252 driver: bad connection
    • 数据库交互时的证书验证错误:tls: failed to verify certificate: x509: certificate is not valid for any names, but wanted to match host.docker.internal
  • AWS环境运行时:failed to initialize database, got error Error 3159: Connections using insecure transport are prohibited while --require_secure_transport=ON

根据AWS文档说明:

The SSL/TLS certificate includes the DB instance endpoint as the Common Name (CN) for the SSL/TLS certificate to guard against spoofing attacks.

请问应如何在代码中指定CN,或采取其他措施建立安全连接?


附:相关代码与配置

Dockerfile

FROM golang:1.22 

# BUILD CODE I BELIEVE IS NOT RELEVANT
    
ADD ./internal/certificates /usr/local/share/ca-certificates
RUN update-ca-certificates

CMD ["./main"]

GoLang 代码

import (
    "crypto/tls"
    "crypto/x509"
    "database/sql"
    "os"
    "sync"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"

    mysqlDriver "github.com/go-sql-driver/mysql"

    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

func InitializeKernel() *ControllerService {

    DB_HOST := os.Getenv("DB_HOST")
    DB_DBNAME := os.Getenv("DB_DBNAME")
    DB_CREDENTIALS := os.Getenv("DB_CREDENTIALS")

    AWS_REGION := os.Getenv("AWS_REGION")
    if AWS_REGION == "" {
        AWS_REGION = "us-west-2"
    }


    var dbCred dbCredentials

    err := json.Unmarshal([]byte(DB_CREDENTIALS), &dbCred)

    if err != nil {
        log.Fatal("could not parse db credentials from env")
    }

    rootCertPool := x509.NewCertPool()
    globPem, err := os.ReadFile("./internal/certificates/global-bundle.pem")
    if err != nil {
        log.Fatal(err)
    }
    if ok := rootCertPool.AppendCertsFromPEM(globPem); !ok {
        log.Fatal("Failed to append global PEM.")
    }

    mysqlDriver.RegisterTLSConfig("custom", &tls.Config{
        RootCAs: rootCertPool,
    })

    dsn := fmt.Sprintf("%s:%s@tcp(%s:3306)/%s?charset=utf8mb4&parseTime=True&tls=custom&loc=Local", dbCred.Username, dbCred.Password, DB_HOST, DB_DBNAME)
    customDb, err := sql.Open("mysql", dsn)
    if err != nil {
        fmt.Println(err.Error())
    }

    db, err := gorm.Open(mysql.New(mysql.Config{
        Conn: customDb,
    }), &gorm.Config{})

    if err != nil {
        fmt.Println(err.Error())
    }

    return &ControllerService{Db: db, DynamoDb: dynamoDb}
}

解决方案

1. 修复本地Docker的CN匹配问题

本地出现host.docker.internal的证书验证错误,是因为你用该域名替代了RDS实际端点,但证书的CN是RDS的官方端点域名。两种解决方式:

  • 直接使用RDS端点:将本地环境的DB_HOST变量设置为RDS的实际端点(例如mydb.xxxxxx.us-west-2.rds.amazonaws.com),而非host.docker.internal
  • 强制指定ServerName:如果必须用host.docker.internal做本地映射,在TLS配置中手动指定ServerName为RDS实际端点,让TLS验证时匹配正确的CN:
mysqlDriver.RegisterTLSConfig("custom", &tls.Config{
    RootCAs:    rootCertPool,
    ServerName: "mydb.xxxxxx.us-west-2.rds.amazonaws.com", // 替换为你的RDS端点
})

2. 确保AWS环境的SSL连接生效

AWS环境的Error 3159说明连接未使用SSL,可按以下步骤排查:

  • 确认DB_HOST设置为RDS的官方端点,而非内网IP(内网IP可能跳过SSL验证)
  • 简化DSN的TLS参数:Dockerfile中已执行update-ca-certificates将AWS证书添加到系统信任库,可直接用tls=true代替自定义配置,让驱动自动使用系统CA:
dsn := fmt.Sprintf("%s:%s@tcp(%s:3306)/%s?charset=utf8mb4&parseTime=True&tls=true&loc=Local", dbCred.Username, dbCred.Password, DB_HOST, DB_DBNAME)

此方式无需手动加载证书,避免自定义配置出错。

3. 代码优化建议

  • 不要忽略sql.Open和gorm.Open的错误,应使用log.Fatal终止程序,避免后续逻辑在无效连接下运行
  • 添加连接测试:打开连接后调用customDb.Ping()验证连接有效性:
if err := customDb.Ping(); err != nil {
    log.Fatal("Failed to ping database:", err)
}

内容的提问来源于stack exchange,提问作者ucios

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 03:35:53