The EJBCA PKI Secrets Engine is a Vault plugin that replicates the built-in Vault PKI secrets engine, but processes requests through EJBCA instead of through Vault. The plugin was designed to be swapped for the built-in Vault PKI secrets engine with minimal changes to existing Vault configurations.
The secrets engine is built on top of the EJBCA REST API and uses the EJBCA Go Client SDK for programmatic access.
The EJBCA PKI Secrets Engine requires the following API endpoints:
GET /v1/ca/{subject_dn}/certificate/download
- Used to fetch CA certificates and certificate chains based on the CA's subject DN.GET /v1/ca
- Used to verify the CA name provided asissuer_ref
.PUT /v1/certificate/{issuer_dn}/{certificate_serial_number}/revoke
- Used to revoke certificates.POST /v1/certificate/pkcs10enroll
- Used to issue certificates.
- EJBCA Community or EJBCA Enterprise
- The "REST Certificate Management" protocol must be enabled under System Configuration > Protocol Configuration.
- HashiCorp Vault >= v1.11.0
From Source
Clone the repository and build the plugin.
git clone https://github.com/Keyfactor/ejbca-vault-pki-engine.git
cd ejbca-vault-pki-engine
Build the plugin for your platform.
go build -o ejbca-vault-pki-engine cmd/ejbca-pki/main.go -v
Calculate the SHA256 checksum of the plugin.
SHA256=$(sha256sum ejbca-vault-pki-engine | cut -d ' ' -f1)
Move the plugin to the Vault plugin directory.
sudo mv ejbca-vault-pki-engine </path/to/vault/plugins>
Register SHA256 checksum of the plugin with Vault.
vault write sys/plugins/catalog/secret/ejbca-vault-pki-engine sha_256=$SHA256 command="ejbca-vault-pki-engine" version="v1.2.0"
Mount the secrets engine and choose a prefix for the path (recommended is ejbca
).
vault secrets enable -path=ejbca -plugin-name=ejbca-vault-pki-engine plugin
From GitHub Release
Download and extract the latest release for your platform.
OS=$(go env GOOS)
ARCH=$(go env GOARCH)
curl -L https://github.com/Keyfactor/ejbca-vault-pki-engine/releases/latest/download/ejbca-vault-pki-engine-$OS-$ARCH.tar.gz
tar xzf ejbca-vault-pki-engine-$OS-$ARCH.tar.gz
Calculate the SHA256 checksum of the plugin.
SHA256=$(sha256sum ejbca-vault-pki-engine | cut -d ' ' -f1)
Move the plugin to the Vault plugin directory.
sudo mv ejbca-vault-pki-engine </path/to/vault/plugins>
Register SHA256 checksum of the plugin with Vault.
vault write sys/plugins/catalog/secret/ejbca-vault-pki-engine sha_256=$SHA256 command="ejbca-vault-pki-engine" version="v1.2.0"
Mount the secrets engine and choose a prefix for the path (recommended is ejbca
).
vault secrets enable -path=ejbca -plugin-name=ejbca-vault-pki-engine plugin
The EJBCA Vault PKI Engine has two levels of configuration.
- The
/config
path configures the connection to EJBCA and contains default values for the EJBCA-specific configuration fields. Default configuration fields are provided in case you already use the in-tree Vault PKI Engine and want to deploy the EJBCA Secrets Engine with minimal intervention. - The
/roles
endpoint configures how the engine should behave when issuing certificates, and configures the validations/requirements for the attributes included in signed certificates. The EJBCA Vault PKI Engine implements a subset of the fields implemented by the in-tree Vault PKI Engine.
The /config
endpoint must be configured first. The following table describes the available fields.
Configuration | Description |
---|---|
hostname |
The hostname of the connected EJBCA server. |
ca_cert |
(optional) The CA certificate(s) used to validate the EJBCA server's certificate. Certificates must be in PEM format. |
client_cert |
The client certificate (public key only) used to authenticate to EJBCA. Must be in PEM format. |
client_key |
The client key matching client_cert used to authenticate to EJBCA. Must be an unencrypted PKCS#8 private key in PEM format. |
token_url |
The OAuth 2.0 token URL used to obtain an access token. |
client_id |
The OAuth 2.0 client ID used to obtain an access token. |
client_secret |
The OAuth 2.0 client secret used to obtain an access token. |
scopes |
(optional) A comma-separated list of OAuth 2.0 scopes used to obtain an access token. |
audience |
(optional) The OAuth 2.0 audience used to obtain an access token. |
default_ca |
The default CA in EJBCA that will be used to issue certificates if not specified by the role or per-request. |
default_end_entity_profile |
The name of an end entity profile in the connected EJBCA instance that will be used to issue certificates if not specified by the role or per-request. |
default_certificate_profile |
The name of a certificate profile in the connected EJBCA instance that is configured to issue certificates if not specified by the role or per-request. |
default_end_entity_name |
(optional) The name of the end entity, or configuration for how the EJBCA UpstreamAuthority should determine the end entity name. See End Entity Name Customization for more info. |
The EJBCA Vault PKI Engine can authenticate to EJBCA using mTLS (client certificate) or using the OAuth 2.0 "client credentials" token flow (sometimes called two-legged OAuth 2.0).
EJBCA Enterprise is required for the OAuth 2.0 "client credentials" token flow. EJBCA Community only supports mTLS (client certificate) authentication.
To configure the plugin to use mTLS, you must configure the /config
object with both of the following fields:
client_cert
client_key
Use the following vault command to create the config
object with mTLS:
vault write ejbca/config \
hostname="https://ejbca.example.com:8443/ejbca" \
client_cert=@/path/to/client/cert.pem \
client_key=@/path/to/client/key.pem \
ca_cert=@/path/to/ca/cert.pem \
end_entity_profile_name="MyEndEntityProfile" \
certificate_profile_name="MyCertificateProfile"
To configure the plugin to use OAuth 2.0, you must configure the /config
object with the following fields:
token_url
client_id
client_secret
- (optional)
scopes
- (optional)
audience
Use the following vault command to create the config
object with OAuth 2.0:
vault write ejbca/config \
hostname="https://ejbca.example.com:8443/ejbca" \
token_url="https://dev.idp.com/oauth/token" \
client_id="<client_id>" \
client_secret="<client_secret>" \
scopes="<comma separated list of scopes>" \
audience="<OAuth audience>" \
ca_cert=@/path/to/ca/cert.pem \
end_entity_profile_name="MyEndEntityProfile" \
certificate_profile_name="MyCertificateProfile"
The EJBCA PKI Secrets Engine supports a subset of the role fields as the built-in Vault PKI secrets engine, and for most usecases, can be used as a drop-in replacement. Use the following command to get descriptions for these fields:
vault path-help ejbca/roles/name
EJBCA implements its own role and policy system. Users should be advised that even if Certificate Enrollment with the EJBCA Vault PKI Engine is valid against the Vault role, it may still be rejected by EJBCA due to EJBCA's own role and policy system.
Concequentially, there may be differences between how the EJBCA Vault PKI Engine and the built-in Vault PKI Engine handle certificate issuance and validation. If you are using the EJBCA Vault PKI Engine as a drop-in replacement for the built-in Vault PKI Engine, it is recommended to test the EJBCA Vault PKI Engine in a non-production environment before deploying it to production.
Please submit an issue if you encounter any differences between the EJBCA Vault PKI Engine and the built-in Vault PKI Engine.
The following example creates a basic role that can be used for issuance:
vault write ejbca/roles/example-dot-com \
allow_any_name=true \
allow_subdomains=true \
max_ttl=8760h \
key_type="rsa" \
key_bits=2048 \
signature_bits=256 \
use_pss=false
The EJBCA PKI Secrets Engine also supports the following additional role fields that are not needed in the in-tree Vault PKI engine.
end_entity_profile_name
- The name of the EJBCA End Entity Profile to use for certificate issuance.certificate_profile_name
- The name of the EJBCA Certificate Profile to use for certificate issuance.end_entity_name
- A value that will either be used to calculate the end entity name, or the end entity name itself. See the (configuring end entity name)[#configuring-end-entity-name] for more details.account_binding_id
- EJBCA Account Binding ID.
Note: If left blank, the
end_entity_profile_name
,certificate_profile_name
, andend_entity_name
fields will default to the values configured in theconfig
object.
The EJBCA Vault PKI Engine can create Vault Leases for issued certificates if the role has generate_lease=true
. If this option is set, the lease and certificate that it represents can be revoked with vault revoke <lease_id>
. When the lease is revoked, the engine revokes the certificate in EJBCA and updates the backend accordingly for the regular paths.
Once the EJBCA PKI Secrets Engine is configured and roles are created, you can use the following paths to issue and sign certificates, list certificates, and revoke certificates.
The following paths can be used to issue and sign certificates. The :role_name
parameter is required for all paths except sign-verbatim
. Paths that require the :issuer_ref
parameter will use the provided name as the EJBCA CA name for certificate issuance.
Note: The
/issue
paths generate the CSR and private key on the Vault server - the private key is never sent over the wire by EJBCA.
Path | Issuer | CSR required | Subject to role restriction | Description | Help Path |
---|---|---|---|---|---|
sign/:role_name | Role selected | Yes | Yes | Sign a CSR using the default CA from Config and validate its attributes against the provided role. | vault path-help ejbca/sign/example |
issuer/:issuer_ref/sign/:role_name | Path selected | Yes | Yes | Sign a CSR using a specific CA and validate its attributes against the provided role | vault path-help ejbca/issuer/example/sign/example |
issue/:role_name | Role selected | No | Yes | Generate a private key configured either by the role or with the request itself, then sign the CSR using the default CA from Config. | vault path-help ejbca/issue/example |
issuer/:issuer_ref/issue/:role_name | Path selected | No | Yes | Generate a private key configured either by the role or with the request itself, then sign the CSR using the provided CA. | vault path-help ejbca/issuer/example/issue/example |
sign-verbatim(/:role_name) | default | Yes | No | Sign a CSR using the default CA and don't validate its attributes against a role. | vault path-help ejbca/sign-verbatim |
issuer/:issuer_ref/sign-verbatim(/:role_name) | Path selected | Yes | No | Sign a CSR using the specified CA and don't validate its attributes against a role. | vault path-help ejbca/issuer/example/sign-verbatim |
The following example issues a certificate using the example-dot-com
role:
vault write ejbca/issue/example-dot-com \
common_name="example.com" \
alt_names="*.example.com" \
format="pem_bundle" \
account_binding_id="abc123"
The following path can be used to revoke certificates. Either the serial_number
or certificate
parameter is required.
Path | Required Parameters | Description | Help Path |
---|---|---|---|
revoke | serial_number or certificate PEM | Revokes a certificate by serial number or certificate itself. | vault path-help ejbca/revoke |
revoke-with-key | certificate private key and serial_number or certificate PEM | Revokes a certificate only if the user proves they have the private key. | vault path-help ejbca/revoke-with-key |
The following example revokes a certificate and provides the private key:
vault write ejbca/revoke-with-key \
serial_number="62:c6:3f:13:12:39:9d:75:2c:77:db:62:bd:e2:47:3a:0b:56:de:de" \
private_key="-----BEGIN EC PRIVATE KEY----- MHcCAQEEII1YXWvr+8i5o8QQ5I3mF/T55AGzQ8VrC2VPHa+m5MvooAoGCCqGSM49 AwEHoUQDQgAEL6+GnD6BtY3mEY2qLfGJVPP4Cx23WeGYBbvxsgz+Kh85S7Z92llx zZUn7uSYC0bvNhHJ1I4SpZNKDWKbXWMgQQ== -----END EC PRIVATE KEY-----"
Note: The EJBCA PKI Secrets Engine cannot revoke certificates that were not issued by the EJBCA PKI Secrets Engine. That is, the certificate must exist in the Secrets Engine's backend.
The following paths can be used to fetch CA certificates. The paths that specify a Content-Type
cannot be consumed using the vault
command, and must be consumed using the Vault HTTP API. Any path that uses ca
as its root will report the default issuer/CA configured in the Config path.
Path | Content-Type | Encoding | Response Format | Whole chain? | Help Path |
---|---|---|---|---|---|
ca | application/pkix-cert | DER | DER | false | vault path-help ejbca/ca |
ca/pem | application/pem-certificate-chain | PEM | PEM | true | vault path-help ejbca/ca/pem |
cert/ca | PEM | JSON | true | vault path-help ejbca/cert/ca |
|
cert/ca/raw | application/pkix-cert | DER | DER | false | vault path-help ejbca/cert/ca/raw |
cert/ca/raw/pem | application/pem-certificate-chain | PEM | PEM | true | vault path-help ejbca/cert/ca/raw/pem |
ca_chain | application/pkix-cert | PEM | PEM | true | vault path-help ejbca/ca_chain |
cert/ca_chain | PEM | JSON | true | vault path-help ejbca/cert/ca_chain |
|
issuer/:issuer_ref | PEM | JSON | true | vault path-help ejbca/issuer/example |
|
issuer/:issuer_ref/pem | application/pem-certificate-chain | PEM | PEM | true | vault path-help ejbca/issuer/example/pem |
The following paths can be used to fetch certificates.
Path | Content-Type | Encoding | Help Path |
---|---|---|---|
cert/:serial | PEM | vault path-help ejbca/cert/123456 |
|
cert/:serial/raw | application/pkix-cert | DER | vault path-help ejbca/cert/123456/raw |
cert/:serial/pem | application/pem-certificate-chain | PEM | vault path-help ejbca/cert/123456/pem |
📌 Note: The fetch methods will never return a private key. Private keys are only returned with the issue
methods.
Serial numbers of certificates and revoked certificates can be found using the following paths.
Path | Description | Help Path |
---|---|---|
certs | Lists all certificates issued by the EJBCA PKI Secrets Engine. | vault path-help ejbca/certs |
certs/revoked | Lists all certificates revoked by the EJBCA PKI Secrets Engine. | vault path-help ejbca/certs/revoked |
The default_end_entity_name
and end_entity_name
fields in the Config and Role paths allow you to configure how the End Entity Name is selected when issuing certificates through EJBCA. This field offers flexibility by allowing you to select different components from the Certificate Signing Request (CSR) or other contextual data as the End Entity Name.
Here are the different options you can set for default_end_entity_name
for the Config path or end_entity_name
for the Role path:
cn
: Uses the Common Name from the CSR's Distinguished Name.dns
: Uses the first DNS Name from the CSR's Subject Alternative Names (SANs).uri
: Uses the first URI from the CSR's Subject Alternative Names (SANs).ip
: Uses the first IP Address from the CSR's Subject Alternative Names (SANs).- Custom Value: Any other string will be directly used as the End Entity Name.
If the end_entity_name
field is not explicitly set, the EJBCA Vault PKI Engine will attempt to determine the End Entity Name using the following default behavior:
- First, it will try to use the Common Name: It looks at the Common Name from the CSR's Distinguished Name.
- If the Common Name is not available, it will use the first DNS Name: It looks at the first DNS Name from the CSR's Subject Alternative Names (SANs).
- If the DNS Name is not available, it will use the first URI: It looks at the first URI from the CSR's Subject Alternative Names (SANs).
- If the URI is not available, it will use the first IP Address: It looks at the first IP Address from the CSR's Subject Alternative Names (SANs).
- If none of the above are available: The certificate issuance will fail.
If the Engine is unable to determine a valid End Entity Name through these steps, an error will be logged and no End Entity Name will be set.