Scalable access control using OpenSSH Certificates


I’ve been using OpenSSH certificates for some time now. They are very handy if you have a bunch of machines you want to trust, or a bunch of machines that shoud trust you.  It’s very effective to trust just one host CA in order to trust all servers with certificates signed by this CA. Or the other way around, have your personal public key signed by a user CA and then be automatically trusted by all servers that trust this CA. But if you working together with alot of people let say within an organisation this becomes problematic pretty soon. Maybe your frontend people should only have access to webservers and database people to the database servers and so on. The solution to this is the little known flags AuthorizedPrincipalsFile and AuthorizedPrincipalsCommand in sshd_config.

OpenSSH Certificates and principals

Lets start with the certificates and the principals within these certificates. In order to make this work I would suggest to use principals within the certificates that are closely tied to the person using it, their company wide username for example. If different keys have different access leves (lets say because on of them are stored on a physical secure element/smart card) it is good to include this kind of information in the principal, according to some standard you make up. Let say I use yubikeys to store my private keys I could have principals like peter_file and peter_physcial. These are easily parsable and  connected to a physical person.

Please note that there could be other access schemes where role is more important that how the key is stored, then role could be a better option for the principal suffix. But please note that if you burn the role into the certificate that person will need to have the current certificate revoked and have a new one issued if the role is ever changed. I will discuss a better way to handle this later.

Another option is to have multiple principals in the same certificate (ie peter,webmaster,root) but this also gets cumbersome when privileges and roles start to change over time.


One solution to this problem is the configuration option AuthorizedPrincipalsFile in sshd_config. With this option you tell sshd where to look for a list of principals valid for a certain user. I looks something like

AuthorizedPrincipalsFile /etc/ssh/%u_principals

When someone tries to log in as peter sshd will check my certificate for validity and then look for valid principals in the file /etc/ssh/peter_principals. sshd expects this file to contain one valid principal per line and optionally preceded by extra options using the same format as the authorized_keys file. (ie from= and command=). This is flexible enough. I can now give multiple principals (or physical persons) access to a specific account by changing a file. I can also restrict access to certain hosts or create force commands for specific principals.

One use case for this could be a webserver where multiple principals(persons) should be able to use the “webmaster” account but at the same time the test/build system should only be allowed to run a certain commands to publish successful builds. Lets say that the account name is www, then the /etc/ssh/www_principals could look something like this:

peter erik from="" command="/bin/publish_website"
buildserver from="" guestworker

Please note: If you are really concerned with security, maybe you have given a certificate to a external partner or something, I would suggest to burn the from and command attributes into the certificate. In this way they will never be overridden by some configuration at the server side. The downside is that you will need to produce a new certificate if something changes.

If you have a pretty static setup and/or a decent configuration manager/orchestration tool this could be enough. It gives full flexibility on who should be able to access what, and how. But in the long run it could be tedious to manage all the principal files. This is where the AuthorizedPrincipalsCommand comes in to the picture.


This works exactly the same as AuthorizedPrincipalsFile but instead of a static file sshd will run a command followed by some options (basically the username that tries to log in) that will generate the principals file dynamically. This gives you a lot of options. Probably the most straight forward one is that you now can have a single ACL file for you whole environment and just let the command read it and produce a host and user specific principal file. One very simple example could look like this:

# Principal(person) user     host
erik                www
peter               www
guestworker         www

peter               db
erik                db

Of course this file could be expanded to include more information and more options but this gives a example on how it can be done.

Other backends

But I think the real power in the AuthorizedPrincipalsCommand is that you now can use whatever backend you like and just have the principals command be a wrapper for this backend which could be some Active Directory, LDAP or whatever you might have at your organisation. This makes it possible to use existing infrastructure and still be able to use ssh certificates which I think is a real killer feature in OpenSSH.

If you have some ideas to improve this concept or an questions, please leave a comment.

Use a smart card or HSM to securely store your SSH CA keys

Depending on the use case, SSH CA keys can be extremely sensitive. Possession of the private key gives you the ability to sign new certificate for arbitrary usernames that will grant access to all machines where this CA is trusted. This is why you should keep your CA keys very safe, preferably offline and of course encrypted (password protected).

One big problem with digital encryption keys is that it is extremely difficult to find out if you lost control over they keys. If they where copied you have no way of finding out. This is where hardware tokens comes in. If you can be sure that the key will never leave the hardware token, you have a better chance of knowing when they keys are lost or stolen.

OpenSSH have support for storing keys onto hardware tokens that talk PKCS#11 such as smart cards and hardware security modules.

If you want to store your personal SSH key on a smart card you can read more about that here: Using Smart Card enabled yubikey for ssh authentication in FreeBSD

