Make network encryption
your business as usual

Scalable, open source X.509 certificate management is an open source project that makes managing and deploying X.509 certificates easy and scalable

Release 1 is here!

We are excited to announce the first alpha release of

Release 1 allows you to work in the offline mode, creating CAs and certificates with ease. While already useful, we advise against using this release in production. We are now working on Release 2, which will allow you to remotely generate keys on the servers over SSH. For more on future releases, see the Roadmap.

Protecting your internal traffic is essential, whether for compliance or simply following security best practices. With you can easily manage certificates for internal infrastructure traffic, SSL and IPSec VPN connections, intranet and operations services, as well as implementing X.509 mutual authentication.

What about Let's Encrypt?

Although there is some overlap, at the moment the two projects are focused on different things.

Let's Encrypt is currently being built to enable Internet-wide encryption of web traffic. They will be running a public CA and most people will automatically rollout domain validated certificates from that CA. Having said that, the ACME protocol can be extended for other purposes. is primarily aimed at infrastructure TLS, for example encrypting between an application server and a database server. You run one or more internal CAs specific to your organisation. It being designed to be an all-in-one tool and runs an admin-centric security model to Let's Encrypt, one that allows us to scale from a single admin operating purely from their workstation, all the way to multiple admin teams managing hundreds or thousands of servers provisioned automatically with the help of a central API service.


This is an alpha release, so please take note of the following:

  • The code has not been audited yet
  • It probably contains security flaws
  • Offline mode only
  • The code is also ugly and undocumented
  • Test coverage is poor
  • There are bugs
  • Important features are missing
  • Documentation is minimal
  • Documented threat modelling only just begun
  • No signed packages yet


Improve security

Deploy TLS by reusing existing trust relationships.

[[email protected] my-org]$ pairing-key new --tags web,database
Loading admin app
Loading admin entity
Loading org entity
Creating the key
Saving key to index
Pairing ID: 70ddaa68f47de74fe04f308ada6c8db1
Pairing key: 4eb44b2911fcbb7a40ba2d012c0bfaaf

Save time

Fast and easy to use thanks to sensible defaults, minimal configuration options and an intuitive command line interface.

[[email protected] ~]$ help ca
Manages Certificate Authorities

Usage: ca [--help] ca new <name> --tags <tags> [--ca-expiry <days>] [--cert-expiry <days>] \
      [--dn-l <locality>] [--dn-st <state>] [--dn-o <org>] [--dn-ou <orgUnit>] \
      [--dn-c <country>] [--dn-street <street>] [--dn-postal <postalCode>] ca list ca delete <name> --confirm-delete <reason>

Keep growing

Scales with you, from one server to thousands, from startups to enterprises.

[[email protected] my-org]$ node cert --name web01 --tags web \
    --export - | ssh web01 'mkdir && tar zxvf - -C'
Loading admin app
Loading admin entity
Loading org entity
Loading node app
Loading node index
Getting certs for tag: web

Works with...

... and anything else that uses X.509 certificates

How it works

(Version 1.0 when released)

Install the agent on your servers. Use tags to identify running services.

Create as many CAs as you need, for example one for each tagged service.

Automatically sign and distribute certificates to your servers.

What it covers brings together X.509 certificate management, configuration management and security to give you as much simplicity or flexibilty as you need.

Server compromised?

Revoke the server! This automatically regenerates any affected CAs, which will automatically generate new certificates for all other related servers, which are automatically deployed to those servers. No need to rely on CRLs or OCSP.

For more details, see the Architecture page.

Getting started


In this example, we're going to install the pre-built binary for Linux. You can download distro packages and binaries for other platforms from the Downloads section.

[[email protected] ~]$ curl -sL -O
[[email protected] ~]$ curl -sL -O
[[email protected] ~]$ sha256sum -c pki.io_0.1.3-release1_linux_amd64.tar.gz-sha256sum
[[email protected] ~]$ sudo tar zxvf pki.io_0.1.3-release1_linux_amd64.tar.gz -C /opt/
[[email protected] ~]$ sudo ln -s /opt/ /usr/local/bin/

Create an organisation organises everything by Organisation, referred to here as Org. You might have an Org for your whole organisation, or different independent teams might manage their own Orgs. All commands are run inside an Org directory, so lets create an one.

[[email protected] ~]$ init my-org
Creating Admin entity
Generating admin keys
Creating Org entity
Generating Org keys
Saving local admin
Saving public admin
Creating org index
Saving org public entity to home
[[email protected] ~]$ cd my-org/
[[email protected] my-org]$ 

CA and standalone certificates

As is designed to manage X.509 infrastructure, we obviously need to be able to create Certificate Authorities (CAs). We also need to be able to create certificates, which can be done in one of two ways. Firstly, we can create standalone certificates that aren't attached to any particular server or machine. Once these are created they aren't tracked by the system. The other way to create certificates is to create a node which will generate Certificate Signing Requests to be signed by a CA.

First, lets create a CA.

[[email protected] my-org]$ ca new web-root --tags web \
    --dn-o --dn-ou webops
Loading admin app
Loading admin entity
Loading org entity
Saving CA
Updating index

We called the CA web-root, tagged it with web and gave a Distinguished Name organisation and organisational unit.

Now we can create a standalone certificate.

[[email protected] my-org]$ cert new test-web-1 --expiry 60 --ca web-root \
    --dn-o --dn-ou web-test --export test1.tar.gz
Loading admin app
Loading admin entity
Loading org entity
Export to 'test1.tar.gz'

We called the certificate test-web-1, so that is what the Common Name will be set to. We set an expiry of 60 days instead of the default 90 days. We then specified the CA that should sign it. We also specified DN values, but we set a different organisational unit than we did for the CA. Here we used web-test, whereas the CA is webops. Finally, as standalone certs aren't tracked, they must be exported.

We can now see what files we've got by looking at the exported file.

[[email protected] my-org]$ tar -tzf test1.tar.gz

We can extract the certificate to stdout, and pass it straight to openssl to take a look.

[[email protected] my-org]$ tar -zxOf test1.tar.gz test-web-1-cert.pem | \
    openssl x509 -noout -subject -issuer -startdate -enddate
subject= /
issuer= /
notBefore=Apr  6 08:18:37 2015 GMT
notAfter=Jun  5 08:18:37 2015 GMT

As you can see, the subject includes the DN elements specified, which differ slightly from the CA.

Node over SSH

You will eventually be able to run as service with agents running on servers etc, referred to as nodes. In the meantime, supports an offline mode that tracks nodes and certificates and lets you export files. You can then distribute these files yourself. This is also useful for platforms that cannot run an agent, for example resource limited embedded systems.

Before we can create a node, we need to create a pairing key, which allow nodes to auto-register within a defined scope. We will associate it with the web tag, which means in our case that it will be associated with the web-root CA.

Creating a node in the offline mode follows the same flow as it does when running a full API service.

[[email protected] my-org]$ pairing-key new --tags web
Loading admin app
Loading admin entity
Loading org entity
Creating the key
Saving key to index
Pairing ID: 70ddaa68f47de74fe04f308ada6c8db1
Pairing key: 4eb44b2911fcbb7a40ba2d012c0bfaaf

The pairing key must be kept secret, so it should be distributed over an existing trusted channel. Because we're working in the offline mode, we don't need to distribute it, but we do need to refer to it when creating the node.

[[email protected] my-org]$ node new web01 --pairing-id 70ddaa68f47de74fe04f308ada6c8db1 \
    --pairing-key 4eb44b2911fcbb7a40ba2d012c0bfaaf
Loading admin app
Loading admin entity
Loading org entity
Creating new node
Generating node keys
Encrypting node for org
Pushing container to org
Switching to node context
Creating node index
Creating node config
Creating CSRs
Generating CSRs

We've created a node called web01 using the pairing id and key. The node generates encryption and signing keys, then pre-generates a batch of CSRs.

At this point, the node has just created itself, but the Org doesn't know anything about it. We need the Org to get the node registration, verify it and sign CSRs.

[[email protected] my-org]$ org run
Loading admin app
Loading admin entity
Loading org entity
Registering nodes
Found 1 nodes to register
Reading pairing key: 70ddaa68f47de74fe04f308ada6c8db1
Verifying and decrypting node registration
Adding node to index
Encrypting and signing node for Org
Looking for CAs for tag web
Found CA 113162238499713286037804545916553267629
Getting CSR for node
Setting CSR name from node
Getting CA
Creating certificate
Tagging cert
Signing cert
Pushing certificate to node
Found 0 nodes to register

The Org has seen the node registration and has processed it. Because the node used a pairing key associated with the web tag, the Org has signed one of the CSRs with the web-root CA.

Now the node needs to get a copy of the certificate that the Org created for it. Because we're in the offline mode, we have to specify which node we would like to run the command for.

[[email protected] my-org]$ node run --name web01
Loading admin app
Loading admin entity
Loading org entity
Loading node app
Loading node index
Processing certs
Found 1 certs to process
Found 0 certs to process
Saving node index

The node has now processed the certificate, so we can take a look at it.

[[email protected] my-org]$ node cert --name web01 --tags web --export - | \
    tar -zxOf - web01-cert.pem | openssl x509 -noout -subject -issuer -startdate -enddate
