SSH certificate login advanced example: Run an SSH CA and connect to VMs using SSH certificates
OpenSSH and SSHD have supported SSH certificate login for almost ten years. In this tutorial, you'll learn how to use SSH certificates (for hosts & users) generated by step-ca using the step ssh sub-command.
About this tutorial
Learn how to configure OpenSSH and SSHD for certificate authentication using step-ca
Examples include copy/paste code blocks and pre-generated PKI.
When complete, you will be able to use OpenSSH and SSHD for SSH certificate login with a private SSH certificate authority.
Estimated effort: Reading time ~10 mins, Lab time ~60 to 180 mins.
The code in this repo comes with a pre-generated PKI. You will need step v0.13.3+ and Vagrant, plus a provider like VirtualBox installed locally.
You're going to run a CA in your local environment and we'll use SSH to connect
to a Vagrant VM (representing a remote host) that has sshd pre-configured to
accept SSH user certificates signed by our CA.
With Vagrant installed, run the following commands inside the repo:
$vagrant upBringing machine 'testhost' up with 'virtualbox' provider...
==> testhost: Importing base box 'ubuntu/bionic64'...
==> testhost: Preparing network interfaces based on configuration...
testhost: Adapter 1: nat
testhost: Adapter 2: hostonly
==> testhost: Forwarding ports...
testhost: 22 (guest) => 2222 (host) (adapter 1)
==> testhost: Running 'pre-boot' VM customizations...
==> testhost: Booting VM...
==> testhost: Waiting for machine to boot. This may take a few minutes...
testhost: SSH address: 127.0.0.1:2222
testhost: SSH username: vagrant
testhost: SSH auth method: private key
testhost: VirtualBox Version: 6.0
==> testhost: Setting hostname...
==> testhost: Configuring and enabling network interfaces...
==> testhost: Mounting shared folders...
testhost: /keys => /Users/sourishkrout/dev/src/smallstep/code/src/github.com/smallstep/step-examples/ssh-example/keys
testhost: /vagrant => /Users/sourishkrout/dev/src/smallstep/code/src/github.com/smallstep/step-examples/ssh-example
==> testhost: Running provisioner: shell...
testhost: Running: inline script
testhost: Add following line to your local hosts ~/.ssh/known_hosts file to accept host certs
testhost: @cert-authority * ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJJM+jkIdieQvdPb8DwnfnJudEc9PgVBqLDWHKgvqoIiMXhuIyGstQ9ULOBMdJkqxMjkRTFZp1iFvIk+iU6hwTA=
testhost: Add a /etc/hosts file entry testhost to resolve to 192.168.0.101
testhost: Check out README.md to learn how to grab user ssh certs to log into testhost
Configure ssh client to accept host certs
Go ahead and follow the instructions printed by Vagrant. This will enable your local SSH client to accept SSH host certificates (signed by the root SSH host private key). The following command will append the SSH host CA key (root SSH host public key corresponding to the root SSH host private key) to your local known_hosts file:
You can also find the root SSH host CA key stored at step/certs/ssh_host_key.pub in this repo.
SSH certificates bind names to public keys. This SSH host certificate has the
identity testhost which is why the following entry must be added to the local
/etc/hosts file on the VM:
$tail -n 1 /etc/hosts192.168.0.101 testhost
Configure sshd to accept user certs
Vagrant has already configured sshd on testhost, the VM generated by Vagrant. Please note that for demo purposes the PKI is shared with the VM using a shared directory mount. Below you can see the relevant lines from the testhost VM's sshd_config:
$tail -n 5 /etc/ssh/sshd_config# PermitTTY no
# ForceCommand cvs server
TrustUserCAKeys: The root SSH user public key used to verify SSH user certificates.
HostKey: The SSH private key specific to this host.
HostCertificate: The SSH public certificate that uniquely identifies this host (signed by the root SSH host private key).
Login to VM via SSH user cert
A valid user certificate is required to log into the testhost VM. Using step, you can authenticate with your SSH-enabled CA and fetch a new SSH certificate.
In one terminal window, run the following command to startup your CA (password is password):
$exportSTEPPATH=pwd/step$step-ca step/config/ca.jsonPlease enter the password to decrypt step/secrets/intermediate_ca_key: password
Please enter the password to decrypt step/secrets/ssh_host_key: password
Please enter the password to decrypt step/secrets/ssh_user_key: password
2019/09/11 22:59:01 Serving HTTPS on :443 ...
In another terminal window run:
$exportSTEPPATH=pwd/step$stepssh certificate testuser testuser_ecdsa --ca-url https://localhost --root step/certs/root_ca.crt✔ Provisioner: admin (JWK) [kid: ux6AhkfzgclpI65xJeGHzNqHCmdCl0-nWO8YqF1mcn0]
✔ Please enter the password to decrypt the provisioner key: password
✔ CA: https://localhost
Please enter the password to encrypt the private key: your-own-password
✔ Private Key: testuser_ecdsa
✔ Public Key: testuser_ecdsa.pub
✔ Certificate: testuser_ecdsa-cert.pub
✔ SSH Agent: yes
step-ca enforces authentication for all certificate requests and uses the
concept of provisioners to carry
out this enforcement. Provisioners are configured in step/config/ca.json.
Authenticating as one of the sanctioned provisioners indicates to step-ca
that you have the right to provision new SSH certificates.
In the above invocation of step ssh certificate, you have authenticated your
request using a JWK provisioner which requires a password to decrypt a private
key. There are a handful of supported provisioners, each with their own
authentication methods. The OIDC provisioner is particularly interesting for
SSH user certificates because it enables Single Sign-On SSH.
step ssh certificate adds the new SSH user certificate to your local ssh
agent. The default lifetime of an SSH certificate from step-ca is 16 hours. The
lifetime can be configured using command line options.
Run step ssh certificate -h in step for documentation and examples).
We recommend using your own PKI for usage outside of this example. You can
initialize your step-ca with both X509 and SSH certificate authorities using the
$exportSTEPPATH=/tmp/mystep$step ca init --ssh✔ What would you like to name your new PKI? (e.g. Smallstep): Smallstep
✔ What DNS names or IP addresses would you like to add to your new CA? (e.g. ca.smallstep.com[,18.104.22.168,etc.]): localhost
✔ What address will your new CA listen at? (e.g. :443): :443
✔ What would you like to name the first provisioner for your new CA? (e.g. email@example.com): admin
✔ What do you want your password to be? [leave empty and we will generate one]:
Generating root certificate...
Generating intermediate certificate...
Generating user and host SSH certificate signing keys...
✔ Root certificate: /tmp/mystep/certs/root_ca.crt
✔ Root private key: /tmp/mystep/secrets/root_ca_key
✔ Root fingerprint: d601c93a6256080e42cf02087fdc737f1429226ada6c040bac6494332e01527e
✔ Intermediate certificate: /tmp/mystep/certs/intermediate_ca.crt
✔ Intermediate private key: /tmp/mystep/secrets/intermediate_ca_key
✔ SSH user root certificate: /tmp/mystep/certs/ssh_user_key.pub
✔ SSH user root private key: /tmp/mystep/secrets/ssh_user_key
✔ SSH host root certificate: /tmp/mystep/certs/ssh_host_key.pub
✔ SSH host root private key: /tmp/mystep/secrets/ssh_host_key
✔ Default configuration: /tmp/mystep/config/defaults.json
✔ Certificate Authority configuration: /tmp/mystep/config/ca.json\n
Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.
Now you can launch your instance of step-ca with your own PKI like so:
$step-ca$(step path)/config/ca.jsonPlease enter the password to decrypt /tmp/mystep/secrets/intermediate_ca_key:
Please enter the password to decrypt /tmp/mystep/secrets/ssh_host_key:
Please enter the password to decrypt /tmp/mystep/secrets/ssh_user_key:
2019/09/11 23:34:13 Serving HTTPS on :443 ...
Please note that after you regenerate ssh_host_key.pub and ssh_user_key.pub, you will have to reconfigure ssh and sshd for clients and hosts to accept the new CA keys. Check out this host bootstrapping script for configuration examples.