Contents

How to install and setup EJBCA 8.2 with galera and HSM module


In this tutorial I will show how to install and setup EJBCA 8.2 with galera cluster using mysql database and Hardware security module (HSM).


Important

  • HSM is hardware device so you must having one to follow this tutorial fully. If you don’t have one you can just ignore HSM configuration steps and you won’t be able to generate pkcs#11 keys.

Steps

  1. For this purpose Debian 12 is installed.
  2. Follow the procedure for EJBCA and HSM installation.
  3. When EJBCA installation is done stop mariadb service.
  4. Follow the procedure for Galera installation.
  5. Open EJBCA Administration page

1. Debian 12 Installation

For more details check official documentation https://www.debian.org/releases/bookworm/amd64/

2. Follow the procedure for EJBCA installation and HSM installation

Preface

The purpose of this part is to describe all necessary steps for CA installation and configuration.

Software Stack

The following software stack is used during the training:

  • Debian: A Linux based Operating system.
  • OpenJDK: Contains the Java Virtual Machine.
  • WildFly: A Java Enterprise Edition (JEE) application server providing middleware services for security, persistance and management of resources.
  • Apache Ant: A build system for compiiling EJBCA.
  • MariaDB: An SQL database supported by EJBCA.
  • MariaDB Java Connector: A Java application acting as a bridge between EJBCA and MariaDB.
  • Utimaco HSM Simmulator: A Hardware Security Module emulator.

System Set-up

Log in as a user vukilis using the password linux!2345 using ssh.

Install the latest update for the Debian 12 GNU/Linux OS.

sudo apt update && sudo apt upgrade

Note

Confirm that IP address is correct using the command ‘ip a’

Install necessary tools:

sudo apt install bash-completion tcpdump net-tools bind9-utils bind9-dnsutils bind9utils ncat wget unzip zip lsof vim lshw telnet tmux rsync nano apt-utils chrony 

Apart from the root user which was created during the installation of the operating system, we are going to create two additional users called vukilis and wildfly.

Note

vukilis user is created during installation proccess.
Wildfly user will be created later during wildfly installation proccess.

User Purpose
vukilis Used during system administration, e.g. to install software, edit configuration files and perform other administrative tasks. Has full access to the system.
wildfly Used by the application server. Has access to all applications under /opt/ directory.

Installation Prerequisites

  • JAVA -> OpenJDK 11 - Supported and recommended.
  • Database -> MariaDB is recommended.
  • Application Server -> Wildfly 26 - is currently recommended.
  • MariaDB Database Driver -> 2.7.11
  • Build Tool -> Apache Ant 1.10.14 or later.
  • EJBCA -> 8_2_0_1

Installing Java

OpenJDK 11 is the open-source edition of the Oracle standard Java Platform that is available to install on almost all Linux systems using their default system repository. It is released under the GNU license and is extremely important if you are planning to install some application that requires JAVA

Although there is already a newer version of OpenJDK available we can install version 11 on Debian 12 Linux with:

echo "deb http://deb.debian.org/debian unstable main non-free contrib" >> /etc/apt/sources.list

Set preferences for the packages:
/etc/apt/preferences

Package: *
Pin: release a=stable
Pin-Priority: 900

Package: *
Pin: release a=unstable
Pin-Priority: 50

Run system update to refresh the APT repository cache:

apt update

Install Java OpenJDK 11 and confirm version:

apt install openjdk-11-jdk-headless

java -version

update-alternatives --config java

Installing Database

Install and configure MariaDB:

apt install mariadb-server mariadb-client

Start MariaDB server:

sudo systemctl start mariadb
sudo systemctl enable mariadb

See wheather Mariadb is started and listening:

ss -tnlp
systemctl status mariadb

Run MariaDB hardening shell script mariadb-secure-installation in order to:

  • set a password for root account (vukilis)
  • disallow root login remotely
  • remove anonymous-user accounts and test databases
  • reload privileges
mariadb-secure-installation


NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
haven't set the root password yet, you should just press enter here.

Enter current password for root (enter for none): 
OK, successfully used password, moving on...

