EJBCA Deployment, Admin, Certificate Management, Integration, and Maintenance

Note

For detailed guidance on EJBCA functionality, administration, and configuration, see the official EJBCA documentation.

Deploy and Manage the EJBCA Application

This section describes the EJBCA application lifecycle on StarlingX, including application upload, configuration, deployment, updates, removal, and deletion.

Upload the EJBCA Application

Upload the application tarball to register it with the platform.

~(keystone_admin)]$ system application-upload /path/to/ejbca-<version>.tgz

For Distributed Cloud deployments, ensure that registry.central contains the required application images before you apply the application on subclouds. You can populate registry.central in one of the following ways:

  • Apply the application on the System Controller to automatically pull the required images into registry.central.

    or

  • Upload the application on the System Controller with the –images option to import the required images into registry.central before deploying the application on subclouds.

    ~(keystone_admin)]$ system application-upload /path/to/ejbca-<version>.tgz --images
    

Apply the EJBCA Application

Before you apply the EJBCA application, configure the required Helm overrides.

Procedure

  1. Set the EJBCA hostname (required). Specify the FQDN that users will use to access EJBCA externally:

    ~(keystone_admin)]$ system helm-override-update ejbca ejbca ejbca \
        --set ejbca.hostname=<ejbca.example.com>
    

    Note

    In a lab environment where a DNS server is not available:

    • To access the EJBCA service by hostname from inside the StarlingX system, add a record to the DNS service to resolve the EJBCA hostname to the OAM floating IP address:

      ~(keystone_admin)]$ system service-parameter-add dns host-record \
          <ejbca.example.com>=<ejbca.example.com>,<OAM_floating_IP>
      
    • To access the EJBCA service by hostname from outside the StarlingX system, add an entry to the /etc/hosts file on the machine from which the EJBCA access is initiated:

      <OAM_floating_IP>  <ejbca.example.com>
      
  2. (Optional) Specify the PostgreSQL storage class. By default, the application uses the cluster’s default StorageClass (for example, ceph-rbd on systems with Ceph). If the cluster does not define a default StorageClass, specify one explicitly:

    ~(keystone_admin)]$ system helm-override-update ejbca ejbca-pg-cluster ejbca \
        --set postgresql.storageClass=<your-storage-class>
    

    In a laboratory environment without Ceph, install and use a local-path provisioner:

    ~(keystone_admin)]$ kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml
    ~(keystone_admin)]$ kubectl get storageclass
    ~(keystone_admin)]$ system helm-override-update ejbca ejbca-pg-cluster ejbca \
        --set postgresql.storageClass=local-path
    

    Note

    • The platform rejects the apply operation if the specified storageClass override does not exist in the cluster.

    • If you do not specify a StorageClass and the cluster does not have a default StorageClass, the platform rejects the apply operation and prompts you to provide one.

    • If the cluster has a default StorageClass and you do not specify an override, the platform automatically uses the default StorageClass.

  3. Apply the application:

    ~(keystone_admin)]$ system application-apply ejbca
    

    If you do not set the hostname override, the platform rejects the apply with an error message:

    Application-apply rejected: ejbca: required helm override 'ejbca.hostname'
    is not set. Set it before applying the app:
    system helm-override-update ejbca ejbca ejbca --set ejbca.hostname=<ejbca.example.com>
    
  4. Verify the application status:

    ~(keystone_admin)]$ system application-show ejbca
    ~(keystone_admin)]$ kubectl get pods -n ejbca
    

Remove the EJBCA Application

Use this operation to stop the EJBCA application while preserving all application data. You can reapply the application at any time.

~(keystone_admin)]$ system application-remove ejbca

After you remove the application:

  • The ejbca namespace, PVCs, PostgreSQL cluster, secrets, certificates, keys, and configuration remain intact.

  • Cluster-scoped resources (CertificateRequestPolicy, ClusterRoles, ClusterRoleBindings) are also preserved.

  • The application returns to the uploaded state, ready to reapplied.

Delete the EJBCA Application

Use this operation to completely remove the EJBCA application and all its data from the platform.

Note

Unlike the remove operation, this operation is irreversible. Ensure you have a backup of CA keys, certificates, and PKI data before proceeding.

~(keystone_admin)]$ system application-delete ejbca

This operation:

  • Deletes the ejbca namespace, including PVCs, the database, and secrets.

  • Removes cluster-scoped resources (CertificateRequestPolicy, ClusterRoles, ClusterRoleBindings).

  • Unregisters the application from the platform.

Update the EJBCA Application

Procedure

  1. Update the application to a new version:

    ~(keystone_admin)]$ system application-update /path/to/ejbca-<new-version>.tgz
    

    The update preserves all existing configuration and PKI data, including user helm overrides, and performs a rolling update of pods.

  2. Monitor the update progress:

    ~(keystone_admin)]$ system application-show ejbca
    ~(keystone_admin)]$ kubectl rollout status deployment -n ejbca
    

Note

Use the application-update command for all application version changes. The platform does not provide an application-upgrade command. Platform upgrades can automatically update the application if the application metadata specifies auto_update: true.

EJBCA CLI Operations

Use the EJBCA CLI (ejbca.sh) inside the EJBCA container to perform administrative operations. The CLI communicates using internal EJB calls and therefore does not require application-level authentication. However, you must have cluster-admin privileges in Kubernetes to run kubectl exec commands.

This section covers common tasks such as managing certificate authorities, certificate profiles, and CMP aliases using the CLI.

Available Operations (Community Edition)

Many operations are available via the CLI, some of which can only be done using the CLI (or Admin GUI). The following table summarizes some of the EJBCA operations and indicates whether each operation can be performed using the CLI, Admin GUI, or both.

Operation

CLI

Admin GUI

Import external CA certificates — ejbca.sh ca importcacert

Yes

No

Sign CSRs (without a pre-created end entity) — ejbca.sh createcert

Yes

No

Set up superadmin authorization — ejbca.sh roles initauthorization

Yes

No

Create Certificate Authorities — ejbca.sh ca init

Yes

Yes

Edit certificate profiles — ejbca.sh ca editcertificateprofile

Yes

Yes

Create end entities — ejbca.sh ra addendentity

Yes

Yes

Configure CMP aliases — ejbca.sh config cmp addalias/updatealias

Yes

Yes

Create certificate profiles

No

Yes

Create end entity profiles

No

Yes

Access the CLI

Run the following command to open an interactive shell session inside the EJBCA container and access the CLI directly.

~(keystone_admin)]$ kubectl exec -it ejbca-0 -n ejbca -c ejbca -- /opt/keyfactor/bin/ejbca.sh

CLI Operation Examples

The following shows some examples of CLI operations that can only be done by CLI and the Admin GUI.

Note

In the following examples, replace the placeholder password changeit with a strong, unique password.

Create a CA

$ export NAMESPACE="ejbca"
$ export EJBCA_POD="ejbca-0"
$ export CONTAINER="ejbca"
$ export E="/opt/keyfactor/bin/ejbca.sh"
$ export CA_NAME="test-ca"
$ export CA_TOKEN_PASS="changeit"

~(keystone_admin)]$ kubectl exec -it ${EJBCA_POD} -n ${NAMESPACE} -c ${CONTAINER} -- $E ca init \
    --caname ${CA_NAME} \
    --dn "CN=${CA_NAME}" \
    --tokenType soft \
    --tokenPass ${CA_TOKEN_PASS} \
    --keytype RSA \
    --keyspec 4096 \
    -v 3650 \
    --policy null \
    -s SHA256WithRSA \
    --signedby 1

Note

Replace the placeholder password changeit with a strong, unique password.

Create a CMP Alias

Before you create a CMP alias, create the certificate profile and end entity profile in the Admin GUI. To automate profile management across deployments, use the CLI commands ca exportprofiles and ca importprofiles to export and import profiles. You can also import profiles from a reference EJBCA system.

Note

Replace the placeholder password changeit with a strong, unique password.

$ export CERT_PROFILE="test-cert-profile"
$ export EE_PROFILE="test-entity-profile"
$ export CMP_ALIAS="cmp-test-alias"
$ export CMP_HMAC_SECRET="changeit"

# Create the alias
~(keystone_admin)]$ kubectl exec ${EJBCA_POD} -c ${CONTAINER} -n ${NAMESPACE} -- $E config cmp addalias \
     --alias ${CMP_ALIAS}

# Configure the alias parameters
$ for kv in \
    "operationmode ra" \
    "authenticationmodule HMAC" \
    "authenticationparameters ${CMP_HMAC_SECRET}" \
    "responseprotection pbe" \
    "defaultca ${CA_NAME}" \
    "ra.certificateprofile ${CERT_PROFILE}" \
    "ra.endentityprofile ${EE_PROFILE}" \
    "ra.namegenerationscheme DN" \
    "ra.caname ${CA_NAME}"; do
  ~(keystone_admin)]$ kubectl exec ${EJBCA_POD} -c ${CONTAINER} -n ${NAMESPACE} -- \
    $E config cmp updatealias \
    --alias ${CMP_ALIAS} --key ${kv%% *} --value "${kv#* }"
done

