This repository contains Helm charts, boilerplate configuration, and scripts to deploy EJBCA and SignServer to Kubernetes FOR TESTING/DEV PURPOSES. Both EJBCA and SignServer are deployed in front of a MariaDB database, and are accessed using an NGINX Ingress Controller. Client certificates are issued by EJBCA and used to authenticate to both the EJBCA and SignServer nodes.
This repository is not intended to be used in production environments. It is intended to be used for testing and development purposes only. For more information on deploying EJBCA and SignServer in production environments, please refer to the EJBCA documentation and SignServer documentation.
EJBCA is deployed with the following CA hierarchy:
ManagementCA
- Self-signed CA used to issue the SuperAdmin end entity certificate, and is the trusted root of the SignServer node.Root-CA
- Self-signed CA that acts as the root of the EJBCA hierarchy.Sub-CA
- CA issued by the Root-CA, and is used to issue end entity certificates. This CA signs the initial TLS end entity certificates for both the EJBCA and SignServer nodes.
EJBCA is configured with the following End Entity Profiles:
adminInternal
- Used to issue the SuperAdmin end entity certificate.ephemeral
- Can be used to issue ephemeral, short-lived end entity certificates that don't get persisted to the database.k8s
- Can be used to issue end entity certificates with common patterns used by Istio and Kubernetes.tlsServerAnyCA
- Can be used to issue end entity certificates used for TLS, and can be signed by any CA in the hierarchy.userAuthentication
- Can be used to issue end entity certificates used for client authentication.
EJBCA is configured with the following Certificate Profiles:
Authentication-2048-3y
- Used to issue end entity certificates with 2048-bit RSA keys that are valid for 3 years.codeSigning-1y
- Used to issue RSA or ECDSA end entity certificates that are valid for 1 year, and have thecodeSigning
extended key usage.istioAuth-3d
- Used to issue end entity certificates with n-bit RSA keys that are valid for 3 days, and have both Client Authentication and Server Authentication extended key usages for mTLS authentication in Istio.tlsClientAuth
- Used to issue end entity certificates with n-bit RSA keys that are valid for 1 year, and have the Client Authentication extended key usage for client authentication.tlsServerAuth
- Used to issue end entity certificates with n-bit RSA keys that are valid for 1 year, and have the Server Authentication extended key usage for server authentication.
This repository contains an action.yml that can be used to deploy EJBCA and SignServer to Kubernetes in GitHub Actions workflows. The following example workflow deploys a single node Kubernetes cluster using Kind, and then deploys EJBCA and SignServer to the cluster:
name: Deploy ephemeral EJBCA and SignServer for CI testing
on:
push:
branches:
- main
jobs:
deploy-ejbca-ss:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Deploy a single node Kubernetes cluster with kind, then deploy EJBCA and SignServer
- uses: m8rmclaren/ejbca-signserver-k8s@main
with:
deploy-k8s: 'true'
deploy-nginx-ingress: 'true'
# Demonstrate the environment variables that are set by the action
- name: Test connection to EJBCA and SignServer
shell: bash
run: |
echo "$EJBCA_HOSTNAME"
echo "$EJBCA_CA_NAME"
echo "$EJBCA_CERTIFICATE_PROFILE_NAME"
echo "$EJBCA_END_ENTITY_PROFILE_NAME"
echo "$EJBCA_CSR_SUBJECT"
echo "$EJBCA_CLIENT_CERT_PATH"
echo "$EJBCA_CLIENT_CERT_KEY_PATH"
echo "$EJBCA_CA_CERT_PATH"
echo "$SIGNSERVER_HOSTNAME"
echo "$SIGNSERVER_CLIENT_CERT_PATH"
echo "$SIGNSERVER_CLIENT_CERT_KEY_PATH"
echo "$SIGNSERVER_CA_CERT_PATH"
curl \
--silent --fail \
--cert "$EJBCA_CLIENT_CERT_PATH" \
--key "$EJBCA_CLIENT_KEY_PATH" \
--cacert "$EJBCA_CA_CERT_PATH" \
"https://$EJBCA_HOSTNAME/ejbca/ejbca-rest-api/v1/certificate/status"
- jq >= v1.6
- curl >= v7.68.0
- openssl >= v1.1.1
- Docker >= v20.10.0
- Kubectl >= v1.11.3
- Kubernetes >= v1.19
- Kubernetes, Minikube, or Kind
- Helm >= v3.0.0
It's recommended to use Docker Desktop, which includes a single-node Kubernetes cluster and the kubectl
CLI.
Install the following tools using Homebrew:
brew install curl helm jq openssl
This section assumes a Debian-derived Linux distribution, such as Ubuntu. If you're using a different distribution, you'll need to install the tools using your distribution's package manager.
Provision the Docker engine. Commands are provided for convenience, but you should follow the official documentation for the latest instructions.
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done
sudo apt-get update
# Dependencies
sudo apt-get install ca-certificates curl gnupg
# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
# Install latest version
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
For a quick start, you can use Minikube to provision a single-node Kubernetes cluster. Commands are provided for convenience, but you should follow the official documentation for the latest instructions.
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
Start Minikube:
minikube start
Alternatively, you can use Kind to provision a single-node Kubernetes cluster. A Kind configuration file is provided as part of this repository. For a quick start, you can use the following commands to provision a single-node Kubernetes cluster:
# For AMD64 / x86_64 [ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64 # For ARM64 [ $(uname -m) = aarch64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-arm64 chmod +x ./kind sudo mv ./kind /usr/local/bin/kind # Deploy a single node cluster with kind kind create cluster --config kindconfig.yaml
Install Helm
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
Install kubectl, if it wasn't installed with your Kubernetes distribution:
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
kubectl version --client
Install the following tools using Apt:
sudo apt-get install curl jq openssl -y
The shell script commands in this repository are not compatible with Windows. You can use the Windows Subsystem for Linux to run the shell scripts.
Deploy an NGINX Ingress Controller. If you're using Minikube, you can use the following command:
minikube addons enable ingress
Otherwise, you can use the following command to deploy the NGINX Ingress Controller as a Helm chart:
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--set controller.allowSnippetAnnotations=true
If you're using Kind, you can use the following command to deploy the NGINX Ingress Controller with the correct port mappings:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml kubectl patch configmap ingress-nginx-controller -n ingress-nginx --patch '{"data":{"allow-snippet-annotations":"true"}}'
Finally, deploy EJBCA and SignServer:
./deploy.sh --signserver-hostname localhost --ejbca-hostname localhost
You may need to adjust your hostname if you're using Minikube or Kind. For example, if you're using Minikube, before you run the deploy.sh
script, add the following entry to your /etc/hosts
file:
echo "$(minikube ip) signserver-node1.local" | sudo tee -a /etc/hosts
echo "$(minikube ip) ejbca-node1.local" | sudo tee -a /etc/hosts
Then, run the deploy.sh
script:
./deploy.sh --signserver-hostname signserver-node1.local --ejbca-hostname ejbca-node1.local
To test the deployment, you can use the following command to retrieve the status of the EJBCA CA:
curl https://localhost/ejbca/ejbca-rest-api/v1/certificate/status \
--cacert ./Sub-CA-chain.pem \
--cert ./superadmin.pem \
--key ./superadmin.key
To quickly configure SignServer, you can use the REST API to create a P12 Crypto Worker and a Plain Signer that uses client-side hashing:
curl -X 'POST' \
'https://localhost/signserver/rest/v1/workers' \
--cacert ./Sub-CA-chain.pem \
--cert ./superadmin.pem \
--key ./superadmin.key \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'X-Keyfactor-Requested-With: APIClient' \
-d '{
"properties": {
"CRYPTOTOKEN_IMPLEMENTATION_CLASS": "org.signserver.server.cryptotokens.KeystoreCryptoToken",
"IMPLEMENTATION_CLASS": "org.signserver.server.signers.CryptoWorker",
"KEYSTOREPASSWORD": "foo123",
"KEYSTOREPATH": "/opt/signserver/res/test/dss10/dss10_keystore.p12",
"KEYSTORETYPE": "PKCS12",
"NAME": "CryptoTokenP12",
"TYPE": "CRYPTO_WORKER"
}
}'
curl -X 'POST' \
'https://localhost/signserver/rest/v1/workers' \
--cacert ./Sub-CA-chain.pem \
--cert ./superadmin.pem \
--key ./superadmin.key \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'X-Keyfactor-Requested-With: APIClient' \
-d '{
"properties": {
"ACCEPTED_HASH_DIGEST_ALGORITHMS": "SHA-256,SHA-384,SHA-512",
"AUTHTYPE": "NOAUTH",
"CLIENTSIDEHASHING": "true",
"CRYPTOTOKEN": "CryptoTokenP12",
"DEFAULTKEY": "signer00003",
"DISABLEKEYUSAGECOUNTER": "true",
"DO_LOGREQUEST_DIGEST": "",
"IMPLEMENTATION_CLASS": "org.signserver.module.cmssigner.PlainSigner",
"LOGREQUEST_DIGESTALGORITHM": "",
"NAME": "PlainSigner",
"SIGNATUREALGORITHM": "NONEwithRSA",
"TYPE": "PROCESSABLE"
}
}'
To uninstall EJBCA and SignServer, run the following command:
./deploy.sh --uninstall