Skip to content

torinvdb/mtls-golang

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mutual TLS (mTLS) Lab

Prerequisites

In order to run this lab, you will need access to a device running a Linux OS. This lab has been tested on Ubuntu 22.04.

You will require the following tools to be installed:

Introduction

We will now build on the PKI fundamentals in the Simple PKI lab to demonstrate how trust can be established between two services, allowing an mTLS connection to be set up between a client and a server. This lab will use two separate signing CAs, each sitting under an organization's Root CA.

graph TD
    RootCA1[Acme Root CA]
    SigningCA1[Acme Signing CA]
    ServerCert[Server TLS cert]
    RootCA2[PartnerOrg Root CA]
    SigningCA2[PartnerOrg Signing CA]
    ClientCert[Client TLS cert]

    RootCA1 -->|signs| SigningCA1
    SigningCA1 -->|signs| ServerCert
    RootCA2 -->|signs| SigningCA2
    SigningCA2 -->|signs| ClientCert
Loading

Running the Lab

PKI Setup

As shown in the Simple local PKI lab, we will first create the Root CA, Signing CA keys and certificates for the Acme organization, as well as issuing a TLS certificate for a server.

Set up the Root CA:

mkdir -p ca/root-ca-1/private ca/root-ca-1/db crl certs
chmod 700 ca/root-ca-1/private
touch ca/root-ca-1/db/root-ca-1.db
touch ca/root-ca-1/db/root-ca-1.db.attr
echo 01 > ca/root-ca-1/db/root-ca-1.crt.srl
echo 01 > ca/root-ca-1/db/root-ca-1.crl.srl

openssl req -new \
    -config config/root-ca.conf \
    -out ca/root-ca-1.csr \
    -keyout ca/root-ca-1/private/root-ca-1.key

openssl ca -selfsign \
    -config config/root-ca.conf \
    -in ca/root-ca-1.csr \
    -out ca/root-ca-1.crt \
    -extensions root_ca_ext

Set up the Signing CA:

mkdir -p ca/signing-ca-1/private ca/signing-ca-1/db crl certs
chmod 700 ca/signing-ca-1/private
touch ca/signing-ca-1/db/signing-ca-1.db
touch ca/signing-ca-1/db/signing-ca-1.db.attr
echo 01 > ca/signing-ca-1/db/signing-ca-1.crt.srl
echo 01 > ca/signing-ca-1/db/signing-ca-1.crl.srl

openssl req -new \
    -config config/signing-ca.conf \
    -out ca/signing-ca-1.csr \
    -keyout ca/signing-ca-1/private/signing-ca-1.key

openssl ca \
    -config config/root-ca.conf \
    -in ca/signing-ca-1.csr \
    -out ca/signing-ca-1.crt \
    -extensions signing_ca_ext

Issue the TLS certificate:

SAN=DNS:localhost \
openssl req -new \
    -config config/server.conf \
    -out certs/acme.example.csr \
    -keyout certs/acme.example.key

openssl ca \
    -config config/signing-ca.conf \
    -in certs/acme.example.csr \
    -out certs/acme.example.crt \
    -extensions server_ext

Bundle the certificates together in a PEM file, so that our client will be able to trust the server:

cat certs/acme.example.crt | openssl x509 > acme.example.pem
cat ca/signing-ca-1.crt | openssl x509 > signing-ca-1.pem
cat ca/root-ca-1.crt | openssl x509 > root-ca-1.pem
cat acme.example.pem >> cert-chain.pem
cat signing-ca-1.pem >> cert-chain.pem
cat root-ca-1.pem >> cert-chain.pem
rm acme.example.pem signing-ca-1.pem root-ca-1.pem

Now we will create the certificates in the PartnerOrg PKI, and bundle them into a PEM file so that the server will be able to trust the client.

Set up the Partner Root CA:

mkdir -p ca/root-ca-2/private ca/root-ca-2/db crl certs
chmod 700 ca/root-ca-2/private
touch ca/root-ca-2/db/root-ca-2.db
touch ca/root-ca-2/db/root-ca-2.db.attr
echo 01 > ca/root-ca-2/db/root-ca-2.crt.srl
echo 01 > ca/root-ca-2/db/root-ca-2.crl.srl

openssl req -new \
    -config config/root-ca-2.conf \
    -out ca/root-ca-2.csr \
    -keyout ca/root-ca-2/private/root-ca-2.key

openssl ca -selfsign \
    -config config/root-ca-2.conf \
    -in ca/root-ca-2.csr \
    -out ca/root-ca-2.crt \
    -extensions root_ca_ext

Set up the Partner Signing CA:

mkdir -p ca/signing-ca-2/private ca/signing-ca-2/db
chmod 700 ca/signing-ca-2/private
touch ca/signing-ca-2/db/signing-ca-2.db
touch ca/signing-ca-2/db/signing-ca-2.db.attr
echo 01 > ca/signing-ca-2/db/signing-ca-2.crt.srl
echo 01 > ca/signing-ca-2/db/signing-ca-2.crl.srl

openssl req -new \
    -config config/signing-ca-2.conf \
    -out ca/signing-ca-2.csr \
    -keyout ca/signing-ca-2/private/signing-ca-2.key

openssl ca \
    -config config/root-ca-2.conf \
    -in ca/signing-ca-2.csr \
    -out ca/signing-ca-2.crt \
    -extensions signing_ca_ext

Issue the Partner client certificate:

SAN=DNS:localhost \
openssl req -new \
    -config config/client.conf \
    -out certs/partner-org.example.csr \
    -keyout certs/partner-org.example.key

openssl ca \
    -config config/signing-ca-2.conf \
    -in certs/partner-org.example.csr \
    -out certs/partner-org.example.crt \
    -extensions server_ext

Build the client certificate chain:

cat certs/partner-org.example.crt | openssl x509 > partner-org.example.pem
cat ca/signing-ca-2.crt | openssl x509 > signing-ca-2.pem
cat ca/root-ca-2.crt | openssl x509 > root-ca-2.pem
cat partner-org.example.pem >> cert-chain-2.pem
cat signing-ca-2.pem >> cert-chain-2.pem
cat root-ca-2.pem >> cert-chain-2.pem
rm partner-org.example.pem signing-ca-2.pem root-ca-2.pem

Note that DNS:localhost has been added to both the server and client certificates so that this example will work locally.

Run the Server and Client

We have provided a simple golang Server and Client, which can be run locally to talk to each other over an mTLS connection. Look through the code to see where the keys, certificates and certificate chain PEM files are loaded in.

Run the Server and Client, observing that an mTLS connection is established:

go run -v server.go

Switch to a second terminal tab, making sure you are in this directory, and run:

go run -v client.go

You should see Never Trust, Always Verify! printed in the second terminal tab, showing that our mTLS connection has been successful.

Now we have seen how mTLS can be used to protect the confidentiality and integrity of data exchanged between two services, whilst confirming the authenticity of the client and server via roots of trust. However, it would be nice if we didn't have to manually create certificates and load them into our services. It would also be nice if we had an easy way to exchange public key material between organizations wanting to establish trust relationships across organizational boundaries (i.e. achieve federation), as we had to do manually in this lab. This is where SPIFFE and SPIRE can help us!

Teardown

Type Ctrl + C in the terminal tab running the server, and run:

rm -f cert-chain.pem cert-chain-2.pem go.mod hello
rm -rf ca certs crl

Disclaimer

This demo was written for LFS183x under the provided Apache License.

About

Mutual TLS (mTLS) with Golang

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages