TLS connection issues
ramonschriks opened this issue · comments
Describe the issue
Unable to connect with Redis master using TLS configuration
Vapor version
4.102.0
Operating system and version
MacOS 14.5
Swift version
Swift 5.10
Steps to reproduce
My situation:
- Setup a Redis master (im using
valkey
due to the closed sourcing of Redis)- Im using a local setup in Docker for development for this.
- Enable TLS on Redis master
- Setup self-signed certificates in Redis master
- Use client cert + CA used in Redis master to connect to Redis master using
redis-cli
$ redis-cli -h valkey-master -p 6379 -a laSQL2019 --tls --cacert 'ca.crt' --cert 'client.crt' --key 'client.key'
Connection gets established correctly using redis-cli
from host machine to Redis master.
Now, on the same host machine im using the latest version of both Vapor
and Vapor/redis
to setup the redis configuration. Ive used many combinations trying to establish an connection:
guard let certFilePath = Environment.get("ENC_GATEWAY_REDIS_CERT_FILE"),
let keyFilePath = Environment.get("ENC_GATEWAY_REDIS_PRIVATE_KEY_FILE"),
let caFilePath = Environment.get("ENC_GATEWAY_REDIS_CA_FILE")
else {
return nil
}
// Load certificates and keys
let clientCerts = try NIOSSLCertificate.fromPEMFile(certFilePath).map { NIOSSLCertificateSource.certificate($0) }
let clientKey = try NIOSSLPrivateKey(file: keyFilePath, format: .pem)
let caCert = try NIOSSLCertificate.fromPEMFile(caFilePath)
// Create TLS configuration
var configuration = TLSConfiguration.makeClientConfiguration()
configuration.certificateVerification = .none
configuration.trustRoots = .certificates(caCert)
configuration.additionalTrustRoots = [.certificates(caCert)]
configuration.certificateChain = clientCerts
configuration.privateKey = .privateKey(clientKey)
return try Redis.RedisConfiguration(
serverAddresses: [masterAddress],
password: self.configuration.password,
tlsConfiguration: configuration
)
Ive tried many many different TLS configurations, but still i cannot connect.
The connecties does gets logged on the Redis Master, but everytime this is the error:
Error accepting a client connection: error:0A00010B:SSL routines::wrong version number (addr=10.0.0.2:26094 laddr=10.0.0.53:6379)
I even tried adding the TLS version and cipher suite below, which does work when connecting using the Redis-cli, but not when configuring it in my Vapor app like so:
configuration.minimumTLSVersion = .tlsv12
configuration.cipherSuiteValues = [.TLS_AES_256_GCM_SHA384]
Maybe im doing something wrong on the Redis master regarding configuration, but then i wouldnt be able to connect using the redis-cli
as well..
In almost any example i can find only, the option configuration.certificateVerification = .none
should work to ignore verification (client side), but i always get the SSL routines::wrong version number
error...
For now i just disable TLS server side (which is definitely not ideal), so hopefully im doing something wrong rather than this is a real issue.
Outcome
Error accepting a client connection: error:0A00010B:SSL routines::wrong version number (addr=10.0.0.2:26094 laddr=10.0.0.53:6379)
With TLS enabled on the Redis master, i always get the above error Server Side
when establishing a connection.
Using the redis-cli
is does work with the same configuration (certs, TLS version and cipher suite)
Additional notes
No response
This is probably an issue with https://github.com/swift-server/RediStack - have you tried just using that directly to ensure that's the cause?
@0xTim Thanks for responding. I've tried that as well, but failed. Finding myself fighting this issue for over 10 hours straight now has driving me crazy.
Yet, i was able to find an (utmost simple) solution for this.
The problem was giving the masteraddress
as SocketAddress object to the Redis Configuration together with the SSLConfiguration.
return try Redis.RedisConfiguration(
serverAddresses: [masterAddress],
password: self.configuration.password,
tlsConfiguration: configuration
)
I changed it like so to make this work! As you can see below, im just providing the connection URL myself, by passing the correct protocol based on whether i have an TLS configuration or not.
let prot: String = self.configuration.tlsConfiguration != nil ? "rediss" : "redis"
return try Redis.RedisConfiguration(
url: "\(prot)://:\(self.configuration.password)@\(host):\(port)",
tlsConfiguration: self.configuration.tlsConfiguration,
pool: .init(
connectionRetryTimeout: .seconds(5)
)
)
Im not sure if this is an issue within this lib or within RediStack
, or if its even an issue? It seems to me that deriving the destination server details from the SocketAddress
together with an TLS configuration does not results in a rediss://
connection string?
For now my issue has been resolved, tho it might be confusing when passing the address as SocketAddress
.