使用CA证书配置Vapor中MySQLKit的MySQL连接
问题描述
我在Vapor后端项目中使用MySQLKit,本地数据库连接配置如下,可正常工作:
let config = MySQLConfiguration(hostname: "127.0.0.1", port: 3306, username: "root", password: "s3#12412r657f", database: "Admin", tlsConfiguration: nil)
现在需要连接远程MySQL数据库,该数据库需要SSL CA证书(PEM格式的ca_cert.crt),在MySQL Workbench的SSL标签页指定该CA文件路径后可正常连接,但在Vapor中配置TLS时遇到问题。
我尝试的配置如下:
static let prod: MySQLConfiguration = { var tls = TLSConfiguration.makeClientConfiguration() do { let bytes = [UInt8](""" -----BEGIN CERTIFICATE----- EX_CERTIFICATE_STRINGS... -----END CERTIFICATE----- """.data(using: .utf8)!) let cert: NIOSSLCertificate = try .init(bytes: bytes, format: .pem) tls.certificateChain = [.certificate(cert)] tls.privateKey = nil let config = MySQLConfiguration(hostname: "192.65.85.577", port: 3658, username: "testadmin", password: "dd#246$@erjt!df^67", database: "Elevate", tlsConfiguration: tls) return config } catch { fatalError("DB SSL CA Error: \(error.localizedDescription)") } }()
执行数据库查询时出现证书验证失败错误:
{ "error": true, "reason": "handshakeFailed(NIOSSL.BoringSSLError.sslError([Error: 268435581 error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED at /Users/At4/Library/Developer/Xcode/DerivedData/Elevate-xcftyy3423/SourcePackages/checkouts/swift-nio-ssl/Sources/CNIOBoringSSL/ssl/handshake.cc:393]))" }
相同的证书和连接参数在MySQL Workbench中可正常使用,求正确的Vapor+MySQLKit TLS配置方法。
解决方案
你的核心问题是把CA证书放错了配置项,同时证书文件的处理方式也可以优化:
1. 证书文件的放置位置
将ca_cert.crt文件放到Vapor项目的Resources文件夹下(没有则新建),然后在Xcode中把该文件添加到项目目标,确保编译时会被复制到应用包内。
2. 正确的TLS配置
CA证书用于验证服务器证书的合法性,应该配置到TLS的trustRoots字段,而非certificateChain(后者是客户端证书,仅当服务器要求客户端身份验证时才需要)。
修改后的配置代码如下:
static let prod: MySQLConfiguration = { var tls = TLSConfiguration.makeClientConfiguration() do { // 读取Resources目录下的CA证书文件 guard let certPath = Bundle.module.path(forResource: "ca_cert", ofType: "crt") else { fatalError("CA certificate file not found") } let certData = try Data(contentsOf: URL(fileURLWithPath: certPath)) let cert = try NIOSSLCertificate(bytes: [UInt8](certData), format: .pem) // 将CA证书添加到信任根集合 tls.trustRoots = .certificates([cert]) // 无需客户端证书时,certificateChain和privateKey保持默认nil即可 let config = MySQLConfiguration( hostname: "192.65.85.577", port: 3658, username: "testadmin", password: "dd#246$@erjt!df^67", database: "Elevate", tlsConfiguration: tls ) return config } catch { fatalError("DB SSL CA Error: \(error.localizedDescription)") } }()
3. 额外注意事项
- 如果远程MySQL服务器的hostname与证书中的Common Name(CN)不匹配,可临时添加
tls.verifyHostname = false跳过主机名验证,但这会降低安全性,仅在测试场景使用。 - 直接读取证书文件比硬编码内容更可靠,也方便后续证书更新。
内容的提问来源于stack exchange,提问作者AppNameExMin
相关产品推荐
相关产品推荐

