Preparing container installation

Prepare networking

Create the Ingress controller on AKS

In PowerShell, execute the following commands as administrator:

  1. helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

    The copy image is missing

  2. helm repo update

    The copy image is missing

  3. 
    helm install ingress-nginx ingress-nginx/ingress-nginx --create-namespace --namespace ingress-basic --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz --set controller.nodeSelector."kubernetes\.io/os"=linux --set controller.admissionWebhooks.patch.nodeSelector."kubernetes\.io/os"=linux --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux

    The copy image is missing

Once Ingress is installed you should be able to get the inbound and outbound IP addresses.

Register the outbound IP Address

Once Ingress is installed, you can get the outbound IP addresses.

  • On Azure portal, look at the Load Balancer configuration for the outbound role, and get the IP address.

  • Configure the outbound IP address be configured for the database instance to allow the containers to connect to the database.

In Oracle OCI, you can enable the IP Address by allowing it in the network configuration. .

Register the Inbound IP Address

Once Ingress is installed you should be able to get the inbound IP addresses.

  • On Azure portal, look at the Load Balancer configuration for the inbound role, and get the IP address.

  • Configure the Inbound IP address s in the DNS for your subdomain.

Prepare Settings

Prepare the Key Vault for installing WorkZone

All pod secrets for WorkZone are stored in a Key Vault. You need to set the pod secrets before doing the actual container deployment. See platform-specific (Azure) documentation for creating a Key Vault.

The following values should exist in the Key Vault.

Key Description
WORKZONE-ADREPLICATOR-OAUTH2-CLIENTSECRET Used in dbupgrade job.
WORKZONE-AZURE-CLIENTID  
WORKZONE-AZURE-CLIENTSECRET Used in oauth2.
WORKZONE-AZURE-TENANTID  
WORKZONE-CONTACTSYNCCONFIG-ENCRYPTION-KEY Encryption for password encryption.
WORKZONE-CONTACTSYNCCONFIG-DECRYPTION-KEY Decryption for decrypting password.
WORKZONE-DB-ARCHIVE  
WORKZONE-DB-DSN  
WORKZONE-DB-HOSTNAME  
WORKZONE-DB-ODBC  
WORKZONE-DB-ODPNET  
WORKZONE-DB-PORT  
WORKZONE-DB-PROTOCOL  
WORKZONE-DB-SERVER-MODE  
WORKZONE-DB-SID  
WORKZONE-DB-SJUSER-PASSWORD  
WORKZONE-DB-SJUSER-USERNAME  
WORKZONE-DB-SYS-PASSWORD  
WORKZONE-DB-SYS-USERNAME  
WORKZONE-PDF-CRAWLER-CLIENTSECRET  
WORKZONE-PROCESS-EXCHANGE-CLIENTID The GUID of the client ID.
WORKZONE-PROCESS-EXCHANGE-CLIENTSECRET The secret used to access the application in Entra ID.
WORKZONE-PROCESS-EXCHANGE-MAILBOX The email address of the Exchange user who sends smartmails.
WORKZONE-PROCESS-EXCHANGE-SERVER-URI The endpoint for the Exchange service.
WORKZONE-PROCESS-EXCHANGE-TENANTID The GUID of the tenant ID.
WORKZONE-PROCESS-OAUTH2-CLIENTSECRET The OAUTH2 secret used by WorkZone Process.
WORKZONE_SHAREPOINT_CLIENT_ID SharePoint client ID
WORKZONE_SHAREPOINT_SP_CLIENT_SECRET SharePoint client secret
WORKZONE_SHAREPOINT_SP_TENANT_ID SharePoint Tenant ID
WORKZONE_ODATA_URL WorkZone OData URL
WORKZONE_WZ_CLIENT_ID Client ID for the WorkZone app registration

WORKZONE_WZ_CLIENT_SECRET

Client secret for the WorkZone app registration

WORKZONE_WZ_TENANT_ID

Tenant ID for the WorkZone app registration

WORKZONE_ALLOWED_URLS

WorkZone server URL (OData)

WORKZONE_WorkZoneSettings__ApplicationIdUrl

Uri of the WorkZone app registration (by default, it is the same as WorkZone URL)

Prepare a namespace for the WorkZone containers

To prepare for WorkZone deployment, it is important to create a namespace to register secrets for the PODS.

