# CFSSL: Cloudflare's PKI and TLS Toolkit for Signing, Verifying and Bundling Certificates

> CFSSL is a Go command line tool and HTTP API server for signing, verifying and bundling TLS certificates, plus a multirootca server for multiple signing keys. It fits engineers who want a scriptable CA without a web UI, and it asks for Go 1.20+ to build.

**cloudflare/cfssl** — CFSSL: Cloudflare's PKI and TLS toolkit

- Repository: https://github.com/cloudflare/cfssl
- Website: https://cfssl.org/
- Stars: 9,478 · Forks: 1,148
- Language: Go
- License: BSD-2-Clause
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/cloudflare-cfssl

## What CFSSL actually does, and who ends up using it

CFSSL is Cloudflare's PKI and TLS toolkit, distributed as a Go module at github.com/cloudflare/cfssl. The README describes it as both a command line tool and an HTTP API server for signing, verifying and bundling TLS certificates. That sentence is the whole product: it is not a certificate management platform with users, roles and a dashboard, it is a set of programs you drive from scripts or from your own code.

The repository ships several binaries, and the split tells you what the authors expect. cfssl is the canonical CLI. cfssljson converts the JSON that cfssl and multirootca print into actual PEM files on disk. multirootca is a certificate authority server that can hold multiple signing keys. mkbundle builds certificate pool bundles. The README also notes a set of Go packages intended for building custom TLS PKI tools, so a team can import the signing logic instead of shelling out to a binary.

Who is this for? Infrastructure engineers who already run a CA and want to automate issuance from a pipeline, and teams that need an internal signing service reachable over HTTP. Someone who just wants a certificate for a website is not the audience; the tool assumes you understand CAs, CSRs and SANs before you start.

## The command surface: sign, bundle, genkey, gencert, serve

The cfssl binary dispatches on a subcommand: sign, bundle, genkey, gencert, serve, version, selfsign and print-defaults. That is a small surface, and the README documents each one at roughly the level of a man page.

Signing takes a CSR and a CA. The README gives the flags as `cfssl sign [-ca cert] [-ca-key key] [-hostname comma,separated,hostnames] csr [subject]`. By default the CA certificate and key are read from ca.pem and ca_key.pem, so a script that runs cfssl from a directory containing those two files needs no flags at all. The -hostname flag overrides the DNS names and IP addresses in the SAN extension, which is useful when a CSR was generated with the wrong names but you do not want to regenerate the key.

Bundling is the other half. `cfssl bundle` takes a CA bundle, an intermediate bundle, a metadata file and a flavor, then a certificate or a domain. The three flavors are named optimal, ubiquitous and force. Optimal targets the shortest chain with the most advanced algorithms; ubiquitous targets the widest acceptance across browsers and operating systems; force looks for a bundle identical to the input. That is a real design choice rather than a cosmetic flag, because the two goals pull in opposite directions, and the README does not tell you which to pick for a given audience.

## Building and installing CFSSL from source

The README requires a working Go 1.20+ installation. It also warns that some Linux distributions strip certain algorithms, naming RHEL-based distributions in particular, and says the golang from the official repositories will not work; those users should install Go manually. This is the kind of detail that saves an afternoon, and it is stated plainly rather than buried.

The simplest install path is the go install command from the README, which downloads, builds and installs all the utility programs at once:

```bash
go install github.com/cloudflare/cfssl/cmd/...@latest
```

After that, cfssl, cfssljson and mkbundle should be on your PATH. The README also points to prebuilt binaries on the GitHub releases page, which is the route to take if you do not want a Go toolchain on the machine.

If you prefer to build from a clone, the README gives these steps, and the Makefile builds each binary from ./cmd/<name> into the bin directory:

```bash
git clone git@github.com:cloudflare/cfssl.git
cd cfssl
make
make install
```

The README shows `tree bin` producing cfssl, cfssl-bundle, cfssl-certinfo, cfssl-newkey, cfssl-scan, cfssljson, mkbundle and multirootca. If a name is missing from that listing after your build, the corresponding cmd/ directory did not compile.

A first real use is generating a key and a certificate request from a JSON spec:

```bash
cfssl genkey csr.json
```

The README does not show the contents of csr.json in the section it gives for this command, so check the doc/ directory and the testdata/ directory in the repository for working examples before you write your own.

## Signing a CSR and reading the JSON with cfssljson

The signing example in the README assumes a CA whose certificate is at /etc/ssl/certs/cfssl.pem and whose key is at /etc/ssl/private/cfssl_key.pem, and a CSR named cloudflare.pem:

```bash
cfssl sign -ca     /etc/ssl/certs/cfssl.pem       \
           -ca-key /etc/ssl/private/cfssl_key.pem \
           -hostname cloudflare.com               \
           ./cloudflare.pem
```

Note that the CSR file in the example is called cloudflare.pem, which is misleading naming on the README's part; the argument is a certificate request, not a certificate. The output is JSON, which is where cfssljson comes in. The README says cfssljson takes the JSON output from cfssl and multirootca and writes certificates, keys, CSRs and bundles to disk. Piping the two together is the normal pattern.

You can also override the subject rather than trusting the CSR. The README shows a JSON subject file with a CN field and a names array carrying C, L, O, OU and ST keys. Passing that file as the optional subject argument replaces the subject information from the CSR. The README adds a caveat worth knowing: as of Go 1.7, self-signed certificates will not include the AKI extension, and it links to the Go commit that changed this. If a downstream verifier insists on an AKI, self-signed output from this tool will not satisfy it.

## The HTTP API server and the multirootca split

`cfssl serve` starts the API server, and the Dockerfile exposes port 8888 with cfssl as the entrypoint and `--help` as the default command. The README lists serve as a subcommand but does not document the API routes in the sections reproduced here, so treat the endpoint surface as something to read from the api/ directory and the doc/ directory rather than from the README.

multirootca is the more interesting piece. The README describes it as a certificate authority server that can use multiple signing keys. That is the shape you want when different parts of an organization need separate signing keys but a single issuance endpoint, or when you are rotating a CA and need both keys live during the overlap. It is a separate binary from cfssl serve, not a mode of it, which means two deployment artifacts to build and monitor.

The Dockerfile builds from golang:1.20, clones cloudflare/cfssl_trust into /etc/cfssl, runs make clean and make all, and copies the binaries into /usr/bin. That clone is what supplies the root and intermediate bundles and the platform metadata that `cfssl bundle` expects, so a container built from this Dockerfile has bundling data available at /etc/cfssl without extra setup. A build that skips the clone will leave bundle operations without their default inputs.

## Where CFSSL gets in your way

The release cadence is the first thing to weigh. The most recent release listed is v1.6.5 from 2024-03-05, preceded by v1.6.4 in 2023-04-10 and v1.6.3 in 2022-10-04. The default branch saw a push on 2026-04-24, so work continues between tags, but if you pin to a release you are pinning to something from March 2024. The repository is not archived, and the CHANGELOG file at the top level is where the changes between tags are recorded.

cgo is the second constraint. The README says cfssl requires cgo, and cgo requires a working compiler toolchain for the target platform. Cross compilation therefore needs more than setting GOOS and GOARCH, which the README states directly. Static, dependency-free binaries are not what this produces.

There is no UI. The README describes a CLI, an API server and supporting binaries, and nothing else. If your operators expect a web console for issuing and revoking certificates, CFSSL will not provide one, and the repository has no frontend entry in its top-level layout.

Finally, there is no ACME story in the README. Nothing in the documented command list speaks the ACME protocol, so if you need automated issuance from a client that only knows ACME, this is the wrong tool and you should not try to bolt it on.

## CFSSL compared with OpenSSL and with Smallstep

The comparison people reach for first is cfssl vs openssl. The difference is shape, not cryptography. OpenSSL is a general cryptography toolkit whose command line grew organically over decades; CFSSL is a purpose-built CA tool whose subcommands map to certificate lifecycle operations and whose default output is JSON designed to be piped into cfssljson. If your workflow is a shell script that signs CSRs and writes PEM files, CFSSL's JSON-in, JSON-out convention is easier to compose than parsing OpenSSL text output. If you need anything outside certificate signing and bundling, OpenSSL covers far more ground and CFSSL does not try to.

The other comparison is cfssl vs smallstep, also searched as cfssl vs step ca. Smallstep's step-ca is an ACME-capable CA server, which is the capability CFSSL's README does not describe. The trade-off runs the other way too: CFSSL ships multirootca for multiple signing keys and mkbundle for building certificate pools from platform metadata, and it exposes the signing packages as a Go library. Choose CFSSL when the CA is one component inside a larger Go or scripted system and you want to embed or drive it. Choose an ACME-based CA when the clients are the ones asking for certificates and you never want to touch their configuration.

## Conclusion

Adopt CFSSL if you need a scriptable CA, an HTTP signing API, or a multirootca setup with several signing keys, and you are comfortable building Go 1.20+ software yourself. Do not adopt it if you want a browser UI, a packaged service with a documented upgrade path, or ACME issuance, none of which the README describes. Verify first that your target platform can build cgo, since the README says cfssl requires it, and check the CHANGELOG for the changes between v1.6.5 and master before you pin a version.

## FAQ

### How do I install CFSSL?

The README gives two routes: run go install github.com/cloudflare/cfssl/cmd/...@latest with a working Go 1.20+ installation, or download the prebuilt binaries from the GitHub releases page. Building from a clone uses make and make install, which places the binaries in the bin folder.

### How do I install CFSSL on Ubuntu?

The README does not give distribution-specific instructions. It warns that some Linux distributions remove certain algorithms, naming RHEL-based distributions, and says the golang from the official repositories will not work, so install Go manually and then use go install or the prebuilt release binaries.

### How do I install CFSSL on Windows?

The README does not document a Windows install path. It notes that cfssl requires cgo and that cgo needs a working compiler toolchain for the target platform, and that cross compilation is done by setting GOOS and GOARCH. Prebuilt binaries are available from the releases page.

### How does CFSSL compare with Smallstep or step-ca?

The README does not mention Smallstep or ACME. What it documents is a CLI and HTTP API server for signing, verifying and bundling certificates, plus multirootca for multiple signing keys and mkbundle for certificate pools. If you need ACME issuance, that capability is not described in the README.

### Does CFSSL support subject alternative names?

Yes. The sign command takes a -hostname flag described as a comma separated hostname list that overrides the DNS names and IP address in the certificate SAN extension.

## Sources

- [cloudflare/cfssl on GitHub](https://github.com/cloudflare/cfssl)
- [License: BSD-2-Clause](https://github.com/cloudflare/cfssl/blob/master/LICENSE)
- [Project website](https://cfssl.org/)
- [README](https://github.com/cloudflare/cfssl/blob/master/README.md)
- [Releases](https://github.com/cloudflare/cfssl/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cloudflare-cfssl
