I’m trying to establish SSL/TLS connection to AWS RDS MySQL. The server is build in Docker and I can’t force it to use certificate bundle provided by AWS…
When I run the service in Docker container I receive first ERROR:
2024/05/31 11:08:16 /app/internal/services/servicecontainer.go:252 driver: bad connection
and with each interaction with DB I receive:
tls: failed to verify certificate: x509: certificate is not valid for any names, but wanted to match host.docker.internal
and this is while run locally. If I try same in AWS I get:
failed to initialize database, got error Error 3159: Connections using insecure transport are prohibited while --require_secure_transport=ON
According to AWS docs. The SSL/TLS certificate includes the DB instance endpoint as the Common Name (CN) for the SSL/TLS certificate to guard against spoofing attacks.
How should I specify CN in my code or what else should I do to establish secure connection?
Thank you for your help!
Docker file:
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 code:
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}
}
I’ve searched for solution and found next information:
- Issue with golang function for verification of CN name: https://github.com/docker/for-linux/issues/248
- AWS documentation about using TLS connection: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html#UsingWithRDS.SSL.CertificatesAllRegions
- Stack issue: How to use the go-mysql-driver with ssl on aws with a mysql rds instance
- GoLang Gorm docs: https://gorm.io/docs/connecting_to_the_database.html
- GoLang driver docs: https://github.com/go-sql-driver/mysql#parameters