kubectl create namespace <insert-namespace-name-here>

Prepare secrets for the WorkZone containers

Register the Oracle Wallet as a Secret

Once the wallet file is available, you can register the secret ”wallet” in the same name space as the WorkZonepods.

Place the prompt in the unpacked wallet folder.

You may have to create the name space for deployment before you register the wallet.

##

kubectl create secret generic wallet `--namespace <WorkZone name Space > `

--from-file=./cwallet.sso `

--from-file=./ewallet.p12 `

--from-file=./keystore.jks `

--from-file=./ojdbc.properties `

--from-file=./README `

--from-file=./sqlnet.ora `

--from-file=./tnsnames.ora `

--from-file=./truststore.jks

##

kubectl get secrets -n workzone

The copy image is missing

Register the SSL Certificates as a Secret

Prerequisite: Valid certificate files are available.
  1. Navigate to the directory that contains SSL certificate files (crt & key files) and create the tls secreat (See Right)

  2. Add/update the secret name and the corresponding host name in the environment file (tls section in ingress)

  3. Ensure each ingress resource can populate the tls field.

  4. Create the secret in the WorkZone namespace using below command:

    kubectl create secret tls <secret-name> -n <namespace-name> --key=<private-key> --cert=<certificate>

    The copy image is missing

    Example:

    kubectl create secret tls ingress-cert-workzone -n workzone --key=key.pem --cert=cert.pem

    ##

    kubectl get secrets -n workzone

Prepare environment files for WorkZone container installation

Prerequisite: You should have a running Azure AKS and a Windows node pool.

  1. Copy and paste the code below, and save it as a values.yaml file.
    # Default values for workzone namespace.
    # This is a YAML-formatted file.
    # Declare variables to be passed into your templates.
    
    affinity: {}
    
    
    
    
    # Azure Key Vault provider for Secrets Store CSI Driver allows you to get secret contents stored in an Azure Key Vault instance and use the Secrets Store CSI driver interface to mount them into Kubernetes pods
      # https://azure.github.io/secrets-store-csi-driver-provider-azure/configurations/identity-access-modes/
      # Modes for accessing a Key Vault instance: PodIdentity, UserAssignedManagedIdentity
      ##accessMode: PodIdentity
      # if eq .Values.secretProvider.accessMode "PodIdentity". The selector to identify which pods should be assigned to the AzureIdentity.
      # AAD Pod Identity will go through a list of pods and look for value of pod label with key aadpodidbinding that is equal to this value
      ##podIdentitySelector: csi-secrets-store
    
    global:
      affinity: {}
    
      podAntiAffinity:
        enabled: false
      
    
      externalSecrets:
        enabled: false
        secretStoreRefName: 
        certStoreRefName: 
        commonStoreRefName: 
    
    
      secretProvider:
        enabled: true
    
      nodeSelector:
        kubernetes.io/os: windows
        kubernetes.io/arch: amd64
    
      tolerations:
        - effect: NoSchedule
          key: os
          operator: Equal
          value: windows
    
      
      podDisruptionBudget:
        enabled: false
        minAvailable: 1
      
      # Vertical Pod Autoscaler configuration
      vpa:
        # Enable VPA for the deployments
        enabled: false
        # Update policy for VPA, refer to https://github.com/kubernetes/autoscaler/blob/master/vertical-pod-autoscaler/docs/quickstart.md
        updatePolicy:
          updateMode: Recreate # InPlaceOrRecreate that updates resource requests in-place is available since Kubernetes 1.33
          minReplicas: 1
    
    
      workzone:
        url: http://localhost
        airGappedConfiguration:
          enabled: false
        gmsaCredentialSpecName: gmsa-workzone
        wzc:
          client:
            url: http://wzc-client/app/client
        wzcnf:
          configurator:
            url: http://wzcnf-configurator/app/configurator
        wzcs:
          autopurge:
            # Cron schedule for running auto purge. Default 12:30 AM
            schedule: "30 0 * * *"
          explorer:
            url: http://wzcs-explorer/explorer
          notifications:
            url: http://wzcs-notifications/notifications
          oauth2:
            url: http://wzcs-oauth2/oauth2
            internalUrl: http://wzcs-oauth2/oauth2
            internalDaprUrl: http://localhost:3500/v1.0/invoke/wzcs-oauth2/method/oauth2
          odata:
            url: http://wzcs-odata/odata
            internalRootUrl: http://wzcs-odata
            internalUrl: http://wzcs-odata/odata
            internalDaprRootUrl: http://localhost:3500/v1.0/invoke/wzcs-odata/method
            internalDaprUrl: http://localhost:3500/v1.0/invoke/wzcs-odata/method/odata
          odata4:
            url: http://wzcs-odata4/odata4
            internalRootUrl: http://wzcs-odata4
            internalUrl: http://wzcs-odata4/odata4
            internalDaprRootUrl: http://localhost:3500/v1.0/invoke/wzcs-odata4/method
            internalDaprUrl: http://localhost:3500/v1.0/invoke/wzcs-odata4/method/odata4
          office:
            url: http://wzcs-office/Office
          sourceimport:
            # Cron schedule for running source import
            schedule: "*/30 * * * *"
          wopi:
            url: http://wzcs-wopi/wopi
          wopiclient:
            url: http://wzcs-wopiclient/wopiclient
          scim:
            url: http://wzcs-scim/provisioning
        wzo:
          api:
            url: http://wzo-api/wzoserver
            publicExchange: true
            graphApi: false
        wzfo:
          staticfilesprovider:
            url: http://wzfo-staticfilesprovider/App/Office
        wzlogic:
          auth:
            wzuser: CONTACTSYNCUSER
            oid: 7911dc40-c92d-4631-b4ab-9fef93204c37
          oauth2:
            clientId: ContactSyncService
          contactlookupservice:
            url: http://wzlogic-contactlookupservice/
            latestApiUrl: http://wzlogic-contactlookupservice/api/v1/ContactLookup
          contactsyncconfigservice:
            url: http://wzlogic-contactsyncconfigservice/
            latestApiUrl: http://wzlogic-contactsyncconfigservice/api/v1/ContactSyncConfiguration
          cprsubscriptionservice:
            url: http://wzlogic-cprsubscriptionservice/
            schedule: "0 4 * * 1-5"
          cprupdateservice:
            url: http://wzlogic-cprupdateservice/
          subscriptionservice:
            url: http://wzlogic-subscriptionservice/
            schedule: "0 4 * * 1-5"
          updateservice:
            url: http://wzlogic-updateservice/
          datafordeler:
            CprBaseUri: https://s5-certservices.datafordeler.dk/
            CvrBaseUri: https://s5-certservices.datafordeler.dk/
            BfeBaseUri: https://certservices.datafordeler.dk/
            EventsBaseUri: https://s5-certservices.datafordeler.dk/
        wzp:
          process:
            url: http://wzp-process/process
            internalUrl: http://wzp-process/process
            localUrl: http://localhost/process
            replicaCount: 1
            # the prerequisite for the functionality of the dedicated node for wzp-process is the appropriate preparation of the environment:
            dedicatedNodes:
              enabled: false
            autoscaling:
              enabled: false
              minReplicas: 1
              maxReplicas: 2
          massdispatch:
            url: http://wzp-massdispatch
            appdata:
              enabled: false
              size: 10Gi
          publicExchange: true
          # This section allows you to provide custom images for wzp components - values should be provided in customer's yaml
          customizations:
            enabled: false
            # image:
              # here you can provide repository for custom images in format <imagename>: <path/to/image>, i.e. init: workzone/EXAMPLE_CUSTOMER/wzp/init
              # tag: "latest"
        wzpdf:
          oauth2:
            clientId: WZPDF.CRAWLER
          pdfengine:
            url: http://wzpdf-pdfengine/render
            dedicatedNodes:
              enabled: false
          pdfcrawler:
            dedicatedNodes:
              enabled: false
          pdfservice:
            url: http://wzpdf-pdfengine/render
          pvc:
            enabled: false
            name: pdfpersistence
        wzsp:
          spconnector:
            url: http://wzsp-spconnector/spconnector
            internalUrl: http://localhost:3500/v1.0/invoke/wzsp-spconnector/method/spconnector
          frontend:
            url: http://wzsp-frontend/frontend
            internalUrl: http://localhost:3500/v1.0/invoke/wzsp-frontend/method/frontend
        kmdtxt:
          api:
            url: https://kmdtxt-api/api
            internalUrl: http://kmdtxt-api:5000
        wzdocumentmerge:
          api:
            url: https://wzdocumentmerge-service/documentmerge
        wzps:
          secretservice:
            url: http://wzps-secretservice/secretservice
            latestApiUrl: http://wzps-secretservice/api/v1/SecretService
        wzrs:
          api:
            url: https://wzrs/wzrs/SuggestRedaction
        
        db: #if need to customize below paramemeters, add value into environment .yaml file(eg. cataks.yaml)
          tablespacemap: DATA
          cultures: da-DK
          corporate_access_code: "N"
          freetext: "N"
        externalServices:
          sharepoint:
            sharepointUrl:
          interact:
            enabled: false
          smartpost:
            enabled: false
      #kmdtxt settings
      api:
        cors:
          allow_origins: "'[\"http://localhost\"]'"
  2. The copy image is missing

    • dapr: Dapr (Distributed Application Runtime) is an open-source, portable, and event-driven runtime that helps developers build microservice-based applications for the cloud and edge environments.
    • secretProvider: Modes for accessing a Key Vault instance: PodIdentity, UserAssignedManagedIdentity. Azure Key Vault provider for Secrets Store CSI Driver allows you to get secret contents stored in an Azure Key Vault instance and use the Secrets Store CSI driver interface to mount them into Kubernetes pods.
    • accessMode: PodIdentity: If eq .Values.secretProvider.accessMode "PodIdentity". The selector to identify which pods should be assigned to the AzureIdentity. AAD Pod Identity will go through a list of pods and look for value of pod label with key aadpodidbinding that is equal to this value.
    • sourceimport: Cron schedule for running source import.
    • db: If you need to customize the db paramemeters, add value into environment.yaml file.
  3. Copy and paste the code below, and save as an environment.yaml file.
    # global env specific file
    global:
      image:
        registry: wzdevcr.azurecr.io
        pullPolicy: Always
        tag: "latest"
    
      # Enable only if secret wzcommon-secrets is present
      commonsecrets:
        enabled: false
    
      dapr:
        enabled: false
        tracing:
          enabled: false
    
      ingress:
        enabled: true
        className: "external-ingress"
        annotations: {
          # Sets Listener protocol HTTPS and port 443
          nginx.ingress.kubernetes.io/use-regex: "true",
          nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
        }
        hostname: <environment_url>
        tls:
          - secretName: <secret-name>
            hosts:
              - <environment_url>
        teamsHostname: <environment_url>
    
      WORKZONE_CORPORATE_ACCESS_CODE: 'false'
      WORKZONE_CULTURES: da-DK;en-GB
      WORKZONE_FREETEXTINDEX: 'false'
      WORKZONE_TABLESPACEMAP: DATA
      
      logs:
        persistence:
          enabled: true
          size: 10Gi
    
      vpa:
        enabled: true
      
      workzone:
        url: https://<environment_url>
        wzc:
          client:
            url: https://<environment_url>/app/client
        wzcnf:
          configurator:
            url: https://<environment_url>/app/configurator
        wzcs:
          agentsub:
            mailerAuthCertificateSecret: wildcard-test-workzone-cloud
            mailerAuthCertificateKeyVault: wz-common-kv
          explorer:
            url: https://<environment_url>/explorer
          notifications:
            url: https://<environment_url>/notifications
          oauth2:
            url: https://<environment_url>/oauth2
          odata:
            url: https://<environment_url>/odata
          odata4:
            url: https://<environment_url>/odata4
          office:
            url: https://<environment_url>/Office
          wopi:
            url: https://<environment_url>/wopi
          wopiclient:
            url: https://<environment_url>/wopiclient
          scim:
            url: https://<environment_url>/provisioning
        wzo:
          api:
            graphApi: true
        wzfo:
          staticfilesprovider:
            url: https://<environment_url>/App/Office
        wzlogic:
          contactlookupservice:
            url: https://<environment_url>/contactlookup
            latestApiUrl: https://<environment_url>/contactlookup/api/v1/ContactLookup
            logLevel: Verbose
          cprsubscriptionservice:
            url: https://<environment_url>/cprsubscriptionservice
            schedule: "0 */3 * * *"
            logLevel: Verbose
          cprupdateservice:
            url: https://<environment_url>/cprupdateservice
            logLevel: Verbose
          subscriptionservice:
            url: https://<environment_url>/subscriptionservice
            schedule: "0 */3 * * *"
            logLevel: Verbose
          updateservice:
            url: https://<environment_url>/updateservice
            logLevel: Verbose
          contactsyncconfigservice:
            url: https://<environment_url>/contactsyncconfigservice
            latestApiUrl: https://<environment_url>/contactsyncconfigservice/api/v1/ContactSyncConfiguration
            logLevel: Verbose
          datafordeler:
            CprBaseUri: https://test04-s5-certservices.datafordeler.dk/
            CvrBaseUri: https://test03-s5-certservices.datafordeler.dk/
            EventsBaseUri: https://test03-s5-certservices.datafordeler.dk/
        wzp:
          process:
            url: https://<environment_url>/process
          massdispatch:
            appdata:
              enabled: true
        wzpdf:
          pdfengine:
            url: https://<environment_url>/render
          pdfservice:
            url: https://<environment_url>/render
        wzrs:
          api:
            url: https://<environment_url>/wzrs/SuggestRedaction
        wzsp:
          spconnector:
            url: https://<environment_url>/spconnector
        kmdtxt:
          api:
            url: https://<environment_url>/kmdtxt
        wzdocumentmerge:
          api:
            url: https://<environment_url>/documentmerge
        wzps:
          secretservice:
            logLevel: Verbose
    
        db:
          ipAddress: 192.168.20.126 ## change to DB IP
          port: 1522 change to DB port
          cultures: da-DK;en-GB
    
        wallet:
          enabled: true
          secretName: wallet
    
        externalServices:
          sharepoint:
            sharepointUrl: https://<your_sharepointUrl>.sharepoint.com
          interact:
            enabled: true
          smartpost:
            enabled: true
      #kmdtxt settings
      api:
        cors:
          allow_origins: "'[\"https://<environment_url>\"]'"
    
    # External Secrets Operator reads information from a third-party service like Azure Key Vault and automatically injects the values as Kubernetes Secrets.
    # Enable this only if you are using External Secrets Operator else set to false
      externalSecrets:
        enabled: true
        provider:                           # pass the provider name, default is Azure KV
        key:                                # provide the key path
        secretStoreRefName: azure-store
        certStoreRefName: azure-store  
        commonStoreRefName: 
    
    # Set to false if you are using External Secrets Operator and remove the block if you are using secretProvider
      secretProvider:
        enabled: false

    The copy image is missing

    • annotations: Sets Listener protocol HTTPS and port 443.
    • <environment_url>: Replace with the URL of your environment
    • <your_sharepointUrl>: Replace with the SharePointUrl for your company
  4. Copy the values.yaml and environment.yaml files into a folder.

Prepare environment files for external secrets

The External Secrets Operator extends Kubernetes with custom resources that define where secrets stored and how they should be synchronized. The controller fetches secrets from an external API and creates the corresponding Kubernetes secrets. If the secret from the external API changes, the controller automatically reconciles the state in the cluster and update the Kubernetes secrets accordingly.

See the official documentation Overview - External Secrets Operator for more information about integrating External Secrets Operator with Kubernetes and using multiple secret providers.

If your secrets are managed by External Secrets Operator, ensure that it is installed on your Kubernetes cluster.

If you are using secretProvider, set its value to true in the values.yaml file as shown below.

Configuration of values.yaml file:

  externalSecrets:
    enabled: false
    secretStoreRefName: 
    certStoreRefName: 
    commonStoreRefName: 

  secretProvider:
    enabled: true

The copy image is missing

If you are using externalSecrets, set the externalSecrets value to true in your environment's value.yaml file. Then provide the appropriate secret store name in the secretStoreRefName field. You must also provide the external secrets provider name, for example vault for Hashi Corp vault, and provide the key path to the key.

If the provider field is empty, the default provider is Azure.

Configuration for your environment's values.yaml file:

  externalSecrets:
    enabled: true
    provider:                               
    key:                                  
    secretStoreRefName: 
    certStoreRefName: 
    commonStoreRefName: 

The copy image is missing

Set the secretProvider value to false if you are using externalSecrets (External Secrets Operator) and remove the secretProvider block if you are using secretProvider.

  secretProvider:
    enabled: false

The copy image is missing