Package: pkictl
pkictlpkictlis a CLI tool for declaratively configuring and provisioning PKI secrets in HashiCorp Vault. Root and Intermediate Certificate Authorities (CAs) along with their associated roles and policies can be defined and created from a YAML file. It simplifies automating the provisioning of an internal PKI using Vault and strives to achieve idempotency.pkictlis inspired bykubectl.How It Workspkictluses the Vault HTTP API to mountPKI secrets enginesfor Root and Intermediate CAs. Intermediate CAs can be signed by a Root CA or other Intermediate CAs. Roles and Policies can be defined in the YAML file for Intermediate CAs.TheKey/Value secrets engineis also used to store the private keys of Intermediate CAs that are configured for export (ie.spec.type: exported).Installationpkictlcan be installed via pip:$ pip install pkictlCompatibilitypkictlhas been tested against versions 0.10.X, 0.11.X, and 1.0.X of Vault.Usage$ pkictl --help

declaratively configure PKI secrets in Hashicorp Vault

optional arguments:
-h, --help     show this help message and exit
-d, --debug    enable debug output
-v, --version  show program's version number and exit

subcommands:

    init         Initializes the Hashicorp Vault server
    apply        Creates PKI secrets from a YAML filePrerequisitesIf you're unfamiliar with Vault's PKI secrets, read this guide:Build Your Own Certificate Authority (CA)pkictlrequires an unsealed Hashicorp Vault server and an authentication token with privileges to:mount PKI and KV secrets enginesread and write PKI secretswrite KV secretsInitializing the Vault serverInitialize a new Vault server and unseal it:$ pkictl init -u https://localhost:8200The Vault server will be initialized with 5 key shares and a key threshold of 3.the root token is saved in.vault-tokenthe master keys shares are saved invault.logInitializing and unsealing the Vault server this way is only provided as a convenience for development/testing and is highly discouraged.Declaratively provisioning PKI secretsA YAML manifest file is used to define Root and Intermediate CAs, Key/Value engines, roles and policies.Create amanifest file:---
kind: RootCA
metadata:
  name: demo-root-ca
  description: pkictl demo Root CA
spec:
  key_type: ec
  key_bits: 384
  ttl: 17532h
  exclude_cn_from_sans: true
  subject:
    common_name: Demo Root CA
    organization: pkictl
    ou: README Demo
    country: US
    locality: San Francisco
    province: California
---
kind: IntermediateCA
metadata:
  name: demo-intermediate-ca
  description: pkictl demo Intermediate CA
  issuer: demo-root-ca
  kv_backend: demo-kv-engine
spec:
  type: exported
  key_type: rsa
  key_bits: 4096
  ttl: 8766h
  subject:
    common_name: Demo Intermediate CA
    organization: pkictl
    ou: README Demo
    country: US
    locality: San Francisco
    province: California
  roles:
  - name: server
    config:
      max_ttl: 8766h
      ttl: 8766h
      allow_subdomains: true
      allowed_domains:
        - demo.pkictl.com
      client_flag: false
      server_flag: true
  - name: client
    config:
      max_ttl: 336h
      ttl: 336h
      allow_any_name: true
      client_flag: true
      server_flag: false
  policies:
  - name: demo-intermediate-ca-pkey
    policy: |
      path "demo-kv-engine" {
        capabilities = ["list"]
      }
      path "demo-kv-engine/demo-intermediate-ca" {
        capabilities = ["read"]
      }
  - name: demo-intermediate-ca-server
    policy: |
      path "demo-intermediate-ca/issue/server" {
        capabilities = ["read", "update"]
      }
      path "demo-intermediate-ca/sign/server" {
        capabilities = ["read", "update"]
      }
  - name: demo-intermediate-ca-client
    policy: |
      path "demo-intermediate-ca/issue/client" {
        capabilities = ["read", "update"]
      }
      path "demo-intermediate-ca/sign/client" {
        capabilities = ["read", "update"]
      }
---
kind: KV
metadata:
  name: demo-kv-engine
  description: pkictl demo KV v1 engine
spec:
  options:
    version: 1The above example will create:an ECDSA-basedRootCA with a TTL of 2 yearsa RSA-basedIntermediateCA with a TTL of 1 year signed by the Root CAaRolenamedserverpermitting the Intermediate CA to issue or sign TLS server certificates for any subdomains on demo.pkictl.comaRolenamedclientpermitting the Intermediate CA to issue or sign TLS client certificatesaPolicymapped to theserverroleaPolicymapped to theclientroleaKey/Valueengine to store the exported private key of the Intermediate CAaPolicypermitting retrieval of the exported private key from the KV engineCreate PKI secrets from the YAML manifest file:$ pkictl apply -u https://localhost:8200 -f manifest.yaml

[*] pkictl - the Vault server has been initialized and is not sealed
[*] pkictl - Enabled KV backend: demo-kv-engine
[*] pkictl - Enabled PKI backend: demo-root-ca
[*] pkictl - Generated Root CA: demo-root-ca
[*] pkictl - Enabled PKI backend: demo-intermediate-ca
[*] pkictl - Created intermediate CA: demo-intermediate-ca
[*] pkictl - Signed intermediate CA 'demo-intermediate-ca' with issuing CA: demo-root-ca
[*] pkictl - Set signed certificate for intermediate CA: demo-intermediate-ca
[*] pkictl - Configured URLs for CA: demo-intermediate-ca
[*] pkictl - Set CRL configuration for CA: demo-intermediate-ca
[*] pkictl - Stored private key for 'demo-intermediate-ca' in KV backend: demo-kv-engine
[*] pkictl - Configured role 'server' for intermediate CA: demo-intermediate-ca
[*] pkictl - Configured role 'client' for intermediate CA: demo-intermediate-ca
[*] pkictl - Configured policy 'demo-intermediate-ca-pkey' for intermediate CA: demo-intermediate-ca
[*] pkictl - Configured policy 'demo-intermediate-ca-server' for intermediate CA: demo-intermediate-ca
[*] pkictl - Configured policy 'demo-intermediate-ca-client' for intermediate CA: demo-intermediate-caObtain a Vault token attached to thedemo-intermediate-ca-serverPolicy:$ VAULT_TOKEN=$(vault token create -policy=demo-intermediate-ca-client -ttl=1h -format json | jq -r .auth.client_token)Use this token to obtain a TLS server certificate and private key for web.demo.pkictl.com from the Intermediate CA:$ vault write demo-intermediate-ca/issue/server common_name=web.demo.pkictl.com ttl=2160hAlternatively, you can generate a certificate signing request (CSR) and private key locally and have the CSR signed by the Intermediate CA:$ openssl req -batch -nodes -sha256 -new -newkey rsa:2048 \
  -keyout web.demo.pkictl.com.key -out web.demo.pkictl.com.csr -subj '/CN=web.demo.pkictl.com/'

$ vault write demo-intermediate-ca/sign/server csr=@web.demo.pkictl.com.csr ttl=2160hVault will return the signed TLS server certificate along with the full chain (the certificates for the Root and Intermediate CA).Obtain a Vault token attached to thedemo-intermediate-ca-clientPolicy:$ VAULT_TOKEN=$(vault token create -policy=demo-intermediate-ca-client -ttl=1h -format json | jq -r .auth.client_token)Use this token to obtain a TLS client certificate and private key from the Intermediate CA:$ vault write demo-intermediate-ca/issue/client common_name="example@demo.pkictl.com" ttl=24hSincespec.type: exported, the private key of this CA has been saved in the KV enginedemo-kv-engine. A Vault token attached to thedemo-intermediate-ca-pkeyPolicy is required to retrieve it:$ VAULT_TOKEN=$(vault token create -policy=demo-intermediate-ca-pkey -ttl=1m -format json | jq -r .auth.client_token)
$ vault kv get -version=1 demo-kv-engine/demo-intermediate-caDocumentationFor documentation and additional examples, see thedocsdirectory.Testingnose2is used for testing. Tests are located inpkictl/tests.To run the unit tests:$ make testEnd to end tests requires Vault running locally. To build and run the Vault container:$ make build-vault-container
$ make run-vault-containerRun the end-to-end tests:$ make e2e-test