Skip to content
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

Support for Redis native TLS #1076

Closed
ilkkao opened this issue Mar 12, 2020 · 16 comments
Closed

Support for Redis native TLS #1076

ilkkao opened this issue Mar 12, 2020 · 16 comments

Comments

@ilkkao
Copy link

ilkkao commented Mar 12, 2020

I couldn't find an existing issue about this so asking here:

Redis 6 (currently in rc phase) supports TLS natively. Details here: https://redis.io/topics/encryption

I built Redis 6 with TLS support and created certs as instructed in Redis TLS.md file. I then tried to connect to it using ioredis:

{
  host: 'localhost',
  tls: {
    key: fs.readFileSync('/Users/ilkkao/redis-6.0-rc2/tests/tls/redis.crt'),
    cert: fs.readFileSync('/Users/ilkkao/redis-6.0-rc2/tests/tls/redis.key'),
    ca: [fs.readFileSync('/Users/ilkkao/redis-6.0-rc2/tests/tls/ca.crt')],
    checkServerIdentity: () => { return null; },
  }
}

Should this work? My redis instance responds

17266:M 12 Mar 2020 15:12:14.455 # Error accepting a client connection: error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol

@ilkkao
Copy link
Author

ilkkao commented Mar 12, 2020

I'm using ioredis-4.14.1

@luin
Copy link
Collaborator

luin commented Mar 14, 2020

Hi @ilkkao, TLS support is to server-side proxies such as stunnel, hitch, and ghostunnel. I'm not sure if there's any difference between them and the native one. Pull requests for this are welcome!

@ilkkao
Copy link
Author

ilkkao commented Mar 15, 2020

I'll try to find out what the difference between e.g stunnel and redis native TLS is, not sure yet.

@assaf-xm
Copy link

assaf-xm commented Apr 17, 2020

I just tested native TLS with 'redis:6.0-rc3-alpine' (docker) + ioredis v4.16.2 + nodejs v12 and it seems to work good.

Client side:

connectionOptions.tls = {
                cert: fs.readFileSync(ssl.cert),
                key: fs.readFileSync(ssl.key),
                ca: fs.readFileSync(ssl.ca)
            }

Server side (redis.conf):

port 0
tls-port 6379
tls-cert-file /usr/local/etc/redis/keys/redis.crt 
tls-key-file /usr/local/etc/redis/keys/redis.key
tls-ca-cert-file /usr/local/etc/redis/keys/ca.crt
tls-replication yes
tls-cluster yes

@agarwalkhushboo
Copy link

How did you generated these certificates?

@Jav3k
Copy link

Jav3k commented Feb 6, 2021

How did you generated these certificates?

@agarwalkhushboo, You can use utils/gen-test-certs.sh to generate self-signed certificates. Also i found useful article

@ilkkao
Copy link
Author

ilkkao commented Feb 6, 2021

I'll close this one. I believe all is good. If not, someone can open a more specific issue.

@ilkkao ilkkao closed this as completed Feb 6, 2021
@silentroach
Copy link

