-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Failed to connect redis with tls #13
Comments
Hi there, thanks for reporting this issue. And sorry for the slow response.
What you accomplished with your workaround is to disable the k6-specific dialer, but go-redis would fallback to using a default dialer instead, so you're likely only masking the Since you want to use I tried to make this work, by creating the certs with Redis' own test script, starting the server with them, creating the I'm sure it's not a server issue, as I can connect with
I'm not 100% sure if I created the But, in theory, this should work the same way as it does for HTTP and WebSocket connections in k6, and you wouldn't need to use In any case, this needs further investigation beyond what I can dedicate time to right now, so let's look into it later. If someone else has time to dig into this, please do so. 🙏 cc: @oleiade EDIT: BTW, I'm not sure if it's relevant, but the suggested way to load TLS certs in redis/go-redis#1306 (comment) is via Footnotes
|
Hi There, My script is able to connect to Redis without any issues by using a workaround. Note: The script is executed locally, using gcloud to tunnel to GCP Memstore. |
@punyapatsw my understanding is that your initial issue is solved as result. Is that correct? If that's the case I would then close it in favor #14 , which intends to improve the documentation regarding using TLS connections with redis 🙇🏻 |
Yes, my issue was solved by using the default dialer instead, but I am not sure about the consequences. |
I see @punyapatsw thanks a lot for coming back to us. We will keep the issue open, and I intend to work on this in the upcoming weeks to see if I streamline support for TLS in the module somehow 👍🏻 |
Hey @punyapatsw 👋🏻 We took time with the k6 team to investigate what might be causing the issue. I can confirm k6 causes it 🙇🏻 The reason this happens is roughly the following:
We have discussed and established a plan forward:
Solving this issue is not so trivial, and my gut feeling is that we can expect to see it addressed either in |
Hey guys, FYI, the same issue is reproduced with AWS ElastiCache via TLS protocol. So I've built a forked k6 version according to @punyapatsw's comment while the issue is not resolved:
docker run --rm -e GOOS=darwin -u "$(id -u):$(id -g)" -v "${PWD}:/xk6" \
grafana/xk6 build v0.44.1 \
--with github.com/grafana/xk6-redis@latest=.
docker run --rm -u "$(id -u):$(id -g)" -v "${PWD}:/xk6" \
grafana/xk6 build v0.44.1 \
--with github.com/grafana/xk6-redis@latest=. |
Hey @vukor 👋🏻 Thanks for the heads-up 🙇🏻 We haven't addressed the issues generally (as opposed to specifically for this use case) yet, but we have planned to give it a shot tentatively in the upcoming release of k6. No promises, though 🤞🏻 |
Hey folks, I took a closer look into this issue, and here are some notes we could discuss. The main issue is that the k6 Dialer (
... because it's expecting the TLS handshake, and k6 is not doing it, so the connection is closed abruptly. I confirmed that if I establish a The reason this works for HTTP in k6 is that We need for the script to specify whether it's connecting to a TCP or a TLS server, as we can't easily make this guess ourselves. Technically, we could establish a TCP connection, try to do the TLS handshake, and if it fails, fallback to TCP, but this requires timing out, which adds a connection delay and possible false negatives if the timeout is too short, etc., so it would be super hacky. Instead, we should allow users to specify this in the See how the Node Redis lib does this: https://github.com/redis/node-redis/blob/master/docs/client-configuration.md My only doubt is how we should handle connecting to a Redis cluster if the URLs have conflicting options. E.g. they use different database names. So I think the way forward is:
The first one is probably the biggest change. The second one is trivial, and the third one is somewhere in the middle. The good news is that this doesn't require changes in k6, AFAICT. We can reuse k6's Dialer, so we can track metrics like received and sent data, reuse blocklists and DNS resolver settings, but the way we handle TLS will be slightly different. @oleiade WDYT? I can draft a tentative API proposal right here, if you agree. |
Thanks a lot for the detailed analysis indeed, much appreciated 🙇🏻 I think you're spot on, and your plan makes a ton of sense 🤝 The Node API looks good and user-friendly indeed, and I agree we should try to reproduce it on our side. I also agree that we should tackle 1., and 2. first and custom TLS certs in a separate issue to have a better separation of concern, which will probably make our lives easier. Please go ahead with a draft proposal @imiric if you find the time and feel like it, and let me know if I can support you in any way 👍🏻 🎉 |
Alright, here's a draft of the API I have in mind: // Simplest form using a URL string
new redis.Client('redis://user:pass@localhost:6379/0');
// Same as above, but passing an object
new redis.Client({
socket: {
host: 'localhost',
port: 6379,
},
username: 'user',
password: 'pass',
database: 0,
});
// TLS with a URL
new redis.Client('rediss://user:pass@localhost:6379/0');
// TLS with an object
new redis.Client({
socket: {
host: 'localhost',
port: 6379,
tls: true, // or tls: {}
},
username: 'user',
password: 'pass',
database: 0,
});
// TLS with a custom CA cert
new redis.Client({
socket: {
host: 'localhost',
port: 6379,
tls: {
ca: open('ca.crt'),
},
},
});
// TLS client auth (mTLS)
new redis.Client({
socket: {
host: 'localhost',
port: 6379,
tls: {
ca: open('ca.crt'),
cert: open('client.crt'),
key: open('client.key'),
},
},
});
// Cluster client, with just URLs
new redis.Client(
cluster: {
nodes: [
'redis://user:pass@host1:6379/0',
'redis://user:pass@host2:6379/0',
],
},
);
// Cluster client with objects
new redis.Client({
cluster: {
nodes: [
{
socket: {
host: 'host1',
port: 6379,
},
username: 'user',
password: 'pass',
database: 0,
},
{
socket: {
host: 'host2',
port: 6379,
},
username: 'user',
password: 'pass',
database: 0,
},
],
},
}); WDYT? Obviously, not all properties under I'm not certain on the repurposing of the If I find this to be cumbersome for whatever reason, I'll create a separate Similarly for allowing plain strings to be passed that will be interpreted as URLs. It's more convenient than having to pass So I've started working on this and hope to create a PR for at least the initial refactor sometime next week. |
Great work @imiric I really love it! 👍🏻 👏🏻 🎉 Clean, comprehensible, and user-friendly, let's do it 🦖 Regarding clustering, I checked out the node-redis API, and what exists on the go-redis counterpart, and my preference goes to having dedicated constructor of some sort in JS, just like node-redis does. I believe that would involve a bit more work to rewire stuff under the hood, but considering this is a specific use case users have been asking about, and we haven't fully supported yet, the hassle of making an explicit API for it feels worth it? WDYT? 🙇🏻 |
@oleiade I'm not sure. I don't see a reason to have a separate constructor for what will essentially be a The only benefit of using a separate constructor is to remove one level from the configuration object (i.e. the Do you see another benefit I'm ignoring?
But using |
That's a fair point indeed 🤝 I guess the aspect that brought this to my mind was that in the proposed API, we do make a distinction between single node, and cluster, which the underlying
Cluster should be supported already, yes. We've had, however, a couple of users reporting issues around it (#15 and grafana/k6#3031). After sleeping on it, I'm happy with your proposal 👏🏻 Let's dismiss the idea of a dedicated Cluster constructor indeed 👍🏻 |
To allow passing objects similar to node-redis. See #13 (comment)
To allow passing objects similar to node-redis. See #13 (comment)
To allow passing objects similar to node-redis. See #13 (comment)
To allow passing objects similar to node-redis. See #13 (comment)
When connecting to redis via tls and setting
"insecureSkipTLSVerify: true,"
the error"ERRO[0001] Uncaught (in promise) EOF executor=shared-iterations scenario=redisPerformance"
will occur.To get around this problem, I removed
"c.redisOptions.Dialer = vuState.Dialer.DialContext"
from func connect() in"redis/client.go."
The text was updated successfully, but these errors were encountered: