Pika PKI is a PKI management Text User Interface (TUI). It's built using gum, which is a dependency. Non gum-TUI interfaces are exposed via CLI options.
More screengrabs: Intermediate CA | Signing CA | Creating a Certificate | Saving a Certificate
- Gum
- OpenSSL
- ncurses
- grep
- sed
- tree
Or, just Docker/Podman.
- Install gum and above other dependencies.
- Clone this repo
git clone https://github.com/kenmoini/pika-pki
- Enter the directory
cd pika-pki
- Run
./pika-pki.sh
- ???????
- PROFIT!!!!!!1
# Create a directory to store the PKI assets
mkdir pika-pki
# Run the container???
podman run --rm -it -v ./pika-pki:/data:Z quay.io/kenmoini/pika-pki:latest
- You can create and manage any number of Root Certificate Authorities
- There can be any number of Intermediate CAs under a Root CA or other Intermediate CAs
- Signing CAs denote the last CA in the chain - it cannot sign Certificates for a subordinate CA
- Any CA along the chain can sign Certificates of any sort, but it's best to leave that to a Signing CA at the end of the chain
- The Workspace directory stores all the assets for the PKI - in that directory structure you will find a
public_bundles
folder with a set of subdirectories calledcerts
andcrls
. This is where public Certificates like CA Certificates and CRLs will be stored. You should be able to copy or symlink the path to where a web server can host those assets. - There is another directory called
private_bundles
in the Workspace directory - this is meant as an easily accessible place to store your Saved Certificates.
- Launch the Pika PKI Text User Interface (TUI)
- You will be prompted to create a Root Certificate Authority for new workspaces
- While you could start creating Certificates and signing them with the Root CA, it's ideal to create an Intermediate CA, or at least a Signing CA. Create an Intermediate CA under the Root CA.
- Continue to create a Signing CA under the Intermediate CA.
- Create a new Certificate, type of Server - give it any FQDN you want.
- With a new Certificate created you can do a number of different things:
- Save the Certificate & Key to a path
- Recreate the Certificate - create a new key, CSR, and Certificate while revoking/deleting the old ones
- Rotate the Certificate - request a new signed Certificate with the existing CSR
- Revoke the Certificate (if the CA has a CRL)
- Delete the Certificate (if the CA does not have a CRL)
Additional Advanced Usage options are available as detailed below.
To override some default behavior you can override some parameters via Environmental Variables.
Variable | Default | Note |
---|---|---|
PIKA_PKI_DIR | $(pwd)/.pika-pki |
Workspace directory - where PKI assets are stored |
PIKA_PKI_DEFAULT_ORG | "" |
Will provide a default answer for the questions asking for an Organization |
PIKA_PKI_DEFAULT_ORGUNIT | "" |
Will provide a default answer for the questions asking for an Organization Unit |
PIKA_PKI_DEFAULT_COUNTRY | "" |
Will provide a default answer for the questions asking for a Country |
PIKA_PKI_DEFAULT_STATE | "" |
Will provide a default answer for the questions asking for a State |
PIKA_PKI_DEFAULT_LOCALITY | "" |
Will provide a default answer for the questions asking for a Locaity |
PIKA_PKI_DEFAULT_EMAIL | "" |
Will provide a default answer for the questions asking for an email address |
PIKA_PKI_DEFAULT_CA_URI_BASE | "" |
Will provide a default answer for the questions asking for a base URI for hosted Certificates & CRLs |
PIKA_PKI_CERT_KEY_ENCRYPTION | "false" |
By default non-CA leaf certificates do not encrypt their private keys - set to true to password encrypt certificate keys |
An example of using these environmental variables to make PKI creation simple with default answers would be something like this:
# Do this once per shell terminal
export PIKA_PKI_DEFAULT_ORG="Kemo Labs"
export PIKA_PKI_DEFAULT_ORGUNIT="InfoSec"
export PIKA_PKI_DEFAULT_COUNTRY="US"
export PIKA_PKI_DEFAULT_STATE="North Carolina"
export PIKA_PKI_DEFAULT_LOCALITY="Raleigh"
export PIKA_PKI_DEFAULT_EMAIL="ken@Kenmoini.com"
export PIKA_PKI_DEFAULT_CA_URI_BASE="http://pki.kemo.network/pub"
# Now run Pika PKI
./pika-pki.sh
When serving your PKI, you'll often need to distribute things such as CA Certificates and CRLs. After starting Pika PKI, there will be a few directories created - one being public_bundles/{certs,crls}
.
By starting Pika PKI with ./pika-pki.sh -m copyBundles
, the application will copy the public bundles of all managed Certificate Authorities to that directory which can then be served easily with a web server of choice. Public bundles include things such as each Certificate Authority's Certificate, CA Chain - with and without root in a full-chain - and Certificate Revocation List (CRL).
Whenever rotating a CRL, the public bundle of that CRL's CA will also be freshly copied to update the CRL file.
The file format when copied is ${CA_TYPE}-ca.{$CA_CN_SLUG}.{cert.der|cert.pem|crl}
where $CA_TYPE
can be root
, intermediate
, or signing
.
The value for $CA_CN_SLUG
comes from a "slugified" (alpha-num only, space/other characters replaced with a dash) value of the Certificate Authority's Common Name. This value is also represented in the CA's folder name along the path, eg kemo-intermediate-ca
in roots/kemo-root-ca/intermediate-ca/kemo-intermediate-ca
.
The generation of these Public Bundle assets means you can serve them from a web server for easy distribution of your PKI chain and CRLs. An example of this would be with something like with Podman to serve it via an Nginx server:
# Start the nginx container
podman run -it --rm -d -p 8085:80 \
-v .pika-pki/public_bundles:/usr/share/nginx/html:Z \
docker.io/nginx
# or - Start the nginx container with directory listing enabled
echo 'server {listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; autoindex on; autoindex_exact_size off; }}' > nginx-default.conf
podman run -it --rm -d -p 8085:80 \
-v .pika-pki/public_bundles:/usr/share/nginx/html:Z \
-v ./nginx-default.conf:/etc/nginx/conf.d/default.conf:Z \
docker.io/nginx
Once you run that command you can access your Public Bundle files from http://localhost:8085/
. You could easily place this behind a reverse proxy and modify the access and routing.
When creating a Certificate Authority, you will be prompted for an optional parameter, "CA URI Root". This is the base path where the CRL will be served for clients to query revoked certificates.
You should provide the base URI to where a public server is available - eg if you provide https://ca.example.com/public
then the CRL will be configured and presented as https://ca.example.com/public/crls/root-ca.my-root-ca.crl
.
The format is ${URI_ROOT}/crls/${CA_TYPE}-ca.${CA_CN_SLUG}.crl
where $CA_TYPE
can be root
, intermediate
, or signing
.
The value for $CA_CN_SLUG
comes from a "slugified" (alpha-num only, space/other characters replaced with a dash) value of the Certificate Authority's Common Name. This value is also represented in the CA's folder name along the path, eg kemo-signing-ca
in roots/kemo-root-ca/intermediate-ca/kemo-intermediate-ca/signing-ca/kemo-signing-ca
.
If you'd like the CRL to be hosted on a different path, then modify the default OpenSSL Configuration - see below for instructions on that.
By default a Certificate Authority is configured for a 30 day long CRL, which can be changed in the OpenSSL configuration with an override detailed below, or after the CA is created by modifying the openssl.cnf
file in the CA directory.
This should be rotated regularly before whatever that expiration is.
To do so easily, you can execute ./pika-pki.sh -m rotateCRL -a path/to/ca -p passwordOrPathToPasswordFile
.
The -m rotateCRL
option will process a CRL rotation/renewal - this is done on a per-CA basis by specifying -a path/to/ca
eg -a .pika-pki/roots/kemo-root/intermediate-ca/kemo-intermediate
.
Since the CRLs have to be signed by the CA Private Key, the password is needed to be provided - do this with -p passwordOrPathToPasswordFile
which, can either be the password plain text, or a path to a file with the password in it.
The default configuration can be found in functions/config.sh
. There is some logic and templating involved which is why it is embedded in a Bash script.
To override these defaults, create a folder called overrides
in this directory, copy the functions/config.sh
file into it, and modify as needed.
In order for Pika PKI to work, there has to be a standard naming convention and directory structure. With this information you could technically import any other PKI into a Pika PKI file structure and use its interface - if that were your thing.
Note: The variable name may only be valid for demonstration purposes and not actual variables to override in the code.
Name | Variable | Default | Notes |
---|---|---|---|
Workspace Directory | PIKA_PKI_DIR |
$(pwd)/.pika-pki |
The base directory where everything is created. |
Root Folder | ROOT_CA_DIRS |
$PIKA_PKI_DIR/roots |
A folder holding the Root CAs |
Public Bundles | PUBLIC_BUNDLES_DIR |
$PIKA_PKI_DIR/public_bundles |
A folder holding the generated public bundle files |
Private Bundles | PRIVATE_BUNDLES_DIR |
$PIKA_PKI_DIR/private_bundles |
A folder holding the optional quick folder for private bundle files when saving certificates |
So with that understanding, starting ./pika-pki.sh
will create a base folder structure such as this:
./.pika-pki/
./.pika-pki/roots/
./.pika-pki/public_bundles/
./.pika-pki/public_bundles/certs
./.pika-pki/public_bundles/crls
./.pika-pki/private_bundles/
Name | Variable | Default | Notes |
---|---|---|---|
A Root CA | CA_DIR |
$ROOT_CA_DIRS/my-pretty-root-ca |
A Root CA named "My Pretty Root CA" - for most purposes, CAs of any type can be treated the same |
Signed Certificates | `` | $CA_DIR/certs |
In every CA there is a subfolder certs/ that houses signed and valid certificates |
CRL | `` | $CA_DIR/crl/ca.crl.pem |
If the CA had a CRL defined during creation, there is a subfolder crl/ that houses the CA's CRL |
CRL - Public Bundle | `` | $PUBLIC_BUNDLES_DIR/crls/$CA_TYPE-ca.${CA_CN_SLUG}.crl |
If the CA had a CRL defined during creation, there will be a copy of its CRL in the public bundles crls folder |
Certificate Signing Requests | `` | $CA_DIR/csrs |
In every CA there is a subfolder csrs/ that houses CSRs generated for Certificates |
New/Serial Certs | `` | $CA_DIR/newcerts |
In every CA there is a subfolder newcerts/ that houses a copy of every signed certificate organized by serial numbers for filenames |
Private Files | `` | $CA_DIR/private |
In every CA there is a subfolder private/ that houses private files such as private keys |
CA Public Bundles | `` | $CA_DIR/public_bundles |
A folder holding the generated public bundle files such as the named CA Chain and CA CRL |
OpenSSL Configuration | `` | $CA_DIR/openssl.cnf |
Every CA has a copy of their own configurable OpenSSL configuration file |
OpenSSL "Database" | `` | $CA_DIR/index.txt |
Every CA has an OpenSSL "database" which is stored as a tab delimited text file |
There are some other files created but those are the key ones to know.
The PKI Chain has common files/folders for each CA created, but their folder structure matters. Assuming a PKI of such...
-
Root CA
-
Intermediate CA 1
- Intermediate CA 3
- Signing CA 2
- Intermediate CA 3
-
Intermediate CA 2
- Signing CA 1
-
-
Other Root CA
- Other Intermediate CA 1
- Other Signing CA 1
- Other Intermediate CA 1
...you would see something similar to this:
roots/root-ca/ # Root CA
roots/root-ca/intermediate-ca/intermediate-ca-1/ # Intermediate CA 1
roots/root-ca/intermediate-ca/intermediate-ca-1/intermediate-ca/intermediate-ca-3/ # Intermediate CA 3
roots/root-ca/intermediate-ca/intermediate-ca-1/intermediate-ca/intermediate-ca-3/signing-ca/signing-ca-2/ # Signing CA 2
roots/root-ca/intermediate-ca/intermediate-ca-2/ # Intermediate CA 2
roots/root-ca/intermediate-ca/intermediate-ca-2/signing-ca/signing-ca-1/ # Signing CA 1
roots/other-root-ca/ # Other Root CA
roots/other-root-ca/intermediate-ca/other-intermediate-ca-1/ # Other Intermediate CA 1
roots/other-root-ca/intermediate-ca/other-intermediate-ca-1/signing-ca/other-signing-ca-1/ # Other Signing CA 1
- You can have any number of Root CAs.
- You can have any number of Intermediate CAs along the chain.
- Signing CAs terminate any further CA along the chain.
- Each Root and Intermediate CA has
intermediate-ca
andsigning-ca
sub folders - Signing CAs do not since they are the end of the chain. - CA Folder names are based on a "sluggified" version of the CA Common Name
- Add CA Operational Commands to menu (Process Bundle, Rotate CRL)