Installation and configuration of Microsoft Double Key Encryption (DKE)
Create a Microsoft Double Key Encryption (DKE) keystore in your Unified Key Orchestrator instance on Red Hat OpenShift Container Platform protect your highly sensitive data. DKE uses two keys to ensure data protection.
- Azure Rights Management Service (Azure RMS), managed by Microsoft.
- UKO key, managed by you.
To access the protected data, both keys are required. By maintaining control over the UKO key, you can ensure that Microsoft cannot access your data, giving you full control over your sensitive information.
Before you begin:
Before you can install the MSDKE and RabbitMQ on Red Hat OpenShift Container Platform, you need to complete the following prerequisites:
Before installing the MSDKE and RabbitMQ on Red Hat OpenShift Container Platform, complete the following requirements:
1. Install the Red Hat OpenShift Container Platform. For detailed instructions, see [Installing OpenShift Container Platform](install-ocp.html)
2. Install [Helm](https://helm.sh/docs/intro/install/).
3. Create a Helm chart repository. The chart repository is a centralized location to store and share the charts.
Configuration options:
• CLI: For more information, see helm [commands manual](https://helm.sh/docs/helm/helm_repo_add/).
• Developer catalogue: For detailed instructions, see the [Red Hat OpenShift documentation](https://docs.openshift.com/container-platform/4.15/applications/working_with_helm_charts/configuring-custom-helm-chart-repositories.html#adding-helm-chart-repositories_configuring-custom-helm-chart-repositories)..
Configuring RabbitMQ for MSDKE Applications Integration:
Perform the following steps to configure RabbitMQ for your application using mTLS (Mutual TLS) and certificate-based authentication:
```
- Add a chart repository
helm repo add bitnami https://charts.bitnami.com/bitnami - Install RabbitMQ Operator with helm
helm install rabbitmq bitnami/rabbitmq-cluster-operator --namespace rabbitmq --create-namespace - Create a ConfigMap to define RabbitMQ resources definitions. You can define virtual host (vhost), user permissions and other key settings.
Example ConfigMap :
yaml apiVersion: v1 kind: ConfigMap metadata: name: definitions namespace: rabbitmq data: definitions.json: | { "product_name": "RabbitMQ", "users": [ { "name": "rabbitmq.eu-de.containers.appdomain.cloud", "password_hash": "", "hashing_algorithm": "rabbit_password_hashing_sha256", "tags": [], "limits": {} } ], "vhosts": [ { "name": "/" } ], "permissions": [ { "user": "rabbitmq.eu-de.containers.appdomain.cloud", "vhost": "/", "configure": ".*", "write": ".*", "read": ".*" } ], "topic_permissions": [], "parameters": [], "global_parameters": [], "policies": [], "queues": [], "exchanges": [], "bindings": [] }
Note :
* You must enter the Common Name (CN) from the client’s certificate as the username.
* Certificate-based authentication does not require a password. Hence, the password_hash configuration option is left blank.
* The virtual host (vhost) is a logical container for queues and exchanges. The user must have full permissions to configure, write and read on the vhost.
* Queues, exchanges and bindings are dynamically created at application startup.
-
Deploy RabbitMQ, for a more detailed configuration options see here
- Create PodDisruptionBudget resource
apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: rabbitmq-prd namespace: rabbitmq spec: maxUnavailable: 1 selector: matchLabels: app.kubernetes.io/name: rabbitmqcluster - Generate mTLS keys and certificates. Example of the simplified guide provided here
- Create mTLS k8s secrets. You need to create the Secret which contains the public certificate and private key to be used for TLS on the RabbitMQ nodes. Assuming you already have these created and accessible as
server.pemandserver-key.pem, respectively, this Secret can be created by running:
In order for peer verification to work, the RabbitMQ nodes must trust a certificate authority which has signed the public certificates of any clients which try to connect. You must create a Secret containing the CA's public certificate so that the RabbitMQ nodes know to trust any certificates signed by the CA. Assuming the CA's certificate is accessible askubectl create secret tls tls-secret --cert=server.pem --key=server-key.pem --namespace rabbitmqca.pem, you can create this Secret by running:kubectl create secret generic ca-secret --from-file=ca.crt=ca.pem --namespace rabbitmq - Create a RabbitmqCluster resource with configured mtls, 3 replicas across different zones and nodes.
apiVersion: rabbitmq.com/v1beta1 kind: RabbitmqCluster metadata: name: rabbitmqcluster namespace: rabbitmq spec: replicas: 3 tls: secretName: tls-secret caSecretName: ca-secret resources: requests: cpu: 1000m memory: 2Gi limits: cpu: 2000m memory: 4Gi rabbitmq: additionalConfig: | ssl_options.verify = verify_peer ssl_options.fail_if_no_peer_cert = true ssl_options.depth = 2 auth_mechanisms.1 = EXTERNAL ssl_cert_login_from = common_name management.load_definitions = /etc/rabbitmq/definitions.json additionalPlugins: - rabbitmq_auth_mechanism_ssl service: type: ClusterIP persistence: storageClassName: ssd # select existing storage class storage: "100Gi" # set to 0 if no persistence is needed affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app.kubernetes.io/name operator: In values: - production-ready topologyKey: kubernetes.io/hostname override: statefulSet: spec: template: spec: securityContext: {} containers: - name: rabbitmq volumeMounts: - mountPath: /etc/rabbitmq/definitions.json subPath: definitions.json # Name of the ConfigMap field containing definitions name: definitions volumes: - name: definitions configMap: name: definitions # Name of the ConfigMap which contains definitions you wish to import topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone #Can be changed to kubernetes.io/hostname if there is only one zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app.kubernetes.io/name: rabbitmqcluster
RabbitMQ config Key points:
-
Mutual TLS (MTLS) for security: The
tlssection specifies the certificates that are used to secure communication between clients and RabbitMQ.ssl_options.verify = verify_peerensures that RabbitMQ verifies the client’s certificate.ssl_options.fail_if_no_peer_cert= true rejects connections that do not provide a valid client certificate.ssl_options.depth = 2controls the depth of certificate verification. You can adjust this if a different depth for CA lookup is needed.
-
Username from Client Certificate: Instead of using a static username and password, we configure RabbitMQ to extract the username from the client’s certificate using the rabbitmq_auth_mechanism_ssl plug-in.
- The option
ssl_cert_login_from = common_namespecifies that RabbitMQ expects the username from the client’s certificate Common Name (CN), ensuring that the certificate itself provides both the identity and the credentials. - By setting
auth_mechanisms.1 = EXTERNAL, we tell RabbitMQ to use the SSL-based authentication mechanism, overriding basic authentication.
- The option
- Create route to access RabbitMQ amqps
Read more about TLS and mTLS configuration hereapiVersion: route.openshift.io/v1 kind: Route metadata: name: amqps-route namespace: rabbitmq spec: host: <hostname> # desired hostname for amqps port: targetPort: 5671 tls: termination: passthrough insecureEdgeTerminationPolicy: None to: kind: Service name: rabbitmqcluster
- Create PodDisruptionBudget resource
Install the HTTP Service:
Configuring MTLS and Secrets for Application to Connect to RabbitMQ
To securely connect your application to RabbitMQ using mTLS, you need to configure the keystore and truststore secrets for certificate authentication. Additionally, ensure that both the keystore and truststore are created with the necessary passwords, as these will be required during the configuration.
-
Create Secrets for RabbitMQ MTLS (Keystore and truststore) You will first create two Kubernetes secrets: one for the keystore and another for the truststore. These files contain the client certificate, private key, and the trusted certificate authority (CA) for RabbitMQ. Important: The PKCS12 keystore and truststore files must be created with the required passwords, as these will be referenced in the next step to securely connect to RabbitMQ.
-
Create the keystore Secret The keystore contains the client certificate and private key, which is used for RabbitMQ to authenticate the application.
Run the following command to create the secret for the keystore:
kubectl create secret generic msdke-keystore-secret --from-file=keystore.p12=<keystore_file> -n msdke- Replace
<keystore_file>with the path to yourkeystore.p12file (containing the client certificate and private key). - This command creates a secret that is named
msdke-keystore-secretin themsdkenamespace. The application uses this keystore for client-side authentication during the mTLS handshake.
- Replace
-
Create the truststore Secret The truststore contains the CA or certificate that RabbitMQ uses to authenticate the server. Run the following command to create the truststore secret:
kubectl create secret generic msdke-truststore-secret --from-file=truststore.p12=<truststore_file> -n msdke- Replace
<truststore_file>with the path to your `truststore.p12 file (containing the trusted CA or certificate). - This creates a secret that is named
msdke-truststore-secretin themsdkenamespace. The truststore is used to verify RabbitMQ’s certificate
- Replace
Both the keystore.p12 and truststore.p12 files must be present in the secrets and created with their respective passwords, which will be used for authentication.
-
-
Create a Secret for RabbitMQ Connection Credentials To complete the RabbitMQ connection setup, you need to create another secret that contains the passwords for the keystore, truststore, and the private key, as well as the RabbitMQ URI. The required environment variables are:
MSDKE_RABBIT_TRUSTSTORE_PASSWORD: The password for thetruststore.p12file.MSDKE_RABBIT_CLIENT_KEY_PASSWORD: The password for the private key inside thekeystore.p12file.MSDKE_RABBIT_CLIENT_KS_PASSWORD: The password for thekeystore.p12file.MSDKE_RABBIT_URI: The RabbitMQ connection URI (formatted asamqps://<rabbitMQ hostname>:<port>).
Example Secret YAML (
secret.yaml):apiVersion: v1 kind: Secret metadata: name: msdke-rabbitmq namespace: msdke type: Opaque data: MSDKE_RABBIT_TRUSTSTORE_PASSWORD: <data in base64> MSDKE_RABBIT_CLIENT_KEY_PASSWORD: <data in base64> MSDKE_RABBIT_CLIENT_KS_PASSWORD: <data in base64> MSDKE_RABBIT_URI: <data in base64>To apply this secret using
kubectl, run:kubectl apply -f secret.yamlAlternatively, you can create the secret using CLI:
kubectl create secret generic msdke-rabbitmq \ --from-literal=MSDKE_RABBIT_TRUST=<data> \ --from-literal=MSDKE_RABBIT_CLIENT_KEY_PASSWORD=<data> \ --from-literal=MSDKE_RABBIT_CLIENT_KS_PASSWORD=<data> \ --from-literal=MSDKE_RABBIT_URI=<data> \ --namespace msdkeIn this command:
- Replace
<data>with the actual passwords and RabbitMQ URI (ensure that the values are properly base64-encoded when creating the secret manually via YAML).
-
Configure Identity Keys for MSDKE: To enable secure communication between services, MSDKE requires a set of identity keys to sign and verify that all messages exchanged. These identity keys, in the form of Elliptic Curve public keys, must be configured via a Kubernetes secret. Required Values:
MSDKE_EC_TRUSTED_KEYS_X509_ENCODED: A comma-separated list of trusted Identity Elliptic Curve Public keys in x509 format. These keys can be retrieved from the logs when services like UKO or other MSDKE Crypto services start. Look for log entries that contain the token value you need. Example log output:
The value of theStarting with the following Crypto Connect identity key label=EKMF.WEB.IDENTITY.KEY, hash=D545792C1CBE5E4E00AFC7DC0D94AFC609EB3FE2, token=30819B301006072A8648CE3D020106052B81040023038186000401EC0E51848E6882FED7CCEA37ED4A7FC0B3BE6B44356A485E3ABB4320B3AD57DE1A283D5EE9465903B12381D83F6247349B3AFC48A3D05036AC06968202F4E76813005281CDD655CB0C78EB343917DE1095E74971B12B0E4FF238619C6CD7B186C68A0322819A38014BC2B4D14C16BA29EE20864537207DB1CC5324EE40AD030BD5646E.tokenfield in the log is the trusted public key that you need to copy and use here.MSDKE_KEYSTORE_PASSWORD: A password is provided by the user to secure the internal keystore where the HTTP service’s own Identity key will be stored. This password can be generated externally if needed but must be supplied during the configuration.
- Create the MSDKE Secret To store these configuration values, create a Kubernetes secret.
-
Create the Secret YAML (
msdke.yaml)apiVersion: v1 kind: Secret metadata: name: msdke-secrets namespace: msdke type: Opaque data: MSDKE_EC_TRUSTED_KEYS_X509_ENCODED: <data in base64> MSDKE_KEYSTORE_PASSWORD: <data in base64>- Replace
<data in base64>forMSDKE_EC_TRUSTED_KEYS_X509_ENCODEDwith the base64-encoded token value(s) retrieved from the logs. - Replace
<data in base64>forMSDKE_KEYSTORE_PASSWORDwith the base64-encoded password provided by the user.
- Replace
-
- Apply the Secret Usinmg
kubectlApply the secret using kubectl:
Alternatively, Create the Secret Using the Command Line:kubectl apply -f msdke.yaml
In this command:kubectl create secret generic msdke-secrets \ --from-literal=MSDKE_EC_TRUSTED_KEYS_X509_ENCODED=<data> \ --from-literal=MSDKE_KEYSTORE_PASSWORD=<data> \ --namespace msdke- Replace
<data>with the actual base64-encoded trusted public keys and keystore password.
- Replace
This ensures that MSDKE is configured with the identity keys and passwords that are needed to securely sign and verify messages that are exchanged between services.
-
Configure
values.yamlfor MSDKE HTTP Service Thevalues.yamlfile contains the configuration options for deploying the MSDKE HTTP service. Adjust this file to suit your environment. Below is a breakdown of key sections from an example configuration:httpHandler: image: de.icr.io/crypto-connect/msdke-http-service tag: 2.3.5 pullPolicy: IfNotPresent imagePullSecrets: [] # - name: "image-pull-secret" replicas: 1 resources: requests: cpu: 250m memory: 512Mi limits: cpu: 500m memory: 1024Mi hpa: enabled: false # Horizontal Pod Autoscaler configuration service: http: portName: http port: 80 https: portName: "" # Leave empty to disable HTTPS port port: "" ingress: # Ingress configuration enabled: true annotations: { route.openshift.io/termination: "edge" } path: "/" pathType: "Prefix" portNumber: 80 host: "" # Preferred hostname tls: "" # - hosts: # - "" # secretName: "" # ingressClassName: openshift-default cryptoHandler: enabled: false # Crypto Service is not supported on OpenShift. It must be deployed on IBM z/OS mainframes. rabbitmq: virtualHost: "/" # Specify the RabbitMQ virtual host. It must match the virtual host defined in RabbitMQ enableHostnameVerification: true # Verify that the hostname in RabbitMQ’s certificate matches the connection origin enableCertAuthentication: true # Use certificate-based authentication (mTLS) instead of username/password existingRabbitSecret: "msdke-rabbitmq" # Secret for RabbitMQ connection credentials (e.g., keystore and truststore passwords) keystoreSecretRef: "msdke-keystore-secret" # Reference to the secret containing the keystore truststoreSecretRef: "msdke-truststore-secret" # Reference to the secret containing the truststore msdke: keystoreType: "PKCS12" # Specify the keystore type; only PKCS12 is supported for OCP deployments existingMsdkeSecret: "msdke-secrets" # Reference to the secret containing MSDKE identity keys and keystore passwordKey Sections Explained:
- HTTP Service (
httpHandler):- Image Configuration: Specifies the container image (
msdke-http-service) and the image tag (2.3.5) for the service. - Replicas: Sets the number of replicas for the service.
- Resource Requests and Limits: Defines CPU and memory requirements to control resource allocation in the cluster.
- HPA: Horizontal Pod Autoscaler (disabled by default).
- Image Configuration: Specifies the container image (
- Service Ports (
service):- HTTP: Exposes the service on port 80 using HTTP.
- HTTPS: The
portNameandportare empty, disabling the HTTPS port by default.
- Ingress Configuration (
ingress):- Ingress: Controls how the service is exposed externally. It uses Red Hat OpenShift’s edge termination for TLS by default, but you can adjust the settings. For example, hostname and TLS secret.
- Crypto Handler:
- Crypto Service: This option is disabled since the deployment on Red Hat OpenShift is not supported. The Crypto service must be deployed on IBM z/OS mainframes if required.
- RabbitMQ Configuration (
rabbitmq):- virtualHost: Specifies the RabbitMQ virtual host, which should match the setup in RabbitMQ.
- Hostname Verification: Ensures that RabbitMQ certificates are validated against the connection's origin hostname.
- Certificate-Based Authentication: Enables mTLS for RabbitMQ communication by using the
rabbitmq_auth_mechanism_sslplug-in. - Secret References:
existingRabbitSecret: Refers to the secret containing RabbitMQ credentials (keystore and truststore passwords).keystoreSecretRef: Reference to the keystore secret for client-side certificate.truststoreSecretRef: Reference to the truststore secret containing trusted CA certificates.
- MSDKE Configuration (
msdke):- Keystore Type: Specifies the type of keystore (PKCS12), which is the only supported format in this OpenShift Container Platform (OCP) deployment.
- Secret Reference: Points to the msdke-secrets secret, which contains MSDKE identity keys and keystore passwords.
This configuration is ready for deployment and can be adjusted based on your specific requirements. Make sure to verify each secret and set any remaining values (for example, hostname and TLS secrets) based on your environment.
- HTTP Service (
-
Install the MSDKE HTTP Service Helm chart with one of the following methods:
-
If you are using CLI, complete the following commands:
helm install -f values.yaml <chart_name> <repository> -
If you are using Developer catalog, you can follow the instructions.
-