# Verify the configuration
~(keystone_admin)]$ kubectl exec ${EJBCA_POD} -c ${CONTAINER} -n ${NAMESPACE} -- \
    $E config cmp dumpalias --alias ${CMP_ALIAS}

Note

For the complete CLI command reference, see: https://docs.keyfactor.com/ejbca/latest/ejbca-operations/ejbca-cli-reference.

EJBCA Admin GUI Access and Operations

To access the EJBCA Admin GUI, you must import both the CA certificate and the superadmin client credential into your browser. The Admin GUI uses mTLS for authentication.

Prerequisites

Before accessing the Admin GUI:

Export the system-local-ca Certificate

Export the CA certificate from the platform to your local machine.

~(keystone_admin)]$ kubectl get secret system-local-ca -n cert-manager \
    -o jsonpath='{.data.ca\.crt}' | base64 -d > system-local-ca.pem

Export the Superadmin Credential

Export the superadmin credential from the platform to your local machine.

$ source /etc/platform/openrc

# Extract the superadmin certificate and key
~(keystone_admin)]$ kubectl get secret ejbca-superadmin-cert -n ejbca \
    -o jsonpath='{.data.tls\.crt}' | base64 -d > /tmp/sa.crt
~(keystone_admin)]$ kubectl get secret ejbca-superadmin-cert -n ejbca \
    -o jsonpath='{.data.tls\.key}' | base64 -d > /tmp/sa.key

# Create a |P12| file to import into your browser
$ openssl pkcs12 -export \
    -out /tmp/superadmin.p12 \
    -inkey /tmp/sa.key \
    -in /tmp/sa.crt \
    -name SuperAdmin \
    -passout pass:<p12-password>

Enable mTLS Authentication

Import the credentials you exported into your browser to enable mTLS authentication.

  1. Import the CA certificate (system-local-ca.pem):

    • In Firefox, select Settings > Privacy & Security > Certificates > View Certificates > Authorities > Import.

    • In Chrome, select Settings > Privacy and Security > Security > Manage certificates > Authorities > Import.

  2. Import the superadmin credential (superadmin.p12):

    • In Firefox, select Settings > Privacy & Security > Certificates > View Certificates > Your Certificates > Import.

    • In Chrome, select Settings > Privacy and Security > Security > Manage certificates > Your Certificates > Import.

    When prompted, enter the PKCS#12 Certificate and Private Key Bundle password you set in the Export the Superadmin Credential procedure.

Access the Admin GUI

Navigate to the following URL to open the Admin GUI:

https://<ejbca-hostname>:7443/ejbca/adminweb/

When prompted, select the superadmin certificate for client authentication.

Common Admin GUI Operations

Use the Admin GUI to view and manage CAs, certificate profiles, end entity profiles, end entities, and certificates.

Operation

Navigation

View all CAs available on the platform, including the default ManagementCA and any CAs you create.

CA Functions > Certificate Authorities

View certificate profiles that define constraints such as allowed key algorithms, key sizes, extensions, and validity periods.

CA Functions > Certificate Profiles

View end entity profiles that define enrollment parameters such as allowed DNs, SANs, and associated certificate profiles.

|RA| Functions > End Entity Profiles

View existing end entities and their associated certificates.

RA Functions > Search End Entities, then select View End Entity or View Certificate

Create certificate profiles and end entity profiles to define key algorithms, validity periods, allowed DNs, SANs, and other enrollment constraints.

See Create Certificate Profiles and End Entity Profiles

Create a CA and issue a certificate using a crypto token, key pairs, and the RA Web interface.

See Create a CA and Issue a Certificate

Create Certificate Profiles and End Entity Profiles

Use certificate and end entity profiles to define enrollment constraints and parameters for certificate requests:

  1. Create a certificate profile. Select CA Functions > Certificate Profiles > Add.

  2. Configure the key algorithm, key size (for example, RSA 4096), validity period, and extensions.

  3. Create an end entity profile. Select RA Functions > End Entity Profiles > Add.

  4. Associate the profile with a certificate profile and default CA, then configure the Subject DN fields and Subject Alternative Names.

Create a CA and Issue a Certificate

Create a new certificate authority and issue a certificate using the Admin GUI.

  1. Create a crypto token. Select CA Functions > Crypto Tokens > Create new (e.g., test-ca-token with password).

  2. Generate the signing and encryption key pairs within the token.

  3. Create a CA. Select CA Functions > Certificate Authorities > Add CA > Create.

  4. Select the crypto token and signing key.

  5. To issue a certificate, select RA Web > Make New Request.

    • Select end entity profile, certificate profile, and CA.

    • Fill in the subject DN and credentials.

    • Download PKCS#12 Certificate and Private Key Bundle or Download PEM.

Note

