GitHubContribute in GitHub: Open doc issue|Edit online

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.

  1. Azure Rights Management Service (Azure RMS), managed by Microsoft.
  2. 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:
  ```
  1. Add a chart repository
    helm repo add bitnami https://charts.bitnami.com/bitnami
    
  2. Install RabbitMQ Operator with helm
    helm install rabbitmq bitnami/rabbitmq-cluster-operator --namespace rabbitmq --create-namespace
    
  3. 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.
  1. 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.pem and server-key.pem, respectively, this Secret can be created by running:
      kubectl create secret tls tls-secret --cert=server.pem --key=server-key.pem --namespace rabbitmq
      
      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 as ca.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:

    1. Mutual TLS (MTLS) for security: The tls section specifies the certificates that are used to secure communication between clients and RabbitMQ.

      • ssl_options.verify = verify_peer ensures 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 = 2 controls the depth of certificate verification. You can adjust this if a different depth for CA lookup is needed.
    2. 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_name specifies 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.
    • Create route to access RabbitMQ amqps
      apiVersion: 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
      
      Read more about TLS and mTLS configuration here

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.

  1. 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.

    1. 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 your keystore.p12 file (containing the client certificate and private key).
      • This command creates a secret that is named msdke-keystore-secret in the msdke namespace. The application uses this keystore for client-side authentication during the mTLS handshake.
    2. 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-secret in the msdke namespace. The truststore is used to verify RabbitMQ’s certificate

    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.

  2. 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 the truststore.p12 file.
    • MSDKE_RABBIT_CLIENT_KEY_PASSWORD: The password for the private key inside the keystore.p12 file.
    • MSDKE_RABBIT_CLIENT_KS_PASSWORD: The password for the keystore.p12 file.
    • MSDKE_RABBIT_URI: The RabbitMQ connection URI (formatted as amqps://<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.yaml
    

    Alternatively, 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 msdke
    

    In 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).
  3. 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:
      Starting with the following Crypto Connect identity key label=EKMF.WEB.IDENTITY.KEY, hash=D545792C1CBE5E4E00AFC7DC0D94AFC609EB3FE2, token=30819B301006072A8648CE3D020106052B81040023038186000401EC0E51848E6882FED7CCEA37ED4A7FC0B3BE6B44356A485E3ABB4320B3AD57DE1A283D5EE9465903B12381D83F6247349B3AFC48A3D05036AC06968202F4E76813005281CDD655CB0C78EB343917DE1095E74971B12B0E4FF238619C6CD7B186C68A0322819A38014BC2B4D14C16BA29EE20864537207DB1CC5324EE40AD030BD5646E.
      
      The value of the token field 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.
    1. 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> for MSDKE_EC_TRUSTED_KEYS_X509_ENCODED with the base64-encoded token value(s) retrieved from the logs.
        • Replace <data in base64> for MSDKE_KEYSTORE_PASSWORD with the base64-encoded password provided by the user.
    2. Apply the Secret Usinmg kubectl Apply the secret using kubectl:
      kubectl apply -f msdke.yaml
      
      Alternatively, Create the Secret Using the Command Line:
      kubectl create secret generic msdke-secrets \
      --from-literal=MSDKE_EC_TRUSTED_KEYS_X509_ENCODED=<data> \
      --from-literal=MSDKE_KEYSTORE_PASSWORD=<data> \
      --namespace msdke
      
      In this command:
      • Replace <data> with the actual base64-encoded trusted public keys and keystore password.

    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.

  4. Configure values.yaml for MSDKE HTTP Service The values.yaml file 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 password
    

    Key Sections Explained:

    1. 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).
    2. Service Ports (service):
      • HTTP: Exposes the service on port 80 using HTTP.
      • HTTPS: The portName and port are empty, disabling the HTTPS port by default.
    3. 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.
    4. 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.
    5. 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_ssl plug-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.
    6. 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.

  5. 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.