Setting the root password or using the unix_socket ensures that nobody
can log into the MariaDB root user without the proper authorisation.

You already have your root account protected, so you can safely answer 'n'.

Switch to unix_socket authentication [Y/n] n
 ... skipping.

You already have your root account protected, so you can safely answer 'n'.

Change the root password? [Y/n] 
New password: 
Re-enter new password: 
Password updated successfully!
Reloading privilege tables..
 ... Success!


By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] 
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] 
 ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] 
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] 
 ... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

For MariaDB, use the following commands to create the database, matching the DataSource in the next step, and add privileges to connect to the database:

mysql -u root -p

mysql> CREATE DATABASE ejbcadb CHARACTER SET utf8 COLLATE utf8_general_ci;
mysql> GRANT ALL PRIVILEGES ON ejbcadb.* TO 'ejbca'@'localhost' IDENTIFIED BY 'vukilis';
mysql> GRANT ALL PRIVILEGES ON ejbcadb.* TO 'ejbca'@'127.0.0.1' IDENTIFIED BY 'vukilis';
mysql> GRANT ALL PRIVILEGES ON ejbcadb.* TO 'ejbca'@'::1' IDENTIFIED BY 'vukilis';
QUIT

Test connection to the new database with:

mysql -u ejbca -D ejbcadb -p

Installing Application Server

EJBCA can run on a supported AS. Due to differences between application servers, your AS should be configured according to the AS specific instructions referenced below.

To download, refer to WildFly download.

Download the Wildfly and extract tar.gz file to /opt folder

sudo mkdir -p /opt/packages

cd /opt/
sudo wget https://github.com/wildfly/wildfly/releases/download/26.0.0.Final/wildfly-26.0.0.Final.zip -O /opt/packages/wildfly-26.0.0.Final.zip

sudo unzip -q /opt/packages/wildfly-26.0.0.Final.zip -d /opt/

Set the APPSRV_HOME environment variable to /opt/wildfly:

echo 'export APPSRV_HOME="/opt/wildfly"' | sudo tee --append /etc/profile.d/vukilis-ejbca.sh
source /etc/profile.d/vukilis-ejbca.sh

Add wildfly user:

useradd -r -U -M -d /opt/wildfly -s /bin/bash -c "Wildfly" wildfly

Note

Change default shell of wildfly to /sbin/nologin after the installation.

Create a symbolic link to point to the WildFly installation directory, and give access to the WildFly group and user:

sudo ln -snf /opt/wildfly-26.0.0.Final /opt/wildfly