EJBCA creates a new end entity and its certificate.

Note

For detailed information about the Admin GUI, refer to the EJBCA documentation: https://docs.keyfactor.com/ejbca/latest/ejbca-operations/ejbca-ca-ui

EJBCA Certificate Operations Using CMP

CMP automates certificate lifecycle management. EJBCA uses CMP aliases to associate enrollment parameters with a specific CA, certificate profile, and end entity profile.

This section shows how to use OpenSSL’s CMP client to enroll, renew, revoke, and check the status of certificates through an EJBCA CMP endpoint.

CMP uses two independent authentication layers:

  • TLS layer — The system-local-ca.pem file acts as the TLS trust anchor that verifies the EJBCA HTTPS endpoint. For mTLS authentication with the EJBCA service, you must provide the Super Administrator client certificate and private key.

  • CMP layer — Initial enrollment (ir) and RA-mode renewal use an HMAC shared secret for authentication. Key update requests (kur) use signature-based authentication with an existing certificate and private key.

Prerequisites

Before you begin, ensure the following are available:

  • A CMP alias configured in EJBCA (see EJBCA CLI Operations).

  • A certificate profile and end entity profile associated with the alias.

  • The HMAC shared secret configured for the alias.

  • OpenSSL 3.0+ with CMP support.

  • The system-local-ca.pem certificate for TLS verification.

  • The superadmin client certificate and key for mTLS authentication with the EJBCA service (the httpd proxy). See Export Superadmin Credentials.

  • Environment variables set for the EJBCA hostname, CMP alias, and credentials. See Environment Setup.

Export Superadmin Credentials

Export the superadmin certificate and key from the platform to your local machine:

~(keystone_admin)]$ kubectl get secret -n ejbca ejbca-superadmin-cert \
    -o jsonpath='{.data.tls\.crt}' | base64 -d > superadmin.crt.pem
~(keystone_admin)]$ kubectl get secret -n ejbca ejbca-superadmin-cert \
    -o jsonpath='{.data.tls\.key}' | base64 -d > superadmin.key.pem

Environment Setup

Set the following environment variables before running the commands in this topic:

$ export EJBCA_HOSTNAME="ejbca.example.com:7443"
$ export CMP_ALIAS="cmp-test-alias"
$ export CMP_HMAC_SECRET="changeit"
$ export CA_NAME="test-ca"
$ export SUPERADMIN_CERT="./superadmin.crt.pem"
$ export SUPERADMIN_KEY="./superadmin.key.pem"

Enroll a Certificate

Generate a key pair and CSR using the following commands, then enroll the certificate through a CMP initial request (ir):

$ export CERT="${CA_NAME}-cert"
$ export CERT_CN="${CA_NAME}-cert"
$ export KEY_FILE="${CERT}.key.pem"
$ export CSR_FILE="${CERT}.csr.pem"
$ export CERT_FILE="${CERT}.cert.pem"
$ export CA_FILE="${CA_NAME}.cert.pem"

# Generate private key
$ openssl genrsa -out ${KEY_FILE} 4096

# Generate CSR with SAN
$ openssl req -new -key ${KEY_FILE} \
    -subj "/CN=${CERT_CN}" \
    -addext "subjectAltName=DNS:${CERT_CN}" \
    -out "${CSR_FILE}"

# Enroll via CMP
$ openssl cmp -cmd ir \
    -server ${EJBCA_HOSTNAME} \
    -path /ejbca/publicweb/cmp/${CMP_ALIAS} \
    -tls_used \
    -tls_trusted ./system-local-ca.pem \
    -tls_cert ${SUPERADMIN_CERT} \
    -tls_key ${SUPERADMIN_KEY} \
    -ref "${CMP_ALIAS}" \
    -secret pass:${CMP_HMAC_SECRET} \
    -subject "/CN=${CERT_CN}" \
    -recipient "/CN=${CA_NAME}" \
    -newkey "${KEY_FILE}" \
    -csr "${CSR_FILE}" \
    -certout "${CERT_FILE}" \
    -cacertsout "${CA_FILE}"

Note

Both -csr and -newkey are required: the CSR provides subject and extensions, while -newkey provides the private key for Proof of Possession (POPO).

The -ref parameter is the CMP alias name (used as senderKID for HMAC lookup). The -recipient specifies the DN of the issuing CA.

Renew a Certificate

To renew a certificate, generate a new key pair and CSR, and then submit a new RA mode ir (initial request) using HMAC authentication. Use the same enrollment procedure that you used for the initial certificate request. EJBCA issues a new certificate for the same subject and does not require the existing certificate or private key.

Note

A true CMP key update (kur) uses signature-based authentication with the existing certificate and private key. You cannot authenticate a kur request with HMAC. The ir-based renewal method shown here provides a simpler alternative for RA mode deployments that use an HMAC shared secret.

# Generate new key and CSR
$ openssl genrsa -out ${CERT}-renewed.key.pem 4096
$ openssl req -new -key ${CERT}-renewed.key.pem \
    -subj "/CN=${CERT_CN}" \
    -addext "subjectAltName=DNS:${CERT_CN}" \
    -out "${CERT}-renewed.csr.pem"

# Re-enroll via CMP ir (same as initial enrollment)
$ openssl cmp -cmd ir \
    -server ${EJBCA_HOSTNAME} \
    -path /ejbca/publicweb/cmp/${CMP_ALIAS} \
    -tls_used \
    -tls_trusted ./system-local-ca.pem \
    -tls_cert ${SUPERADMIN_CERT} \
    -tls_key ${SUPERADMIN_KEY} \
    -ref "${CMP_ALIAS}" \
    -secret pass:${CMP_HMAC_SECRET} \
    -subject "/CN=${CERT_CN}" \
    -recipient "/CN=${CA_NAME}" \
    -newkey "${CERT}-renewed.key.pem" \
    -csr "${CERT}-renewed.csr.pem" \
    -certout "${CERT}-renewed.cert.pem" \
    -cacertsout "${CA_FILE}"

Revoke a Certificate

To revoke a certificate, submit a CMP revocation request (rr) using the ${CERT_FILE} certificate file generated during enrollment.

$ openssl cmp -cmd rr \
    -server ${EJBCA_HOSTNAME} \
    -path /ejbca/publicweb/cmp/${CMP_ALIAS} \
    -tls_used \
    -tls_trusted ./system-local-ca.pem \
    -tls_cert ${SUPERADMIN_CERT} \
    -tls_key ${SUPERADMIN_KEY} \
    -ref "${CMP_ALIAS}" \
    -secret pass:${CMP_HMAC_SECRET} \
    -recipient "/CN=${CA_NAME}" \
    -oldcert "${CERT_FILE}" \
    -revreason 0 \
    -unprotected_errors

The supported revocation reasons are:

  • 0 — unspecified

  • 1 — keyCompromise

  • 3 — affiliationChanged

  • 4 — superseded

  • 5 — cessationOfOperation

Note

Use the -unprotected_errors flag to display the actual error messages. Without this flag, EJBCA may return signature-protected error responses that you cannot verify without a trust anchor.

Check Certificate Status

To verify the status of an issued or revoked certificate, query the EJBCA OCSP responder:

$ openssl ocsp \
    -issuer ${CA_FILE} \
    -cert ${CERT_FILE} \
    -url https://${EJBCA_HOSTNAME}/ejbca/publicweb/status/ocsp \
    -CAfile ${CA_FILE} \
    -verify_other ${CA_FILE}

Note

For the complete CMP protocol reference, see: https://docs.keyfactor.com/ejbca/latest/protocols/ejbca-cmp

EJBCA Certificate Operations Using REST API

EJBCA provides a REST API that allows you to enroll, renew, revoke, and manage certificates. To access the API, authenticate with a client certificate that has the required EJBCA administrator role permissions (for example, the Super Administrator certificate) over mTLS.

This section shows how to use the EJBCA REST API and curl to enroll, renew, revoke, and check the status of certificates.

Prerequisites

Before you begin, complete the following prerequisites:

  • Enable the REST protocol in EJBCA. In the EJBCA Admin GUI, navigate to System Configuration > Protocol Configuration > REST Certificate Management, and then select Enabled.

  • Export the Super Administrator certificate and private key from the cluster to your local machine. For instructions, see Export Superadmin Credentials.

  • Obtain the system-local-ca.pem certificate and use it as the TLS CA trust anchor.

  • Set the required environment variables for the EJBCA hostname, REST base URL, and credentials. For details, see Setup the Environment Variables.

Note

The REST API endpoint /v1/endentity for creating end entities is not available in EJBCA Community Edition. Use the CLI to create end entities before enrolling certificates using the REST API.

Export Superadmin Credentials

Export the superadmin certificate and key from the cluster to your local machine:

~(keystone_admin)]$ kubectl get secret -n ejbca ejbca-superadmin-cert \
    -o jsonpath='{.data.tls\.crt}' | base64 -d > superadmin.crt.pem
~(keystone_admin)]$ kubectl get secret -n ejbca ejbca-superadmin-cert \
    -o jsonpath='{.data.tls\.key}' | base64 -d > superadmin.key.pem

Setup the Environment Variables

Define the environment variables that the examples in this topic use to connect to EJBCA and authenticate REST API requests:

$ export EJBCA_HOSTNAME="ejbca.example.com:7443"
$ export REST_BASE="https://${EJBCA_HOSTNAME}/ejbca/ejbca-rest-api"
$ export SUPERADMIN_CERT="./superadmin.crt.pem"
$ export SUPERADMIN_KEY="./superadmin.key.pem"
$ export CA_NAME="test-ca"
$ export CERT_PROFILE="test-cert-profile"
$ export EE_PROFILE="test-entity-profile"

Enroll a Certificate

Create the end entity using the CLI, then enroll the certificate using the REST API:

# Step 1: Create the end entity (CLI — required for CE)
$ export ENTITY="test-ca-cert01"
$ export ENTITY_PWD="changeit"

~(keystone_admin)]$ kubectl exec ejbca-0 -c ejbca -n ejbca -- /opt/keyfactor/bin/ejbca.sh ra addendentity \
    --username ${ENTITY} \
    --password ${ENTITY_PWD} \
    --dn "CN=${ENTITY}" \
    --caname ${CA_NAME} \
    --type 1 \
    # --token USERGENERATED: user-generated key pair
    --token USERGENERATED \
    --certprofile ${CERT_PROFILE} \
    --eeprofile ${EE_PROFILE}

# Step 2: Generate key and CSR
$ export KEY_FILE="${ENTITY}.key.pem"
$ export CSR_FILE_DER="${ENTITY}.csr.der"
$ export CERT_FILE="${ENTITY}.cert.pem"

$ openssl genrsa -out ${KEY_FILE} 4096
$ openssl req -new -key ${KEY_FILE} \
    -subj "/CN=${ENTITY}" \
    -addext "subjectAltName=DNS:${ENTITY}" \
    -outform |DER| -out ${CSR_FILE_DER}

# Step 3: Enroll via REST API (pkcs10enroll accepts a |P10| —
# the standard format for certificate signing requests)
$ CSR_B64=$(base64 -w0 ${CSR_FILE_DER})

$ curl \
    --cacert ./system-local-ca.pem \
    --cert ${SUPERADMIN_CERT} --key ${SUPERADMIN_KEY} \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -X POST "${REST_BASE}/v1/certificate/pkcs10enroll" \
    -d "{
      \"certificate_request\": \"${CSR_B64}\",
      \"certificate_profile_name\": \"${CERT_PROFILE}\",
      \"end_entity_profile_name\": \"${EE_PROFILE}\",
      \"certificate_authority_name\": \"${CA_NAME}\",
      \"username\": \"${ENTITY}\",
      \"password\": \"${ENTITY_PWD}\",
      \"include_chain\": true
    }" | python3 -m json.tool

The response returns the certificate in base64-encoded DER format. Decode and display it using:

# Extract the certificate field from the JSON response, decode, and display
$ echo "<base64-certificate-from-response>" | base64 -d | \
    openssl x509 -inform |DER| -text -noout

Note

Include the end_entity_profile_name field in every request. If you omit it, EJBCA returns a 500 Internal Server Error with a NullPointerException.

Renew a Certificate

To renew a certificate, generate a new key pair and CSR, and then re-enroll through the pkcs10enroll endpoint (the EJBCA REST endpoint for PKCS#10 Certificate Signing Request enrollment). The REST API manages the end entity status automatically, so you do not need to reset it to NEW.

# Generate new key and CSR
$ openssl genrsa -out ${ENTITY}-renewed.key.pem 4096
$ openssl req -new -key ${ENTITY}-renewed.key.pem \
    -subj "/CN=${ENTITY}" \
    -addext "subjectAltName=DNS:${ENTITY}" \
    -outform |DER| -out ${ENTITY}-renewed.csr.der

# Re-enroll via REST API
$ CSR_B64=$(base64 -w0 ${ENTITY}-renewed.csr.der)

$ curl \
    --cacert ./system-local-ca.pem \
    --cert ${SUPERADMIN_CERT} --key ${SUPERADMIN_KEY} \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -X POST "${REST_BASE}/v1/certificate/pkcs10enroll" \
    -d "{
      \"certificate_request\": \"${CSR_B64}\",
      \"certificate_profile_name\": \"${CERT_PROFILE}\",
      \"end_entity_profile_name\": \"${EE_PROFILE}\",
      \"certificate_authority_name\": \"${CA_NAME}\",
      \"username\": \"${ENTITY}\",
      \"password\": \"${ENTITY_PWD}\",
      \"include_chain\": true
    }" | python3 -m json.tool

Revoke a Certificate

To revoke a certificate, extract the serial number and issuer DN from the certificate file, then submit a REST API revocation request.

