Join GitHub today
GitHub is home to over 36 million developers working together to host and review code, manage projects, and build software together.
Sign uphttps server should allow changing credentials dynamically #4464
Comments
petkaantonov
added
https
feature request
labels
Dec 29, 2015
mscdex
added
tls
and removed
https
labels
Dec 29, 2015
This comment has been minimized.
This comment has been minimized.
|
An API like
Doesn't seem so reasonable if the implication is that the server needs to track active sockets. If the logic is something like /cc @nodejs/crypto |
This comment has been minimized.
This comment has been minimized.
|
Perhaps it should be called |
This comment has been minimized.
This comment has been minimized.
|
I don't really like disconnecting sockets either, IMO this is not reasonable and has way too much implicit behavior for suggested method name. |
This comment has been minimized.
This comment has been minimized.
|
@petkaantonov could you explain some use-cases for this? I can't imagine one so perhaps it'd be helpful for others as well to hear why this might be needed. |
This comment has been minimized.
This comment has been minimized.
tallskog
commented
Feb 9, 2016
|
The use case is an embedded system where https server is handling mission critical information. If administrator wants/needs to change the certificates, it will happen on the fly. Without this modification https server needs to be restarted leading to possible loss of data. |
This comment has been minimized.
This comment has been minimized.
Iirc this check was in the |
This comment has been minimized.
This comment has been minimized.
|
@petkaantonov ... still interested in this? I share some of the same concerns voiced already but would definitely welcome a PR to review. |
This comment has been minimized.
This comment has been minimized.
|
I could work on a PR this weekend |
This comment has been minimized.
This comment has been minimized.
voxsoftware
commented
Oct 1, 2016
|
This it's really necessary |
addaleax
referenced this issue
Dec 20, 2016
Closed
HTTPS Feature request: Hotswap TLS certificates #10349
This comment has been minimized.
This comment has been minimized.
By terminating existing connections when they try to write something, aren't you losing data? |
This comment has been minimized.
This comment has been minimized.
fresheneesz
commented
Dec 20, 2016
|
Why would you have to terminate existing connections? Why not just let existing connections stay open as long as they want, and only give the new cert to new connections? If you want to, you can always kill connections yourself. |
This comment has been minimized.
This comment has been minimized.
retrohacker
commented
Apr 21, 2017
|
For a Let's Encrypt certificate, the cert needs to be cycled every 90 days or so. Long-term, they are planning on pushing this number as low as 2 days. In P2P protocols that have "trust", up-time and reliability are important in maintaining high trust on the network. Severing existing connections to cycle a server can hurt your reputation, but gracefully shutting down by rejecting new connections and finishing current connections increases the time your service is offline, especially when serving long-term connections (i.e. streaming a GB file to a client). While you can get around this in most enterprise settings by doing a rolling update of your clients, most end users aren't setup with load balancing, let alone rolling updates. They simply SNI is a solution, but not all clients support SNI and it is really just a hack for the job, we aren't trying to serve multiple hostnames from a single ip. Also, SNI bleeds information outside of SSL (the hostname) in order for the server to determine which cert needs to be served. It looks like the If so, we can simply
|
This comment has been minimized.
This comment has been minimized.
|
I know it is unofficial API, but has anyone tried: |
This comment has been minimized.
This comment has been minimized.
retrohacker
commented
Apr 21, 2017
•
|
@indutny, I can give it a shot! I'm out of my depth here though, I know just enough about SSL right now to be dangerous, which isn't enough to put together a convincing test case :-\ |
This comment has been minimized.
This comment has been minimized.
retrohacker
commented
Apr 23, 2017
•
|
@indutny I'm not sure if this is convincing, but it seems to work! Script: var https = require('https')
var fs = require('fs')
var opts = {
key: fs.readFileSync('./good_cert/privkey.pem', 'utf8'),
cert: fs.readFileSync('./good_cert/fullchain.pem', 'utf8'),
ca: fs.readFileSync('./good_cert/chain.pem', 'utf8')
}
var bad_opts = {
key: fs.readFileSync('./bad_cert/privkey.pem', 'utf8'),
cert: fs.readFileSync('./bad_cert/fullchain.pem', 'utf8'),
ca: fs.readFileSync('./bad_cert/chain.pem', 'utf8')
}
var s = https.createServer(opts, (req, res) => {
console.log('connect')
res.writeHead(200)
res.write('Hello World!\n')
s._sharedCreds.context.setCert(bad_opts.cert)
s._sharedCreds.context.setKey(bad_opts.key)
res.end('Goodbye World!\n')
})
s.listen(9999)Result: It looks like the current connection continues using the old cert, but the next connection uses the new cert.
|
This comment has been minimized.
This comment has been minimized.
|
Cool, thank you for testing! Each connection maintains the reference to the cert. @bnoordhuis what do you think about making an API on top of this? |
This comment has been minimized.
This comment has been minimized.
|
@indutny No objections. |
bnoordhuis
referenced this issue
Apr 26, 2017
Closed
https server with short lived ssl credentials #603
Trott
added
the
help wanted
label
Aug 2, 2017
This comment has been minimized.
This comment has been minimized.
grantila
commented
Aug 31, 2017
|
Another, perhaps more composable and flexible and even secure approach, would be to allow the certificate data to be provided through a callback instead of as static properties - This would allow for packages dedicated to ACMEv1 or ACMEv2 (or any other custom CA protocol) to fully take over responsibility of providing the certificates, including things like storing (disk or ram - potentially unswappable memory), caching, invalidation, lifecycle management etc. Leaving this to (forcing it upon) each application developer to handle such critical flow is surely possible but perhaps not ideal. |
This comment has been minimized.
This comment has been minimized.
grantila
commented
Aug 31, 2017
@indutny, not available to the application I hope? The cert should be irrelevant once the handshake is established, and especially the private key shouldn't be thrown around, imo. I don't want to have to trust all npm packages that get direct or indirect access to the socket. |
This comment has been minimized.
This comment has been minimized.
|
@grantila npm packages that you use have full access to the file system and networking. Although, getting cert is complicated, I don't see how one can trust more to them than we already do. |
bnoordhuis
referenced this issue
Sep 1, 2017
Closed
Reload certificate files of https.createServer() without restarting node server #15115
This comment has been minimized.
This comment has been minimized.
nolimitdev
commented
Jan 16, 2018
•
|
Dear @retrohacker your code seems to works fine for me in websocket server. Thank you! I think we do not need global.gc() or close existing connections because valid certificate is only needed during handshake. When connection is established expired certificate is not problem for that connection. Once certificate file is changed new connections will use new certificate for handshake. Question is why _sharedCreds.context.setCert and _sharedCreds.context.setKey are not part of public API? We can use it but without warranty because it is not documented. Code below is minimalistic example for WSS websocket server with hot reloading certificate after certificate file is changed (by certbot or acme.sh)... var ws = require('ws');
var fs = require('fs');
var https = require('https');
var options = {
server : https.createServer({
cert : fs.readFileSync('/path/to/crt'),
key : fs.readFileSync('/path/to/key'),
}).listen(2000)
};
var timeout;
fs.watch('/path/to/crt', () => {
clearTimeout(timeout);
timeout = setTimeout(() => {
options.server._sharedCreds.context.setCert(fs.readFileSync('/path/to/crt'));
options.server._sharedCreds.context.setKey(fs.readFileSync('/path/to/key'));
}, 1000);
});
new ws.Server(options);It is enough to watch just certificate file (because when private key is changed also certificate must be changed). Timeout is used because fs.watch fires callback several times depending on OS/platform. |
This comment has been minimized.
This comment has been minimized.
danosaure
commented
Jun 7, 2018
|
@nolimitdev I'm not sure how the setTimeout() helps you here, as it will still be called as many times as the Thanks for your example, it helps me think about a solution for LetsEncrypt and 0-down time. |
This comment has been minimized.
This comment has been minimized.
nolimitdev
commented
Jun 7, 2018
•
|
@danosaure thanks to setTimeout() methods setCert() and setKey() fire only once per certificate file change. Depending on OS/platform re-saving file only once fires fs.watch callback several times during short time. You can add console.log() into fs.watch callback and you will understand. Of course you can ignore that little overhead by calling setCert() and setKey() more times and remove setTimeout() completely. |
This comment has been minimized.
This comment has been minimized.
danosaure
commented
Jun 7, 2018
•
|
@nolimitdev Sorry, I just noticed the For this case, you want the cert to be available as soon as possible, so you should look into throttle() (I misspoke with |
This comment has been minimized.
This comment has been minimized.
nolimitdev
commented
Jun 7, 2018
|
@danosaure I do not need cert to be available as soon as possible because the old one is still valid for about next 2 weeks :) |
This comment has been minimized.
This comment has been minimized.
amruthar
commented
Oct 8, 2018
•
|
hi, I have an express server that I start with
server._sharedCreds.context.setCert(fs.readFileSync('/path/to/crt')); don't seem to be working for me (No such method setCert or setKey in the context object). The server still serves requests with the same server cert and key. I have exposed an api in my server to change the server cert and key before it expires. I need to be able to do this without a server.close() and server.listen() again as it takes as long as a few minutes for the server.close() callback to be executed. Does anybody have a solution to this? |
This comment has been minimized.
This comment has been minimized.
nolimitdev
commented
Oct 8, 2018
|
@amruthar How it is possible that you have no such method setCert or setKey in the context object? I just tested different nodejs versions (v6, v7, v8, v9 and newest v10) and methods are available in each version. What version exactly do you use? |
This comment has been minimized.
This comment has been minimized.
amruthar
commented
Oct 8, 2018
•
|
@nolimitdev my bad, seems to work. I had checked with setCa which isn't a method apparently. Thank you. However, how does one modify the ca field in options to add or delete the ca certs used to authenticate client certs? |
This comment has been minimized.
This comment has been minimized.
nolimitdev
commented
Oct 8, 2018
|
@amruthar you can concat your domain cert with CA cert to one file and link it in "cert" option without using "ca" option and then you do not need sth. like setCa(). Try to search sth. like https://www.google.sk/search?q=concat+ca+and+cert |
This comment has been minimized.
This comment has been minimized.
amruthar
commented
Oct 9, 2018
|
@nolimitdev , I tried concatenating the end domain cert of my server along with the ca certs that are required for authenticating the client certs for incoming requests, my code looks like this now:
However I am not able to make any requests as the server isn't able to verify the client cert that I am providing for the request. (since I've removed the ca field in options and concatenated ca certs in cert field itself.) |
This comment has been minimized.
This comment has been minimized.
nolimitdev
commented
Oct 9, 2018
|
Ca certs usually have expiration for several years. Maybe you do not need hot reloading for it at all. Just use hot reloading for domain certificate and key using setCert() and setKey(). |
This comment has been minimized.
This comment has been minimized.
amruthar
commented
Oct 9, 2018
|
@nolimitdev , context.addCACert seems to work for adding additional CA certs, still can't find a way to remove an already added CA cert from the array though. |
This comment has been minimized.
This comment has been minimized.
amruthar
commented
Oct 9, 2018
|
@nolimitdev , I need to add a new CA cert, not a renewed CA cert that already existed. It is a custom CA cert, which means I have to add it in my trusted ca fields option. |
cjihrig
added a commit
to cjihrig/node-1
that referenced
this issue
Oct 13, 2018
cjihrig
referenced this issue
Oct 13, 2018
Merged
tls: support changing credentials dynamically #23644
cjihrig
added a commit
to cjihrig/node-1
that referenced
this issue
Oct 16, 2018
cjihrig
added a commit
to cjihrig/node-1
that referenced
this issue
Oct 21, 2018
cjihrig
closed this
in
#23644
Oct 21, 2018
jasnell
added a commit
that referenced
this issue
Oct 21, 2018
cinderblock
referenced this issue
Nov 26, 2018
Open
NODE_EXTRA_CA_CERTS cannot be set in code or relative #20432
This comment has been minimized.
This comment has been minimized.
gaxolio
commented
Nov 30, 2018
Hi. Have you found a method to remove a single CA cert ? Thanks |
This comment has been minimized.
This comment has been minimized.
suparpat
commented
Dec 10, 2018
•
|
As I'm using pfx, I modified @nolimitdev 's solution to:
|
mrstegeman
referenced this issue
Feb 19, 2019
Merged
Swap certificates in running server after renewal. #1667
cinderblock
referenced this issue
Apr 3, 2019
Open
Documented way to add certificates to existing SecureContext #27079
sam-github
added a commit
to sam-github/node
that referenced
this issue
Apr 26, 2019
sam-github
added a commit
to sam-github/node
that referenced
this issue
Apr 26, 2019
This comment has been minimized.
This comment has been minimized.
matth-c3
commented
Apr 27, 2019
•
|
Hello, I also try with use case : automatic rotation of the certificates on random interval on the servers. Thanks by advance. |


petkaantonov commentedDec 29, 2015
We need to change the certificate info (credentials/secureContext) dynamically while the server is online without having to shut down and start a new server. We have patched node with code that enables this, but it would be nice to have it on upstream as well.
The API we have is:
server.setSharedCredentials(secureContext)
Used to change the server's TLS options such as the server certificate on the fly.
secureContextmust be an instance ofSecureContextas is created withtls.createSecureContext().After the call, if there were active sockets using old context, those sockets will be disconnected next time data is sent over them.