Since a SSH CA is just a regular SSH key they can also be stored on smart cards. But there is a few subtle differences in how you use it. First of all you need a token with a RSA key present. There is no option in OpenSSH to ask for a specific key stored on the token, instead we specifiy the public key that matches the private key we want to use. Lets download the public key from the token:

$ ssh-keygen -D /usr/local/lib/
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCOvhEqFq9Ualp1iYiNs0JFs3MgvGU+By/VvyW4qkymW+w/MmHAaHl+/UFnE+kgXChdYHaGEVxxGi6dQlSq+1ZKAWPJsOEbkysK6cgjgvP21gVNjL62TlQz+QfGF82mv0hfSGXQrZQR7VDs+6xJOe3S/0i1HvnnRTdR2v9QSJzd2EWNLmUcPy7+4x4rEB11G0oPt+Xyx60WaleJctwJHHhJS/jqHdvuf7HO6MS/EQn2NTnwIjChlmm2kUT7obnev/r6uEwz87NubnYJUrYImRDMafjS9taq8l7y33ydT00QHEI76kmrSSi7hTfmxUgStQWuQ2mq10YEVd8kZ2sqmC3N

We put this into a file, let say Now we are ready to start using the token for certificate signing.

$ ssh-keygen -s -D /usr/local/lib/ -I key_id 
Enter PIN for 'Framkant HSM Test (UserPIN)': 
Signed user key id "key_id" serial 0 valid forever

To look at the certificate we can use ssh-keygen.

% ssh-keygen -L -f
        Type: user certificate
        Public key: RSA-CERT SHA256:AtPyAu1DL5cFruTo9XnsVz7tdec7xF9SbpX8DzsQrbs
        Signing CA: RSA SHA256:Pbdx6TAvXvwZTKQVMRYWsWYPomw6AxBVoqbtXgy9pfs
        Key ID: "key_id"
        Serial: 0
        Valid: forever
        Principals: (none)
        Critical Options: (none)

In a real life scenario I would recommend against this kind of certificate. Give it some validity and specify principals.

Two nice affordable options for hardware tokens are the Yubikey and the Smart Card HSM

Setting up a SSH Certificate Authority (CA)

Are you managing a couple of machines over ssh and have begun to feel frustrated about the key management? Find it tedious to distribute your public key to every machine you want to administer? Well, there is a simple solution, that does not include LDAP or some other central authentication server. A little known fact is that OpenSSH have support for both server and client certificates (not x509) since version 5.4. These can be used to set up a trusted Certificate authority on every server once and for all.

This is a very useful tool in environments where server access are harmonized (Where the same set of users should have access to all servers).

The other part is the signing of host keys. This solves the problem of having to manually check and verify the host key fingerprint every time you connect to a new server. If the server key is signed by a CA that you choose to trust you will not be asked to verify the fingerprint. If you have some configuration orchestration like Puppet you can have the puppetmaster create the host certificates on the fly.

From the release notes of OpenSSH 5.4:

* Add support for certificate authentication of users and hosts using a
   new, minimal OpenSSH certificate format (not X.509). Certificates
   contain a public key, identity information and some validity
   constraints and are signed with a standard SSH public key using
   ssh-keygen(1). CA keys may be marked as trusted in authorized_keys
   or via a TrustedUserCAKeys option in sshd_config(5) (for user
   authentication), or in known_hosts (for host authentication).

Creating CA keys
First of all I strongly recommend that you create separate CA keys for hosts and users for security reasons.

The CA keys are just regular ssh keys, you can create them like this:

$ ssh-keygen -a 256 -o -t rsa -b 4096 -f user_ca
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in user_ca.
Your public key has been saved in

$ ssh-keygen -a 256 -o -t rsa -b 4096 -f host_ca
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in host_ca.
Your public key has been saved in

Securing the private key
Since we are in the process of essentially giving one ssh key access to all of our severs we want keep the private key used for certificate signing very secure. The absolute minimum is to have the key encrypted (password protected). But other than that you should also enable KDF which you can read more about here. I also recommend that you store your keys offline and only have them mounted to a system when you use them. One way could be a encrypted partition on a USB drive, but have two of them since USB drives have a tendency to fail.

Another way to secure your keys is to have them stored on a hardware token, you can read about that here.

Singning your ssh key
First of all you need a regular ssh key which you create with ssh-keygen. Then we can sign this key and create a certificate. This is also done with ssh-keygen:

$ ssh-keygen -s /path/to/ca_key -n peter -z 1234 -V +52w1d-I key_id /path/to/
Signed user key id "peter_cert" serial 1234 for peter valid from 2016-10-09T22:23:00 to 2017-10-09T22:24:57

The file can now be used together with your private key to access machines that accept the

To look at the newly created certificate run:

