Learn how to deploy the EJBCA container in the Kubernetes distribution MicroK8s.

This tutorial shows you how to use Ingress for external access to EJBCA and deploy Apache HTTPD for internal services to access EJBCA. The power of EJBCA is leveraged by deploying in Kubernetes to use internally in the Kubernetes cluster as well as externally.

In this tutorial, you will learn how to:

  • Deploy the EJBCA container into a Kubernetes runtime
  • Use Ingress for external access to EJBCA
  • Deploy Apache HTTPD container for containers inside of the Kubernetes cluster to access EJBCA
  • Configure certificates issued from the EJBCA container to terminate TLS for accessing EJBCA

Prerequisites

  • Before you begin, you need MicroK8s installed and configured. To learn how to install and configure the Kubernetes distribution MicroK8s to deploy the EJBCA container, follow the tutorial Install MicroK8s to run EJBCA.
  • To issue TLS certificates in a later step, you need to configure EJBCA by following the previous tutorials in this tutorial series Get started with EJBCA and Istio to create a PKI Hierarchy in EJBCA, issue TLS server and client certificates with EJBCA, and create roles in EJBCA.
  • Additionally, you should be familiar with the YAML format and have a basic understanding of how to use the Kubernetes command line tool kubectl.

Step 1 - Create a namespace and secrets for EJBCA and MariaDB

In Kubernetes, namespaces provide a mechanism for isolating groups of resources within a single cluster and are used in environments with many users spread across multiple teams, or projects. A Kubernetes Secret is an object intended to hold confidential data and contains a small amount of sensitive data such as a password, a token, or a key. Using a Secret means that you do not need to include confidential data in your application code.

To isolate resources into a group in a Kubernetes cluster and create secrets for the database passwords, follow these steps:

  1. SSH to the MicroK8s server.
  2. In your terminal, enter the following to create a namespace:

    $ kubectl create namespace ejbca-k8s
    CODE
  3. Create a secret for the MariaDB root password:

    $ kubectl create secret generic -n ejbca-k8s mariadb-secret --from-literal=mariadb-root-password=ejbca
    CODE
  4. Create a secret for the EJBCA MariaDB user account:

    $ kubectl create secret generic -n ejbca-k8s ejbca-mariadb-secret --from-literal=ejbca-db-password=ejbca
    CODE

Step 2 - Create Load Balancer Ingress Service

To configure external access to EJBCA, the Metal LB load balancer is leveraged by creating an Ingress service type.

To create a load balancer Ingress service, follow these steps:

  1. Use a text editor such as vim to create the ingress service file ingress-service.yml:

    $ vim ingress-service.yml
    CODE

     

  2. Add the following to the file:

    apiVersion: v1
    kind: Service
    metadata:
      name: ejbca-node1
      namespace: ingress
    spec:
      selector:
        name: nginx-ingress-microk8s
      type: LoadBalancer
      # loadBalancerIP is optional. MetalLB will automatically allocate an IP from its pool if not
      # specified. You can also specify one manually.
      # loadBalancerIP: x.y.z.a
      ports:
        - name: http
          protocol: TCP
          port: 80
          targetPort: 80
        - name: https
          protocol: TCP
          port: 443
          targetPort: 443
    YML

     

  3. Save and close the file:

    :wq
    CODE

     

  4. Apply the YAML file to create the Ingress service:

    $ kubectl apply -f ingress-service.yml
    CODE
  5. Check what external IP the ingress service is using:

    $ kubectl get all,ingress -n ingress
    CODE
  6. Record this IP Address that can be added to the hosts file with the name ejbca-node1 for accessing the EJBCA.

Continue to the next step to create a persistent volume claim for the MariaDB database container.

Step 3 - Create a Persistent Volume Claim for the MariaDB container

To maintain the database state when the MariaDB container is stopped or upgraded, a Persistent Volume Claim (PVC) is used to store the DB data in a persistent storage location. For more information on PVCs, refer to the Kubernetes documentation topic Persistent Volumes.

To create a PVC, follow these steps:

  1. Use a text editor such as vim to create the PVC file ejbca-pvc.yml:

    $ vim ejbca-pvc.yml
    CODE
  2. Add the following to the file:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: mariadb-pvc
      namespace: ejbca-k8s
    spec:
      accessModes: [ReadWriteOnce]
      resources: { requests: { storage: 100M } }
    YML

     

  3. Save and close the file:

    :wq
    CODE
  4. Apply the YAML file to create the PVC:

    $ kubectl apply -f ejbca-pvc.yml
    CODE

Continue with creating the services required for accessing the database and EJBCA.

Step 4 - Create services for the database and EJBCA

EJBCA needs to connect to the MariaDB database container. A service is used to allocate an IP address and port for the connection. EJBCA requires a service for Ingress and Apache HTTPD to connect with using AJP.

To create the two services, follow these steps:

  1. Use a text editor such as vim to create the services file ejbca-svc.yml:

    $ vim ejbca-svc.yml
    CODE
  2. Add the following to the file:

    apiVersion: v1
    kind: Service
    metadata:
      name: ejbca-database-service
      namespace: ejbca-k8s
      labels:
        app: mariadb
    spec:
      type: ClusterIP
      ports:
      - name: database-port
        port: 3306
        targetPort: 3306
      selector:
        app: mariadb
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: ejbca-service
      namespace: ejbca-k8s
      labels:
        app: ejbca
    spec:
      type: ClusterIP
      ports:
      - name: ajp
        port: 8009
        targetPort: 8009
      selector:
        app: ejbca
    YML

     

  3. Save and close the file:

    :wq
    CODE
  4. Apply the YAML file to create the services:

    $ kubectl apply -f ejbca-svc.yml
    CODE

The services are now created and you can continue to the next step to deploy the MariaDB container.

Step 5 - Create deployment for the MariaDB container

The EJBCA container supports MariaDB, Microsoft SQL Server, Oracle, and PostgreSQL databases. Deploying the EJBCA container with an external database stores the state and configuration. That means if the EJBCA container is stopped or restarted, the PKI configuration is not lost and requires everything to be configured all over again. A deployment is used to deploy the MariaDB container that will use the PVC and service created in the previous steps.

To deploy MariaDB in a container, follow these steps:

  1. Use a text editor such as vim to create the MariaDB deployment file ejbca-db.yml:

    $ vim ejbca-db.yml
    CODE

     

  2. Add the following to the file:

    apiVersion: apps/v1
    kind: Deployment # what to create?
    metadata:
      name: mariadb-deployment
      namespace: ejbca-k8s
      labels:
        app: mariadb
    spec: # specification for deployment resource
      replicas: 1 # how many replicas of pods we want to create
      selector:
        matchLabels:
          app: mariadb
      template: # blueprint for pods
        metadata:
          labels:
            app: mariadb # service will look for this label
        spec: # specification for pods
          volumes:
            - name: datadir
              persistentVolumeClaim:
                claimName: mariadb-pvc
          containers:
          - name: mariadb
            image: mariadb:latest
            ports:
            - containerPort: 3306 #default one
            env:
            - name: MARIADB_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mariadb-secret
                  key: mariadb-root-password
            - name: MARIADB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: ejbca-mariadb-secret
                  key: ejbca-db-password
            - name: MARIADB_DATABASE
              value: ejbca
            - name: MARIADB_USER
              value: ejbca
            volumeMounts:
            - name: datadir
              mountPath: /var/lib/mysql/
    YML

     

  3. Save and close the file:

    :wq
    CODE

     

  4. Apply the YAML file to create the MariaDB deployment:

    $ kubectl apply -f ejbca-db.yml
    CODE

A deployment of MariaDB running in a container is now being deployed. Continue to the next step to deploy the EJBCA container.

Step 6 - Create deployment for the EJBCA container

As the pieces to support deploying EJBCA in Kubernetes were completed in previous steps, it's now time to create a deployment for the EJBCA container.

To deploy the EJBCA container, follow these steps:

  1. Use a text editor such as vim to create the EJBCA deployment file ejbca-ca.yml:

    $ vim ejbca-ca.yml
    CODE

     

  2. Add the following to the file:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ejbca-deployment
      namespace: ejbca-k8s
      labels:
        app: ejbca
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: ejbca
      template:
        metadata:
          labels:
            app: ejbca
        spec:
          containers:
            - name: ejbca-node1
              image: keyfactor/ejbca-ce:latest
              imagePullPolicy: Always
              resources:
                limits:
                  cpu: "16"
                  memory: "4096Mi"
                requests:
                  cpu: 1000m
                  memory: "2048Mi"
              ports:
                - containerPort: 8009
                  name: ejbca-ajp
              env:
                - name: DATABASE_JDBC_URL
                  value: "jdbc:mariadb://ejbca-database-service:3306/ejbca?characterEncoding=utf8"
                - name: DATABASE_USER
                  value: ejbca
                - name: PROXY_AJP_BIND
                  value: "0.0.0.0"  
                - name: DATABASE_PASSWORD
                  valueFrom:
                    secretKeyRef:
                      name: ejbca-mariadb-secret
                      key: ejbca-db-password
                - name: LOG_AUDIT_TO_DB
                  value: "true"
    YML

     

  3. Save and close the file:

    :wq
    CODE
  4. Apply the YAML file to create the EJBCA deployment:

    $ kubectl apply -f ejbca-ca.yml
    CODE

EJBCA is deploying and the next step is to configure ingress for external access to EJBCA.

Step 7 - Create Ingress for external access to EJBCA

To configure external access to EJBCA using Ingress, follow these steps:

  1. Use a text editor such as vim to create the EJBCA Ingress file ejbca-ingress.yml

    $ vim ejbca-ingress.yml
    CODE

     

  2. Add the following the file:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        # Use AJP with appserver
        nginx.ingress.kubernetes.io/backend-protocol: AJP
        nginx.ingress.kubernetes.io/auth-tls-verify-client: "optional_no_ca"
        nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "true"
      name: ejbca-node1
      namespace: ejbca-k8s
    spec:
      ingressClassName: public
      rules:
      - host: ejbca-node1
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: ejbca-service
                port:
                  number: 8009
      tls:
      - hosts:
        - ejbca-node1.ejbca-k8s
        secretName: tls-secret
    YML
  3. Save and close the file:

    :wq
    CODE

     

  4. Apply the YAML file to create the EJBCA Ingress:

    $ kubectl apply -f ejbca-ingress.yml
    CODE
  5. Query the Ingress IP to use for accessing EJBCA:

    $ kubectl -n ingress get services -o json | jq -r '.items[] |.status.loadBalancer?|.ingress[]?|.ip ' | cut -d : -f 2
    CODE
  6. Create a hosts file entry in /etc/hosts file or applicable file if using a none Linux OS with the IP from step 5. and the hostname ejbca-node1.ejbca-k8s, for example:

    # Add to the hosts file:
    172.16.170.187 ejbca-node1.ejbca-k8s
    CODE

External access to EJBCA using Ingress is now configured.

Step 8 - Issue TLS certificates for EJBCA external and internal access

The following provides steps for updating the current TLS server end entity profile and certificate profile to use the Management CA and RSA key type. Once updated, two certificates will be issued to use for TLS termination to access EJBCA

Before you begin, you need to configure EJBCA by following the previous tutorials in this tutorials series, Get started with EJBCA and Istio to create a PKI Hierarchy in EJBCA, Issue TLS server and client certificates with EJBCA, and create roles in EJBCA.

To update the profiles and issue the two TLS certificates to use with the MicroK8s EJBCA deployment, follow these steps:

  1. Log in to EJBCA and click Certificate Profiles under CA Functions.
  2. To edit the server profile values to fit your needs, find the TLS Server Profile in the list and click Edit.
  3. On the Edit page, update the following:
    • Add RSA to the selection of Available Key Algorithms, ECDSA and RSA should both be selected.

    • Select 2040 bits - 4096 bits for the Available Bit Lengths.
    • Scroll down to the Available CAs and additionally select ManagementCA, so that ManagementCA and MyPKISubCA-G1 are both selected.

  4. Click Save.
  5. Next, to add the Management CA to the End Entity Profile, click End Entity Profiles under RA Functions.
  6. Select TLS Server Profile, then click Edit End Entity Profile
  7. Scroll down to the Available CAs and additionally select ManagementCA, so that ManagementCA and MyPKISubCA-G1 are both selected.
  8. Click Save.
  9. In EJBCA, click RA Web to access the EJBCA RA UI.
  10. Select Make New Request from the Enroll menu.
  11. For Certificate Type, select your TLS Server Profile.
  12. For CA, select ManagementCA.
  13. For Key-pair generation, select By the CA.
  14. For Key Algorithm, select RSA 2048 bits.
  15. Specify the following information to be used in the certificate:
    • For CN, Common Name, specify a name, in this example ejbca-node1.
    • For the second DNS Name in the Subject Alternative Name Attributes, specify the full cluster name ejbca-node1.ejbca-k8s.
    • For Username, add ejbca-node1 to register the user under the username identical to the common name. The Username is the name that will go into the database and is often the same as the Common Name. 
    • For Enrollment code, enter a password twice.
    • Click Download PEM to download and save the ejbca-node1.pem file.
  16. To create a second internal certificate, scroll up and specify the following information to be used in the certificate:
    • For CN, Common Name, specify a name, in this example ejbca-internal.
    • For the second DNS Name in the Subject Alternative Name Attributes, specify the full cluster name ejbca-internal.ejbca-k8s.
    • For Username, add ejbca-internal to register the user under the username identical to the common name. The Username is the name that will go into the database and is often the same as the Common Name. 
    • For Enrollment code, enter a password twice.
    • Click Download PEM to download and save the ejbca-internal.pem file.

TLS certificates have been issued from the Management CA that will be used to terminate TLS to the EJBCA container. Continue to the steps below to configure these certificates to use.

Step 9 - Create Kubernetes Secret and ConfigMap for the TLS certificates

Next, the two certificates issued in the previous step must be configured to be used with Ingress and Apache HTTPD.

You will create a Kubernetes Secret and ConfigMap for the TLS certificates:

  • A Kubernetes Secret is an object that contains a small amount of sensitive data such as a password, a token, or a key. Using a Secret means that you do not need to include confidential data in your application code.
  • A ConfigMap is an API object used to store non-confidential data in key-value pairs. A ConfigMap allows you to decouple environment-specific configuration from your container images so that your applications are easily portable.

Secrets are similar to ConfigMaps but are specifically intended to hold confidential data. For more information, refer to the Kubernetes documentation topics Secrets and ConfigMaps.

To prepare Ingress and HTTPD to use certificates issued from EJBCA, follow these steps:

  1. Open a new SSH session to the server.
  2. To create the Kubernetes Secret, create three separate files for the ejbca-node1 certificate, key, and CA certificate:
  3. Open the ejbca-node1.pem file with a text editor of your choice.
    1. To create a server.crt file:
      • Use a text editor such as vim to create the server.crt file:

        $ vim server.crt
        CODE
      • Add the ejbca-node1 certificate to the file from the ejbca-node1.pem file opened in the text editor. The following shows an example certificate:

        -----BEGIN CERTIFICATE-----
        MIIEnDCCAoSgAwIBAgIUC/uQvaEzLXFrULutwEFoXMdvPekwDQYJKoZIhvcNAQEL
        BQAwQjEVMBMGA1UEAwwMTWFuYWdlbWVudENBMRwwGgYDVQQKDBNLZXlmYWN0b3Ig
        Q29tbXVuaXR5MQswCQYDVQQGEwJTRTAeFw0yMzAzMTkxNzI2NDZaFw0yNDAzMTQx
        NzI2NDVaMEExCzAJBgNVBAYTAlNFMRwwGgYDVQQKDBNLZXlmYWN0b3IgQ29tbXVu
        aXR5MRQwEgYDVQQDDAtlamJjYS1ub2RlMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
        ADCCAQoCggEBAInoar+qRCeeLiuYknOSPjqboJ93W1YxBdYTScnDdXqRut2uDn0L
        oDijfP9CF3yWS4pvUkoBteOkIWs7eFi+7XA5JWQqrXzMo6dChdhI4tEnQ5XEVj+I
        SlAjFydTBXM4vNr8RKVMYHVvWLfT3Px6WX6BszueWMGkxwipdTwX4I7SBOt4gt9v
        njIvkdIsSGExuzi7h8u+JPhj/6vqgcflHhwWjCqVrEyy3aj7KN1zUJlXHxZ6Jp64
        WNHPHd7brUCIPr8H+OT30LCZa1QYfMZK5ozHjlYOXJ+gE95NwR5oR2k/pHmqTwK6
        YhvSiVt33RefQuGXt3ho2rCC7kiMsfm98A0CAwEAAaOBijCBhzAfBgNVHSMEGDAW
        gBTX/jGUQ0k8X6G7Xv4FgAQsBPOg0jAgBgNVHREEGTAXghVlamJjYS1ub2RlMS5l
        amJjYS1rOHMwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFEI3cF7EhrqN
        ZjlafvuMan1gR604MA4GA1UdDwEB/wQEAwIFoDANBgkqhkiG9w0BAQsFAAOCAgEA
        Nrdbh+9tIpL+UqNwsqnXgFGCsdDROrIv6ZAfdt1q0UM3iHAaRWT9DF105Nk4J7j2
        tXacE8vkv35aCwBGJuG1uWoHm/H0+/fOs8pRW/9M4sjfpe/KM/hFjRXGVJfDlfVl
        rrvn2ixh240V9SkLStb0jStA0Jc4+fm3pnDppyGGYUFyk5gL0JNT67C7i2MR1vmA
        nHl3Z8Mq+FfteEuDSgYbf7Q5eCbnPOpGs4D6/msw4fEK2YiFPpgcnBR5RYFSLugF
        iI9p3RPWrfuOamkY43et3K1Ky37WvmrV1KJ7XquLn7xPJc6oOX9WGSvmXOUpZP4t
        iwqo1Ml7VXkQxtC0/zZjX6OK5d4B/H6TzqJBDDI+jrlNiTevtyieouhnQMx4PtjO
        GgNbaHpkbbVxFxrB0GgF0XPoKw6rDG7XDruO/6KgrsWYNZ4jJTu7pCIZNfrJPQXI
        YwsJBE2jNMG5Hpuj87XhM29M0eO2GYXE3fkjnTlz+5NHF0dR2tOQB9ZsCB4OEO8m
        lJeR5aRVJF+M3+/Lth1lWfZj4p4hHhGX3Bf609YWkrEXkllcMMx1D6hPK0PIMVRI
        gS1ZbY9vqs+nO3SP+FK0JuN/dpr24yyLnbH68zfToo7oggDlcKOiu4LFdOp51cUB
        8mcVkwTsNCX1Y3kon2I1CmC7i4wBfSReh6gI1lL6FOY=
        -----END CERTIFICATE-----
        CODE
      • Save and close the file:

        :wq
        CODE
    2. To create a server.key file:

      • Use a text editor such as vim to create the server.key file:

        $ vim server.key
        CODE

         

      • Add the ejbca-node1 private key to the file from the ejbca-node1.pem file opened in the text editor. The following shows an example private key:

        -----BEGIN PRIVATE KEY-----
        MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCJ6Gq/qkQnni4r
        mJJzkj46m6Cfd1tWMQXWE0nJw3V6kbrdrg59C6A4o3z/Qhd8lkuKb1JKAbXjpCFr
        O3hYvu1wOSVkKq18zKOnQoXYSOLRJ0OVxFY/iEpQIxcnUwVzOLza/ESlTGB1b1i3
        09z8ell+gbM7nljBpMcIqXU8F+CO0gTreILfb54yL5HSLEhhMbs4u4fLviT4Y/+r
        6oHH5R4cFowqlaxMst2o+yjdc1CZVx8WeiaeuFjRzx3e261AiD6/B/jk99CwmWtU
        GHzGSuaMx45WDlyfoBPeTcEeaEdpP6R5qk8CumIb0olbd90Xn0Lhl7d4aNqwgu5I
        jLH5vfANAgMBAAECggEAFO+bBxpk6uPNbBJnR1LQDisyrQrca58ZHPkEJnR9KPyn
        MwC509t4OSj+sKy6rpANi0hfpHsSfyrbZPFcEZL4rmUKi2ScPlo9zQZhFebowipV
        DQ9HrbD14SkWmoJ0zRtztkX+cN7BtQpQnGW2QoEbhYRQrrAZFtq6WZMKSHNyhJPe
        G+VPaR1kgmbqV6sambmdvwQ8ZO3Q+PU5TWrKiNc3iUC03iNMuQpt5coA9Mxwumox
        vO9j4HWz9SoSn49Ik5M89N8A9D5te2FBoA+Nne6NbT+U1pMJlPSFCFuYzE21Ht4p
        6IgSLoYiO2fnzpaPdjX2rfW5GHTY1cbvBeqFIotI4QKBgQC+SJEbBdtxJnAffA1y
        EulN1+w6Lle5CPo6igpMu6otHiB9z1un/v1Kq/I+xwAYDPHGnxOGNeMqzlHPBSQ7
        dpRbPdWjRgUtKo+mqgQVnRZYrSyZ8Al9fZoU8WBlYSB3f6RpHYiD3UUlir6C58qy
        bA5YV0cLF0RQ6WzcxVXLQbVSIQKBgQC5iTHZZqHrWR8jiMqymJztXxytZi1FJU6n
        +31j4WbSVbcq3Qh55XvPg5Ujx98dbp8ESRUhO8hpvoFITHH5j1fbjRXNwc2Mevls
        OF8lT3MOsuD/XlxnLVeetYnsyQUbigkiCTWU0FH5AOzvWjaHMmIlsMCwpWhOF6eU
        eokkLLr4bQKBgFydQVMfxLEL/mK0pG6zWa6zu5yN1dCP2AsKCP1UEf4nvbS+amQY
        LfxcOGnpvdf25O7BmmUmcUzyYssaO4pdqtPGAueXOwnCv2xlL9u9O5UppJ3AQT49
        FfO/kCWH4p+HFuS6pSlZV0BwiU15uCSjh0/kGwYA6xVep8fEnH9zmedBAoGAS7/U
        x2Lctt7DFNnzj+k5ILzVU4JE91cc/v5xmkbbmQJ/7xMhM8taukWJrXsb/8M7Tx+b
        bd8fmvS5idAUNISupSe8AC6hAjru/J0jU3NVkWm87OYUqddcT6LktfT4jd7Ujb3e
        z2wiG5yiH7LgUmBiq+q3MSfHJyMHO1qwBUHx8B0CgYAYQJQDv3MMtrev6QobFxNc
        sWFrqzUN9CYJA8OtS5zubPuFoage9P9LUOqqR4VCo4AoIj7xUunrDh0jUDgZ0KRA
        akfJm2mg7PULx0n4CKfd9gQociNFfQHlwvX9UobsEfNNIxYTHcixMaWOOjBKIXpB
        gpi9cRgUlgV60HdiVe5jwg==
        -----END PRIVATE KEY-----
        CODE
      • Save and close the file:

        :wq
        CODE
    3. To create a ca.crt file:

      • Use a text editor such as vim to create the ca.crt file:

        $ vim ca.crt
        CODE
      • Add the Management CA certificate to the file from the ejbca-node1.pem file opened in the text editor. The following shows an example Management CA certificate:

        -----BEGIN CERTIFICATE-----
        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
        qMN+i82CAMeU
        -----END CERTIFICATE-----
        
        CODE
      • Save and close the file:

        :wq
        CODE
  4. Create Kubernetes Secret for the ejbca-node1 certificate, key, and a secret for the CA certificate file that Ingress will use to terminate TLS to the EJBCA container:

    $ kubectl create secret tls -n ejbca-k8s tls-ejbca-node1 --cert server.crt --key server.key
    $ kubectl create secret generic -n ejbca-k8s mtls-trust-chain --from-file=ca.crt=ca.crt
    CODE
  5. To create the Kubernetes ConfigMap, create two separate files for the ejbca-node1 certificate and key (the CA certificate file ca.crt will be reused for the Management CA certificate).
  6. Open the ejbca-internal.pem file with a text editor.
    1. To create a ejbca-internal.crt file:
      • Use a text editor such as vim to create the ejbca-internal.crt file:

        $ vim ejbca-internal.crt
        CODE
      • Add the ejbca-internal certificate to the file from the ejbca-internal.pem file opened in the text editor. The following shows an example certificate:

        -----BEGIN CERTIFICATE-----
        MIIEojCCAoqgAwIBAgIUPaLkQD5t3sJyXqyDZ9oakKCef4IwDQYJKoZIhvcNAQEL
        BQAwQjEVMBMGA1UEAwwMTWFuYWdlbWVudENBMRwwGgYDVQQKDBNLZXlmYWN0b3Ig
        Q29tbXVuaXR5MQswCQYDVQQGEwJTRTAeFw0yMzAzMTkxNzI3MTJaFw0yNDAzMTQx
        NzI3MTFaMEQxCzAJBgNVBAYTAlNFMRwwGgYDVQQKDBNLZXlmYWN0b3IgQ29tbXVu
        aXR5MRcwFQYDVQQDDA5lamJjYS1pbnRlcm5hbDCCASIwDQYJKoZIhvcNAQEBBQAD
        ggEPADCCAQoCggEBAIxh+0WaKmw+Yrim+/2c7Li/gWDJKdsd+mS170V6rnHSfRDd
        qfcW1q9ADwRZyu3Pc3s+w6UmjSciwOtvovPOfC5D0dUog4bgQ/1cSWuVUC8gd/Xy
        xb7DuKqbGtg8kB5BMD7O3oF89b2iGisfw4Ei9Njf1hrgl9DWuFfQ6+/d5luUXCRv
        cKYeQl05ZRii8LwLc8vvb613HbQi4n47QbLHMDgQDqdiqvefhyDE8gdgJyOBM5nV
        dsc2/6sxsKDNTMV86N1POWSXBrM9b4T/jFAik76dGjcCv/WTY/3VbPCuGypB5SaL
        ++8/eLCEmZDgBovZT8WJIGK5odrdFbnSvtCwhZ0CAwEAAaOBjTCBijAfBgNVHSME
        GDAWgBTX/jGUQ0k8X6G7Xv4FgAQsBPOg0jAjBgNVHREEHDAaghhlamJjYS1pbnRl
        cm5hbC5lamJjYS1rOHMwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFJtU
        ZTtTpL9zsDKstua4doISNMo5MA4GA1UdDwEB/wQEAwIFoDANBgkqhkiG9w0BAQsF
        AAOCAgEAkTxtIref9DVm4fcB2jzNdaiLPpWQbhREWgdg8oGaaams832JnoiCJjga
        lBnp8wNb8M9AxgEIU15il0xdw9oOoHAhz04Z3DV6snS1wmPs1u+un9zN0ZdBEEbC
        zchc/tUg4lVYLlKieTjUcg8Dy/wVBegwBYxDXfzbabhMe8GFCs0qXll2hIetjesq
        XtILq3Y5L7qVL7CaEeD2SX+Eb9Zz89xl069Jh3wWc34rBTI9L1f+ysBX0FhUyqqg
        mU8xUjLDaDXpkF+tQH1tIxtu3A1J1k1aRp8jDb2w6urxERy3+Huxl50wrb80HJRg
        /IdccIckpoFzga76hxV5l/mKlyxerr7Uev9prnTGeGSNF58dkJrGkwenvaYQC/Pk
        I5MdqmrielVy56/o8ldS+12a1BtejMRE7I/KkPFF7ZIcTdh214NQe+FksaU8Wui4
        ozAb8ULYjodMbrvU798TnXht8ySF0PPdTJ7B7gA9oUGZsnYTKO/M6OP6NHte4ezm
        t3qvQpzsYeUOILz0+YeBZfCZrn2lJzQSkzaoernYO2igAEv/EGqJQ43hDKBnKKtJ
        WMAHqzfaJuSnJfRnRIg1iDvQ+8XsTyMIY0uGgBWJt0qPAUxpgLBsjN+X9uu6DKuu
        CEQLNQ0oAbNYKjgqMU7yxf2YkhMP6nppS/I0JgVR9PKyMptyGJ0=
        -----END CERTIFICATE-----
        CODE
      • Save and close the file:

        :wq
        CODE
    2. To create a ejbca-internal.key file:

      • Use a text editor such as vim to create the ejbca-internal.key file:

        $ vim ejbca-internal.key
        CODE

         

      • Add the ejbca-internal private key to the file from the ejbca-internal.pem file opened in the text editor. The following shows an example private key:

        -----BEGIN PRIVATE KEY-----
        MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCMYftFmipsPmK4
        pvv9nOy4v4FgySnbHfpkte9Feq5x0n0Q3an3FtavQA8EWcrtz3N7PsOlJo0nIsDr
        b6LzznwuQ9HVKIOG4EP9XElrlVAvIHf18sW+w7iqmxrYPJAeQTA+zt6BfPW9ohor
        H8OBIvTY39Ya4JfQ1rhX0Ovv3eZblFwkb3CmHkJdOWUYovC8C3PL72+tdx20IuJ+
        O0GyxzA4EA6nYqr3n4cgxPIHYCcjgTOZ1XbHNv+rMbCgzUzFfOjdTzlklwazPW+E
        /4xQIpO+nRo3Ar/1k2P91WzwrhsqQeUmi/vvP3iwhJmQ4AaL2U/FiSBiuaHa3RW5
        0r7QsIWdAgMBAAECggEACG3wv+DuN7I2TNawDm5AE6biLqzdn8vox2faTn57n5eP
        TXY1+MGNEhhjXnRC2G1KxqWB63aJZsZyNaDuNLwbHk8RuD42yaBJTNsgCH7+gdnu
        Ah16DMalXc8y+TWHxN1Ot5LF7xoRCnpDnn/JhkVSVPx514LRcueVyaYgqLZXGPwU
        lLsEzZjy87w+wWYdkaUL0FlZPjJSsUcpDgTo4IVyLHYgKijwKa6GGAC1LRaF7xnG
        IX7SHhAr8Aec26jd5GNWecJaftSh22GP7o6eaf2IJMc1r7JQE21T+nG//hLHZ9hI
        nwHdKXXjStKpnqLfwZsEt/gOwCJ7MQk+UPo0t+b9MQKBgQDFCOOQ3iU3CPjoyK5b
        eR0XRHdtHNwLFOFP7bMpkwQuS86TUxFau2VOE3yPOU3UI+eWNXU6tHD9J4ep+BWn
        kqjdeehdBSmZePtGjsktmXf96rVZR3801Lfpar2tMfB8b4ngdIJcBCdsFNUY9VFh
        U0vO9xDflag5w3GONiiwaJ5GUQKBgQC2ZOdJqebkJ7n9MHY8Yc67anX4m9sLGhX7
        Sc4U8OLjGAAxXJrutoPYUPeUFGWwMfQvpXbydQRtnG4Jw42qnSino69xhwUqvhPS
        ZqMTU4NEq5DQBIrT9LV2Ih0BkvE9sdfQsvtZzXWDl7yMm1R2YlCwozlZTBn9GCf3
        EOBxs/VbjQKBgBr4k4YCEqAM912OEufslUHZGmvyNmDB8/Gn/Q1k1X6s29Mo3MhJ
        vJ1KZ5OHaZLvc0UJfkmR56GPpq9qiTRODBV9GYSaL06V0/edlgZK6rT0Suy0r8IA
        mEg4V0x8+IlgD0SNTkbgPrE5zM3EzuX+q/LhuQqSBtwZV9L6sOks+PVxAoGADSiK
        Zw4S0jLrgBCW9xQ3Td4IVL8ptktTeqWAcJJQTAHXQbhklQQlzt1Ify5Zh7SS4T0W
        r7cxcpbueVXaSoy7+hwc9BvBi6va0jsFWMeVmMan09oACfqFfNhJL2via4kBANVo
        vLnN2IiB2cL6/O9q0tNzt7V9ynyLpY9aIdnRwaECgYBe67DpIIF+6o7+epHogfmN
        SLu/UdGhsBtJqbg9WJv7mXzpHWk+Vmx2HwYn6H9a8YW35C6E2GygVriuB72Ov5GV
        YPzw/mJ2YNLz1of0iBaH0Skru2kHP5fVNd4bpCz7Wt7WdB6ZEUfZerUEcprY30wr
        PkZVKHoa6btaotnw2IwNsQ==
        -----END PRIVATE KEY-----
        CODE
      • Save and close the file:

        :wq
        CODE
  7. Create a Kubernetes ConfigMap for the ejbca-internal certificate and key, and re-use the CA certificate file created for the Kubernetes Secret (since the certificates are issued off the same CA) to use HTTPD to terminate TLS to the EJBCA container:

    $ kubectl -n ejbca-k8s create configmap httpd-certs-configmap --from-file=ejbca-internal.crt=ejbca-internal.crt --from-file=ejbca-internal.key=ejbca-internal.key --from-file=ca.crt=ca.crt
    CODE

The certificates, keys, and Management CA certificate are now configured to use for TLS by Apache HTTPD and Ingress. Continue to the next step to swap the TLS certificate used by Ingress.

Step 10 - Update EJBCA Ingress configuration to use new TLS certificate

Ingress has been using a self-signed certificate for terminating TLS to access the EJBCA CA UI and RA UI. The following outlines how to update the Ingress configuration to use and trust the certificate issued from the EJBCA Management CA.

To change the TLS certificate used by Ingress to access EJBCA, follow these steps:

  1. Use a text editor such as vim to create the EJBCA Mutual TLS (mTLS) Ingress file ejbca-mtls-ingress.yml

    $ vim ejbca-mtls-ingress.yml
    CODE

     

  2. Add the following to the file:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        # Use AJP with appserver
        nginx.ingress.kubernetes.io/backend-protocol: AJP
        nginx.ingress.kubernetes.io/auth-tls-verify-client: "optional"
        nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "true"
        nginx.ingress.kubernetes.io/auth-tls-secret: "ejbca-k8s/mtls-trust-chain"   
      name: ejbca-node1
      namespace: ejbca-k8s
    spec:
      ingressClassName: public
      rules:
      - host: ejbca-node1
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: ejbca-service
                port:
                  number: 8009
      tls:
      - hosts:
        - ejbca-node1.ejbca-k8s
        secretName: tls-ejbca-node1
    YML

     

  3. Save and close the file:

    :wq
    CODE

     

  4. Remove the current EJBCA Ingress configuration:

    $ kubectl delete -f ejbca-ingress.yml
    CODE
  5. Apply the YAML file to create the EJBCA mTLS Ingress:

    $ kubectl apply -f ejbca-mtls-ingress.yml
    CODE

Ingress is now using a certificate issued from the EJBCA Management CA. Continue to the next step to deploy and configure Apache HTTPD.

Step 11 - Deploy Apache HTTPD for internal Kubernetes cluster access

Apache HTTPD is used as a reverse proxy to terminate TLS and provide access to EJBCA for internal cluster access. Containers, service mesh, or whatever else needs to access EJBCA within the cluster will use Apache HTTPD.

To deploy and configure Apache HTTPD, follow these steps:

  1. Use a text editor such as vim to create the EJBCA HTTPD file ejbca-httpd.yml

    $ vim ejbca-httpd.yml
    CODE

     

  2. Add the following to the file:

    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: ejbca-internal
      namespace: ejbca-k8s
      labels:
        app: ejbca-httpd
    spec:
      type: ClusterIP
      ports:
      - name: apache
        port: 443
        targetPort: 443
      - name: open
        port: 80
        targetPort: 80
      selector:
        app: ejbca-httpd
    ---
    apiVersion: v1
    data:
      httpd.conf: |+
        LoadModule mpm_event_module modules/mod_mpm_event.so
        LoadModule headers_module modules/mod_headers.so
        LoadModule authz_core_module modules/mod_authz_core.so
        LoadModule access_compat_module modules/mod_access_compat.so
        LoadModule log_config_module modules/mod_log_config.so
        LoadModule proxy_module modules/mod_proxy.so
        LoadModule proxy_http_module modules/mod_proxy_http.so
        LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
        LoadModule unixd_module modules/mod_unixd.so
        LoadModule filter_module modules/mod_filter.so
        LoadModule substitute_module modules/mod_substitute.so
        LoadModule rewrite_module modules/mod_rewrite.so
        LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
        LoadModule ssl_module modules/mod_ssl.so
        MaxKeepAliveRequests 1000
        KeepAlive On
        KeepAliveTimeout 180
        # Don't think we need this
        # Include conf/extra/httpd-ssl.conf
        <IfModule unixd_module>
            User daemon
            Group daemon
        </IfModule>
        ErrorLog /proc/self/fd/2
        LogLevel info
        <IfModule log_config_module>
            LogFormat "%h %A:%p %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
            LogFormat "%h %A:%p %l %u %t \"%r\" %>s %b" common
            CustomLog /proc/self/fd/1 common
        </IfModule>
        ServerRoot "/usr/local/apache2"
        Listen 443
        Listen 80
        <Directory />
            AllowOverride none
            Require all denied
        </Directory>
        <VirtualHost *:443>
            DocumentRoot /var/www/html/
            # Disallow any HTTP method that is not HEAD, GET or POST
            RewriteEngine On
            RewriteCond %{REQUEST_METHOD} !^(HEAD|GET|POST|PUT)$ [NC]
            RewriteRule .* - [F,L]
            SSLEngine on
            SSLCipherSuite HIGH:!ADH:!aDSS:!aDH
            SSLProtocol all -SSLv2 -SSLv3 -TLSv1 +TLSv1.2 -TLSv1.3
            # SSLProtocol -all +TLSv1.2
            SSLOptions +ExportCertData +StdEnvVars
            SSLCertificateFile /etc/httpd/ssl/ejbca-internal.crt
            SSLCertificateKeyFile /etc/httpd/ssl/ejbca-internal.key
            SSLVerifyClient optional
            SSLVerifyDepth 3
            SSLCACertificateFile /etc/httpd/ssl/ca.crt
            <Location /ejbca/ejbcaws>
                SSLVerifyClient require
            </Location>
            <Location /ejbca/adminweb>
                SSLVerifyClient require
            </Location>
            # Allow encoded slashes for OCSP GET
            AllowEncodedSlashes On
            ProxyPass /ejbca/        ajp://ejbca-service:8009/ejbca/ keepalive=On ping=500ms retry=1 timeout=300
            #Add ProxyPass for EST and .well-known URLs
            ProxyPass /.well-known/        ajp://ejbca-service:8009/.well-known/ keepalive=On ping=500ms retry=1 timeout=300
            # Redirect /, /ejbca, /signserver and non-proxied URLs to /ejbca/
            RewriteCond %{THE_REQUEST} !(/ejbca/.*|/.well-known/.*)
            RewriteRule (.*) https://%{HTTP_HOST}/ejbca/
        </VirtualHost>
        <VirtualHost *:80>
            DocumentRoot /var/www/html/
            # Disallow any HTTP method that is not HEAD, GET or POST
            RewriteEngine On
            RewriteCond %{REQUEST_METHOD} !^(HEAD|GET|POST)$ [NC]
            RewriteRule .* - [F,L]
            # Redirect legacy EJBCA enrollment to HTTPS
            RewriteCond %{HTTPS} !=on
            RewriteRule ^/?ejbca/enrol/(.*) https://%{SERVER_NAME}/ejbca/enrol/$1 [R,L]
            # Allow encoded slashes for OCSP GET
            AllowEncodedSlashes On
            ProxyPass /ejbca/      ajp://ejbca-service:8009/ejbca/ keepalive=On ping=500ms retry=1 timeout=300 nocanon
            ProxyPass /signserver/ ajp://ejbca-service:8009/signserver/ keepalive=On ping=500ms retry=1 timeout=300
            # Redirect /, /ejbca, /signserver and non-proxied URLs to /ejbca/
            RewriteCond %{THE_REQUEST} !(/signserver/.*|/ejbca/.*) [OR]
            RewriteCond %{THE_REQUEST} (/ejbca/ejbcaws.*)
            RewriteRule (.*) http://%{HTTP_HOST}/ejbca/
            RewriteCond %{THE_REQUEST} (/ejbca/ejbcaws.*|/ejbca/adminweb.*)
            RewriteRule (.*) https://%{HTTP_HOST}/ejbca/
        </VirtualHost>
    kind: ConfigMap
    metadata:
      namespace: ejbca-k8s
      name: config-httpd-configmap
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ejbca-httpd
      namespace: ejbca-k8s
      labels:
        app: ejbca-httpd
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: ejbca-httpd
      template:
        metadata:
          labels:
            app: ejbca-httpd
        spec:
          containers:
            - name: httpd
              image: library/httpd:latest
              ports:
                - containerPort: 443
                  name: httpd-http
                - containerPort: 80
                  name: http
              volumeMounts:
                - name: config-httpd-volume
                  mountPath: /usr/local/apache2/conf/
                - name: certificates-volume
                  mountPath: /etc/httpd/ssl
          volumes:
            - name: config-httpd-volume
              configMap:
                name: config-httpd-configmap
            - name: certificates-volume
              configMap:
                name: httpd-certs-configmap
    YML

     

  3. Save and close the file:

    :wq
    CODE

     

  4. Apply the YAML file to deploy and configure the Apache HTTPD container:

    $ kubectl apply -f ejbca-httpd.yml
    CODE

Apache HTTPD is now deployed and configured for internal cluster resources to access.

Next steps

In this tutorial, you learned how to deploy EJBCA in MicroK8s using MariaDB as the database and configure access to EJBCA internally and externally.

To learn how to use a service mesh to issue mutual TLS certificates with EJBCA running in Kubernetes., follow the tutorial Deploy EJBCA container to issue certificates to an Istio service mesh.