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

Add support for mTLS #1731

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

thekevinbrown
Copy link

Description

This PR adds support for mTLS by changing two things:

  1. Supplying the ca and requestCert: true parameters for the server when in use.
  2. Populating the event.identity.clientCert object when new requests come in.

Both of these behaviours only activate if you have a httpsProtocol directory configured in the serverless offline config, and have put a ca.pem file in it alongside the key.pem and cert.pem files.

Motivation and Context

We use mTLS in our environment with API Gateway and want a way to test this locally. Serverless Offline doesn't currently support mTLS (#1730), so we figured it'd be nice to add support for it so we can use Serverless Offline to more fully emulate our AWS setup.

How Has This Been Tested?

You'll need to create some files to test this

Creating a Certificate Authority (CA)

  1. Create a private key for the Certificate Authority (ca.key):
$ openssl genrsa -out ca.key 4096
  1. Self sign it and generate the certificate to identify the certificate authority to clients (ca.pem):
$ openssl req -x509 -new -nodes \
  -key ca.key \
  -sha256 \
  -days 365 \
  -subj "/C=AU/ST=Tasmania/L=Hobart/O=Some Company/OU=Certificate Services" \
  -out ca.pem

Creating a Certificate for the Server

  1. Generate the private key for the server (key.pem):
$ openssl genrsa -out key.pem 4096
  1. Generate a certificate signing request (CSR) using this key (server.csr):
$ openssl req -new -sha256 \
  -key key.pem \
  -subj "/C=AU/ST=Tasmania/L=Hobart/O=Some Company/OU=Certificate Services" \
  -out server.csr
  1. Sign it as the CA and create the certificate (cert.pem):
$ openssl x509 -req \
  -in server.csr \
  -days 365 -sha256 \
  -CA ca.crt \
  -CAkey ca.key \
  -CAserial ca.srl \
  -CAcreateserial \
  -out cert.pem

Creating a Certificate for the Client

  1. Generate the private key for the client (client.key):
$ openssl genrsa -out client.key 4096
  1. Generate a certificate signing request (CSR) using this key (client.csr):
$ openssl req -new -sha256 \
  -key client.key \
  -subj "/C=AU/ST=New South Wales/L=Barangaroo/O=Exogee/OU=Data Collection Services/CN=exogee.com" \
  -out client.csr
  1. Sign it as the CA and create the certificate (client.pem):
$ openssl x509 -req \
  -in client.csr \
  -days 365 -sha256 \
  -CA ca.crt \
  -CAkey ca.key \
  -CAserial ca.srl \
  -CAcreateserial \
  -out client.crt

Now you should have the following files:

  • ca.key
  • ca.pem
  • ca.srl
  • cert.pem
  • client.key
  • client.pem
  • key.pem

Create a Node JS client passing the ca.pem, client.key and client.pem parameters as follows:

import { Client } from 'undici';

const ca = await fsPromises.readFile('ca.pem');
const cert = await fsPromises.readFile('client.pem');
const key = await fsPromises.readFile('client.key');

const apiClient = new Client('https://localhost:3000', {
	connect: { ca, cert, key },
});

const apiResponse = await apiClient.request({
	path: '/',
	method: 'POST',
	body: JSON.stringify({ test: true }),
});

Screenshots (if appropriate):

This results in the following event being sent to the handler:

{
  "body": "{\"test\":true}",
  // ...
  "requestContext": {
    //...
    "identity": {
      // ...
      "clientCert": {
        "clientCertPem": "-----BEGIN CERTIFICATE-----\n[certificate contents in base64]\n-----END CERTIFICATE-----",
        "issuerDN": "C=AU,ST=Tasmania,L=Hobart,O=Some Company,OU=Certificate Services",
        "serialNumber": "032AA3D423A340C86DA38CE2EEF2114090EFC291",
        "subjectDN": "C=AU,ST=Tasmania,L=Hobart,O=Exogee,OU=Data Collection Services,CN=exogee.com",
        "validity": {
          "notAfter": "Sep  7 04:18:08 2024 GMT",
          "notBefore": "Sep  8 04:18:08 2023 GMT"
        }
      }
    }
  },
}

I've also tested without the ca.pem file in the directory to make sure nothing breaks / changes, and it worked fine for me.

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.

None yet

1 participant