% ssh-keygen -L -f
        Type: user certificate
        Public key: RSA-CERT SHA256:AtPyAu1DL5cFruTo9XnsVz7tdec7xF9SbpX8DzsQrbs
        Signing CA: RSA SHA256:8PYQAJojSknTl3BqgBkFKigmaufDhL/7d8zYUNFm7Po
        Key ID: "peter_cert"
        Serial: 1234
        Valid: from 2016-10-09T22:23:00 to 2017-10-09T22:24:57
        Critical Options: (none)

Singning host keys
The signing of host keys is done exactly as above, the only difference is that you add -h and the value given to -n should be the hostname.

Configure sshd
To tell sshd to accept key signed with your newly created ca you just need to upload the and add one line to sshd_config. To tell the server to provide a host certificate to the client you need to add one line per key type to the configuration.

TrustedUserCAKeys /etc/ssh/
HostCertificate /etc/ssh/
HostCertificate /etc/ssh/
HostCertificate /etc/ssh/

and restart sshd.

Configure the client to accept host certificates
To accept host certificates signed by the host_ca you need to add a line to your known_hosts file.
Its just @cert-authority * < public key >

It should look something like this:

@cert-authority * ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC3pcm4IJGw76YKZSrf7pZA6s3Hu9eRzKbyzKPgg5OkBWU9ztUz2e1bXtR0UDqQKuOUx+ZDx6wmR3rVRM/BhYt1oeAv6rhxNRW2XPiakpn3EzuEWlbp68QRY8p+k6gjy7cnvF2uyaP0R0Ov819tTMHkdS3Rn57m7pfFk+tuRKLjJnQN2g6uxT+PBJonTQr2XcS5oAzwjel1x7xLqmz0MMrE98uE0GaZHxf/hioXOHt1ihzTF+GPqZ31ZrR3GIWtFEKtvcroaiS25VIV9W39LfVh7RRZTh8oCrjcEdoeFKUKA1PpqblsJhqg1XU2/xa9CAKb6SHb7gwQ18nUaQ/Sk6qYJMgkwWUtXbwS1RIm1k5QlKk8VD4H10jyqiAUBC8SHfNxnqOwKe275AfOVc/iuh4F2NsrIuHfh8tno5LqWSP63D3gXpXXm/4j3Sop2NqNz6EIqoqj0HPIL21/SneJgWXS7xxV/ShgnLVGB0dsJf8PsCnsVt0s5thO22VvE/IVQ1KM/ac1lEafBeSZsuPiOfcIeZu9mm4DfuoyqaHmnV6yBguW6zb894IdcYXsrVnMy3Hp85gnymEZn/qfPJ+dhNbBAANgjWphz5ZaBKdrpgCESz8Ka9S6V7fXr2ikB21YiUKB7XuoPjDncOokSEHU0p5iMQjE+Le7K3nOTtokhrZjXw==

Revoking Certificates
This will be added later.

Publish certificate fingerprints in DNS (TLSA/DANE)

Ever had second thoughts on paying a certificate authority (CA) a lot of money to sign your web servers public encryption key to get a trusted certificate? With the birth of DNSSEC the need for this could fade away, at least partly. It is now possible to create a self signed certificate and post the signatures securely in DNS. This way there is a secure out of band method to check the validity of a certificate. There is a special record type for this called TLSA and you can read more about it in RFC 6698

The support for these records in todays browsers are very limited, but there is a plugin available for the most popular browsers called DNSSEC validator. With this plugin it is possible to get a green light, even with a self signed certificate.

If you run your own mail server it could be interesting to know that Postfix have support for TLSA records since a few versions back.

A TLSA record could look like this:

_443._tcp TLSA (3 0 2 4FB72400493E364A499B24CDC5E5715F

_443._tcp tells us that a certificate with this sha-512 hash should be handed to us if we connect to tcp port 443.

There are three options before the hash. The first option defines “certificate usage”, the second “TLSA selector” and the third is basically hash type. The fourth field is the actual hash of the certificate. In the above example we have a sha-512 of the full certificate of a “Domain-issued certificate”. Please read more about this in the RFC (section 7).

Using the *nix command host the fetch this record looks like this

> host -t tlsa has TLSA record 3 0 2 4FB72400493E364A499B24CDC5E5715F97543262CBCB90C8483C5AB3 E8A37C9ECC4E021C8C12B3E485CFF3A082348FE6ED39EBBF2F812B3B A8857DBB1C96AFF0

It is pretty easy to find out the hash of a certificate using openssl. The following command gives us the sha512 hash of a certificate from file.

> openssl x509 -noout -fingerprint -sha512 -in framkant.crt | tr -d :

Remember that for this to have any effect on your security or your ability to have self signed certificates you need to have DNSSEC up and running for your domain. Please have a look at my article about OpenDNSSEC if you run your own authoritative dns server.

Protect your private SSH-key with KDF (key derivation function)

Ever heard someone saying that using ssh-keys is a perfect way to have “passwordless” logins to servers? Probably you have. There is a big problem with this approach (I will ignore ssh-agents and stuff like this in this article). If you really want a completley passwordless login, you will need to store the private key unencrypted. The key can be stolen without you knowing it and the attacker could use it “as is”.

The first countermeasure is to encrypt the key and protect it with a passphrase. But since the key is just a file without any brute force protection it could (if the passphrase is weak or semiweak) be very easy to crack the key open. The encryption key used is just a md5 hash of your passphrase and md5 is… fast. Since OpenSSH 6.5 there is a bettery way to protect your ssh-keys. A new private key format is used where you can apply KDF (key deviation function) to slow down the decryption of your private key.

To create a key in the new format with KDF applied you use -o for the new key format and -a specify how many rounds of KDF to use. (more rounds is slower to decrypt)

> ssh-keygen -a 256 -o -t rsa -b 4096 -f test
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in test.
Your public key has been saved in
The key fingerprint is:
45:20:9e:50:d2:6e:c9:11:bb:3a:fe:1c:a3:c6:93:48 peter
The key's randomart image is:
+--[ RSA 4096]----+
|    oo+....      |
|     +o+ .       |
|     o+o  .      |
|      =. .       |
|     .. S        |
|  E  .           |
| . oo.o          |
|  ..=+ o         |
|   .ooo          |

How many rounds to use depends on your environment and how concerned you are about losing your private keys. 256 rounds on a reasonable modern computer takes me ~4s to decrypt. This is a infinite amount of time compared md5 brute force.

Publish ssh public host key fingerprints in DNS (SSHFP)

This article describes a solution to the problem where people answers ‘yes’ on the question if they are sure they want to continue connection to a new/unknown SSH server. The solution is to publish SSHFP records in DNS.

Have you ever blindly answered yes to something like this?

The authenticity of host ' (' can't be established.
ECDSA key fingerprint is 42:f9:b3:40:17:61:89:e4:80:cf:d5:ae:bb:bb:7d:75.
+--[ECDSA  256]---+
|   ....o+o       |
|  .  oooo.       |
|   o .=..        |
|    oo o.        |
|      o.S        |
|      .o o  . E  |
|       ..  . .   |
|      ..  .      |
|      ++..       |
Are you sure you want to continue connecting (yes/no)? 

Well, dont. Of course its very important to know WHERE you are connecting. In a directed attack the attacker could have set up a server of their own to fool you to reveal important passwords or other information. But most people dont think to much about this and just answers yes to get rid of the message.

The problem is, HOW do you distribute the correct fingerprint and check it? In a datacenter there are many was to do this (configuration orchestration, ldap and so on) but to end users and home computers this is a probem. Of coruse you could post your fingerprints on a webpage secured with https, but the chances a user would really sit down and compare the numbers are slim.

The solution is DNSSEC. When your zone is signed and the chain of trust is complete a client can really trust the correctness of the information present in the DNS tree. Publishing your ssh host key fingerprints here sounds like a great idea. The new record type SSHFP solves this problem and the good news is that OpenSSH have support since a few years back. Its even so simple that ssh-keygen can generate the new records for you:

> ssh-keygen -r IN SSHFP 1 1 d6a64454a9a559ec35f59994c2e5f8376ff86ac8 IN SSHFP 1 2 99d78eff62823561bab2661a72250f1e8344c1c6a4e8903f0d5d8ebce6d819b7 IN SSHFP 2 1 9572024308e542074768bbfd6a3ff8b30e940ce2 IN SSHFP 2 2 ab63e4ebe5ba0b9eb12a9735a533cfdf5e2807bac852e8b019dedfb630841896 IN SSHFP 3 1 fe1160646ac00872d269ebd7ddaa07cb83d7d6af IN SSHFP 3 2 6580debbe37b4a2f32eed78aec2e2f943de6559f24f2b6d7671e78a0ca469728

The first digit represent the key type and the second represent the hash used. You can read more about this in RFC 4255. If your zone is signed by DNSSEC and the chain of trust is complete you will see something like this when connecting to a server with SSHFP records attached to it.

debug1: Server host key: ECDSA 42:f9:b3:40:17:61:89:e4:80:cf:d5:ae:bb:bb:7d:75
debug1: found 6 secure fingerprints in DNS
debug1: matching host key fingerprint found in DNS
debug1: ssh_ecdsa_verify: signature correct

OpenSSH uses two different methods to find out if the records are secured by DNSSEC. If compiled with ldns-support it will perform the DNSSEC-validation itself. If not, it will trust the resolvers in resolv.conf to do the validation. The resolver will set a special bit, the AD-bit (Authenticated Data) if dnssec validates. If the AD-bit is set on the response from the resolver ssh will assume that the records can be trusted.

If you want ssh to always try to use information found in DNS add this to your ~/.ssh/config

Host *
    VerifyHostKeyDNS yes

RFC 4255

WPA2 Enterprise with hostapd

After setting up my wireless FreeBSD router I wanted to secure my wireless network with WPA2 Enterprise.

I’ve had a really hard time finding any good documentation on hostapd, but I finally got it to work. So why would you use WPA2 Enterprise, isnt Personal good enough? Well, the problem is these days that anyone can set up a wireless network with the same name as yours. If you connect to this fake network beliving you are connected to your own someone have full access to everything you send and receive. WPA2 Enterprise fixes this because the access point also has to prove its identity by providing a valid SSL Certificate. If this certificate changes you will be notified right away.

So, how do you set it up in hostapd? Well, its not that complex at all, the problem is that you cant find any documentation on it.


Here is my configuration for WPA2 Enterprise. This uses hostapds own internal RAIDUS-server but you could as well use FreeRADIUS or some other RADIUS server out there, but then you’ll have to figure out how to configure that in hostapd. 😀


wpa_pairwise=TKIP CCMP

# Path for EAP server user database


"peter@domain.tld" PEAP [ver=0]
"peter@domain.tld" MSCHAPV2 "passphrase" [2]

You can also set up it to require client certificate to connect to make it even more “secure”. It all depends on how you handle your certificates and passwords.

#"peter@domain.tld" PEAP [ver=0]
"peter@domain.tld" TLS

I use free host and client certificates from but if you want to set up your own CA you can find and excellent article here
I have found some “documentation” in the form of well commented configurationfiles.

Secure wireless FreeBSD router

One of my hobby projects is to build a “fully fledged” wireless  FreeBSD router. To do this I got a Soekris 6501-50 which has four gigabit ports and two mini PCIe slots.

For storage I have a small 30GB miniPCIe SSD (OCZ-NOCTI). I have two wireless cards installed one dual band 3x3MIMO minipcie card from COMPEX (When FreeBSD gets up to speed with 802.11ac I will upgrade to a WLE900VX) and for legacy 2.4Ghz I use a TPLINK TL-WN781ND. These two cards are then used for two virtual interfaces each, one for my primary wlan and one for my guest wlan.


One important part of the wireless part of the router is the antennas. For a long time I used three consumer antennas (ALLNET ALL19003) for 5GHz use for my COMPEX card, but when I moved to a new apartment and switched to 5GHz I didnt get good speeds everywhere in the apartment. This got me thinking about a ceiling antenna. But I found it very hard to find one in consmer stores, so I turned to Ebay. I found a decently cheap Laird S2451DBT 6port antenna which is now mounted in the ceiling at a central point of the apartment.


To do packet filtering I use the OpenBSD derived pf(4) which has been in FreeBSD for a long time now.

Wireless networks

Like I told you in earlier I have two physical cards and two networks (ssid). One primary and one guest networks with tighter rules but less strict authentication.

The firt step here is to find a card supported by FreeBSD, but also have support for hostap mode, obviously mine does. To get it to run WPA2 Personal on a specific channel the configuration is very easy


Lately I started to use the more secure WPA2 Enterprise and you can read about my configuration here

Other networks

My internet provider is Telia and I have something they call Triple Play.. (Internet, TV and Tele in the same cable). In order to get this to work you should use their Thompson router that has som magic for splitting up your one incoming fiber into three different networks. After some reading on the interwebs I found out this is really just tagged vlans and I can split them myself without any problem. “Internet” comes untagged and the IPTV traffic comes in on tag 845, so I just create a vlan interface with my external interface as parent and then bridge this interface to one of my internal interfaces on the Soekris. (and of coruse connect the IPTV-box to this port). You can read more about this configuration here (swedish)


This is how the interfaces are configured


OpenSSH with ECDSA keys on yubikey/smart card

In one of the latest versions of OpenSSH it is now possible to store ECDSA keys on smart cards. If you managed to use ssh with your RSA keys on the yubikey its fairly simple to go to ECDSA. The only thing you need is a late snapshot of OpenSSH portable and a patch.

# fetch
# tar zxf openssh-SNAP-20151124.tar.gz
# cd openssh 
# fetch "" -o ecdsa.patch
# patch -s < ecdsa.patch
# ./configure
# gmake

Now you should be able to use get public keys from the smart card on your yubikey. Make sure pcscd is running then fetch the key with your newly compiled ssh-keygen.

# ./ssh-keygen -D /usr/local/lib/
C_GetAttributeValue failed: 18
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAJGTLvC9BHSNPAfOw3s4lEix3zKLBKRgZlQ9kSxyttSG8XZ/NIoxm+ZYGbkYxji1kN7brMff21mgXGUzfxp58M=


Running OpenDNSSEC

During the years there have been several vulnerabilities found in the DNS protocol making it possible to fool clients in different ways. Maybe the most well known is called dns cache poisoning. To resolve some of these problems people came up with DNSSEC. DNSSEC is a way to cryptographically prove the authenticity of a DNS response by validating signatures all the way up to the root zone. You can read more about it on wikipedia.

This article is an attempt to describe how to implement DNSSEC on your own authoritative name servers. The first and most important step before you even begin to think about implementing DNSSEC is to find out if your registrar supports publishing DS records in the parent zone. If this is not the case your chain of trust will be broken and dnssec will fail.

OpenDNSSEC uses a PKCS#11 enabled backend to store cryptographic material (Hardware Security Module). These could be very expensive, so they also provide a software version of a HSM. This way you can start using OpenDNSSEC without having to pay thousands of dollars on crypto hardware. I’ve been looking into a quite affordable HSM for my (very small) needs.

We start by installing the software from packages

# pkg install opendnssec
# pkg install softhsm

We start by setting up the SoftHSM. It comes default with this configuration which will work just fine for us.

# SoftHSM configuration file
# Format:
# :
# The given paths are just an indication to SoftHSM on where it should
# store the information for each token.


We then need to initialize the HSM by running

# softhsm --init-token --slot 0 --label "OpenDNSSEC"
The SO PIN must have a length between 4 and 255 characters.
Enter SO PIN: 
The user PIN must have a length between 4 and 255 characters.
Enter user PIN: 
The token has been initialized.

You will later use the SO PIN to reset/reinit the HSM and the user PIN will be used to access your keys.

Now we can start looking at OpenDNSSEC. First make sure that /usr/local/etc/opendnssec/conf.xml looks reasonable (it does for most people). Just make sure the repository section matches information you gave to OpenHSM.

Then we have a quick look at the kasp.xml “Key and Signature Policy”. This file specifies at which intervals you want to renew the cryptographic keys in you setup. You have have two types of keys for every domain you handle within OpenDNSSEC. KSK and ZSK. The KSK is the “Key Signing Key”. If you are familiar with Certificate authorities this is sort of the Root CA. Its the signature this of key you pass upwards to the parent in the chain of trust. The ZSK is the “Zone Signing Key” and its used to sign the Records in the zone. In the CA anology this is a Intermidiate CA. The purpose of using two keys is to give the opportunity to store the KSK more securely (even offline) when its not used. If you store your keys very securley you can extend the lifetime of the KSK without any problems. The lifetime of your KSK defines how often you need to talk to your registrar and publish new fingerprints in the parent zone. OpenDNSSEC will manage ZSK key rollover for you.

Now we can start opendnssec and begin to have some zones signed. First of all we need to create the databases needed

# ods-ksmutil setup
*WARNING* This will erase all data in the database; are you sure? [y/N] y

Then we can start the opendnssec daemons.

# sh /usr/local/etc/rc.d/opendnssec onestart
Starting enforcer...
OpenDNSSEC ods-enforcerd started (version, pid 42305
Starting signer engine...
OpenDNSSEC signer engine version
Engine running.

To have it start at boot put opendnssec_start=”YES” in /etc/rc.conf.

Key management
I run OpenDNSSEC and my DNS-server (nsd) on the same machine so I sign the zones and put them in a folder that nsd can reach. It is also possible to send your zones with zone transfers if you are having a separate machine for OpenDNSSEC. Anyway, this is how you add a new zone to OpenDNSSEC and then tell it to sign it.

# ods-ksmutil zone add --zone --input /usr/local/etc/nsd/chroot/zones/ --output /usr/local/etc/nsd/chroot/zones/signed/
zonelist filename set to /usr/local/etc/opendnssec/zonelist.xml.
Imported zone:
# ods-ksmutil update zonelist
zonelist filename set to /usr/local/etc/opendnssec/zonelist.xml.
kasp filename set to /usr/local/etc/opendnssec/kasp.xml.
Zone found; policy set to default
Notifying enforcer of new database...
# ods-signer sign
Zone scheduled for immediate re-sign.

An here is the before and after:

$TTL 300
@ SOA (
				3H	; Refresh after three hours
				1H	; Retry after one hour
				1W	; Expire after one week
				1D )	; Minimum one day TTL

		MX	10
		MX	20
@		A
		AAAA	2001:470:6c08::1

www		A
		AAAA	2001:470:6c08::1

Signed:	3600	IN	SOA 2015032504 10800 3600 604800 3600	3600	IN	RRSIG	SOA 8 2 3600 20151214230507 20151130173240 26386 iheuqDSSeLdoXJpYOI9ICFSDETnxXbls5K8YnnLBqeQOqgvxNRESWqy1rgAtnReFHnijcMpwly3ttFGUVtd9C4x3dQwMSbgwe9mXY0Tp/ojDdXG0UQLUXHgys0jFen1Go+c3r97lRH8RblIDVu5D5tVynO8+fN9FKzy29ZWfcbc=	3600	IN	DNSKEY	257 3 8 AwEAAdbN+hOWIvhXB/M4R6KUPPALZA+DUcsW/jEl/Q/1BNi2ff9JZECgNi+2sv1nTdZ+6nOchKNP8UoZ41X4d82MQsO+mGIZeXW5Cb0Riqk7+B7EQWd6jH/pXs9/wNBRQHCNGk1NsyHQNgGxdAq3w99oeIaEbiI+4r/fnwjqKpg3boMyWZlNW30XcJMObXu57hO3S6f09I/+r+7d1bH8FbPBI1VWqiDPgQqjMOkJHrroJ3QWNr8qqSJSsxe2Zb9rTmkx6htrS2XQT2v1kvTT3iBO/Vf+JNbSNYOX4BnR5otgwr9I9OteLDFW4NGn5JNm3Q+kvrLAjByGyOsq0hI3TbvXp20= ;{id = 60509 (ksk), size = 2048b}	3600	IN	DNSKEY	256 3 8 AwEAAfNwi9djf7sYUVQpqScBOBMqjFD9GqHeI11Y/62SWINheq8+sQ8H/yN2H3eqmW9+ffBVNU8VTCVcdLOwkPGEF5Q1lE7hIbHGLunCAUo5OC8yFhuEtXNFoYo/EuGGbgUmcgYLNKIu8+RxzL5VO9dV7FTUy60tnCsYi/tKDGBP376p ;{id = 26386 (zsk), size = 1024b}	3600	IN	RRSIG	DNSKEY 8 2 3600 20151214194904 20151130173136 60509 G6+/6njI1NSCvWIeOhyvFo/+v1uSSFRx2Art3bv7Gw2nSJA2aMiu1ZVaIw7uGf75xdWr6lSj6ndb61UmTl+N6ccdbTU80HxwPmBA/fVZpGIAJrQ8psLgx8uDY3AxCfZdEq3YM0JzPewLnKGUaoVFsTzoWNNw2NRYqUuRiBnlebibcci70vaI0QpyRlXfSJ4DWls3H0isk0BWdukcpYEKNx4hl6GsRDCpNRoNs27TXgHnAcv7YV1528gyrgbw63DT6yyyL49nlN+TEV5aiDlNsjnkYJqgy869xfMROAw0VScHderqnixW4LlAGX0QYuPuOoK2dPx874i7xH7JhOoTbQ==	0	IN	NSEC3PARAM	1 0 5 c2d153cf47fb60fa	0	IN	RRSIG	NSEC3PARAM 8 2 0 20151214120059 20151130173136 26386 DlSk0ye1kcP7g0z6QJy0QYpB75ZPpWhbypyRJ3a+L0BaL4cY/cdRS9SACxmhXu/kEkrmadJ/IcfDMhMHOj9D0uY+8ksbKfVhpAX237sFp18V8rsH0zkOPjMjD1O4c30N+isLVdnaPX3OyIRxqRFrRL2XH4kMOR9c8uBpBtin/MU=	300	IN	NS	300	IN	NS	300	IN	RRSIG	NS 8 2 300 20151214130253 20151130173136 26386 X9V2dv2+tyWoom6SC5zwkgkMj0buTu/wvGO/ClE7KveJ3YwmG/kPH0z37sS6GWK+j1MzNTzDepcUdxxghO/shDZvSz/7WAtvuHVPWfo2lg+iGG7nxCmYqcmq7Vo2+GZCU5TRjivsCDxen9w+e8+AuZtpuTkEppTQMbEIq+qNGyw=	300	IN	MX	10	300	IN	MX	20	300	IN	RRSIG	MX 8 2 300 20151215000707 20151130173136 26386 Yw1eRGRESXu1bGh/RNhqJNFpjv+MsDzoyxoPOTNTZiBr+OmlCq6p8M6QgfEPIipmg0VzrHJjzEFfpb4WQmPTKKehH/nEoevKLAogPjbozucr+lgjAXh3AoXr15OYF9dyJilyuTLQ3TyyWDAOxSHtnHy5w704ibaIyGoeKniTf3k=	300	IN	A	300	IN	RRSIG	A 8 2 300 20151214104407 20151130173136 26386 zmVjO5Rh1R+lpIUdIvsyTCmhGt2qL1wHUIOlZJbBkiiVpdE051MhRTShRjU79LQ5a+SlBeE5jjVeRrAXhTAb6KhNzZ5j5JaTjPYXzqxe//ddpMYEDzGhmuO1zkfUjtKCFhxgk92lFqimHXJFTj3nXdgbmqvK1io7aqYWCRvKxt4=	300	IN	AAAA	2001:470:6c08::1	300	IN	RRSIG	AAAA 8 2 300 20151214075539 20151130173136 26386 ymUD9mz9uQ6on0SF8TSFbb5xU100mJZuZeJafub1YkeolsxmcyXP0HQl0c20QFHWWp7qX4L7rY7QKIgc9aeaMkskrT9BEmwFoTB/MMu9nrweZyyAUdnnrD06mJ6BumBM0ZWBt6qHLe4tiPh8YVqCCjhFBo+SUvDOfelg3k/QAkY=	3600	IN	NSEC3	1 0 5 c2d153cf47fb60fa  h0gt9jkpqemi2oumlejri2lvo60uc2qt A NS SOA MX AAAA RRSIG DNSKEY NSEC3PARAM	3600	IN	RRSIG	NSEC3 8 3 3600 20151214151238 20151130173240 26386 6iNFSodcFOSydizrXrduzAsTPkZB+wqqr0IrdqEL+YcoM1aefmHfX3l5Kems01KCihozii5O23oprGXw0niYk4ESvXjYH0pOK/J6KWes9PirDQj0P8w//FiX9I7jYL4YkfAqf+pKU1vx2mVDT5ATD2Dkty4GX7eKg4h7qDvgSUM=	300	IN	A	300	IN	RRSIG	A 8 3 300 20151214080233 20151130173136 26386 TqG3vzzO3vIPVLZpWHh5Sh6ijNBr61u+7jEMlpl/kfj7S5wvmMgUkWl+hmNaokgrDvrEahpCdTQ0yjSmWl+m5aVFlV17x0x5lJN+Fcx+SuOqqdkHkYKDyTShWdyfDRj9rAQxThbrhvOz3+6gfTJ1HMeGBXIkLMzf1MEojHDlhEg=	300	IN	AAAA	2001:470:6c08::1	300	IN	RRSIG	AAAA 8 3 300 20151214134021 20151130173136 26386 reaA1ca5Jly76YPU+Nfq6CEwgqx7/T2xYh7IzfJ4aZ034vF7djYJFvNMvKMF5wuX7hbP44B3lQk/mnYlzmuVsKGYIwNvU+4+ggIsahgdCItasFOLdJln3oY7f+ch/o6XljE9JKusWFYT2GcPLCsr73PcEIF3QkdXDgXZzSDuZBc=	3600	IN	NSEC3	1 0 5 c2d153cf47fb60fa  rl1jo83jomo43daiudaavkfofbmtkks2 A AAAA RRSIG	3600	IN	RRSIG	NSEC3 8 3 3600 20151215051041 20151130173240 26386 lbAGEJm+kCHy68wZ9YqbAFuESnabPvL5TwA0MnwtliUa+lB5DEI2/DIPa+QS7sekjWUxmve2FQoQC+0gFbCP9gOFle8bTwZsAf7ZtZJeVuzEI/HcisNbJk5bV/E/p6xyIBwUDKbcdPh1vhmyDXkhSOZ0o16vLbPgZwuBKtk8J2s=

To handle your created keys you can use ods-ksmutil

# ods-ksmutil key list --verbose
SQLite database set to: /usr/local/var/opendnssec/kasp.db
Zone:                           Keytype:      State:    Date of next transition (to):  Size:   Algorithm:  CKA_ID:                           Repository:                       Keytag:                    KSK           publish   2015-12-01 09:31:35 (ready)    2048    8           adcfe72699de3bb9afe511d67a112580  SoftHSM                           60509                    ZSK           active    2016-02-28 19:31:35 (retire)   1024    8           fcf02532b68b64f7f0dbccf85be3677f  SoftHSM                           26386

Now you need to publish a fingerprint of you key in the parent zone. Please refer to your registrar on how to do this. In sweden at least .SE, binero and loopia have support for this. To get the DS record you can use:

ods-ksmutil key export --ds --zone
;active KSK DS record (SHA1):	3600	IN	DS	65041 8 1 766dee3e0d5cac1c19529d4474eb828d72a91d24
;active KSK DS record (SHA256):	3600	IN	DS	65041 8 2 a5aba22e70dcc7ad0ee9d31210f87b4f8e99bf6222463eb9c53f3d7a46143129

This is the information you need to send to your registrar. When you can see the DS-record in the parent zone

# drill DS
;; ->>HEADER<

it is time to tell OpenDNSSEC that the keys are in place and its time to mark the KSK as active.

# ods-ksmutil key ds-seen --zone --keytag 60509

Now you are up and running, and if all goes well it will work just fine for one year, until you will need to change the DS records present at the tld. Please refer to the OpenDNSSEC documentation for more information.