Loading admin app
Loading admin entity
Loading org entity
Loading node app
Loading node index
Getting certs for tag: web
subject= /
issuer= /
notBefore=Apr  6 08:20:48 2015 GMT
notAfter=Jul  5 08:20:48 2015 GMT

Once again, we specify the name of the node we're working with. We also provide the tag web to limit the certificates we want to export. You can see a list of tags for the node using the node show command.

You will also notice that the DN organisation and organisational unit for the certificate are the same as the CA's, and that the CN is the name of the node. This is because automatically scopes the DN to the CA, which prevents the node from choosing an arbitrary certificate subject.

Finally, we can export the certificate and pipe it straight to an SSH connection to the node where we extract the files.

[[email protected] my-org]$ node cert --name web01 --tags web \
    --export - | ssh web01 'mkdir && tar zxvf - -C'
Loading admin app
Loading admin entity
Loading org entity
Loading node app
Loading node index
Getting certs for tag: web

Downloads is available as source code, pre-built binaries and as packages for various platforms. It has been tested on Debian, CentOS, OS X and FreeBSD.

Mac OS X 64-bit

Linux 64-bit

FreeBSD 64-bit

Checksums and all other release files are available on GitHub, as is the source code.

Development release

The latest development release is also on GitHub. This includes new features that will eventually become part of the next release.

Linux package installation

[[email protected] ~]$ curl -sL -O
[[email protected] ~]$ curl -sL -O
[[email protected] ~]$ sha256sum -c pki.io_0.1.3-release1_amd64.deb-sha256sum
./pki.io_0.1.3-release1_amd64.deb: OK
[[email protected] ~]$ sudo dpkg -i pki.io_0.1.3-release1_amd64.deb
[[email protected] ~]$ sudo ln -s /opt/ /usr/local/bin/

Use rpm -i for the RPM.

Linux tar.gz installation

[[email protected] ~]$ curl -sL -O
[[email protected] ~]$ curl -sL -O
[[email protected] ~]$ sha256sum -c pki.io_0.1.3-release1_linux_amd64.tar.gz-sha256sum
./pki.io_0.1.3-release1_linux_amd64.tar.gz: OK
[[email protected] ~]$ sudo tar zxvf pki.io_0.1.3-release1_linux_amd64.tar.gz -C /opt/
[[email protected] ~]$ sudo ln -s /opt/ /usr/local/bin/

No sudo? tar into your home directory instead.

Other tar.gz installation

[[email protected] ~]$ curl -sL -O
[[email protected] ~]$ curl -sL -O
[[email protected] ~]$ sha256sum -c pki.io_0.1.3-release1_darwin_amd64.tar.gz-sha256sum
./pki.io_0.1.3-release1_darwin_amd64.tar.gz: OK
[[email protected] ~]$ sudo tar zxvf pki.io_0.1.3-release1_darwin_amd64.tar.gz -C /usr/local/
[[email protected] ~]$ sudo ln -s /usr/local/ /usr/local/bin/

Applies to OS X and FreeBSD.


Further documentation can be found on GitHub.

Guides available include:



  • Admins are trusted
  • Re-uses existing trusted platforms and relationships
  • API service for availability only, admins hold the keys to the kingdom
  • Encrypt-then-MAC used for all secured data
  • Group encryption with random AES key encrypted with each admin public key
  • NIST P-256 ECIES and ECDSA by default, 2048 bit RSA alternative
  • AES 256 for symmetric
  • SHA-256 used for hashing where required
  • PBKDF2 used for key expansion
  • Secure PRNG
  • 128 bit random shared keys

Disclosure policy

Threat modelling

We have started threat modelling, but this is also far from complete. For traditional component modelling we are using Elevation of Privilege and STRIDE. The model is available here.

We are also experimenting with a code-level threat specification language to bridge the gap between model and code.

A typical threat spec looks something like this:

// ThreatSpec TMv0.1 for ExpandKey
// Mitigates cryptography against Use of Password Hash With Insufficient Computational Effort (CWE-916) with PBKDF2 provided by standard package
// Mitigates cryptography against Use of a One-Way Hash without a Salt (CWE-759) with salt create by function
// Mitigates cryptography against Use of a One-Way Hash with a Predictable Salt (CWE-760) with salt created with good PRNG

// ExpandKey is an opinionated helper function to cryptographically expand a key using a 128 bit salt and PBKDF2.
// If the salt is of 0 length, it generates a new salt, and returns the expanded key and salt as byte arrays.
// A salt should only be provided as part of a decryption or verification process. When using ExpandKey to create a new key, let ExpandKey generate the salt. This is to lessen the risk of a weak or non-unique salt being used.
func ExpandKey(key, salt []byte) ([]byte, []byte, error) {

The generated report can be found here: ThreatSpec-TMv0.1

Other documents

Other security related documentation can be found on the wiki.