# Get certificate serial number and issuer DN
$ SERIAL=$(openssl x509 -in ${CERT_FILE} -noout -serial | cut -d= -f2)
$ ISSUER_DN=$(openssl x509 -in ${CERT_FILE} -noout -issuer | sed 's/issuer=//')
# URL-encode the issuer DN for use in the REST path
$ ISSUER_ENC=$(python3 -c "from urllib.parse import quote; print(quote('${ISSUER_DN}', safe=''))")

$ curl \
    --cacert ./system-local-ca.pem \
    --cert ${SUPERADMIN_CERT} --key ${SUPERADMIN_KEY} \
    -H "Accept: application/json" \
    -X PUT \
    "${REST_BASE}/v1/certificate/${ISSUER_ENC}/${SERIAL}/revoke?reason=UNSPECIFIED" \
    | python3 -m json.tool

The supported revocation reasons are:

  • UNSPECIFIED

  • KEY_COMPROMISE

  • CA_COMPROMISE

  • AFFILIATION_CHANGED

  • SUPERSEDED

  • CESSATION_OF_OPERATION

  • CERTIFICATE_HOLD

  • PRIVILEGES_WITHDRAWN

Check Certificate Status

To verify the status of an issued or revoked certificate, query the EJBCA REST API revocation status endpoint:

$ curl \
    --cacert ./system-local-ca.pem \
    --cert ${SUPERADMIN_CERT} --key ${SUPERADMIN_KEY} \
    -H "Accept: application/json" \
    "${REST_BASE}/v1/certificate/${ISSUER_ENC}/${SERIAL}/revocationstatus" \
    | python3 -m json.tool

Note

For the complete REST API reference, see: https://docs.keyfactor.com/ejbca/latest/protocols/ejbca-rest-interface

EJBCA Integration with Kubernetes cert-manager

The ejbca-cert-manager-issuer integrates EJBCA with Kubernetes cert-manager, enabling EJBCA to automatically issue and renew certificates using standard cert-manager Certificate resources.

EJBCA cert-manager Resources

The app-ejbca deployment automatically installs the supporting resources needed for cert-manager integration:

  • ejbca-cert-manager-issuer — the issuer controller

  • cert-manager-approver-policy — the policy controller

  • A CertificateRequestPolicy (approve-ejbca-issuer) — approval policy

  • ClusterRoles and ClusterRoleBindings:

    • cert-manager-approver-policy — The base role/role binding for the approver-policy controller to evaluate CertificateRequests against policy rules

    • cert-manager-approver-policy:ejbca — The EJBCA-specific role/role binding granting the controller permissions to read EJBCA CRDs (EJBCAIssuer, EJBCAClusterIssuer) during evaluation

    • cert-manager-policy:ejbca — The EJBCA-specific role/role binding granting the requester cert-manager SA permission to “use” the approve-ejbca-issuer policy

  • CA bundle secret (ejbca-ca-bundle) — contains the system-local-ca bundle for the issuer to verify the EJBCA HTTPS endpoint

  • ejbca-superadmin-cert secret — contains the superadmin’s certificate and key that the issuer (and Admin GUI, CMP, REST API) uses for client authentication to the EJBCA service

Prerequisites

Before creating certificates, ensure the CA, certificate profile, and end entity profile exist in EJBCA. If they do not exist, create them using the CLI or Admin GUI. See EJBCA CLI Operations or EJBCA Admin GUI Access and Operations.

Create an EJBCA ClusterIssuer

To create a ClusterIssuer that connects to your EJBCA instance, complete the following steps:

  1. Set environment variables:

    $ export CA_NAME="test-ca"
    $ export CERT_PROFILE="test-cert-profile"
    $ export EE_PROFILE="test-entity-profile"
    $ export SVC_HOST="ejbca-httpd.ejbca.svc.cluster.local:443"
    
  2. Create the ClusterIssuer resource:

    $ cat > ejbca-clusterissuer.yaml << EOF
    apiVersion: ejbca-issuer.keyfactor.com/v1alpha1
    kind: ClusterIssuer
    metadata:
      name: ejbca-issuer
    spec:
      # Must match the internal service hostname
      hostname: "ejbca-httpd.ejbca.svc.cluster.local:443"
    
      # CA configuration (must match |EJBCA| setup)
      certificateAuthorityName: "${CA_NAME}"
      certificateProfileName: "${CERT_PROFILE}"
      endEntityProfileName: "${EE_PROFILE}"
    
      # Client certificate for |mTLS| authentication
      ejbcaSecretName: "ejbca-superadmin-cert"
    
      # CA bundle to trust |EJBCA| HTTPS endpoint
      caBundleSecretName: "ejbca-ca-bundle"
    
      # End entity naming strategy
      endEntityName: "cn"
    EOF
    
  3. Apply and verify:

    ~(keystone_admin)]$ kubectl apply -f ejbca-clusterissuer.yaml
    ~(keystone_admin)]$ kubectl get clusterissuers.ejbca-issuer.keyfactor.com
    

