Here is my testing playground for a EJBCA based CA. This is not on production level since I did not deploy a Subordinate CA, instead I issued the server certificate directly with the root CA.
So far I think EJBCA is a very powerful tool but the documentation for the community edition is partly outdated. Also the environment variable
TLS_SETUP_ENABLED=true
was missing in the Docker Compose documentation, without that variable it’s not possible to issue the SuperAdmin certificate.
EJBCA Community Edition - Docker Compose Stack #
Folder Structure #
# Create folder structure
sudo mkdir -p /opt/ejbca/mariadb && cd /opt/ejbca
DNS Entry #
# Create a DNS record for ejbca
192.168.30.91 ejbca.jklug.local
Docker Compose #
# Create Docker Compose file
sudo vi docker-compose.yml
version: '3.9'
services:
mariadb:
image: mariadb:latest
container_name: ejbca-database
environment:
- MYSQL_ROOT_PASSWORD=foo123
- MYSQL_DATABASE=ejbca
- MYSQL_USER=ejbca
- MYSQL_PASSWORD=ejbca
volumes:
- ./mariadb:/var/lib/mysql:rw
restart: unless-stopped
ejbca-ce:
hostname: ejbca.jklug.local
container_name: ejbca-ce
image: keyfactor/ejbca-ce:latest
depends_on:
- mariadb
environment:
- DATABASE_JDBC_URL=jdbc:mariadb://ejbca-database:3306/ejbca?characterEncoding=UTF-8
- LOG_LEVEL_APP=INFO
- LOG_LEVEL_SERVER=INFO
- TLS_SETUP_ENABLED=simple
- TLS_SETUP_ENABLED=true
ports:
- "80:8080"
- "443:8443"
restart: unless-stopped
Start Container #
# Start container
sudo docker compose up -d
Check Logs #
Check the container logs and wait till the end where the URL and password are listed:
# Check logs
sudo docker compose logs -f
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) ***********************************************************************************************
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) * *
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) * A fresh installation was detected and a ManagementCA was created for your initial *
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) * administration of the system. *
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) * *
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) * Initial SuperAdmin client certificate enrollment URL (adapt port to your mapping): *
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) * *
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) * URL: https://ejbca.jklug.local:443/ejbca/ra/enrollwithusername.xhtml?username=superadmin *
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) * Password: QOVHATeCTRXi3EcqJLJDd4Xg *
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) * *
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) * Once the P12 is downloaded, use "QOVHATeCTRXi3EcqJLJDd4Xg" to import it. *
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) * *
ejbca-ce | 2024-01-26 22:29:49,823+0000 INFO [/opt/keyfactor/bin/start.sh] (process:1) ***********************************************************************************************
Issue SuperAdmin certificate #
The following SuperAdmin certificate is password protected and later used to access the actual EJBCA webinterface. It’s necessary to import the SuperAdmin certificate into the browser.
Use the URL and password from the Docker logs:
# Open the webinterface in a browser
https://192.168.30.91:443/ejbca/ra/enrollwithusername.xhtml?username=superadmin
# Password:
QOVHATeCTRXi3EcqJLJDd4Xg
Import Certificate #
# Open browser settings: Firefox
about:preferences#privacy
- Import the
SuperAdmin.p12
certificate
- Enter the password
QOVHATeCTRXi3EcqJLJDd4Xg
Access EJBCA CA UI #
https://ejbca.jklug.local/ejbca/adminweb/
Create Root Certificate Authority #
Certificate Profiles #
Create a “JKW-RootCA-Profile”
- Disable
Authority Key ID
>Use
- Disable
Subject Alternative Name
>Use
- Disable
Issuer Alternative Name
>Use
- Disable
LDAP DN order
>Use
Crypto Tokens #
-
Create a CryptoToken “JKW-RootCA-CryptoToken”
-
Type
SOFT
stores the keys encrypted in the database -
Define authentication code. After the container reboot the crypto token must be activated using the authentication code
-
Optional: Check “Auto-activation” to automatically activate the crypto token after a container reboot
- Create a sign key “JKW-RootCA-SignKey0001” for the crypto token
- Create a encryption key “JKW-RootCA-EncryptKey0001” for the crypto token
- Create a test key “Testkey” for the crypto token
c
Certification Authorities #
- Create new Certification Authoritie “JKW-RootCA”
-
Select
Crypto Token
>JKW-RootCA-CryptoToken
-
Select
defaultKey
>JKW-RootCA-EncryptKey0001
-
Select
certSignKey
>JKW-RootCA-SignKey0001
-
Select
testKey
>Testkey
-
Define
Subject DN
>CN=JKW-RootCA,O=JKW,C=AT
-
Define
Validity
> 30 years30y
-
Disable
LDAP DN order
>Use
- Define
CRL Expire Period
(Certificate Revocation List) > three months3mo
- Create certification authority
Export / Import Certificates #
Export Certificates #
Export both the “ManagementCA” certificate that enables the secure connection to the https://ejbca.jklug.local/ejbca/adminweb/
interface and the
newly create CA certificate:
ManagementCA: ManagementCA.crt
JKW-RootCA: JKWRootCA.crt
- Go to the
RA Web
section
-
Go to
CA Certificates and CRLs
-
Click
Internet Explorer
to export the certificates
ManagementCA certificate: JKWRootCA.crt
JKW-RootCA certificate: JKWRootCA.crt
Import Certificates #
Open the MMC Certificate Manager for local computer:
# Run
certlm.msc
- Import both the “JKWRootCA.crt” and the “ManagementCA.crt” certificates:
TLS Server Certificate #
Certificate Profiles #
- Create a new template: “JKW-TLS-Server-Profile”
- Edit the profile
-
Define
Available Key Algorithms
-
Define
Available Bit Lengths
-
Define
Validity or end date of the certificate
-
Disable
Basic Constraints
>Use...
-
Select
Key Usage
>Digital Signature
&Key encipherment
-
Select
Extended Key Usage
>Server Authentication
-
Disable
Issuer Alternative Name
>Use...
Optional:
-
Enable
CRL Distribution Points
>Use...
-
Enable
Use CA defined CRL Distribution Point
>Use...
-
Enable
Authority Information Access
>Use...
-
Enable
Use CA defined OCSP locator
>Use...
-
Enable
Use CA defined CA issuer
>Use...
-
Disable
LDAP DN order
>Use
-
Define the CA: “JKW-Root-CA”
End Entity Profiles #
- Create a end entitity profile
- Edit the profile
-
Disable
End Entity E-mail
>Use
-
Check
CN, Common name
>Required
&Modifiable
-
Add
O, Organization
, CheckRequired
-
Add
C, Country
, CheckRequired
-
Add
DNS Name
: CheckUse entity CN field
-
Add
DNS Name
: Blank DNS name -
Define
Available Certificate Profiles
>JKW-TLS-Server-Profile
-
Define
Available CAs
>JKW-RootCA
-
Define
Available Tokens
>User Generated
&PEM file
- Save the profile
Server Certificate #
- Go to the
RA Web
section
- Go to
Enroll
>Make New Request
- Select the earlier created TLS Server Profile in the
Certificate Type
section
- Define a
Common Name
and theDNS Name
for the certificate
- Define a Username and Password for the certificate enrollment
Nginx Certificate Test #
TLS Server Certificate #
# Create folder for the TLS server certificate
sudo mkdir -p /etc/certs/nginx.jklug.work
- Add the newly created certificate
# Set permissions
sudo chmod 0400 /etc/certs/nginx.jklug.work/nginx.pem
HTML Test Website #
# Create folder for website
sudo mkdir -p /var/www/nginx.jklug.local
# Change permissions
sudo chmod 0755 /var/www/nginx.jklug.local
# Create html file
sudo vi /var/www/nginx.jklug.local/index.html
# Change permissions
sudo chmod 644 /var/www/nginx.jklug.local/index.html
<!-- /var/www/nginx.jklug.local/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>EJBCA TLS Test</title>
</head>
<body>
<h1>EJBCA TLS Test</h1>
</body>
</html>
Virtual Host Configuration #
# Install nginx
sudo apt install nginx
# Copy the default virtual host configuration
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/nginx.jklug.local
# Edit the new virtual host configuration
sudo vi /etc/nginx/sites-available/nginx.jklug.local
server {
listen 80;
listen [::]:80;
server_name nginx.jklug.local;
return 302 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /etc/certs/nginx.jklug.local/nginx.pem;
ssl_certificate_key /etc/certs/nginx.jklug.local/nginx.pem;
server_name nginx.jklug.local;
root /var/www/nginx.jklug.local;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
}
Note: EJBCA only exports one .pem certificate file that includes both the key and the chain. In the Nginx virtual host configuration just point both ssl_certificate
and ssl_certificate_key
to the same .pem certificate file.
# Disable default configuration
sudo rm /etc/nginx/sites-enabled/default
# Enable the virtual host configuration
sudo ln -s /etc/nginx/sites-available/nginx.jklug.local /etc/nginx/sites-enabled/
# Restart Nginx
sudo systemctl restart nginx
Test TLS Encryption #
Links #
# Official Documentation
https://doc.primekey.com/ejbca/tutorials-and-guides/quick-start-guide-start-ejbca-container-with-client-certificate-authenticated-access
https://doc.primekey.com/ejbca/tutorials-and-guides/tutorial-start-out-with-ejbca-docker-container
https://doc.primekey.com/ejbca/tutorials-and-guides/tutorial-create-your-first-root-ca-using-ejbca
https://doc.primekey.com/ejbca/tutorials-and-guides/tutorial-create-a-pki-hierarchy-in-ejbca
https://doc.primekey.com/ejbca/tutorials-and-guides/tutorial-issue-tls-server-certificates-with-ejbca