sudo rm -f /opt/wildfly/bin/*.{bat,ps1}
sudo find /opt/wildfly/ -type d -exec chmod 0750 {} \;
sudo find /opt/wildfly/ -type f -exec chmod 0640 {} \;
sudo chown -R root:wildfly /opt/wildfly/
sudo chown -R wildfly /opt/wildfly/standalone/

Configuring JBOSS/WildFly

Backup default/original standalone.conf configuration file:

cp -rp /opt/wildfly/bin/standalone.conf /opt/wildfly/bin/standalone.conf.bak

Replace standalone.conf with the following:
/opt/wildfly/bin/standalone.conf

if [ "x$JBOSS_MODULES_SYSTEM_PKGS" = "x" ]; then
     JBOSS_MODULES_SYSTEM_PKGS="org.jboss.byteman"
fi

if [ "x$JAVA_OPTS" = "x" ]; then
     JAVA_OPTS="-Xms{{ HEAP_SIZE }}m -Xmx{{ HEAP_SIZE }}m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m"
     JAVA_OPTS="$JAVA_OPTS -Dhttps.protocols=TLSv1.2,TLSv1.3"
     JAVA_OPTS="$JAVA_OPTS -Djdk.tls.client.protocols=TLSv1.2,TLSv1.3"
     JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true"
     JAVA_OPTS="$JAVA_OPTS -Djboss.modules.system.pkgs=$JBOSS_MODULES_SYSTEM_PKGS"
     JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true"
     JAVA_OPTS="$JAVA_OPTS -Djboss.tx.node.id={{ TX_NODE_ID }}"
     JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
     JAVA_OPTS="$JAVA_OPTS -Djdk.tls.ephemeralDHKeySize=2048"
else
     echo "JAVA_OPTS already set in environment; overriding default settings with values: $JAVA_OPTS"
fi

Set allowed memory usage

By default, 512 MB of heap (RAM) is allowed to be used by the AS. This is not sufficient to run EJBCA. We recommended to allocate at least 2048 MB of RAM. To increase the default value, run the following command:

sed -i -e 's/{{ HEAP_SIZE }}/2048/g' /opt/wildfly/bin/standalone.conf

Set the Transaction Node ID

Set the transaction node ID to a unique number. The node ID is used by the transactions subsystem and ensures that the transaction manager only recovers branches which match the specified identifier. It is imperative that this identifier is unique between WildFly instances sharing either an object store or access common resource managers (i.e. when EJBCA is operating in a cluster).

sed -i -e "s/{{ TX_NODE_ID }}/$(od -A n -t d -N 1 /dev/urandom | tr -d ' ')/g" /opt/wildfly/bin/standalone.conf

Configure WildFly as a Service

cp /opt/wildfly/docs/contrib/scripts/systemd/launch.sh /opt/wildfly/bin
cp /opt/wildfly/docs/contrib/scripts/systemd/wildfly.service /etc/systemd/system

mkdir /etc/wildfly/
cp /opt/wildfly/docs/contrib/scripts/systemd/wildfly.conf /etc/wildfly/

systemctl daemon-reload
chown -R wildfly:wildfly /opt/wildfly-26.0.0.Final/
sudo chmod 0750 /opt/wildfly/bin/*.sh

echo 'export APPSRV_HOME="/opt/wildfly"' > /etc/profile.d/wildfly.sh
source /etc/profile.d/wildfly.sh

Start and enable wildfly service

systemctl start wildfly
systemctl enable wildfly
systemctl status wildfly

Create an Elytron Credential Store

You can protect passwords by storing them in a credential store. The credential is encrypted with a master password which is fetched by WildFly on startup.

Create a master password, by creating a script which outputs the master password to stdout and ensure the script can only be executed by the wildfly user:

echo '#!/bin/sh' > /usr/bin/wildfly_pass
echo "echo '$(openssl rand -base64 24)'" >> /usr/bin/wildfly_pass
chown wildfly:wildfly /usr/bin/wildfly_pass
chmod 700 /usr/bin/wildfly_pass

Create a credential store in /opt/wildfly/standalone/configuration encrypted with the password echoed by the wildfly_pass script.

mkdir /opt/wildfly/standalone/configuration/keystore
chown wildfly:wildfly /opt/wildfly/standalone/configuration/keystore

/opt/wildfly/bin/jboss-cli.sh --connect '/subsystem=elytron/credential-store=defaultCS:add(path=keystore/credentials, relative-to=jboss.server.config.dir, credential-reference={clear-text="{EXT}/usr/bin/wildfly_pass", type="COMMAND"}, create=true)'

MariaDB Database Driver Setup

Download MariaDB Java Connector and copy this file manually to the wildfly deployment directory:

wget https://dlm.mariadb.com/3478926/Connectors/java/connector-java-2.7.11/mariadb-java-client-2.7.11.jar -O /opt/packages/mariadb-java-client-2.7.11.jar

Copy existing mariadb-java-client.jar to deployment directory in order to hot-deploy JDBC driver. This will be picked up by WildFly and deployed so we can create a data source straigh away.

cp /opt/packages/mariadb-java-client-2.7.11.jar /opt/wildfly/standalone/deployments/mariadb-java-client.jar

Fix permissions:

chown -v wildfly: /opt/wildfly/standalone/deployments/mariadb-java-client.jar
chmod -v 0640 /opt/wildfly/standalone/deployments/mariadb-java-client.jar

Datasource Configuration

/opt/wildfly/bin/jboss-cli.sh --connect

/subsystem=elytron/credential-store=defaultCS:add-alias(alias=dbPassword, secret-value="linux!2345")

data-source add --name=ejbcads --connection-url="jdbc:mysql://127.0.0.1:3306/ejbcadb" --jndi-name="java:/EjbcaDS" --use-ccm=true --driver-name="mariadb-java-client.jar" --driver-class="org.mariadb.jdbc.Driver" --user-name="ejbca" --credential-reference={store=defaultCS, alias=dbPassword} --validate-on-match=true --background-validation=false --prepared-statements-cache-size=50 --share-prepared-statements=true --min-pool-size=5 --max-pool-size=150 --pool-prefill=true --transaction-isolation=TRANSACTION_READ_COMMITTED --check-valid-connection-sql="select 1;"

Configure Remoting

EJBCA needs to use JBOSS Remoting for EJBCA CLI to work. Configure it to use a separate port 4447 and remove any other dependency on remoting except for what EJBCA needs.

/subsystem=remoting/http-connector=http-remoting-connector:write-attribute(name=connector-ref,value=remoting)
/socket-binding-group=standard-sockets/socket-binding=remoting:add(port=4447,interface=management)
/subsystem=undertow/server=default-server/http-listener=remoting:add(socket-binding=remoting,enable-http2=true)
:reload

Configure Logging

Configure logging in WildFly to be able to dynamically change logging while the application server is running.

Logging options:

  1. INFO - Recommended Logging
  2. QUIET - audit log messages, warnnings and errors

Note

INFO log level for org.ejbca and org.cesecore is recommended for production systems.

/subsystem=logging/logger=org.ejbca:add(level=INFO)
/subsystem=logging/logger=org.cesecore:add(level=INFO)
/subsystem=logging/logger=com.keyfactor:add(level=INFO)

Audit logging to file

You can write the EJBCA audit log to a separate file (/opt/wildfly/standalone/log/cesecore-audit.log), rotate every 128 MB and keep one rotated file:

/subsystem=logging/size-rotating-file-handler=cesecore-audit-log:add(file={path=cesecore-audit.log, relative-to=jboss.server.log.dir}, max-backup-index=1, rotate-size=128m)
/subsystem=logging/logger=org.cesecore.audit.impl.log4j.Log4jDevice:add
/subsystem=logging/logger=org.cesecore.audit.impl.log4j.Log4jDevice:add-handler(name=cesecore-audit-log)

HTTP(S) Configuration

The following section explains how to configure HTTP(S) using Undertow.

Run the following commands in JBoss CLI to remove existing TLS and HTTP configuration:

/subsystem=undertow/server=default-server/http-listener=default:remove()
/socket-binding-group=standard-sockets/socket-binding=http:remove()
/subsystem=undertow/server=default-server/https-listener=https:remove()
/socket-binding-group=standard-sockets/socket-binding=https:remove()
:reload

Wait for the reload to complete by checking the server log or the result of:

:read-attribute(name=server-state)

The following section explains how to set up Undertow with 3-port separation. Port 8080 is used for HTTP (unencrypted traffic), port 8442 for HTTPS (encrypted) traffic with only server authentication and port 8443 for HTTPS (encrypted) traffic with both server and client authentication.

To add new interfaces and sockets, use the following:

/interface=http:add(inet-address="0.0.0.0")
/interface=httpspub:add(inet-address="0.0.0.0")
/interface=httpspriv:add(inet-address="0.0.0.0")
/socket-binding-group=standard-sockets/socket-binding=http:add(port="8080",interface="http")
/socket-binding-group=standard-sockets/socket-binding=httpspub:add(port="8442",interface="httpspub")
/socket-binding-group=standard-sockets/socket-binding=httpspriv:add(port="8443",interface="httpspriv")

Configure TLS

/subsystem=elytron/credential-store=defaultCS:add-alias(alias=httpsKeystorePassword, secret-value="serverpwd")
/subsystem=elytron/credential-store=defaultCS:add-alias(alias=httpsTruststorePassword, secret-value="changeit")
/subsystem=elytron/key-store=httpsKS:add(path="keystore/keystore.p12",relative-to=jboss.server.config.dir,credential-reference={store=defaultCS, alias=httpsKeystorePassword},type=PKCS12)
/subsystem=elytron/key-store=httpsTS:add(path="keystore/truststore.p12",relative-to=jboss.server.config.dir,credential-reference={store=defaultCS, alias=httpsTruststorePassword},type=PKCS12)
/subsystem=elytron/key-manager=httpsKM:add(key-store=httpsKS,algorithm="SunX509",credential-reference={store=defaultCS, alias=httpsKeystorePassword})
/subsystem=elytron/trust-manager=httpsTM:add(key-store=httpsTS)
/subsystem=elytron/server-ssl-context=httpspub:add(key-manager=httpsKM,protocols=["TLSv1.3","TLSv1.2"],use-cipher-suites-order=false,cipher-suite-filter="TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",cipher-suite-names="TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256")
/subsystem=elytron/server-ssl-context=httpspriv:add(key-manager=httpsKM,protocols=["TLSv1.3","TLSv1.2"],use-cipher-suites-order=false,cipher-suite-filter="TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",cipher-suite-names="TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256",trust-manager=httpsTM,need-client-auth=true)

Add HTTP(S) Listeners

/subsystem=undertow/server=default-server/http-listener=http:add(socket-binding="http", redirect-socket="httpspriv")
/subsystem=undertow/server=default-server/https-listener=httpspub:add(socket-binding="httpspub", ssl-context="httpspub", max-parameters=2048)
/subsystem=undertow/server=default-server/https-listener=httpspriv:add(socket-binding="httpspriv", ssl-context="httpspriv", max-parameters=2048)
:reload

HTTP Protocol Behaivor Configuration

/system-property=org.apache.catalina.connector.URI_ENCODING:add(value="UTF-8")
/system-property=org.apache.catalina.connector.USE_BODY_ENCODING_FOR_QUERY_STRING:add(value=true)
/system-property=org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH:add(value=true)
/system-property=org.apache.tomcat.util.http.Parameters.MAX_COUNT:add(value=2048)
/system-property=org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH:add(value=true)
/subsystem=webservices:write-attribute(name=wsdl-host, value=jbossws.undefined.host)
/subsystem=webservices:write-attribute(name=modify-wsdl-address, value=true)

Redirect to Application for Unknown URLs

Known URLs for EJBCA starts with /ejbca, /crls, /certificates or /.well-known (EST and ACME) according to the following example:

/subsystem=undertow/configuration=filter/rewrite=redirect-to-app:add(redirect=true,target="/ejbca/")
/subsystem=undertow/server=default-server/host=default-host/filter-ref=redirect-to-app:add(priority=1,predicate="method(GET) and not path-prefix(/ejbca,/crls,/certificates,/.well-known) and not equals({\%{LOCAL_PORT}, 4447})")

URL Rewriting

/subsystem=undertow/configuration=filter/rewrite=crl-rewrite:add(target="/ejbca/publicweb/crls/$${1}")
quit

Execute following command:

/opt/wildfly/bin/jboss-cli.sh --connect "/subsystem=undertow/server=default-server/host=default-host/filter-ref=crl-rewrite:add(predicate=\"method(GET) and regex('/crls/(.*)')\")"

You can remove the ExampleDS datasource as it is not being used.

/opt/wildfly/bin/jboss-cli.sh --connect

/subsystem=ee/service=default-bindings:remove()
data-source remove --name=ExampleDS
:reload
quit

Install Apache Ant

cd /opt/packages/

wget https://dlcdn.apache.org//ant/binaries/apache-ant-1.10.14-bin.zip
wget https://downloads.apache.org/ant/binaries/apache-ant-1.10.14-bin.zip.sha512

unzip /opt/packages/apache-ant-1.10.14-bin.zip -d /opt/
sudo ln -s /opt/apache-ant-1.10.14 /opt/ant

Note

Edit /etc/profile.d/ant.sh with nano or vi.

# /etc/profile.d/ant.sh
export ANT_HOME=/opt/ant
export PATH=${PATH}:${ANT_HOME}/bin
source /etc/profile.d/ant.sh

EJBCA Installation

Extract archive to /opt and create symbolic link

unzip ejbca_ee_8_2_0_3.zip -d /opt/

ln -snf /opt/ejbca_ee* /opt/ejbca

The folder /opt/ejbca contains the EJBCA source code. Create folder /opt/ejbca-custom contains following configuration files within conf directory:

mkdir -p /opt/ejbca-custom/conf

ejbca-custom/
└── conf
    ├── cesecore.properties
    ├── database.properties
    ├── ejbca.properties
    ├── install.properties
    └── web.properties

Edit next configuration files:

  • /opt/ejbca-custom/conf/cesecore.properties
allow.external-dynamic.configuration=true
certificate.validityoffset=-10m
database.crlgenfetchsize=500000
securityeventsaudit.implementation.0=org.cesecore.audit.impl.log4j.Log4jDevice
securityeventsaudit.implementation.1=org.cesecore.audit.impl.integrityprotected.IntegrityProtectedDevice
securityeventsaudit.exporter.1=org.cesecore.audit.impl.AuditExporterXml
  • /opt/ejbca-custom/conf/database.properties
datasource.jndi-name=EjbcaDS
database.name=mysql
database.url=jdbc:mysql://127.0.0.1:3306/ejbcadb?characterEncoding=UTF-8
database.driver=org.mariadb.jdbc.Driver
database.username=ejbca
database.password=linux!2345
  • /opt/ejbca-custom/conf/ejbca.properties
appserver.home=/opt/wildfly
appserver.type=jboss
ejbca.productionmode=true
allow.external-dynamic.configuration=true
ejbca.cli.defaultusername=ejbca
ejbca.cli.defaultpassword=ejbca
  • /opt/ejbca-custom/conf/install.properties
ca.name=ManagementCA
ca.dn=CN=ManagementCA,O=Vukilis,C=RS
ca.tokentype=soft
ca.tokenpassword=null
ca.keyspec=2048
ca.keytype=RSA
ca.signaturealgorithm=SHA256WithRSA
ca.validity=3650
ca.policy=null
  • /opt/ejbca-custom/conf/web.properties
java.trustpassword=changeit
superadmin.cn=SuperAdmin-Training
superadmin.dn=CN=${superadmin.cn},O=Vukilis,C=RS
superadmin.password=ejbca
superadmin.batch=true
httpsserver.password=serverpwd
httpsserver.hostname=localhost
httpsserver.dn=CN=${httpsserver.hostname},O=Vukilis,C=RS
httpsserver.tokentype=P12

Fix file and directory permissions:

chown -R wildfly:wildfly /opt/wildfly/*
chown -R wildfly:wildfly /opt/ejbca-custom/
chown -R wildfly:wildfly /opt/ejbca_*/
chown -R wildfly:wildfly /opt/wildfly-*/
chown -R wildfly:wildfly /etc/utimaco/
chown -R wildfly:wildfly /opt/utimaco/

HSM configuration

Before you start configuring ejbca for HSM be sure you configured correctly HSM.

  • /opt/ejbca-custom/conf/catoken.properties
sharedLibrary /opt/utimaco/p11/libcs_pkcs11_R3.so
slotLabelType=SLOT_NUMBER
slotLabelValue=3

# CA key configuration
defaultKey sign
certSignKey sign
crlSignKey sign
testKey test

Add following lines in /opt/ejbca-custom/conf/web.properties

echo "cryptotoken.p11.lib.110.name=Utimaco R3" >> /opt/ejbca-custom/conf/web.properties
echo "cryptotoken.p11.lib.110.file=/opt/utimaco/p11/libcs_pkcs11_R3.so" >> /opt/ejbca-custom/conf/web.properties

Copy following files and directories from the client PC to the remote server:

  • p11tool2
  • libcs_pkcs11_R3.so
scp -r <file> [email protected]:/tmp/

Create utimaco configuration directory:

mkdir -p /opt/utimaco/p11/

Move files from /tmp to /opt/packages/utimaco/

mv /tmp/p11tool2 /opt/utimaco/p11/
mv /tmp/libcs* /opt/utimaco/p11/
  • Create file /opt/utimaco/p11/libcs_pkcs11_R3.ini
[Global]
Timeout = 5000
Logging = 0
Logpath = /tmp

[CryptoServer]
Device     = 172.10.0.34
Timeout    = 600000
AppTimeout = 172800
SlotCount  = 2

Set permissions:

chmod -v 0750 /opt/utimaco/p11/p11tool2
chmod -v 0644 /opt/utimaco/p11/libcs_pkcs11_R3.so
chmod u+w /opt/utimaco/p11/libcs_pkcs11_R3.ini

Build EJBCA

Log in as wildfly user and change working directory to /opt/ejbca:

su - wildfly

cd /opt/ejbca

ant -q clean deployear

Build clientToolBox

ant -q clientToolBox

Install The EJBCA:

ant runinstall

Deploy keystore:

ant deploy-keystore

Restart EJBCA

Note

First try to access EJBCA Public page without wildfly service restart. If there is problem with TLS handshake, please do restart wildlfly service.

Access the EJBCA Public Web using web browser using first node on the following link:

@ http://172.10.0.10:8080/ejbca

Download superadmin.p12. It is located under:

/opt/ejbca/p12/

Import superadmin.p12 into browser and restart web browser in order to reload its cert store.

Open EJBCA Administration page:

@ https://172.10.0.10:8443/ejbca/adminweb

3. When EJBCA installation is done stop mariadb service

On each nodes stop mariadb service with following command:

sudo systemctl stop mariadb.service

4. Follow the procedure for Galera installation

Prerequisites

  1. 3 servers with preinstalled Debian 12 Linux distribution
  2. For each server, 2 network adapters configured
    a) 1 adapter for Internet access
    b) 1 adapter for communication/replication among the nodes
    • (172.30.0.165, 172.30.0.166, 172.30.0.167)
  3. Root password set to ‘linux!2345
  4. Optional: Default configuration of Debian installation doesn’t have an active firewall. For other Linux distribution it is needed to open and configure ports 3306 (TCP), 4444 (TCP), 4567 (TCP and UDP), 4568 (TCP) and configure SELinux policies if needed.

Installation

On each node create galera configuration file:

sudo nano /etc/mysql/conf.d/galera.cnf

On the first node, add the following configuration to (/etc/mysql/conf.d/galera.cnf) file.
(IP address of the first node is 172.30.0.165):

[mysqld]
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0

# Galera Provider Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so

# Galera Cluster Configuration
wsrep_cluster_name="alg_cluster"
wsrep_cluster_address="gcomm://172.10.0.166,172.10.0.167"

# Galera Synchronization Configuration
wsrep_sst_method=rsync

# Galera Node Configuration
wsrep_node_address="172.10.0.165"
wsrep_node_name="galera1"

On the second node, add the following configuration to (/etc/mysql/conf.d/galera.cnf) file
(IP address of the second node is 172.10.0.166):

[mysqld]
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0

# Galera Provider Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so

# Galera Cluster Configuration
wsrep_cluster_name="alg_cluster"
wsrep_cluster_address="gcomm://172.10.0.165,172.10.0.167"

# Galera Synchronization Configuration
wsrep_sst_method=rsync

# Galera Node Configuration
wsrep_node_address="172.10.0.166"
wsrep_node_name="galera2"

On the third node, add the following configuration to (/etc/mysql/conf.d/galera.cnf) file
(IP address of the third node is 172.10.0.167):

[mysqld]
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0

# Galera Provider Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so

# Galera Cluster Configuration
wsrep_cluster_name="alg_cluster"
wsrep_cluster_address="gcomm://172.10.0.165,172.10.0.166"

# Galera Synchronization Configuration
wsrep_sst_method=rsync

# Galera Node Configuration
wsrep_node_address="172.10.0.167"
wsrep_node_name="galera3"

On the first node start galera cluster:

sudo galera_new_cluster

On the first node execute the following command to check the cluster size
(DB root password “linux!2345”):

mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_size'"


Output
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 1     |
+--------------------+-------+

On the second node start mariadb service and add the node to the cluster:

sudo systemctl start mariadb

On the third node start mariadb service and add the node to the cluster:

sudo systemctl start mariadb

On the first node execute the following command to check the updated cluster size:

mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_size'"

Output
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 3     |
+--------------------+-------+

Testing Replication

On the first node create a database and insert test data:

mysql -u root -p -e 'CREATE DATABASE playground;'
mysql> CREATE TABLE playground.equipment ( id INT NOT NULL AUTO_INCREMENT, type VARCHAR(50), quant INT, color VARCHAR(25), PRIMARY KEY(id));
mysql> INSERT INTO playground.equipment (type, quant, color) VALUES ("slide", 2, "blue");

Look at the second node to verify that replication is working:

mysql -u root -p -e 'SELECT * FROM playground.equipment;'

Output
+----+-------+-------+-------+
| id | type  | quant | color |
+----+-------+-------+-------+
|  1 | slide |     2 | blue  |
+----+-------+-------+-------+

On the second node insert test data:

mysql -u root -p -e 'INSERT INTO playground.equipment (type, quant, color) VALUES ("swing", 10, "yellow");'

From the third node, you can read all of this data by querying the table again:

Output
+----+-------+-------+--------+
| id | type  | quant | color  |
+----+-------+-------+--------+
|  1 | slide |     2 | blue   |
|  2 | swing |    10 | yellow |
+----+-------+-------+--------+

Again, you can add another value from this node:

mysql -u root -p -e 'INSERT INTO playground.equipment (type, quant, color) VALUES ("seesaw", 3, "green");'

Back on the first node, you can verify that your data is available everywhere:

mysql -u root -p -e 'SELECT * FROM playground.equipment;'

Output
+----+--------+-------+--------+
| id | type   | quant | color  |
+----+--------+-------+--------+
|  1 | slide  |     2 | blue   |
|  2 | swing  |    10 | yellow |
|  3 | seesaw |     3 | green  |
+----+--------+-------+--------+

Note

Always start Galera Cluster on the node where mariadb service was the last stopped.
If the last time you stopped mariadb service in the following order galera3 –> galera2 –> galera1, you should initiate Galera Cluster on galera1 node.

MariaDB Backup and Restore

On each node install MariaDB backup package:

sudo apt-get install mariadb-backup

On the third node create backup directory:

mkdir -p /var/mariadb/backup/

On the third node make a backup of MariaDB database:

sudo mariabackup --backup --target-dir=/var/mariadb/backup/ --user=root --password=linux!2345

On the third node check the backed up content:

sudo ls -l /var/mariadb/backup/

On the third node stop mariadb service:

sudo systemctl stop mariadb

On the third node first prepare backup in order to restore it:

sudo mariabackup --prepare --target-dir=/var/mariadb/backup/

On the third node remove the content from the MariaDB data directory (/var/lib/mysql/):

sudo rm -rf /var/lib/mysql/*

On the third node start MariaDB restore:

sudo mariabackup --copy-back --target-dir=/var/mariadb/backup/

On the third node fix the file permissions for the restored data:

sudo chown -R mysql:mysql /var/lib/mysql/

On the third node start mariadb service, join the existing Galera Cluster and sync the restored data:

sudo systemctl start mariadb

On the third node check the restored and synced data.

5. Open EJBCA Administration page

Download each superadmin.p12 file.

On node1:

cd /opt/ejbca/p12/
cp superadmin.p12 /tmp
scp [email protected]:/tmp/superadmin.p12 /tmp/superadminca1.p12

On node2:

cd /opt/ejbca/p12/
cp superadmin.p12 /tmp
scp [email protected]:/tmp/superadmin.p12 /tmp/superadminca2.p12

On node3:

cd /opt/ejbca/p12/
cp superadmin.p12 /tmp
scp [email protected]:/tmp/superadmin.p12 /tmp/superadminca3.p12

Import each superadmin.p12 into browser and restart web browser in order to reload its cert store.
You need to open private browser window for each cert store of specific node. When you are asked to identify yourself, you need to choose the certificate of said node.

certificate

References

https://doc.primekey.com/ejbca/tutorials-and-guides