-
Notifications
You must be signed in to change notification settings - Fork 13
Bug Fix and Other Enhancements to CA Support for mTLS #31
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
Bug Fix and Other Enhancements to CA Support for mTLS #31
Conversation
Signed-off-by: hfuss <haydenfuss@gmail.com>
Signed-off-by: hfuss <haydenfuss@gmail.com>
|
|
||
| export const extractPeerSenderFromRequest = (req: Request): string => { | ||
| const cert = ((req.socket) as TLSSocket).getPeerCertificate(); | ||
| return getPeerID(cert.subject.O, cert.subject.OU); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may need to update custom.d.ts to avoid potential compiler issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hadn't hit compiler issues when I built and tested this code in my deployments, but I updated custom.d.ts for good measure and removed the unused interfaces.
| certBundle = cert; | ||
| log.debug("Loaded cert"); | ||
| } | ||
| log.debug("\n" + certBundle); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In an early prototype of DX the CA was explicitly loaded. However, later the code was simplified as the file can just be picked up when reading the cert files. The constant was left in the utils file. The key question would be, is there a reason why it is explicitly loaded here? I was under the impression that as long as the file is placed in the correct directory, it will be picked up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah so, if a ca.pem (or really so long as it is a .pem) is in the peer-certs that will definitely work like you said.
The biggest advantage of this is if a new org and DX comes along with a different / renewed CA cert. With this approach, the DX can advertise this CA as part of its cert so that the other existing DX's do not need to be redeployed in order to trust the new DX - essentially making CA-signed certs be treated / trusted more like self-signed certs (which is debatably not the best approach from a security perspective).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm alright with removing this for now to keep the change small and give us time to think this through more, but we will need DX to support org's having separate CAs for our FireFly deployments outside Kaleido (and ideally DX's do not need to be redeployed to have others' CAs as that causes a lot of discovery issues on the cloud engineering side).
…nt interface Signed-off-by: hfuss <haydenfuss@gmail.com>
Fixes
Originally p2p APIs were using
req.client.getPeerCertificate().issuerto determine the ID of the DX which sent the request. This worked for self-signed certificates because theissuer == subject, however for CA-signed certs provisioned w/ cert-manger, or internal Kaleido certs signed with a environment's CA, theissuer != subjectand it was causing issues with private messaging E2E tests in those environments.subjectshould be used because DX uses it to derive its own peer ID that it advertises onGET /id.For example, w/ a cert-manager cert signed by a CA (the CA happened to not have an O or OU) the DX would get the following error when trying to hit another org's DX:
By casting the socket of the req to the
TLSSocketit allows Typescript to then retrieve thesubjectfrom the peer's certificate which is what should be used to derive the DX's ID from the O and OU.Additions
With cert-manager certificates, the
cert.pemdoes not include the CA which signed it. If the CA is self-signed, this needs to be advertised inGET /idso peers can include the CA in theirHttpsAgentand when they persist the certs in thepeer-certsdirectory.This adds support to optionally (if the file exists) read a
ca.pemfile from theDATA_DIRECTORY(same directory askey.pemandcert.pem) and prepend it thecert.pemstoring it in a new varcertBundle.certBundleis then returned onGET /idso peers will receive both the cert and the provided CA. Thecertvar is left to only contain thecert.pembecause including the CA seemed to break the server startup when used in theTLSContext.While self-signed CAs were already supported by putting a
ca.pemin thepeer-certsdirectory before startup (as what was is currently documented in the README) this allows peers to have certs signed by separate CAs w/o every peer needing to be aware of them on startup. It also allows new DX peers to join the network with renewed CA certs.Original Issue
These changes arose from issues we found w/ FF DX deployments using self-signed CAs where the NodeJS HTTPS agent couldn't trust the cert from a peer bc the CA wasn't included in the chain (in a lot of ways this was just a config issue):
However, in Kubernetes environments where
peer-certsis backed by a PVC, theca.pemcannot be included into the directory before startup without init/bootstrap scripts (for example see the Helm chart PR in firefly). Upon adding theca.pem/certBundlefeature the bug above around thesubjectof the peer certificate was then discovered and needed to be fixed.