Need an example :(

@assaf-xm, what is ssl.* files?

@manast
Copy link

manast commented Dec 9, 2021

I am currently struggling with this. In redis.com it is possible to configure TLS without requiring client keys, just the CA authority .pem file, so this works using the cli for example (using the "redis fixed certificate" that you can download from your account page)

redis-cli -h redis-xxx.cloud.redislabs.com -p 16261 --tls  --cacert redislabs_ca.pem

Whereas this does not work

const redis = new Redis({
    host: 'hostname',
    port: <port>,
    tls: {
        ca: [ fs.readFileSync('path_to_ca_certfile', 'ascii') ]
    }
});

Give the following error:

 Error: Connection is closed.
        at close (/Users/manuelastudillo/Dev/taskforce/taskforce-backend/node_modules/ioredis/built/redis/event_handler.js:183:25)
        at TLSSocket.<anonymous> (/Users/manuelastudillo/Dev/taskforce/taskforce-backend/node_modules/ioredis/built/redis/event_handler.js:150:20)
        at Object.onceWrapper (events.js:417:26)
        at TLSSocket.emit (events.js:322:22)
        at net.js:672:12
        at TCP.done (_tls_wrap.js:557:7)

Interestingly in the official Redis documentation they only refer to an example using client certificates too:
https://docs.redis.com/latest/rs/references/client_references/client_ioredis/

const Redis = require('ioredis');
const fs = require('fs');

const redis = new Redis({
    host: 'hostname',
    port: <port>,
    tls: {
        key: fs.readFileSync('path_to_keyfile', 'ascii'),
        cert: fs.readFileSync('path_to_certfile', 'ascii'),
        ca: [ fs.readFileSync('path_to_ca_certfile', 'ascii') ]
    }
});

Any ideas?

@luin
Copy link
Collaborator

luin commented Dec 11, 2021

@manast

I'm able to connect to Redis Clould with the following code:

const redis = new Redis({
  host: "redis-xxxx.xxxxx.us-east-1-4.ec2.cloud.redislabs.com",
  port: 12836,
  tls: {
    ca: [readFileSync("/Users/luin/Downloads/redislabs_ca.pem")],
  },
  password: "xxxxxx",
});

Or just:

const redis = new Redis({
  host: "redis-xxxx.xxxxx.us-east-1-4.ec2.cloud.redislabs.com",
  port: 12836,
  tls: "RedisCloudFixed",
  password: "xxxxxx",
});

I'm using a fixed plan and the SSL config is:

CleanShot 2021-12-11 at 11 11 40@2x

Do I miss something?

@manast
Copy link

manast commented Dec 11, 2021

Okok, got it. It was not the connection itself, it works by using one of the built-in profiles, the problem comes when issueing a quit() command, check this out:

const Redis = require("ioredis");

const test = async () => {
  const redis = new Redis({
    host: "redis-xxx.cloud.redislabs.com",
    port: 16261,
    tls: "RedisCloudFixed",
    password: "xxx",
  });

  const info = await redis.info();

  console.log(info);

  await redis.quit();
};
test();

Prints the info correctly but then fails with this error:

(node:87282) UnhandledPromiseRejectionWarning: Error: Connection is closed.
    at close (/xxx/node_modules/ioredis/built/redis/event_handler.js:183:25)
    at TLSSocket.<anonymous> (/xxx/node_modules/ioredis/built/redis/event_handler.js:150:20)
    at Object.onceWrapper (events.js:417:26)
    at TLSSocket.emit (events.js:322:22)
    at net.js:672:12
    at TCP.done (_tls_wrap.js:557:7)

Weird, does not happen with other non TLS connections or other non redislabs TLS connections AFAIK.

@luin
Copy link
Collaborator

luin commented Dec 11, 2021

@manast

I think it's a server side implementation issue that when receiving the QUIT command, the server just closes the connection without sending a response OK first:

$  ~ redis-cli -h redis-xxxx.xxxxx.us-east-1-4.ec2.cloud.redislabs.com -p 12836 --tls --cacert Downloads/redislabs_ca.pem quit
Error: Server closed the connection
$  ~ redis-cli quit
OK

We can probably ignore connection close errors for the QUIT command but not sure if we should actually catch this on our side.

@manast
Copy link

manast commented Dec 11, 2021

Hmm ok. So maybe it is Redis SSL implementation that is handling the quit command differently than non SSL, and since all the other Redis cloud providers implement TLS using a proxy service they are not affected by this.

@GertSallaerts
Copy link
Contributor

GertSallaerts commented Dec 27, 2021

I've contacted Redis Cloud support about this as we are seeing the same issue on our servers, will keep you guys updated as well.

@GertSallaerts
Copy link
Contributor

Got this back:

Apologies for the inconvenience caused due to this issue.

We are aware of the issue and will fix it in the future versions of Redis Enterprise. I am afraid I can't share an ETA at the moment.

Do you see this as something we can add a workaround for in ioredis @luin? Something along the lines of resolving the quit command when the server is closed as a response to it? Probably similar to this: https://github.com/luin/ioredis/pull/720/files

@luin
Copy link
Collaborator

luin commented Dec 27, 2021

Thanks for the update! Personally, I'd just wait for their fix. Feel a little too much to land a workaround on ioredis for this. No strong opinion though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants