Chris Swan, Engineer

Eating Our Own Cooking - NoPorts for Certificate Authority

TL;DR

We’ve recently had to stand up a private Certificate Authority (CA), but it needs to be reachable from various systems that aren’t local to where it’s hosted. NoPorts (and policy) means that we can connect with ease.

Why did we need something?

Every Atsign has a personal data service (PDS) associated with it, and those PDSs use X.509 certificates to identify themselves so that clients can check they’re connecting to a genuine service.

When Atsigns talk to each other they make use of mutual transport layer security (mTLS). The ‘client’ Atsign presents its certificate to the ‘server’ Atsign so that both ends of the conversation can verify their identity. This makes use of the fact that public certificate authorities like Let’s Encrypt issue certificates that carry extended key usage (EKU) metadata that lets them be used for client authentication and server authentication.

Unfortunately that’s coming to an end. The Google Chrome team changed their certificate authority policy to ‘Promote use of Dedicated TLS Server Authentication PKI Hierarchies’. This in turn has forced CAs like Let’s Encrypt into ‘Ending TLS Client Authentication Certificate Support in 2026’.

This means we now need to get the client certificate for mTLS from another CA, and we chose to deal with that by standing up our own CAs using SmallStep’s step-ca.

We don’t have a LAN

Atsign has never had an office, so we’ve never had any traditional infrastructure. We don’t have a local area network (LAN).

That’s probably not uncommon for newer companies. Like many born in this era we’ve built everything in the cloud.

But lots of ‘enterprise’ software is built with the expectation of the old LAN model, and that has somewhat carried over into modern times with virtual private clouds (VPCs) in cloud networks.

Things would be pretty easy if we exposed the new CA within its VPC, and everything that needed to access it was within that VPC. Sadly real world deployments don’t always play on easy settings, and in practice there’s a bunch of stuff that needs to access the CA that’s not conveniently on the same VPC.

NoPorts + Policy + step-ca

To maximise security of the new CAs they don’t expose any services beyond their localhost. So they’re not even accessible (or exploitable) within their VPC. All connections are made over NoPorts tunnels, and everything is mediated by policy.

This contrasts to the guide for ‘Exposing step-ca to the internet’, which comes with pretty dire warnings in the ‘Proxying an ACME Provisioner’ section. Nope!

This means that it doesn’t matter if certificates are needed on the same VPC (such as our hosted Atsign swarms), or a CI/CD pipeline, or privately hosted. They can all connect to the CA over NoPorts.

Techie details

HTTPS

Step-ca (of course) expects a connection over HTTPS. The DNS name used for the CA resolves to 127.0.0.1, which is the entry point for the NoPorts tunnel.

The mildly tricky part here is that the certificates presented by the CA come from that CA. So we have to ensure that we trust the CA by adding its root certificate to the connecting system’s roots of trust. Generally that’s a straightforward case of copying the CA root into place and running a script to update-ca-certificates. But we did trip over an issue with Python scripts running inside (uv created) virtual environments, as the venv has its own roots of trust, and they also need to be updated (or overridden).