Issue a Certificate with EJBCA ClusterIssuer

To issue a certificate using the ClusterIssuer, do the following:

  1. Create a cert-manager Certificate resource:

    $ cat > test-certificate.yaml << EOF
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: test-ejbca-cert
      namespace: default
    spec:
      secretName: test-ejbca-cert
      commonName: test.example.com
      dnsNames:
        - test.example.com
      privateKey:
        algorithm: RSA
        size: 4096
      duration: 8760h    # 1 year
      renewBefore: 720h  # 30 days before expiry
      issuerRef:
        name: ejbca-issuer
        kind: ClusterIssuer
        group: ejbca-issuer.keyfactor.com
    EOF
    

    Important

    The privateKey.size must match the allowed key lengths in the EJBCA certificate profile. If the profile only allows 4096-bit keys, requesting 2048-bit (cert-manager’s default) will fail with: “Illegal key length, not authorized by certificate profile: 2048”

  2. Apply the Certificate resource and verify that it was issued and the certificate secret was created:

    ~(keystone_admin)]$ kubectl apply -f test-certificate.yaml
    ~(keystone_admin)]$ kubectl get certificate test-ejbca-cert
    ~(keystone_admin)]$ kubectl get secret test-ejbca-cert
    

Renew a Certificate Using EJBCA ClusterIssuer

cert-manager handles renewal automatically based on the renewBefore field. To manually trigger renewal and confirm the certificate was renewed:

~(keystone_admin)]$ kubectl cert-manager renew test-ejbca-cert
~(keystone_admin)]$ kubectl get certificaterequest -o wide

Back Up and Restore EJBCA Data

StarlingX provides Ansible playbooks for backing up and restoring the EJBCA application data, including all CA keys, certificates, profiles, and database content. The playbooks are located in:

/usr/share/ansible/stx-ansible/playbooks/

Backup EJBCA Data

Run the EJBCA backup playbook:

$ sudo ansible-playbook /usr/share/ansible/stx-ansible/playbooks/ejbca_backup.yml     -e "initial_backup_dir=/opt/platform-backup"

The playbook creates a .tgz file in /opt/platform-backup. Use this filename when running the restore playbook.

Restore EJBCA Data

Before running the restore playbook, ensure the backup .tgz file is present in /opt/platform-backup.

$ sudo ansible-playbook /usr/share/ansible/stx-ansible/playbooks/ejbca_restore.yml     -e "initial_backup_dir=/opt/platform-backup"     -e "backup_filename=<filename>.tgz"

Replace <filename>.tgz with the backup filename from /opt/platform-backup.

After the restore process is completed, all EJBCA PKI data (CAs, keys, profiles, and certificates) is available, and the application is ready for use.

Note

A platform full restore can leave app-ejbca in a failed state after the restore completes. If this occurs, wait until the storage resources are ready and then reapply app-ejbca.

Automatic EJBCA Server Certificate Renewal

Overview

The EJBCA server certificate (ejbca-tls-cert) is issued by the system-local-ca ClusterIssuer and managed by cert-manager.

cert-manager automatically renews the certificate 30 days before expiration (renewBefore: 720h) and updates the associated Kubernetes secret.

After cert-manager renews the certificate and updates the associated Kubernetes secret, the EJBCA pod must be restarted to reload the updated TLS certificate used by the httpd sidecar. The Stakater Reloader application (app-reloader) automates this process.

Deployed as a separate platform application, app-reloader detects updates to the certificate secret and automatically restarts the EJBCA pod, allowing the httpd sidecar to load the renewed certificate.

Prerequisites

Automatic pod restart requires the app-reloader platform application.

Upload and apply the app-reloader application:

~(keystone_admin)]$ system application-upload /path/to/reloader-<version>.tgz
~(keystone_admin)]$ system application-apply reloader

Verify that the application is running:

~(keystone_admin)]$ system application-show reloader
~(keystone_admin)]$ kubectl get pods -n reloader

Manually Reload the Renewed Certificate

Note

When app-reloader is installed, no manual intervention is required after certificate renewal.

If app-reloader is not deployed, cert-manager still renews the certificate and updates the Kubernetes secret, but the EJBCA pod is not automatically restarted. To load the renewed certificate, manually restart the pod:

~(keystone_admin)]$ kubectl rollout restart statefulset ejbca -n ejbca