gcp

mTLS using GCP KMS Keys

2022-10-10

This article demonstrates how you can use a crypto.Signer implementation i wrote some years ago to make an mTLS connection using a private key that exists only in GCP KMS.

Basically, you will create a KMS key that is enabled for RSA-PSS Signing.

We will then issue a Certificate Signing Request (csr) using the private key to sign the request.

From there, we have a local Certificate Authority that will issue the x509 cert for the client.

We will then run an https server that requires client certificates issued by that same CA

The client will use the client x509 and KMS private key reference to establish an mTLS connection to the server.


You can find the source here

this repo is not supported by google


For more information, see


Create KMS Key

First create a KMS key

export GCLOUD_USER=`gcloud config get-value core/account`

gcloud kms keyrings create tlskr --location=global

gcloud kms keys create k1 --keyring=tlskr \
   --location=global --purpose=asymmetric-signing \
   --default-algorithm=rsa-sign-pss-2048-sha256

gcloud kms keys add-iam-policy-binding k1  \
     --keyring=tlskr --location=global   \
	   --member=user:$GCLOUD_USER  --role=roles/cloudkms.signer

gcloud kms keys add-iam-policy-binding k1  \
     --keyring=tlskr --location=global   \
	   --member=user:$GCLOUD_USER  --role=roles/cloudkms.viewer

images/key.png

$ gcloud kms keys list --keyring=tlskr --location=global
NAME                                                                        PURPOSE          ALGORITHM                 PROTECTION_LEVEL 
projects/PROJECT/locations/global/keyRings/tlskr/cryptoKeys/k1  ASYMMETRIC_SIGN  RSA_SIGN_PSS_2048_SHA256  SOFTWARE

recall the public key (your’s will ofcourse be different)

$ gcloud kms keys versions get-public-key 1    --key=k1 --keyring=tlskr   --location=global
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzHdXnqlUgvFlTaAXBMAU
cxi74Vfb0tA7Pn/356xIqB820t6bSRmCutPOnHUYz02piNFJP2Vx+HKiqmT3S7jy
Yv6xPWxGfOHmKbwl8UkMzOdPtTyMLk11TSGA0Wgar9e/chU1UxH1Rk9sQ5CG8xBK
7ToGGIn0fxBvyWeAucsgn3PONuuqrKsTfW/hckyk866oI8e8C7+XWrbtM6gBt4/U
Z2OiF/QfdoXB4oBFLi+NHkLdYBk0pM6R/xaXCGUchLQkfw6MdD68MvfNVSY7YIuy
g5ZIrWFQzSptCtn4mF9CLooRK/2d360d9hsCUybCTRAw6D8Ra27aVS5+Vl+lajxu
JQIDAQAB
-----END PUBLIC KEY-----

Create a CSR

now create a CSR:

export PROJECT_ID=`gcloud config get-value core/project`

cd csr/

go run main.go --projectID=$PROJECT_ID --cn client.domain.com --filename ../certs/client.csr

Sign CSR

Then initialize the CA using the certificate authority here (you can create you own CA here).

cd certs/

rm -rf /tmp/kmsca
mkdir -p /tmp/kmsca

cp /dev/null /tmp/kmsca/tls-ca.db
cp /dev/null /tmp/kmsca/tls-ca.db.attr

echo 01 > /tmp/kmsca/tls-ca.crt.srl
echo 01 > /tmp/kmsca/tls-ca.crl.srl


openssl ca \
    -config tls-ca.conf \
    -in client.csr \
    -out client.crt \
    -extensions client_ext

You can also confirm the certificate has the same public key from KMS

$ openssl x509 -pubkey -noout -in client.crt 
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzHdXnqlUgvFlTaAXBMAU
cxi74Vfb0tA7Pn/356xIqB820t6bSRmCutPOnHUYz02piNFJP2Vx+HKiqmT3S7jy
Yv6xPWxGfOHmKbwl8UkMzOdPtTyMLk11TSGA0Wgar9e/chU1UxH1Rk9sQ5CG8xBK
7ToGGIn0fxBvyWeAucsgn3PONuuqrKsTfW/hckyk866oI8e8C7+XWrbtM6gBt4/U
Z2OiF/QfdoXB4oBFLi+NHkLdYBk0pM6R/xaXCGUchLQkfw6MdD68MvfNVSY7YIuy
g5ZIrWFQzSptCtn4mF9CLooRK/2d360d9hsCUybCTRAw6D8Ra27aVS5+Vl+lajxu
JQIDAQAB
-----END PUBLIC KEY-----

Run Server

Now run the TLS Server

cd example/
go run server/main.go

Run Client

cd example
go run client/client.go --projectID $PROJECT_ID

Once you connect, the server will show the peer certificate’s public key it recieved….and surprise, its

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzHdXnqlUgvFlTaAXBMAU
cxi74Vfb0tA7Pn/356xIqB820t6bSRmCutPOnHUYz02piNFJP2Vx+HKiqmT3S7jy
Yv6xPWxGfOHmKbwl8UkMzOdPtTyMLk11TSGA0Wgar9e/chU1UxH1Rk9sQ5CG8xBK
7ToGGIn0fxBvyWeAucsgn3PONuuqrKsTfW/hckyk866oI8e8C7+XWrbtM6gBt4/U
Z2OiF/QfdoXB4oBFLi+NHkLdYBk0pM6R/xaXCGUchLQkfw6MdD68MvfNVSY7YIuy
g5ZIrWFQzSptCtn4mF9CLooRK/2d360d9hsCUybCTRAw6D8Ra27aVS5+Vl+lajxu
JQIDAQAB
-----END PUBLIC KEY-----

AuditLogs

If you enabled auditlogs for KMS, you will see both the csr and client request a sign API request on either side to establish the mTLS connection

images/log.png

Issues, issues

Latency

Well…yeah, there is some and thats one of the biggest reasons this is a bit academic. I ran this setup a couple times and saw that the API calls from my laptop to establish just a TLS connection using one KMS key added on about 150ms…This would be faster on a compute engine or on GKE on cloud though…but its still a lot.

This site supports webmentions. Send me a mention via this form.