This article describes how to migrate an existing Nexus Certificate Manager (CM) installation to Kubernetes using Helm.
Prerequisites
-
Certificate Manager (CM) is installed with CM version 8.15.x or later.
-
Earlier CM versions are not supported for migration and must be updated before a migration.
-
-
A supported database server must be installed/available. Access to the database itself and the type of deployment of the database is not part of the scope of this guide.
-
Knowledge or experience of deployment and troubleshooting in Kubernetes.
-
Kubernetes version 1.33.8 or later.
-
License file must be available.
-
Helm version 3.6.2 or later.
-
Kubectl version 1.33.8 or later.
-
Any supported Podman version, Docker version, or other container image build tool, such as Buildah.
-
Administrator's Workbench, Registration Authority, and Certificate Controller clients from CM distributable package.
-
A Kubernetes namespace for the deployment exists and access to it is available, with both
kubectlandhelmcommands configured to use it as the current namespace. -
Before deploying, verify that the storage class configured for the CF PVCs supports
ReadWriteManyaccess mode.
Recommendations
Migration to Kubernetes is an advanced topic and requires analysis of the current configuration and use cases to adapt it to fit well on a Kubernetes deployment. It’s recommended to use the cf-example and pgw-example as a starting point but those charts likely may still need modifications to fully fit all use cases.
-
Configuration files and libraries/addons (such as HSM) can be mounted as volumes to the pods, via
ConfigMaps, orSecrets. Libraries or addons which require write access for files (which could be for example a PKCS#11 library writing configuration or logs), may need to be copied to persistent volumes which must then be mounted in each container requiring them. -
Data such as configuration or libraries should be deployed as read-only data in
ConfigMapsorSecrets(by usingHelmorkubectl) to the highest extent possible. Removing volumes can lead to loss of data and configuration. -
It is recommended to keep the Helm deployment/umbrella chart in a version controlled code repository with the exception of configuration files, certificates and keystores, which contain binary data or may hold sensitive data, such as passwords and private keys.
Step-by-step instructions
Deployment directory setup
-
The distributable contains a
helmdirectory where the Helm charts are stored. It contains the following charts:-
cf -
cf-example -
pgw -
pgw-example
-
The cf and pgw charts are the base charts. These charts contain the base templates for Certificate Manager and Protocol Gateway application deployment, but do not contain any configuration.
The cf-example and pgw-example charts are the parent charts. The parent charts are example charts with configuration for an initial example deployment, and can be renamed and modified by the customer as needed, with customer specific configuration, trust stores and key stores.
The cf-example and pgw-example charts have explicit dependencies to the cf and pgw base charts in their Chart.yaml files. The path to the base charts must match where the charts are stored on the file system.
Copy all these charts to a suitable location in a host which can reach the targeted Kubernetes-based system.
Once the charts are extracted from the deliverable, the existing configuration to be migrated can be added to the parent charts.
It is recommended to keep the parent charts under a version control system, such as Git. The base charts may also be uploaded to an OCI registry, but they shall not be uploaded to any publicly available registries or repositories.
For deploying both Certificate Manager server and Protocol Gateway at the same time, an umbrella chart may also be defined with both cf-example and pgw-example as dependencies.
See the official Helm documentation for more information.
Load the container images
The container images for CM are located in the images directory within the distributable package.
The images can be read with below commands.
Example using docker, podman and buildah tools:
docker image load --input images/cf-server-image-<version>.tar
docker image load --input images/pgw-image-<version>.tar
podman image load --input images/cf-server-image-<version>.tar
podman image load --input images/pgw-image-<version>.tar
buildah pull docker-archive:images/cf-server-image-<version>.tar
buildah pull docker-archive:images/pgw-image-<version>.tar
If images are stored in private container registries they could be pulled by updating the configuration file values.yaml:
# the image and tag references for the CF image. The image is required to be
# stored in a registry.
image:
repository: <registry-url>/x-repo
tag: <version-tag>
pullPolicy: IfNotPresent
CF and CIS migration initialization
Once extracted from the deliverable, the cf-example chart will contain configuration files and certificates with initial configuration:
├── Chart.yaml
├── files
│ ├── certs
│ │ ├── kek.p12
│ │ ├── pin.p12
│ │ ├── tls.p12
│ │ ├── tcsigner.p12
..etc.
│ ├── config
│ │ ├── cis.conf
│ │ ├── cm.conf
...etc.
│ ├── inputviews
│ │ ├── ac-iv.conf
│ │ ├── acme-account-reg-search.conf
│ │ ├── acme-prereg-search.conf
...etc.
│ ├── keystore
│ ├── license
│ ├── pinprocedures
│ │ ├── generate_puk.conf
...etc.
All obfuscated configuration files will require their .seed file to be copied alongside its obfuscated configuration file to the corresponding subdirectory under files in the cf-example Helm chart.
While CM allows for obfuscating new parameters in configuration files it’s not recommended to do so for Kubernetes deployments, because each time the CF pods restart, scale in or are re-deployed, the obfuscation changes are lost. To have a permanent effect, the seed file as well as the configuration file must be copied from the container to the Helm chart configuration, as the Helm chart is the source of the configuration.
Migrating CF and CIS configuration files
-
Copy any customized PIN procedures from the source CM installation to the
cf-examplechart:
cp <old CM server dir>/config/pinprocedures/* cf-example/files/pinprocedures/
-
From the source CM installation, copy all configuration files from the old CM installation directory to the
cf-example chart:
cp <old CM server dir>/config/* cf-example/files/config/
If any of the config name contains space characters as in for example ecs template.tpl, replace the space character with two underscore characters, as follows: ecs__template.tpl.
-
Remove all existing files in the
certsdirectory incf-example, and then copy all files from the old CM installationcertsdirectory to thecf-examplechart.
rm -f cf-example/files/certs/
cp <old CM server dir>/certs/* cf-example/files/certs/
-
The CIS keystores must be moved to the directory
keystorein thecf-examplechart as these cannot be backed by a read-only Secret from the chart directly. In a default deployment the commands to move the keystore files would be as follows:
mv cf-example/files/certs/ca.p12 cf-example/files/keystore/
mv cf-example/files/certs/rsapss.p12 cf-example/files/keystore/
mv cf-example/files/certs/dsa.p12 cf-example/files/keystore/
mv cf-example/files/certs/ecdsa.p12 cf-example/files/keystore/
mv cf-example/files/certs/edwards.p12 cf-example/files/keystore/
mv cf-example/files/certs/ml-dsa.p12 cf-example/files/keystore/
mv cf-example/files/certs/pure-slh-dsa.p12 cf-example/files/keystore/
mv cf-example/files/certs/hash-slh-dsa.p12 cf-example/files/keystore/
If any of the keystore files are not found it means such keys were never added. The mv errors can be ignored.
-
Verify the CIS keystore name and path for
cis.crypto.deviceis correct incis.confMigrating CF format filesexample
cis.crypto.device.1.file = keystore/ca.p12
Customized certificate format files and other format files require creating additional ConfigMap templates inside cf-example/templates. The ConfigMap templates can be defined in the same way as for example pinprocedures.yaml, and then be mounted to the CF container by using the extraVolumes and extraVolumeMounts parameters in cf-example/values.yaml. The ConfigMap may also be a Secret with type Opaque instead if so desired.
There is an example on how to use the extraVolumes and extraVolumeMounts to mount a ConfigMap as files in the Migrating HSM libraries and configuration section below.
Migrating license files
Copy license files from old CM installation under the license folder cf-example/files/license:
cp <old CM install dir>/config/license/* cf-example/files/license/
CM license file
Place the CM license files under the license folder cf-example/files/license.
Migrating HSM drivers and configuration
Configuring HSM PKCS#11 drivers with CM on Kubernetes may be done in several ways. The most important aspect of it is that CIS and CF can point out the path to the HSM PKCS#11 library file, and also read the corresponding environment variables for locating the configuration file of the HSM PKCS#11 driver.
One way to handle this is to mount a volume in the CF containers containing the configuration for the HSM driver by creating a Secret or ConfigMap with the configuration files into the desired destination directory in the CF container. Then an environment variable is provided with a ConfigMap which points out the location of the HSM configuration files.
The HSM library/driver file is typically too large to deploy via a ConfigMap or a Secret, so it must be copied to the container in some other way. kubectl cp cannot be used because the CF container image lacks the support to use it due to security hardening reasons.
Instead, a Kubernetes Job can be used to deploy a Pod running a temporary container with a suitable temporary image such as busybox. The container in this Pod must mount the drivers subdirectory from the shared volume cf. This way, any files copied to the drivers directory in the temporary Pod will also be reflected in the CF Pod in /opt/drivers.
kubectl can then be used to copy the HSM driver library files to where the drivers sub path is mounted.
Here follows an example for configuring an Utimaco HSM library:
-
Create the directory
example-cf/files/hsm/and copy the HSM config file toexample-cf/files/hsm/cs_pkcs11_R3.cfg. -
Create a new
ConfigMaptemplate, for examplecf-example/templates/hsm-files.yaml, with the content:
apiVersion: v1
kind: ConfigMap
metadata:
name: hsm-files
binaryData:
{{- $files := .Files }}
{{- range $key, $value := .Files.Glob "files/hsm/*" }}
{{- if hasPrefix "files/hsm/" $key }}
{{ $key | trimPrefix "files/hsm/" }}: {{ $files.Get $key | b64enc }}
{{- end }}
{{- end }}
-
Create another
ConfigMaptemplate for environment variables,cf-example/templates/hsm-config.yamlwith the following content:
apiVersion: v1
kind: ConfigMap
metadata:
name: hsm-env
data:
CS_PKCS11_R3_CFG: /opt/hsm/cs_pkcs11_R3.cfg
-
Add volume and volume mount for the
hsm-filesConfigMapand environment variableshsm-envincf-example/values.yaml:
extraVolumes:
- name: hsm-files
configMap:
name: hsm-files
defaultMode: 0555
extraVolumeMounts:
- name: hsm-files
mountPath: /opt/hsm
readOnly: true
environment:
- name: CS_PKCS11_R3_CFG
valueFrom:
configMapKeyRef:
name: hsm-env
key: CS_PKCS11_R3_CFG
Steps to add the HSM driver:
Copy the HSM driver library inside the CF pod mount path /opt/drivers/ by using a batch job.
-
Make sure to copy the HSM driver library file
libcs_pkcs11_R3.soto the host wherekubectlhas access to the target Kubernetes environment. -
Create a new YAML file, for example
copy_job.yaml. Avoid creating the YAML file in any of the Helm charts directories. -
Save the YAML file with the below content:
apiVersion: batch/v1 kind: Job metadata: name: copy-hsm-driver spec: template: spec: containers: - name: app image: busybox command: ["sleep", "600"] volumeMounts: - mountPath: /opt/drivers name: cf subPath: drivers volumes: - name: cf persistentVolumeClaim: claimName: cf restartPolicy: Never -
Deploy the new YAML file:
kubectl apply -f copy_job.yaml -
Run the command to copy the HSM driver library:
kubectl cp libcs_pkcs11_R3.so copy-hsm-driver-<id>:/opt/drivers/ -
Verify that the HSM driver library is present inside the CF Pods on the path
/opt/drivers:kubectl exec cm-cf-0 -- ls -la /opt/drivers Defaulted container "cf" out of: cf, cf-init (init) total 4539 drwxrwxrwx 2 0 1000 0 Aug 14 08:28 . drwxr-xr-x 1 0 0 4096 Aug 14 11:34 .. -rwxrwxrwx 1 0 1000 4639392 Aug 14 09:13 libcs_pkcs11_R3.so -
Delete the
copy_job.yamlfile. -
Delete
job.batch/copy-hsm-driverfrom the namespace:kubectl delete job.batch/copy-hsm-driver
Device Configurations
-
Edit
cis.confand make sure that the device configuration points to the HSM library file, as in this example:
;- Examples of PKCS#11 device configurations
cis.crypto.device.10.name = CryptoServer (RSA and RSASSA-PSS)
cis.crypto.device.10.type = PKCS11
cis.crypto.device.10.label = CIS Slot
cis.crypto.device.10.library = /opt/drivers/libcs_pkcs11_R3.so
cis.crypto.device.10.algorithm = RSA
;;cis.crypto.device.10.algorithmOID = RSA
cis.crypto.device.10.keysize = 2048 3072 4096 8192
cis.crypto.device.10.pin = 1234
cis.crypto.device.10.hashInCis = false
The Utimaco HSM driver library file is now present in the path /opt/drivers/libcs_pkcs11_R3.so and can be referenced from cm.conf and cis.conf by specifying this path.
Deploy the CF application
Run the following commands to deploy the cf-example chart:
cd cf-example
helm dependency build
helm install -n <your-namespace> cm .
Monitor the CF Pods and make sure they start up correctly.
kubectl logs <cf-pod> -n <your-namespace>
To forward the port 5009, simply run the below command in a shell:
kubectl port-forward service/cm-cf 5009:5009
PGW migration initialization
Migrating Protocol Gateway requires collecting important files, such as TLS keystores, trust store files and configuration files, such as server.xml.
Migrate PGW configuration
The content from the following directories needed to be added as content for the volumes in the pgw-example chart:
-
PGW configuration which contains the
confandcertdir:<pgw_home>/conf -
Tomcat configuration which contains the TLS and
server.xml:<tomcat_home>/conf
When copying files into the chart,
-
Include only the CA certificate, any
*.p12files, and other relevant configuration files that override existing content. Excludelogging.properties; do not override this file inpgw-example/files/conforpgw-example/files/tomcat -
Copy
<pgw_home>/conf/certdir/*topgw-example/files/certdir/ -
WebUI is not supported with helm charts for now skip
<pgw_home>/conf/Json-templatefor this version
find <pgw-home>/conf/ -type f -not -name 'logging.properties' -exec cp '{}' 'pgw-example/files/conf/{}' ';'
cp <pgw-home/conf/certdir/* pgw-example/files/certdir/
cp <tomcat-home>/conf/* pgw-example/files/tomcat/
Verify that the connectivity
For connection verify the details in pgw-example/files/conf/cm-gateway.properties are correct.
-
The
cmhostparameter should point to thecmhost=<cf-server-host>ClusterIP load balancing service.-
example
cmhost=cm-cf
-
-
The
officer.keyfilehas correct cert path
Make sure that the Tomcat health check valve is configured in server.xml below the Host XML element:
<Valve className="org.apache.catalina.valves.HealthCheckValve" />
The connectors defined in server.xml must map to the ports defined in the service, which can be seen in the pgw base chartpgw/values.yaml default service ports are 8080, 8443, 8444. If the service or liveness and readiness probe ports are different in the values.yaml, then either they can be overridden in the pgw-example umbrella chart or changed in server.xml to map correctly to those defined on the service, liveness and readiness probes.
Configure HSM with PGW container
Configuring the HSM with PGW can be performed similar to the approach outlined in the section Migrating CF and CIS HSM libraries and configuration above.
Deploy the PGW application
Run the following commands to deploy the pgw-example chart:
cd pgw-example
helm dependency build
helm install -n <your-namespace> pgw .
Monitor the PGW Pods and make sure they start up correctly.
kubectl logs <pgw-pod> -n <your-namespace>
To access the Protocol Gateway ports for testing, forward them by running the below command in a shell:
kubectl port-forward service/pgw 8080:8080 8443:8443 8444:8444