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

Allow connecting to Redis with TLS #11

Merged
merged 5 commits into from
Sep 30, 2024
Merged

Allow connecting to Redis with TLS #11

merged 5 commits into from
Sep 30, 2024

Conversation

wjt
Copy link
Member

@wjt wjt commented Sep 27, 2024

Previously we've been using a client-side proxy to connect to
our TLS-enabled ElastiCache cluster. But ioredis supports connecting with TLS
natively. There are two ways to opt in:

  1. If a connection string is passed to the Redis constructor, using rediss://
    rather than redis:// as the scheme enables TLS.
  2. Pass a 'tls' option whose value is a (possibly-empty) object of options to
    pass through to Node's tls.connect() method.

Add a new REDIS_TLS environment variable, which can be set to '1' or 'true' to
connect with TLS. If set, set the 'tls' option to an empty object to enable TLS.

Stacked on top of:

https://phabricator.endlessm.com/T35672

@wjt wjt force-pushed the T35672-support-redis-tls branch from 0c56658 to e3f8c55 Compare September 27, 2024 15:24
Copy link
Member

@dbnicholson dbnicholson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obviously, to be flexible we'd want to allow setting TLS options. For our needs, it seems like the default will be fine, though.

/* ioredis uses tls.connect() if the tls option is set, and passes it as
* additional options to tls.connect().
*/
let tls = config.redis_tls ? {} : undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we also need to support setting the CA certificate since ElastiCache uses a custom certificate and the node tls module only trusts Mozilla's list. That or just always override it to read /etc/ssl/certs/ca-certificates.crt or something like that.

Hmm, I guess not, actually. It does not appear that ElastiCache uses a custom certificate and the Mozilla list will probably work fine. I imagine you already tested this, anyways.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did test this. It's running in dev. I was dreading having to do all that tedious plumbing (or forcing node to use the system ca store in our derived image) but it just worked.

@wjt wjt force-pushed the T35672-support-redis-tls branch 2 times, most recently from 6381b0c to 68f07b7 Compare September 30, 2024 10:57
wjt added 5 commits September 30, 2024 12:11
Passing a 4-argument function to `app.use` indicates that it is an error
handler, called when an exception escapes a request handler.

Previously, the function checked whether its first parameter, `err`, is truthy.
According to the documentation this is not necessary.

Previously, the function would always send a response. According to the
documentation, you must first check whether the response headers have already
been sent, and if so chain to the next handler (which will in practice be the
default handler that abruptly closes the connection in that case).

Previously, wheen running under NODE_ENV=test, the function would stringify the
error and then join it to the error's stack trace. This is unnecessary because
err.stack starts with err.toString(). Simplify this.

https://expressjs.com/en/guide/error-handling.html
In the logs for the production instance I see:

   error: undefined

This indicates that, somewhere, an undefined value is being passed to
`logger.error()`. Previously there were four calls to `logger.error()` that did
not include any additional log message. Add additional context to each.

https://phabricator.endlessm.com/T35672
When an ElastiCache Redis cluster is upgraded, the old nodes stick around as
long as someone is connected to them, but as readonly replicas. Attempting any
write operation fails with:

> READONLY You can't write against a read only replica

(As described in the ioredis documentation, this can also happen when a replica
is promoted to primary due to some error if the Auto-failure ElastiCache option
is disabled; but the ElastiCache clusters in Endless's instance of this service
have this option set to true, which leads to different behaviour.)

Handle the READONLY case as suggested in the ioredis documentation: implement a
callback for Redis protocol-level errors that matches against the prefix
READONLY and triggers a reconnect in this case.

(I would like to add an integration test for this but it's quite non-trivial to
do so...)

https://github.com/redis/ioredis/blob/main/README.md#reconnect-on-error
https://phabricator.endlessm.com/T35146
Previously we've been using a client-side proxy to connect to our TLS-enabled
ElastiCache cluster. But ioredis supports connecting with TLS natively. There
are two ways to opt in:

1. If a connection string is passed to the Redis constructor, using rediss://
   rather than redis:// as the scheme enables TLS.
2. Pass a 'tls' option whose value is a (possibly-empty) object of options to
   pass through to Node's tls.connect() method.

Add a new REDIS_TLS environment variable, which can be set to '1' or 'true' to
connect with TLS. If set, set the 'tls' option to an empty object to enable TLS.

https://phabricator.endlessm.com/T35672
@wjt wjt force-pushed the T35672-support-redis-tls branch from 68f07b7 to 8373c45 Compare September 30, 2024 11:11
@wjt wjt merged commit 92bba54 into master Sep 30, 2024
2 checks passed
@wjt wjt deleted the T35672-support-redis-tls branch September 30, 2024 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants