2018-08-06 21:42:46 +00:00
|
|
|
---
|
2020-01-18 00:18:09 +00:00
|
|
|
layout: guides
|
|
|
|
page_title: Build Your Own Certificate Authority - Guides
|
|
|
|
sidebar_title: Build Your Own CA
|
2018-08-06 21:42:46 +00:00
|
|
|
description: |-
|
|
|
|
The PKI secrets engine generates dynamic X.509 certificates. With this secrets
|
|
|
|
engine, services can get certificates without going through the usual manual
|
|
|
|
process of generating a private key and CSR, submitting to a CA, and waiting
|
|
|
|
for a verification and signing process to complete. Vault's built-in
|
|
|
|
authentication and authorization mechanisms provide the verification
|
|
|
|
functionality.
|
|
|
|
---
|
|
|
|
|
|
|
|
# Build Your Own Certificate Authority (CA)
|
|
|
|
|
|
|
|
Vault's PKI secrets engine can dynamically generate X.509 certificates on
|
|
|
|
demand. This allows services to acquire certificates without going through the
|
|
|
|
usual manual process of generating a private key and Certificates Signing
|
|
|
|
Request (CSR), submitting to a CA, and then wait for the verification and
|
|
|
|
signing process to complete.
|
|
|
|
|
|
|
|
## Reference Material
|
|
|
|
|
2020-01-22 20:05:41 +00:00
|
|
|
- [PKI (Certificates) Secrets Engine](/docs/secrets/pki)
|
|
|
|
- [PKI Secrets Engine (API)](/api/secret/pki)
|
2018-08-06 21:42:46 +00:00
|
|
|
- [RFC 5280 Internet X.509 Public Key Infrastructure Certificate and Certificate
|
2020-01-18 00:18:09 +00:00
|
|
|
Revocation List (CRL) Profile](https://tools.ietf.org/html/rfc5280)
|
2018-08-06 21:42:46 +00:00
|
|
|
- [OpenSSL x509 Man Pages](https://www.openssl.org/docs/man1.1.0/apps/x509.html)
|
|
|
|
|
|
|
|
## Estimated Time to Complete
|
|
|
|
|
|
|
|
15 minutes
|
|
|
|
|
|
|
|
## Personas
|
|
|
|
|
|
|
|
The steps described in this guide are typically performed by **security
|
|
|
|
engineer**.
|
|
|
|
|
|
|
|
## Challenge
|
|
|
|
|
|
|
|
Organizations should protect their website; however, the Traditional PKI process
|
|
|
|
workflow takes a long time which motivates organizations to create certificates
|
|
|
|
which do not expire for a year or more.
|
|
|
|
|
|
|
|
## Solution
|
|
|
|
|
|
|
|
Use Vault to create X509 certificates for usage in MTLS or other arbitrary PKI
|
2020-01-18 00:18:09 +00:00
|
|
|
encryption. While this can be used to create web server certificates. If
|
2018-08-06 21:42:46 +00:00
|
|
|
users do not import the CA chains, the browser will complain about self-signed
|
|
|
|
certificates.
|
|
|
|
|
|
|
|
Creating PKI certificates is generally a cumbersome process using traditional
|
2020-01-18 00:18:09 +00:00
|
|
|
tools like `openssl` or even more advanced frameworks like CFSSL. These tools
|
2018-08-06 21:42:46 +00:00
|
|
|
also require a human component to verify certificate distribution meets
|
2020-01-18 00:18:09 +00:00
|
|
|
organizational security policies.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
Vault PKI secrets engine makes this a lot simpler. The PKI secrets engine can
|
2018-08-06 21:42:46 +00:00
|
|
|
be an Intermediate-Only certificate authority which potentially allows for
|
|
|
|
higher levels of security.
|
|
|
|
|
|
|
|
1. Store CA outside the Vault (air gapped)
|
|
|
|
1. Create CSRs for the intermediates
|
|
|
|
1. Sign CSR outside Vault and import intermediate
|
|
|
|
1. Issue leaf certificates from the Intermediate CA
|
|
|
|
|
|
|
|
## Prerequisites
|
|
|
|
|
|
|
|
To perform the tasks described in this guide, you need to have a Vault
|
2020-01-18 00:18:09 +00:00
|
|
|
environment. Refer to the [Getting
|
2020-01-22 20:05:41 +00:00
|
|
|
Started](/intro/getting-started/install) guide to install Vault.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
Alternatively, you can use the [Vault
|
|
|
|
Playground](https://www.katacoda.com/hashicorp/scenarios/vault-playground)
|
|
|
|
environment.
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
### Policy requirements ((#policy))
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
-> **NOTE:** For the purpose of this guide, you can use **`root`** token to work
|
|
|
|
with Vault. However, it is recommended that root tokens are only used for just
|
|
|
|
enough initial setup or in emergencies. As a best practice, use tokens with
|
|
|
|
appropriate set of policies based on your role in the organization.
|
|
|
|
|
|
|
|
To perform all tasks demonstrated in this guide, your policy must include the
|
|
|
|
following permissions:
|
|
|
|
|
|
|
|
```shell
|
|
|
|
# Enable secrets engine
|
|
|
|
path "sys/mounts/*" {
|
|
|
|
capabilities = [ "create", "read", "update", "delete", "list" ]
|
|
|
|
}
|
|
|
|
|
|
|
|
# List enabled secrets engine
|
|
|
|
path "sys/mounts" {
|
|
|
|
capabilities = [ "read", "list" ]
|
|
|
|
}
|
|
|
|
|
|
|
|
# Work with pki secrets engine
|
|
|
|
path "pki*" {
|
|
|
|
capabilities = [ "create", "read", "update", "delete", "list", "sudo" ]
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
If you are not familiar with policies, complete the
|
2020-01-22 20:05:41 +00:00
|
|
|
[policies](/guides/identity/policies) guide.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
## Steps
|
|
|
|
|
|
|
|
In this guide, you are going to first generate a self-signed root certificate.
|
|
|
|
Then you are going to generate an intermediate certificate which is signed by
|
|
|
|
the root. Finally, you are going to generate a certificate for
|
|
|
|
`test.example.com` domain.
|
|
|
|
|
New Docs Website (#5535)
* conversion stage 1
* correct image paths
* add sidebar title to frontmatter
* docs/concepts and docs/internals
* configuration docs and multi-level nav corrections
* commands docs, index file corrections, small item nav correction
* secrets converted
* auth
* add enterprise and agent docs
* add extra dividers
* secret section, wip
* correct sidebar nav title in front matter for apu section, start working on api items
* auth and backend, a couple directory structure fixes
* remove old docs
* intro side nav converted
* reset sidebar styles, add hashi-global-styles
* basic styling for nav sidebar
* folder collapse functionality
* patch up border length on last list item
* wip restructure for content component
* taking middleman hacking to the extreme, but its working
* small css fix
* add new mega nav
* fix a small mistake from the rebase
* fix a content resolution issue with middleman
* title a couple missing docs pages
* update deps, remove temporary markup
* community page
* footer to layout, community page css adjustments
* wip downloads page
* deps updated, downloads page ready
* fix community page
* homepage progress
* add components, adjust spacing
* docs and api landing pages
* a bunch of fixes, add docs and api landing pages
* update deps, add deploy scripts
* add readme note
* update deploy command
* overview page, index title
* Update doc fields
Note this still requires the link fields to be populated -- this is solely related to copy on the description fields
* Update api_basic_categories.yml
Updated API category descriptions. Like the document descriptions you'll still need to update the link headers to the proper target pages.
* Add bottom hero, adjust CSS, responsive friendly
* Add mega nav title
* homepage adjustments, asset boosts
* small fixes
* docs page styling fixes
* meganav title
* some category link corrections
* Update API categories page
updated to reflect the second level headings for api categories
* Update docs_detailed_categories.yml
Updated to represent the existing docs structure
* Update docs_detailed_categories.yml
* docs page data fix, extra operator page remove
* api data fix
* fix makefile
* update deps, add product subnav to docs and api landing pages
* Rearrange non-hands-on guides to _docs_
Since there is no place for these on learn.hashicorp, we'll put them
under _docs_.
* WIP Redirects for guides to docs
* content and component updates
* font weight hotfix, redirects
* fix guides and intro sidenavs
* fix some redirects
* small style tweaks
* Redirects to learn and internally to docs
* Remove redirect to `/vault`
* Remove `.html` from destination on redirects
* fix incorrect index redirect
* final touchups
* address feedback from michell for makefile and product downloads
2018-10-19 15:40:11 +00:00
|
|
|
![Overview](/img/vault-pki-4.png)
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
In this guide, you perform the following:
|
|
|
|
|
|
|
|
1. [Generate Root CA](#step1)
|
|
|
|
1. [Generate Intermediate CA](#step2)
|
|
|
|
1. [Create a Role](#step3)
|
|
|
|
1. [Request Certificates](#step4)
|
|
|
|
1. [Revoke Certificates](#step5)
|
|
|
|
1. [Remove Expired Certificates](#step6)
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
### Step 1: Generate Root CA ((#step1))
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
In this step, you are going to generate a self-signed root certificate using
|
|
|
|
PKI secrets engine.
|
|
|
|
|
|
|
|
#### CLI command
|
|
|
|
|
|
|
|
1. First, enable the `pki` secrets engine at `pki` path:
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
```plaintext
|
|
|
|
$ vault secrets enable pki
|
|
|
|
```
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
1. Tune the `pki` secrets engine to issue certificates with a maximum time-to-live (TTL) of 87600 hours.
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
```plaintext
|
|
|
|
$ vault secrets tune -max-lease-ttl=87600h pki
|
|
|
|
```
|
2018-08-06 21:42:46 +00:00
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Generate the **_root_** certificate and save the certificate in `CA_cert.crt`.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
```plaintext
|
|
|
|
$ vault write -field=certificate pki/root/generate/internal common_name="example.com" \
|
|
|
|
ttl=87600h > CA_cert.crt
|
|
|
|
```
|
2018-08-06 21:42:46 +00:00
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
This generates a new self-signed CA certificate and private key. Vault will
|
|
|
|
_automatically_ revoke the generated root at the end of its lease period
|
|
|
|
(TTL); the CA certificate will sign its own Certificate Revocation List
|
|
|
|
(CRL).
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
1. Configure the CA and CRL URLs:
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
```plaintext
|
|
|
|
$ vault write pki/config/urls \
|
|
|
|
issuing_certificates="http://127.0.0.1:8200/v1/pki/ca" \
|
|
|
|
crl_distribution_points="http://127.0.0.1:8200/v1/pki/crl"
|
|
|
|
```
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
#### API call using cURL
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. First, enable the `pki` secrets engine at `pki` path using `/sys/mounts` endpoint:
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ curl --header "X-Vault-Token: <TOKEN>" \
|
|
|
|
--request POST \
|
|
|
|
--data <PARAMETERS> \
|
|
|
|
<VAULT_ADDRESS>/v1/sys/mounts/<PATH>
|
|
|
|
```
|
|
|
|
|
|
|
|
Where `<TOKEN>` is your valid token, and `<PARAMETERS>` holds [configuration
|
2020-01-22 20:05:41 +00:00
|
|
|
parameters](/api/system/mounts#enable-secrets-engine) of the secret engine.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
**Example:**
|
|
|
|
|
|
|
|
The following example mounts `pki` secret engine.
|
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
|
|
|
--request POST \
|
|
|
|
--data '{"type":"pki"}' \
|
|
|
|
https://127.0.0.1:8200/v1/sys/mounts/pki
|
|
|
|
```
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Tune the `pki` secrets engine to issue certificates with a maximum
|
|
|
|
time-to-live (TTL) of 87600 hours.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
2020-01-18 00:18:09 +00:00
|
|
|
--request POST \
|
|
|
|
--data '{"max_lease_ttl":"87600h"}' \
|
|
|
|
https://127.0.0.1:8200/v1/sys/mounts/pki/tune
|
2018-08-06 21:42:46 +00:00
|
|
|
```
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Generate the **_root_** certificate and extract the CA certificate and save
|
|
|
|
it as `CA_cert.crt`.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
> **NOTE:** The following command uses `jq` tool to parse the output JSON.
|
2020-01-18 00:18:09 +00:00
|
|
|
> You can install [`jq`](https://stedolan.github.io/jq/download/) or manually
|
|
|
|
> copy and paste the certificate in a file, `CA_cert.crt`.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ tee payload.json <<EOF
|
|
|
|
{
|
|
|
|
"common_name": "example.com",
|
|
|
|
"ttl": "87600h"
|
|
|
|
}
|
|
|
|
EOF
|
|
|
|
|
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
2020-01-18 00:18:09 +00:00
|
|
|
--request POST \
|
|
|
|
--data @payload.json \
|
|
|
|
https://127.0.0.1:8200/v1/pki/root/generate/internal \
|
|
|
|
| jq -r ".data.certificate" > CA_cert.crt
|
2018-08-06 21:42:46 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
This generates a new self-signed CA certificate and private key. Vault will
|
|
|
|
_automatically_ revoke the generated root at the end of its lease period
|
|
|
|
(TTL); the CA certificate will sign its own Certificate Revocation List
|
|
|
|
(CRL).
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Configure the CA and CRL URLs:
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ tee payload-url.json <<EOF
|
|
|
|
{
|
|
|
|
"issuing_certificates": "http://127.0.0.1:8200/v1/pki/ca",
|
|
|
|
"crl_distribution_points": "http://127.0.0.1:8200/v1/pki/crl"
|
|
|
|
}
|
|
|
|
EOF
|
|
|
|
|
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
|
|
|
--request POST \
|
|
|
|
--data @payload-url.json \
|
|
|
|
https://127.0.0.1:8200/v1/pki/config/urls
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Web UI
|
|
|
|
|
|
|
|
Open a web browser and launch the Vault UI (e.g. http://127.0.0.1:8200/ui) and
|
|
|
|
then login.
|
|
|
|
|
|
|
|
1. Select **Enable new engine**.
|
|
|
|
1. Select **PKI** from the **Secrets engine type** drop-down list.
|
|
|
|
1. Click **More options** to expand and set the **Maximum lease TTL** to **`87600 hours`**.
|
|
|
|
1. Click **Enable Engine**.
|
|
|
|
1. Select **Configure**.
|
|
|
|
1. Click **Configure CA**.
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Leave **CA Type** as **root**, and **Type** to be **internal**. Enter
|
|
|
|
**`example.com`** in the **Common Name** field.
|
2018-08-06 21:42:46 +00:00
|
|
|
1. Select **Options** and then set **TTL** field to be **87600 hours**.
|
|
|
|
1. Click **Save**.
|
|
|
|
1. Click **Copy Certificate** and save it in a file named, **`CA_cert.crt`**.
|
|
|
|
1. Click the **URLs** tab, and then set:
|
2020-01-18 00:18:09 +00:00
|
|
|
- Issuing certificates: `http://127.0.0.1:8200/v1/pki/ca`
|
|
|
|
- CRL Distribution Points: `http://127.0.0.1:8200/v1/pki/crl`
|
|
|
|
![Configure URL](/img/vault-pki-1.png)
|
2018-08-06 21:42:46 +00:00
|
|
|
1. Click **Save**.
|
|
|
|
|
|
|
|
-> **NOTE:** To examine the generated root certificate, you can use
|
|
|
|
[OpenSSL](https://www.openssl.org/source/).
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
```shell
|
|
|
|
# Print the certificate in text form
|
|
|
|
$ openssl x509 -in CA_cert.crt -text
|
2018-08-06 21:42:46 +00:00
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
# Print the validity dates
|
|
|
|
$ openssl x509 -in CA_cert.crt -noout -dates
|
|
|
|
```
|
2018-08-06 21:42:46 +00:00
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
### Step 2: Generate Intermediate CA ((#step2))
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
Now, you are going to create an intermediate CA using the root CA you regenerate
|
|
|
|
in the previous step.
|
|
|
|
|
|
|
|
#### CLI Command
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. First, enable the `pki` secrets engine at **`pki_int`** path:
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ vault secrets enable -path=pki_int pki
|
|
|
|
```
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Tune the `pki_int` secrets engine to issue certificates with a maximum
|
|
|
|
time-to-live (TTL) of 43800 hours.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ vault secrets tune -max-lease-ttl=43800h pki_int
|
|
|
|
```
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Execute the following command to generate an intermediate and save the CSR as
|
|
|
|
`pki_intermediate.csr`:
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ vault write -format=json pki_int/intermediate/generate/internal \
|
|
|
|
common_name="example.com Intermediate Authority" ttl="43800h" \
|
|
|
|
| jq -r '.data.csr' > pki_intermediate.csr
|
|
|
|
```
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Sign the intermediate certificate with the root certificate and save the
|
|
|
|
generated certificate as `intermediate.cert.pem`:
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ vault write -format=json pki/root/sign-intermediate csr=@pki_intermediate.csr \
|
2019-06-03 20:45:11 +00:00
|
|
|
format=pem_bundle ttl="43800h" \
|
2018-08-06 21:42:46 +00:00
|
|
|
| jq -r '.data.certificate' > intermediate.cert.pem
|
|
|
|
```
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Once the CSR is signed and the root CA returns a certificate, it can be
|
|
|
|
imported back into Vault:
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ vault write pki_int/intermediate/set-signed certificate=@intermediate.cert.pem
|
|
|
|
```
|
|
|
|
|
|
|
|
#### API call using cURL
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. First, enable the `pki` secrets engine at **`pki_int`** path:
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
**Example:**
|
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
|
|
|
--request POST \
|
|
|
|
--data '{"type":"pki"}' \
|
|
|
|
https://127.0.0.1:8200/v1/sys/mounts/pki_int
|
|
|
|
```
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Tune the `pki_int` secrets engine to issue certificates with a maximum
|
|
|
|
time-to-live (TTL) of 43800 hours.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
2020-01-18 00:18:09 +00:00
|
|
|
--request POST \
|
|
|
|
--data '{"max_lease_ttl":"43800h"}' \
|
|
|
|
https://127.0.0.1:8200/v1/sys/mounts/pki_int/tune
|
2018-08-06 21:42:46 +00:00
|
|
|
```
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Generate an intermediate using the `/pki_int/intermediate/generate/internal`
|
|
|
|
endpoint.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ tee payload-int.json <<EOF
|
|
|
|
{
|
|
|
|
"common_name": "example.com Intermediate Authority",
|
|
|
|
"ttl": "43800h"
|
|
|
|
}
|
|
|
|
EOF
|
|
|
|
|
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
2020-01-18 00:18:09 +00:00
|
|
|
--request POST \
|
|
|
|
--data @payload-int.json \
|
|
|
|
https://127.0.0.1:8200/v1/pki_int/intermediate/generate/internal | jq
|
2018-08-06 21:42:46 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
Copy the generated CSR.
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Sign the intermediate certificate with the root certificate and save the
|
|
|
|
certificate as `intermediate.cert.pem`.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
-> **NOTE:** The API request payload should contain the CSR you obtained.
|
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ tee payload-int-cert.json <<EOF
|
|
|
|
{
|
|
|
|
"csr": "...",
|
2019-06-03 20:45:11 +00:00
|
|
|
"format": "pem_bundle",
|
|
|
|
"ttl": "43800h"
|
2018-08-06 21:42:46 +00:00
|
|
|
}
|
|
|
|
EOF
|
|
|
|
|
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
2020-01-18 00:18:09 +00:00
|
|
|
--request POST \
|
|
|
|
--data @payload-int-cert.json \
|
|
|
|
https://127.0.0.1:8200/v1/pki/root/sign-intermediate | jq
|
2018-08-06 21:42:46 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
> **NOTE:** The **`format`** in the payload specifies the format of the
|
2020-01-18 00:18:09 +00:00
|
|
|
> returned data. When `pem_bundle`, the certificate field will contain the
|
|
|
|
> certificate.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
Copy the generated certificate.
|
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Once the CSR is signed and the root CA returns a certificate, it can be
|
|
|
|
imported back into Vault using the `/pki_int/intermediate/set-signed` endpoint.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
-> **NOTE:** The API request payload should contain the certificate you
|
|
|
|
obtained.
|
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ tee payload-signed.json <<EOF
|
|
|
|
{
|
|
|
|
"certificate": "..."
|
|
|
|
}
|
|
|
|
EOF
|
|
|
|
|
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
2020-01-18 00:18:09 +00:00
|
|
|
--request POST \
|
|
|
|
--data @payload-signed.json \
|
|
|
|
https://127.0.0.1:8200/v1/pki_int/intermediate/set-signed
|
2018-08-06 21:42:46 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
#### Web UI
|
|
|
|
|
|
|
|
1. Select **Enable new engine** in the **Secrets** tab.
|
|
|
|
1. Select **PKI** from the **Secrets engine type** drop-down list.
|
|
|
|
1. Enter **`pki_int`** in the **Path** field.
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Click **More options** to expand and set the **Maximum lease TTL** to **`43800 hours`**.
|
2018-08-06 21:42:46 +00:00
|
|
|
1. Click **Enable Engine**.
|
|
|
|
1. Select **Configure**.
|
|
|
|
1. Click **Configure CA**.
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Select **intermediate** from **CA Type** drop-down list.
|
2019-06-03 20:45:11 +00:00
|
|
|
1. Enter **`example.com Intermediate Authority`** in the **Common Name** field.
|
|
|
|
1. Enter **`43800`** in the **TTL** field, choose **`hours`** and then click **Save**.
|
2018-08-06 21:42:46 +00:00
|
|
|
1. Click **Copy CSR** and save it in a file, `pki_intermediate.csr`.
|
|
|
|
1. Select **pki** from the **Secrets** tab to return to the root CA.
|
|
|
|
1. Select **Configure** and then click **Sign intermediate**.
|
|
|
|
1. Paste in the CSR in the **Certificate Signing Request (CSR)** field.
|
|
|
|
1. Enter **`example.com`** in the **Common Name**.
|
|
|
|
1. Select **pem_bundle** from the **Format** drop-down list, and then click
|
2020-01-18 00:18:09 +00:00
|
|
|
**Save**.
|
2018-09-11 23:49:31 +00:00
|
|
|
1. Click **Copy Certificate** and save the generated certificate in a file, `intermediate.cert.pem`.
|
2018-08-06 21:42:46 +00:00
|
|
|
1. Select **pki_int** from the **Secrets** tab to return to the intermediate CA.
|
|
|
|
1. Select **Configure** and then click **Set signed intermediate**.
|
|
|
|
1. Paste in the certificate in the **Signed Intermediate Certificate** field and
|
2020-01-18 00:18:09 +00:00
|
|
|
then click **Save**.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
### Step 3: Create a Role ((#step3))
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
A role is a logical name that maps to a policy used to generate those
|
|
|
|
credentials. It allows [configuration
|
2020-01-22 20:05:41 +00:00
|
|
|
parameters](/api/secret/pki#create-update-role) to control
|
2018-08-06 21:42:46 +00:00
|
|
|
certificate common names, alternate names, the key usages that they are valid
|
|
|
|
for, and more.
|
|
|
|
|
|
|
|
Calling out some of the parameters:
|
|
|
|
|
|
|
|
- **`allowed_domains`** - specifies the domains of the role (used with
|
|
|
|
`allow_bare_domains` and `allow-subdomains` options)
|
|
|
|
- **`allow_bare_domains`** - specifies if clients can request certificates
|
2020-01-18 00:18:09 +00:00
|
|
|
matching the value of the actual domains themselves
|
2018-08-06 21:42:46 +00:00
|
|
|
- **`allow_subdomains`** - specifies if clients can request certificates with
|
2020-01-18 00:18:09 +00:00
|
|
|
CNs that are subdomains of the CNs allowed by the other role options (NOTE: This
|
2018-08-06 21:42:46 +00:00
|
|
|
includes wildcard subdomains.)
|
|
|
|
- **`allow_glob_domains`** - allows names specified in allowed_domains to
|
2020-01-18 00:18:09 +00:00
|
|
|
contain glob patterns (e.g. ftp\*.example.com)
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
In this step, you are going to create a role named, **`example-dot-com`**.
|
|
|
|
|
|
|
|
#### CLI Command
|
|
|
|
|
|
|
|
Create a role named **`example-dot-com`** which allows subdomains.
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
```shell-session
|
2018-08-06 21:42:46 +00:00
|
|
|
$ vault write pki_int/roles/example-dot-com \
|
|
|
|
allowed_domains="example.com" \
|
|
|
|
allow_subdomains=true \
|
|
|
|
max_ttl="720h"
|
|
|
|
```
|
|
|
|
|
|
|
|
#### API call using cURL
|
|
|
|
|
|
|
|
Create a role named **`example-dot-com`** which allows subdomains.
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
```shell-session
|
2018-08-06 21:42:46 +00:00
|
|
|
$ tee payload-role.json <<EOF
|
|
|
|
{
|
|
|
|
"allowed_domains": "example.com",
|
|
|
|
"allow_subdomains": true,
|
|
|
|
"max_ttl": "720h"
|
|
|
|
}
|
|
|
|
|
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
|
|
|
--request POST \
|
|
|
|
--data @payload-role.json \
|
|
|
|
https://127.0.0.1:8200/v1/pki_int/roles/example-dot-com
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Web UI
|
|
|
|
|
|
|
|
Create a role named **`example-dot-com`** which allows subdomains.
|
|
|
|
|
|
|
|
1. Click **pki_int** and then select **Create role**.
|
|
|
|
1. Enter **`example-dot-com`** in the **Role name** field.
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Select **Options** to expand, and then set the **Max TTL** to **`43800 hours`**. Select **Hide Options**.
|
2018-08-06 21:42:46 +00:00
|
|
|
1. Select **Domain Handling** to expand, and then select the **Allow
|
2020-01-18 00:18:09 +00:00
|
|
|
subdomains** check-box. Enter **`example.com`** in the **Allowed domains**
|
|
|
|
field.
|
|
|
|
![Create Role](/img/vault-pki-2.png)
|
2018-08-06 21:42:46 +00:00
|
|
|
1. Click **Create role**.
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
### Step 4: Request Certificates ((#step4))
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
Keep certificate lifetimes to be short to align with Vault's philosophy of
|
|
|
|
short-lived secrets.
|
|
|
|
|
|
|
|
#### CLI Command
|
|
|
|
|
|
|
|
Execute the following command to request a new certificate for `test.example.com`
|
|
|
|
domain based on the `example-dot-com` role:
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
```shell-session
|
2018-08-06 21:42:46 +00:00
|
|
|
$ vault write pki_int/issue/example-dot-com common_name="test.example.com" ttl="24h"
|
|
|
|
|
|
|
|
Key Value
|
|
|
|
--- -----
|
|
|
|
certificate -----BEGIN CERTIFICATE-----
|
|
|
|
MIIDwzCCAqugAwIBAgIUTQABMCAsXjG6ExFTX8201xKVH4IwDQYJKoZIhvcNAQEL
|
|
|
|
BQAwGjEYMBYGA1UEAxMPd3d3LmV4YW1wbGUuY29tMB4XDTE4MDcyNDIxMTMxOVoX
|
|
|
|
...
|
|
|
|
|
|
|
|
-----END CERTIFICATE-----
|
|
|
|
issuing_ca -----BEGIN CERTIFICATE-----
|
|
|
|
MIIDQTCCAimgAwIBAgIUbMYp39mdj7dKX033ZjK18rx05x8wDQYJKoZIhvcNAQEL
|
|
|
|
...
|
|
|
|
|
|
|
|
-----END CERTIFICATE-----
|
|
|
|
private_key -----BEGIN RSA PRIVATE KEY-----
|
|
|
|
MIIEowIBAAKCAQEAte1fqy2Ekj+EFqKV6N5QJlBgMo/U4IIxwLZI6a87yAC/rDhm
|
|
|
|
W58liadXrwjzRgWeqVOoCRr/B5JnRLbyIKBVp6MMFwZVkynEPzDmy0ynuomSfJkM
|
|
|
|
...
|
|
|
|
|
|
|
|
-----END RSA PRIVATE KEY-----
|
|
|
|
private_key_type rsa
|
|
|
|
serial_number 4d:00:01:30:20:2c:5e:31:ba:13:11:53:5f:cd:b4:d7:12:95:1f:82
|
|
|
|
```
|
|
|
|
|
|
|
|
The response contains the PEM-encoded private key, key type and certificate
|
|
|
|
serial number.
|
|
|
|
|
|
|
|
#### API call using cURL
|
|
|
|
|
|
|
|
Invoke the **`/pki_int/issue/<role_name>`** endpoint to request a new certificate.
|
|
|
|
|
|
|
|
**Example:**
|
|
|
|
|
|
|
|
Request a certificate for `test.example.com` domain based on the
|
|
|
|
`example-dot-com` role:
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
```shell-session
|
2018-08-06 21:42:46 +00:00
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
|
|
|
--request POST \
|
|
|
|
--data '{"common_name": "test.example.com", "ttl": "24h"}' \
|
|
|
|
https://127.0.0.1:8200/v1/pki_int/issue/example-dot-com | jq
|
|
|
|
{
|
|
|
|
"request_id": "6fa8d77d-0758-33ae-b5ea-8b3d15014fd1",
|
|
|
|
"lease_id": "",
|
|
|
|
"renewable": false,
|
|
|
|
"lease_duration": 0,
|
|
|
|
"data": {
|
|
|
|
"certificate": "-----BEGIN CERTIFICATE-----\nMIIDvzCCAqegAwIBAgIUG7H0Pzpqm+...-----END CERTIFICATE-----",
|
|
|
|
"issuing_ca": "-----BEGIN CERTIFICATE-----\nMIIDNTCCAh2gAwIBAgIUQhIX9D...-----END CERTIFICATE-----",
|
|
|
|
"private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAr6IsROOW5...-----END RSA PRIVATE KEY-----",
|
|
|
|
"private_key_type": "rsa",
|
|
|
|
"serial_number": "1b:b1:f4:3f:3a:6a:9b:e8:33:af:f7:1b:b1:4d:57:7f:65:65:39:c1"
|
|
|
|
},
|
|
|
|
"wrap_info": null,
|
|
|
|
"warnings": null,
|
|
|
|
"auth": null
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
The response contains the PEM-encoded private key, key type and certificate
|
|
|
|
serial number.
|
|
|
|
|
|
|
|
#### Web UI
|
|
|
|
|
|
|
|
1. Select **Secrets**.
|
|
|
|
1. Select **pki_int** from the **Secrets Engines** list.
|
|
|
|
1. Select **example-dot-com** under **Roles**.
|
|
|
|
1. Enter **`test.example.com`** in the **Common Name** field.
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Select **Options** to expand, and then set the **TTL** to **`24 hours`**.
|
2018-08-06 21:42:46 +00:00
|
|
|
1. Select **Hide Options** and then click **Generate**.
|
2020-01-18 00:18:09 +00:00
|
|
|
![Issue Certificate](/img/vault-pki-3.png)
|
2018-08-06 21:42:46 +00:00
|
|
|
|
2020-01-18 00:18:09 +00:00
|
|
|
> The response contains the PEM-encoded private key, key type and certificate
|
|
|
|
> serial number.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
1. Click **Copy credentials** and save it in a file.
|
|
|
|
|
|
|
|
-> **NOTE:** A certificate can be rotated at any time by simply issuing a new
|
|
|
|
certificate with the same CN.
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
### Step 5: Revoke Certificates ((#step5))
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
If a certificate must be revoked, you can easily perform the revocation action
|
|
|
|
which will cause the CRL to be regenerated. When the CRL is regenerated, any
|
|
|
|
expired certificates are removed from the CRL.
|
|
|
|
|
|
|
|
#### CLI Command
|
|
|
|
|
|
|
|
In a certain circumstances, you may wish to revoke an issued certificate.
|
|
|
|
|
|
|
|
To revoke:
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
```shell-session
|
2018-08-06 21:42:46 +00:00
|
|
|
$ vault write pki_int/revoke serial_number=<serial_number>
|
|
|
|
```
|
|
|
|
|
|
|
|
**Example:**
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
```shell-session
|
2018-08-06 21:42:46 +00:00
|
|
|
$ vault write pki_int/revoke serial_number="48:97:82:dd:f0:d3:d9:7e:53:25:ba:fd:f6:77:3e:89:e5:65:cc:e7"
|
|
|
|
Key Value
|
|
|
|
--- -----
|
|
|
|
revocation_time 1532539632
|
|
|
|
revocation_time_rfc3339 2018-07-25T17:27:12.165206399Z
|
|
|
|
```
|
|
|
|
|
|
|
|
#### API call using cURL
|
|
|
|
|
|
|
|
Invoke the **`/pki_int/revoke`** endpoint to invoke a certificate using its
|
|
|
|
serial number.
|
|
|
|
|
|
|
|
**Example:**
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
```shell-session
|
2018-08-06 21:42:46 +00:00
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
|
|
|
--request POST \
|
|
|
|
--data '{"serial_number": "48:97:82:dd:f0:d3:d9:7e:53:25:ba:fd:f6:77:3e:89:e5:65:cc:e7"}' \
|
|
|
|
https://127.0.0.1:8200/v1/pki_int/revoke
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Web UI
|
|
|
|
|
|
|
|
1. Select **Secrets**.
|
|
|
|
1. Select **pki_int** from the **Secrets Engines** list.
|
|
|
|
1. Select the **eCertificates** tab.
|
|
|
|
1. Select the serial number for the certificate you wish to revoke.
|
2020-01-18 00:18:09 +00:00
|
|
|
1. Click **Revoke**. At the confirmation, click **Revoke** again.
|
2018-08-06 21:42:46 +00:00
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
### Step 6: Remove Expired Certificates ((#step6))
|
2018-08-06 21:42:46 +00:00
|
|
|
|
|
|
|
Keep the storage backend and CRL by periodically removing certificates that have
|
|
|
|
expired and are past a certain buffer period beyond their expiration time.
|
|
|
|
|
|
|
|
#### CLI Command
|
|
|
|
|
|
|
|
To remove revoked certificate and clean the CRL.
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
```shell-session
|
2018-10-29 23:29:35 +00:00
|
|
|
$ vault write pki_int/tidy tidy_cert_store=true tidy_revoked_certs=true
|
2018-08-06 21:42:46 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
#### API call using cURL
|
|
|
|
|
|
|
|
Invoke the **`/pki_int/tidy`** endpoint to remove revoked certificate and clean
|
|
|
|
the CRL.
|
|
|
|
|
|
|
|
**Example:**
|
|
|
|
|
2020-05-21 17:18:17 +00:00
|
|
|
```shell-session
|
2018-08-06 21:42:46 +00:00
|
|
|
$ curl --header "X-Vault-Token: ..." \
|
|
|
|
--request POST \
|
2018-10-29 23:29:35 +00:00
|
|
|
--data '{"tidy_cert_store": true, "tidy_revoked_certs": true}' \
|
2018-08-06 21:42:46 +00:00
|
|
|
https://127.0.0.1:8200/v1/pki_int/tidy
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Web UI
|
|
|
|
|
|
|
|
1. Select **Secrets**.
|
|
|
|
1. Select **pki_int** from the **Secrets Engines** list.
|
|
|
|
1. Select **Configure**.
|
|
|
|
1. Select the **Tidy** tab.
|
|
|
|
1. Select the check-box for **Tidy the Certificate Store** and **Tidy the Revocation List (CRL)**.
|
|
|
|
1. Click **Save**.
|
|
|
|
|
|
|
|
## Next steps
|
|
|
|
|
|
|
|
Check out the [Streamline Certificate Management with HashiCorp
|
|
|
|
Vault](https://www.hashicorp.com/resources/streamline-certificate-management-with-vault)
|
|
|
|
webinar recording.
|