-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add documentation on CIEPS protocol (#22398)
* Add documentation on CIEPS protocol Signed-off-by: Alexander Scheel <[email protected]> * Update website/content/docs/secrets/pki/cieps.mdx Co-authored-by: Steven Clark <[email protected]> * Update website/content/docs/secrets/pki/cieps.mdx Co-authored-by: Steven Clark <[email protected]> * Fix indentation, link to Vault SDK Signed-off-by: Alexander Scheel <[email protected]> --------- Signed-off-by: Alexander Scheel <[email protected]> Co-authored-by: Steven Clark <[email protected]>
- Loading branch information
1 parent
5ab5369
commit 7d361ee
Showing
3 changed files
with
327 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,314 @@ | ||
--- | ||
layout: docs | ||
page_title: Certificate Issuance External Policy (CIEPS) | PKI - Secrets Engines | ||
description: An overview of the Certificate Issuance External Policy (CIEPS) protocol | ||
--- | ||
|
||
# PKI secrets engine - Certificate Issuance External Policy Service (CIEPS) <EnterpriseAlert inline="true" /> | ||
|
||
This document covers high-level architecture and service APIs used by the | ||
Vault PKI Secrets Engine when communicating with the Certificate Issuance | ||
External Policy Service (CIEPS) <EnterpriseAlert inline="true" />. | ||
|
||
## What is Certificate Issuance External Policy Service (CIEPS)? | ||
|
||
Hashicorp Vault's PKI Secrets Engine has a mechanism for issuing leaf | ||
certificates with arbitrary structure: [`/pki/sign-verbatim`](/vault/api-docs/secret/pki#sign-verbatim). | ||
This requires an organization to run an application/user-accessible service | ||
for authenticating, authorizing, and validating certificate issuance requests | ||
(potentially handling key pair generation as well), before asking PKI to sign | ||
the resulting CSR and leaf certificate with its own highly-privileged Vault | ||
token. If any attribute is missing from the original requester's CSR, the | ||
original service must reject the request as `sign-verbatim` does not give the | ||
controlling service the ability to modify the request. | ||
|
||
The Certificate Issuance External Policy Service (CIEPS) <EnterpriseAlert inline="true" /> | ||
protocol solves this by placing the validation and certificate templating | ||
gated behind the PKI, solving: | ||
|
||
1. **Auditing**, so the original requester is still identified and both the | ||
original request and subsequent response are tracked. | ||
2. **Central access**, so applications only need to use a new URL for | ||
requesting certificates. | ||
3. **Certificate modification**, so customization of the requester's | ||
submission can be exposed to this external service. | ||
4. **External validation**, when compared to the Role-based system, as the | ||
CIEPS implementation can reach out to customer-defined external systems | ||
for validation. | ||
|
||
Either of these two mechanisms allow an organization to leverage the Vault | ||
PKI Secrets Engine to build their own flexible issuance control architecture, | ||
leveraging Vault as a PKI-as-a-Service platform. However, CIEPS grants far | ||
greater control to the organization than the `sign-verbatim` approach. | ||
|
||
### Custom policy with `sign-verbatim` | ||
|
||
With `sign-verbatim`, the policy validation service must sit in front of | ||
Vault, processing requests from the user (which cannot use Vault | ||
authentication and needs to authenticate themselves separately to this | ||
service). This RA service then handles its own authentication to Vault, | ||
which provides the signing capabilities via the PKI plugin. | ||
|
||
When the application retains control over its own key material by providing | ||
a CSR, the policy service cannot modify the requested CSR and thus cannot | ||
modify the resulting certificate. It can only approve or deny requests | ||
without allowing operators to hide implementation details from calling | ||
applications. This is because PKI's `sign-verbatim` endpoint lacks the | ||
ability for the Vault API caller (in this case, the fronting policy service) | ||
to modify the certificate independent of the provided CSR. | ||
|
||
If, however, the policy service can control key material (and this is an | ||
acceptable risk to the organization), the policy service could modify requests | ||
on behalf of the calling application. However, this still requires the | ||
external application to know how to authenticate to this external policy | ||
service. | ||
|
||
Additionally, to ensure compatibility with Vault, this policy service (and its | ||
developers) would need to add support for the ACME protocol. For any new | ||
protocols Vault supports in the future, this service would also need to | ||
implement support to retain compatibility. | ||
|
||
### Custom policy with Certificate Issuance External Policy Service (CIEPS) | ||
|
||
With CIEPS, users still authenticate to Vault and use the normal request | ||
workflow to sign and issue certificates, including via ACME. However, | ||
Vault's PKI Engine reaches out to the configured CIEPS implementation to | ||
validate and template the requested certificate, transparently from the | ||
calling application. | ||
|
||
Notably, the application can opt to either retain full control over its key | ||
material or delegate key creation to the trusted Vault service, with no impact | ||
on the functionality CIEPS can provide. The CIEPS service can be scoped to | ||
respond to requests from either a single PKI mount or multiple, getting | ||
information about the requesting user and the Vault PKI instance from the | ||
CIEPS messages. | ||
|
||
Because the CIEPS service only needs knowledge of validating requests and | ||
templating the final certificate structure, its developers need only be | ||
concerned with the business policy logic and not broader PKI concerns (such | ||
as generating key material or re-implementing support for other issuance | ||
protocols). | ||
|
||
## Certificate Issuance External Policy Service (CIEPS) webhook format | ||
|
||
The CIEPS protocol is a REST-based, optionally mTLS protected webhook. The | ||
external service configuration specifies the single URL that Vault will POST | ||
the formatted CIEPS request to. When the CIEPS service is unavailable (either | ||
due to misconfiguration or outage), Vault will reject the request and it is | ||
up to the client to retry the request at a later time. | ||
|
||
For convenience, Go versions of these structs are available [from the Vault | ||
SDK](https://github.com/hashicorp/vault/blob/main/sdk/helper/certutil/cieps.go). | ||
|
||
### Vault to CIEPS request format | ||
|
||
This document outlines CIEPS request/response version 1. | ||
|
||
Using the `application/json` content type, Vault will post the following | ||
request body as a JSON object: | ||
|
||
- `request_version` `(int: 1)` - The version of the CIEPS request sent by | ||
Vault; a compatible response format is expected. | ||
|
||
- `request_uuid` `(string)` - A random UUID which serves to identify this | ||
request. This value must be sent in the response. | ||
|
||
- `synchronous` `(bool: true)` - A boolean indicating whether the request is | ||
synchronous or not. Presently set to true; no asynchronous response is | ||
understood. | ||
|
||
- `user_request_key_values` `(map[string]interface{})` - The unvalidated | ||
request parameters sent by the user. It is up to the CIEPS service to | ||
validate these prior to using them. The following fields may be present, | ||
including any other fields submitted by the user: | ||
|
||
- `csr` `(string)` - A PEM format CSR submitted either by the client ( | ||
in the case of `/sign` or ACME requests) or on the client's behalf | ||
(in the case of `/issue` requests, where key material is generated | ||
by Vault). | ||
|
||
- `identity_request_key_values` `(map[string]interface{})` - Values related | ||
to the user's identity. When the request type is ACME, this value is not | ||
populated. These are: | ||
|
||
- `entity_id` `(string)` - The entity identifier from the request after | ||
authentication. | ||
|
||
- `entity` `(map[string]interface{})` - The entire resolved `logical.Entity` | ||
of the user after authentication; subject to change by the | ||
`entity_jmsepath` parameter in the configuration. | ||
|
||
- `groups` `([]map[string]interface{})` - The set of resolved | ||
`logical.Groups` of the user after authentication; subject to change by | ||
the `group_jmsepath` parameter in the configuration. | ||
|
||
~> **Note**: in the event that the direct token backend or a root token is | ||
used, entity information may not exist. In either case, | ||
`identity_request_key_values` will be omitted. | ||
|
||
- `acme_request_key_values` `(map[string]interface{})` - Values related to | ||
ACME authorizations challenges attached to the finished order. Only present | ||
when the request type is ACME. These are: | ||
|
||
- `authorizations` `(map[string]interface{})` - Authorizations and | ||
challenges solved by the client to move this order to the finalization | ||
state. | ||
|
||
- `account` `(map[string]interface{})` - Information related to the ACME | ||
account issuing the request. These are: | ||
|
||
- `id` `(string)` - The UUID of the ACME account. | ||
|
||
- `directory` `(string)` - The path to the ACME directory requested by | ||
this account. | ||
|
||
- `contact` `([]string)` - Unverified contact information submitted by | ||
the requesting ACME account on creation. | ||
|
||
- `created_date` `(string: RFC 3999 format)` - Timestamp when the account | ||
was created. | ||
|
||
- `eab` `(map[string]interface{}, optional)` - When present, the details | ||
of the EAB used to authorize this account via Vault authentication. If | ||
not present, this ACME account was created without EAB bindings. | ||
|
||
- `key_id` `(string)` - Identifier of the EAB binding used by this | ||
account. | ||
|
||
- `key_type` `(string)` - Key type of the EAB binding used by this | ||
account. | ||
|
||
- `created_date` `(string: RFC 3999 format)` - Timestamp when the | ||
account was created. | ||
|
||
- `vault_request_values` `(map[string]interface{})` - Request value validated | ||
or created by Vault. These have higher trust than the unvalidated | ||
`user_request_key_values`. These are: | ||
|
||
- `policy_name` `(string: "")` - The optional policy name specified by the | ||
requester. When the issuance mode is not ACME (or if it was ACME and EAB | ||
was enforced), this has been validated by Vault's ACL system. | ||
|
||
- `mount` `(string)` - The request's mount path as known by the PKI plugin. | ||
|
||
- `namespace` `(string)` - The request's namespace the mount path exists | ||
within as known by the PKI plugin. | ||
|
||
- `vault_is_performance_standby` `(bool)` - Asserted when this requesting | ||
node is a standby node. When the service indicates storage is required in | ||
its response, Vault will forward the user's HTTP request up to an active | ||
node, requiring it to re-submit the CIEPS request. In this case, if the | ||
service knows it must always store certificates and sees a request from | ||
a standby node, it can skip policy and template evaluation or cache the | ||
results for a second pass. | ||
|
||
- `vault_is_performance_secondary` `(bool)` - Asserted when this requesting | ||
node is from a performance secondary versus the primary cluster. | ||
|
||
- `issuance_mode` `(string: "sign", "issue", "ica", or "acme")` - The type | ||
of the request: whether a REST call to `/external-policy/sign(/:policy)`, | ||
to `/external-policy/issue(/:policy)`, `/external-policy/sign-intermediate(/:policy)`, | ||
or an ACME request, respectively. | ||
|
||
- `vault_generated_private_key` `(bool)` - Whether or not Vault generated | ||
the key material behind this request. Set to true when | ||
`issuance_mode="issue"` only presently. | ||
|
||
- `requested_issuer_name` `(string)` - Name of the user's requested issuer; | ||
can be changed by modifying the response `issuer_ref` value. | ||
|
||
- `requested_issuer_id` `(string)` - UUID of the user's requested issuer; | ||
can be changed by modifying the response `issuer_ref` value. | ||
|
||
- `requested_issuer_cert` `(string)` - PEM format certificate of the user's | ||
requested issuer; can be changed by modifying the response `issuer_ref` | ||
value. | ||
|
||
- `requested_issuance_config` `(map[string]interface{})` - Configuration | ||
used for leaf certificate issuance. These are: | ||
|
||
- `aia_values` `(map[string]interface{})` - AIA values (CA, CRL, and | ||
OCSP) for the suggested issuer. These may differ from the actual values | ||
used for issuance of this request if `issuer_ref` is set on the response. | ||
|
||
- `leaf_not_after_behavior` `(string: "err", "truncate", or "permit")` - leaf | ||
validity period behavior for the suggested issuer. | ||
|
||
- `mount_default_ttl` `(string)` - Suggested default TTL set on mount tuning. | ||
|
||
- `mount_max_ttl` `(string)` - Suggested maximum TTL set on the mount tuning. | ||
|
||
### CIEPS to Vault response format | ||
|
||
The CIEPS engine must reply to this POST response with a `200 OK` status, | ||
regardless of whether a certificate should be issued or not. Redirects will | ||
not be followed by Vault; any proxy or load balancing functionality should be | ||
strictly transparent to the caller. Any verbatim message returned by a non-200 | ||
status code will not be returned, either in Vault server logs or to the user. | ||
|
||
In the response to the above request, only one of the `certificate` or `error` | ||
fields should be specified. In the event both `certificate` and `error` are | ||
present, the `error` will be appended to the returned `warnings` and the | ||
`certificate` will be issued. | ||
|
||
Using the `application/json` content type, the server should reply with the | ||
following JSON object: | ||
|
||
- `request_uuid` `(string)` - The random UUID which the server used to | ||
identify this request. | ||
|
||
- `error` `(string, optional)` - The error message to be returned to the | ||
user about why their request failed. Only one of the `error` or | ||
`certificate` response parameters should be specified. | ||
|
||
- `warnings` `([]string, optional)` - Optional warnings to be returned to the user | ||
about minor issues with their request. | ||
|
||
- `certificate` `(string, optional)` - A PEM format certificate to be signed | ||
by the Vault service. Only one of the `error` or `certificate` response | ||
parameters should be specified. | ||
|
||
- `issuer_ref` `(string)` - The issuer reference to use to sign this request. | ||
If the user's issuer choice (in `requested_issuer_id`) is OK, this must | ||
be set in this field. | ||
|
||
- `store_certificate` `(bool: false)` - Whether or not to store the signed | ||
certificate. | ||
|
||
- `generate_lease` `(bool: false)` - Whether or not Vault should generate an | ||
associated lease for the certificate. Note that to generate a lease, | ||
`store_certificate` also needs to be set to `true`, otherwise no lease | ||
will be generated. | ||
|
||
The certificate's signature will be ignored and replaced by a signature created | ||
by the specified issuer. If a signature algorithm compatible with this issuer | ||
is specified on the certificate, it will be preserved; otherwise, the default | ||
signature algorithm for this issuer's key type will be used. | ||
|
||
The certificate's AIA information will be replaced by the information from the | ||
specified issuer, if present, else the global AIA URLs will be set, replacing | ||
the AIA URIs and CRL distribution point extensions. Additionally, the | ||
Authority Key Identifier extension will be replaced by the issuer's Subject | ||
Key Identifier extension value as mandated by RFC 5280. | ||
|
||
## Tutorial | ||
|
||
Refer to the following tutorials for PKI secrets engine usage examples: | ||
|
||
- [Build Your Own Certificate Authority (CA)](/vault/tutorials/secrets-management/pki-engine) | ||
- [Build Certificate Authority (CA) in Vault with an offline Root](/vault/tutorials/secrets-management/pki-engine-external-ca) | ||
- [Enable ACME with PKI secrets engine](/vault/tutorials/secrets-management/pki-acme-caddy) | ||
- [PKI Secrets Engine with Managed Keys](/vault/tutorials/enterprise/managed-key-pki) | ||
- [PKI Unified CRL and OCSP With Cross Cluster | ||
Revocation](/vault/tutorials/secrets-management/pki-unified-crl-ocsp-cross-cluster) | ||
- [Configure Vault as a Certificate Manager in Kubernetes with | ||
Helm](/vault/tutorials/kubernetes/kubernetes-cert-manager) | ||
- [Generate mTLS Certificates for Nomad using | ||
Vault](/vault/tutorials/secrets-management/vault-pki-nomad) | ||
|
||
|
||
## API | ||
|
||
The PKI secrets engine has a full HTTP API. Please see the | ||
[PKI secrets engine API](/vault/api-docs/secret/pki) for more | ||
details. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters