Step v0.9.0: Curl mTLS services with SSO certificates via OAuth OpenID Connect
Max Furman
At Smallstep, we believe that the right thing to do also needs to be the easy thing to do. Otherwise people will just do the easy thing, even though it's wrong.
We believe that all communication in your infrastructure can and should be mutually authenticated and encrypted. The right way for a developer to connect to a service that enforces mutual authentication (mTLS) is with a client certificate - a certificate that personally identifies the developer. But, in our experience, this is not the easy way. Why? Because obtaining a scoped, personal certificate that is valid within one's infrastructure is an unreasonable expectation for most developers. The much easier solution is probably some sequence of SSH and curl commands that allows one to bypass all security measures. Let's fix this!
Our mission, at Smallstep, is to build tools and workflows that make secure communication within your infrastructure simple and seamless. That's why we've created step
, the zero trust command-line swiss army knife, and step certificates
, a sub-project that adds certificate creation and management capabilities to step
. Today's step
release, v0.9.0, makes it easy for developers to obtain personal certificates by taking advantage of existing SSO providers.
Installing step
To follow along you'll need to install step
.
Brew
$ brew install step
Or, if you've already installed step
via homebrew, run:
$ brew upgrade step
Linux
Linux users can install step 0.9.0
using dpkg
(or build from source).
$ curl -Os https://github.com/smallstep/cli/releases/download/v0.9.0/step-cli_0.9.0_amd64.deb && sudo dpkg -i step-cli_0.9.0_amd64.deb
Docker
If you use docker you can launch our base image locally:
$ docker run -it --rm smallstep/step-cli:0.9.0
Or in a kubernetes cluster:
$ kubectl run step -it --rm --image smallstep/step-cli:0.9.0 --restart Never
Easily curl services secured by mutual TLS
In the blog post announcing our previous release we discussed why Let's Encrypt is a great free service to obtain certificates for public websites and APIs. However, we also argue that Let's Encrypt is less optimal when used to generate certificates for internal infrastructure.
For your internal infrastructure (users, services, hosts, etc.) we believe that you should use an internal Certificate Authority (CA). That's why we've built step certificates
to make using a CA and managing certificates for internal services as easy as Let's Encrypt.
To begin, simply run the init
workflow:
$ step ca init --name "Local CA" --provisioner admin \
--dns localhost --address ":443"
You'll be prompted for a password to encrypt key material. Let's call this password your step-key
password; you will need it when you start (and restart) your CA.
Next, start your CA using the generated configuration (you'll be prompted for your sudo password so we can listen on port 443, then your step-key
password):
sudo step-ca $(step path)/config/ca.json
You can get a certificate from your CA for any name, including localhost
. In another terminal run (you'll be prompted for your step-key
password):
step ca certificate localhost localhost.crt localhost.key
If you'd rather not run an online CA see the section below highlighting our new
offline
features.
Armed with certificates your internal services can be easily configured to trust your CA. That means they can securely connect across the internet and enjoy the many benefits of using mutual TLS!
Managing your internal PKI using step
to identify services connecting over TLS will enforce strong mutual authentication between them. If every entity in your infrastructure can easily obtain a valid certificate then you can require mutual authentication for every connection in your network.
Q: How do I allow engineers to connect directly to services (for debugging, metrics aggregation, etc.) if every connection requires mutual authentication?
A: Make it easy for engineers to obtain self-identifying (personal) certificates.
If you followed the announcement of step certificates
, you probably already know that step certificates
comes with a bootstrapping protocol. The CA authorizes provisioners which can be flexibly integrated into config management, container orchestration, and other deploy automation tools to generate one-time-tokens which workloads can redeem for valid certificates. This works great for machines and services but falls short for user identities.
Enter personal certificates using step certificates
and step cli
!
Personal certificates via OAuth OpenID Connect
step
v0.9.0's newest feature: OpenID Connect authentication support for step certificates
.
Unlike an inventory of machines or services, user identities are usually already managed by your existing G-Suite, Okta, Salesforce, or Microsoft Office 365. Almost all of these enterprise services expose OpenID Connect identity providers which are a suite of single-sign-on protocols that allow creation of accounts and login into third party applications using a single account per user identity.
In step
v0.9.0 you can now leverage OpenID Connect to authenticate with step certificates
to make issuance of personal certificates simple for your whole team.
Here's how it works:
- Make sure your CA is running.
In your terminal:
$ step-ca $(step path)/config/ca.json
- Add an OpenID Connect provisioner for you G-Suite.
In a different terminal:
$ step ca provisioner add Google --type oidc --ca-config $(step path)/config/ca.json \
--client-id 650445034027-jsjdrkiskeq9ke99ud2rqkst82ft8uch.apps.googleusercontent.com \
--client-secret 6Q7lGMua_Oox4nA92QBXYypT \
--configuration-endpoint https://accounts.google.com/.well-known/openid-configuration \
--domain smallstep.com --domain gmail.com
- Reload the CA.
Return to the terminal from which you originally ran your CA where you'll be re-prompted for your sudo password so we can listen on port 443, and your step-key
password:
kill -SIGHUP $(ps aux | grep step-ca | grep -v grep | awk '{print $2}')
- Get a personal certificate using your G-Suite account.
Be sure to specify your G-Suite email address (the command's first argument) and select the Google
provisioner from the dropdown:
$ step ca certificate davey.oauth.jones@gmail.com personal.crt personal.key
Use the arrow keys to navigate: ↓ ↑ → ←
What provisioner key do you want to use?
pDpbCsI8Thvci7EqyJJY7AoUIadufTeZQnAcBCwGuHE (admin)
▸ 650445034027-jsjdrkiskeq9ke99ud2rqkst82ft8uch.apps.googleusercontent.com (Google)
Unlike regular JWK-based provisioners no password prompt will come up in the terminal. Instead expect the default browser to open the G-Suite login screen. After successfully logging-in the CA will issue a certificate for the respective user.
$ step certificate inspect --short personal.crt
X.509v3 TLS Certificate (ECDSA P-256) [Serial: 1445...0545]
Subject: 113900523962383213156
davey.oauth.jones@gmail.com
Issuer: Local CA Intermediate CA
Provisioner: Google [ID: 6504....com]
Valid from: 2019-03-20T18:17:55Z
to: 2019-03-21T18:17:55Z
Now you can mutually authenticate with your services using TLS. Bring up a web server:
$ step ca root root_ca.crt
$ step ca localhost localhost.crt localhost.key # if you didn't run this earlier
$ python <<EOF
import BaseHTTPServer, ssl
class H(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200); self.send_header('content-type', 'text/html; charset=utf-8'); self.end_headers()
san = self.connection.getpeercert().get('subjectAltName')[0][1]
self.wfile.write(b'\n\xf0\x9f\x91\x8b Hello '+san+'! Welcome to mTLS \xf0\x9f\x94\x92\xe2\x9c\x85\n\n')
httpd = BaseHTTPServer.HTTPServer(('', 8443), H)
httpd.socket = ssl.wrap_socket (httpd.socket, server_side=True, keyfile="localhost.key", certfile="localhost.crt",
cert_reqs=ssl.CERT_REQUIRED, ca_certs="root_ca.crt")
httpd.serve_forever()
EOF
Now we're ready to ping the HTTPS endpoint using curl. All we need to do is provide a root certificate for client-side server authentication plus your personal certificate and private key to pass the server-side client authentication.
$ curl --cacert root_ca.crt \
--cert personal.crt --key personal.key \
https://localhost:8443
Success! Using OpenID Connect to make personal certificates for your teams self-serve is an easy and powerful way to unlock strong identity for everybody everywhere. For more details including how to setup the OAuth backend please review step certificates
' documentation.
What else is new?
CA offline mode
It's not always practical or desirable to run an Online CA. step
now provides the means to create certificates without step certificates
CA running. step
offline mode will still leverage the CA's configuration, which must be available locally, to issue certificates.
$ step ca init --name "Local CA" --provisioner admin \
--dns localhost --address ":443"
$ step ca certificate --offline foo.smallstep.com foo.crt foo.key
step
can also generate bootstrap tokens in offline
mode and exchange them with a running CA for a certificate. This workflow is useful when generating tokens on a host without direct access to the running CA.
TOKEN=$(step ca token --offline foo.smallstep.com)
step ca certificate --token=$TOKEN foo.smallstep.com foo.crt foo.key
NOTE: You cannot exchange a token for a certificate that will be generated offline - the token must be exchanged with an online CA.
Shell auto-complete for bash and zsh
step
now comes with auto-completion for bash
and zsh
using the standard _<TAB>_
key as you type out commands.
$ step certificate ins<TAB>
-- values --
inspect -- print certificate or CSR details in human readable format
install -- install a root certificate in the system truststore
Shorter format for step certificate inspect
The new short format of step certificate inspect
with the --short
flag will provide a quick peek at the most important information of a certificate without getting lost in the weeds. Handy for debugging and troubleshooting.
$ step certificate inspect --short https://smallstep.com
X.509v3 TLS Certificate (ECDSA P-256) [Serial: 3263...4954]
Subject: smallstep.com
Issuer: Let's Encrypt Authority X3
Valid from: 2019-02-08T13:07:44Z
to: 2019-05-09T13:07:44Z
Better audit logging for CA
We've added better audit logging for api requests to step certificates
. The logs now record the PEM encoded body of the certificate, the provisioner token, and a number of the most commonly searched attributes from the certificate for later audits.
[...]
INFO[467190] certificate="[CERT-PEM]" duration=3.164401ms duration-ns=3164401 fi
elds.time="2019-03-18T16:28:05-07:00" issuer="Example Inc. Intermediate CA" meth
od=POST name=ca ott=[OTT] path=/sign protocol=HTTP/2.0 provisioner="gif@example.
com (EWCA8ltRBtL17eEA-Hun3AkB7K1LDaQr-6Gouw7EphU)" public-key="ECDSA P-256" refe
rer= remote-address=127.0.0.1 request-id=bi82j1crtr3746jf72pg serial=67532934347
487000046383869679560614883 size=1618 status=201 subject=foo user-agent=Go-http-
client/2.0 user-id= valid-from="2019-03-18T23:28:05Z" valid-to="2019-03-19T23:28
:05Z"
[...]
Let us know what you think
We strive to make step
the best open source solution for managing your internal PKI and enabling you to run TLS everywhere. In future releases, we will ship tighter integrations with common cloud and container environments, more advanced certificate lifecycle management, and better visibility into certificate operations. As always, we'd love to hear from you.
Stay tuned by following us on twitter and GitHub!