Red Hat® OpenShift®

Red Hat® OpenShift® is an enterprise-ready Kubernetes container platform with full-stack automated operations to manage hybrid cloud and multicloud deployments.

Repository

The IBM Security Verify Access OIDC Provider (ISVAOP) image is available from IBM Cloud Container Registry.

See Software Downloads > Containers for more information.

Pre-requisites

Configuration

The configuration for the container is supplied as YAML files, template files, and JavaScript files, along with other potential supporting files (for example, PEM certificate files).

📘

Note

Boilerplate YAML configuration is available for download from the Resources Github Repository.

When the container starts, it processes the configuration found at '/var/isvaop/config' directory. The configuration for the container needs to be present in this directory before the container is started or mounted as part of the startup.

The ISVAOP container can be packaged to start with the configuration information in different ways. Here are some non-exhaustive options.

  1. Pre-baking the configuration into a new image which is based on the ISVAOP image. A Dockerfile which can be used to create a pre-baked image is shown below:
##
## You can build this image by issuing the following command:
##          docker build -t acme-isvaop:1.0 $PWD
##

## The container is based on the ISVAOP container.
FROM icr.io/isva/verify-access-oidc-provider:24.08

## Copy the configuration files from the data directory
## to the docker image.
COPY data/. /var/isvaop/config/


## Some labels which will be associated with the image.
LABEL maintainer="[email protected]" \
    vendor="ACME"
  1. Use OpenShift ConfigMaps and Secrets to hold configuration information.

Approach: Using OpenShift resources

Pre-deployment steps

  1. Create an OpenShift Secret for Keystores, Certificates and Keys.

    Put the following files in the same folder and use the command line to create the Secret.

    • P12 keystore and the obf file contains the P12's obfuscated password.
    • Individual keystore .zip file. Make sure the keystore zip file has the personal and signer folders at its root.
    • PEM format certificate and key files.

    Use the following command to create the Secret:

    oc create secret generic isvaop-keystores --from-file=./keystores
    
  2. Create an OpenShift Secret for Server Credentials.

    Create an OpenShift Secret yaml file with the server credentials like below:

    kind: Secret
    apiVersion: v1
    metadata:
      name: isvaop-server
    stringData:
      db_hostname: ...
      db_hostport: ...
      db_username: ...
      db_password: ...
      db_db_name: ...
       ...
    type: Opaque
    

    Use the following command to create the Secret:

    oc apply -f server_secret.yml
    
  3. Create an OpenShift Secret for obfuscation and encryption keys.
    Create an OpenShift Secret yaml file with the server credentials as shown in the following example.

    kind: Secret
    apiVersion: v1
    metadata:
      name: isvaop-obf
    stringData:
      obf_key: "ENC:<encrypted_obf_key>"
      enc_key: |
        -----BEGIN RSA PRIVATE KEY-----
        ...
        -----END RSA PRIVATE KEY-----
    type: Opaque
    

    Use the following command to create the Secret:

    oc apply -f obf_secret.yml
    
  4. If necessary, create more OpenShift Secrets.

  5. Create an OpenShift ConfigMap for static clients.

    Put the client yaml files in the same folder, and use the following command to create the ConfigMap:

     oc create configmap isvaop-clients --from-file=./clients
    
  6. Create an OpenShift ConfigMap for access policies.

    Put the access policy files in the same folder, and use the following command to create the ConfigMap:

    oc create configmap isvaop-access-policies --from-file=./accesspolicy
    
  7. Create an OpenShift ConfigMap for mapping rules.

    Put the mapping rule files in the same folder, and use the following command to create the ConfigMap:

    oc create configmap isvaop-mapping-rules --from-file=./mappingrule
    
  8. Create an OpenShift ConfigMap for customized template pages.

    Compress the customized template pages. Make sure the .zip file has the language folders like C, fr, and it at its root.
    Use the following command to create the ConfigMap:

    oc create configmap isvaop-templates --from-file=./templates.zip
    
  9. If necessary, create more OpenShift ConfigMaps.

  10. Create the main OpenShift ConfigMap with top-level configuration keys.

    • For more information about top-level keys and an example, see Configuration.
    • For more information about YAML configuration details, see YAML Config Guide.

    Create yaml configuration files with top-level keys, and use configmap: or secret: annotation refer to configurations in OpenShift ConfigMaps or Secrets.

    The configuration can in the same file or spread across multiple files.

    📘

    Note

    The configuration file extensions must be .yml or .yaml.
    Set top-level key version to 24.08 to enable full yaml configuration.

    The following code is a configuration file example with all top-level keys.

    version: 24.08
    server:
      ssl:
        key: 'secret:isvaop-keystores/httpserverkey.pem'
        certificate: 'secret:isvaop-keystores/httpservercert.pem'
      pages:
        type: zip
        content: 'configmap:isvaop-templates/templates.zip'
    logging:
      level: debug
    secrets:
      obf_key: 'secret:isvaop-obf/obf_key'
      enc_key: 'secret:isvaop-obf/private.pem'
    template_macros:
      user_macros:
        - name
        - family_name
        - given_name
        - display_name
      request_macros:
        - authorization_details
        - claims
        - user_code
        - state
    ssl:
      certificate:
        - ks:rt_profile_keys
      disable_hostname_verification: true
    definition:
      id: 1
      name: OIDC Definition
      grant_types:
        - authorization_code
        - implicit
        - password
        - client_credentials
        - refresh_token
        - 'urn:openid:params:grant-type:ciba'
        - urn:ietf:params:oauth:grant-type:jwt-bearer
      access_policy_id: default_policy
      pre_mappingrule_id: pretoken
      post_mappingrule_id: posttoken
      base_url: 'https://auth.isvaop.com:445'
      mtls_base_url: 'https://auth.isvaop.com:445'
      mtls_certificate_header_name: X-Client-Certificate
      features:
        enable_fault_tolerance: false
        enable_dynamic_registration: true
        consent_prompt: NEVER_PROMPT
        fapi_compliant: false
        enforce_par: false
      token_settings:
        issuer: 'https://www.ibm.com'
        signing_alg: RS256
        signing_keystore: rt_profile
        signing_keylabel: rsa256
        authorization_code_lifetime: 300
        access_token_lifetime: 7200
        id_token_lifetime: 3600
        refresh_token_lifetime: 64800
      request_object:
        lifetime: 3600
        require_expiry: true
        only_request_object_params: false
        enforce_single_usage: false
      backchannel_settings:
        default_expiry: 900
        maximum_expiry: 1800
        polling_interval: 5
        notifyuser_mappingrule_id: notifyuser
        checkstatus_mappingrule_id: checkstatus
      attribute_map:
        name: name
        preferred_username: preferred_username
        email: email
      metadata:
        claims_supported:
          - iss
          - name
          - displayName
    janitor:
      batch_size: 1000
      max_duration: 0
      check_frequency: 10
    jwks:
      signing_keystore: rt_profile
      encryption_keystore: rt_profile_keys
    authentication:
      endpoint: >-
        https://auth.isvaop.com:445/oauth2/auth
      callback_param_name: Target
    javascript:
      timeout: 0
      max_load: 16
      max_idle_time: 600
      max_ctx_in_isolate: 60
      cleanup_frequency: 300
      use_pool: false
    dynamic_registration:
      recipe: Default
      mappingrule_id: dcr
      software_statement_validation:
        jwks_uri: >-
          https://isvaop.ibmcloudsecurity.com/oidc/endpoint/default/jwks
        signing_algs:
          - PS256
          - ES256
      registration_endpoint_authentication:
        require_mtls: false
        require_bearer_token: false
        require_software_statement: false
        allow_custom_client_creds: true
      management_endpoint_authentication:
        require_mtls: false
        require_bearer_token: true
        require_software_statement: false
      registration_access_token:
        generate: true
        lifetime: 86400
        scopes:
          - 'cdr:registration'
    runtime_db: db2srv
    session_cache:
      type: redis
      cfg: redis-standalone
    server_connections:
      - name: db2srv
        type: db2
        database_name: 'secret:isvaop-server/db_db_name'
        hosts:
          - hostname: 'secret:isvaop-server/db_hostname'
            hostport: 'secret:isvaop-server/db_hostport'
        credential:
          username: 'secret:isvaop-server/db_username' 
          password: 'secret:isvaop-server/db_password'
        ssl:
          certificate:
            - ks:db2client
          disable_hostname_verification: true
      - name: redis-standalone
        type: redis
        deployment:
          model: standalone
        hosts:
          - hostname: 'secret:isvaop-server/redis_hostname'
            hostport: 'secret:isvaop-server/redis_hostport'
        credential:
          username: 'secret:isvaop-server/redis_username' 
          password: 'secret:isvaop-server/redis_password'
        ssl:
          certificate:
            - ks:rt_profile
          disable_hostname_verification: true
      - name: ldap_staging
        type: ldap
        hosts:
          - hostname: 'secret:isvaop-server/ldap_hostname'
            hostport: 'secret:isvaop-server/ldap_hostport'
            credential:
              bind_dn: 'secret:isvaop-server/ldap_bind_dn'
              bind_password: 'secret:isvaop-server/ldap_bind_pwd'
        ssl:
          certificate:
            - ks:rt_profile
          disable_hostname_verification: true
    attribute_sources:
      - id: 1
        name: name
        type: ldap
        value: displayName
        scope: subtree
        filter: (|(|(objectclass=ePerson)(objectclass=person))(objectclass=User))
        selector: cn,displayName,mail
        srv_conn: ldap_staging
        baseDN: dc=ibm,dc=com
      - id: 2
        name: preferred_username
        type: ldap
        value: cn
        scope: subtree
        filter: (|(|(objectclass=ePerson)(objectclass=person))(objectclass=User))
        selector: cn,displayName,mail
        srv_conn: ldap_staging
        baseDN: dc=ibm,dc=com
      - id: 3
        name: email
        type: ldap
        value: mail
        scope: subtree
        filter: (objectclass=*)
        selector: cn,displayName,mail
        srv_conn: ldap_staging
        baseDN: dc=ibm,dc=com
    ldapcfg:
      - name: ldap_staging_cfg_01
        scope: subtree
        user_object_classes: top,Person,organizationalPerson,inetOrgPerson
        filter: (|(|(objectclass=ePerson)(objectclass=person))(objectclass=User))
        selector: objectClass,cn,sn,givenName,userPassword
        srv_conn: ldap_staging
        attribute: uid
        baseDN: dc=ibm,dc=com
    rules:
      access_policy:
        - name: default_policy
          content: 'configmap:isvaop-access-policies/default_policy.js'
      mapping:
        - name: pretoken
          content: 'configmap:isvaop-mapping-rules/pretoken.js'
        - name: posttoken
          content: 'configmap:isvaop-mapping-rules/posttoken.js'
        - name : dcr
          content: 'configmap:isvaop-mapping-rules/dcr.js'
        - name: ropc
          content: 'configmap:isvaop-mapping-rules/ropc.js'
        - name : notifyuser
          content: 'configmap:isvaop-mapping-rules/notifyuser.js'
        - name: checkstatus
          content: 'configmap:isvaop-mapping-rules/checkstatus.js'
    clients:
      - "configmap:isvaop-clients/client01.yml"
      - "configmap:isvaop-clients/client02.yml"
      - "configmap:isvaop-clients/client03.yml"
    keystore:
      - name: db2client
        type: p12
        content: "secret:isvaop-keystores/db2client.p12"
        password: "secret:isvaop-keystores/db2client.obf"
      - name: rt_profile
        type: zip
        content: "secret:isvaop-keystores/rt_profile.zip"
      - name: rt_profile_keys
        type: pem
        certificate:
          - label: cert01
            content: "secret:isvaop-keystores/rt_profile_keys_signer_cert01.pem"
          - label: cert02
            content: "secret:isvaop-keystores/rt_profile_keys_signer_cert02.pem"
        key:
          - label: key01
            content: "secret:isvaop-keystores/rt_profile_keys_personal_key01.pem"
          - label: key02
            content: "secret:isvaop-keystores/rt_profile_keys_personal_key02.pem"
    

    Put the configuration file(s) with top-level keys in the same folder, and use the following command to create the ConfigMap:

    oc create configmap isvaop-config --from-file=./config
    
  11. Create a service account.

## Create a serviceaccount called isvaop.
oc create serviceaccount isvaop
  1. Assign ConfigMap and Secret read permission to the service account.
    Create a role with ConfigMap and Secret read permission using the following command:
oc create role view-configmap-secret --verb=get,list,watch --resource=secrets,configmaps

Create a Rolebinding to assign the role to the service account by using the following command.

📘

Note

The RoleBinding applies to specific OpenShift project.

Replace <ocp_project> with the actual project.

oc create rolebinding --role=view-configmap-secret <ocp_project>-isvaop-view-configmap-secret --serviceaccount=<ocp_project>:isvaop

Deployment

To deploy a running IBM Security Verify Access OIDC Provider container in a OpenShift environment a deployment descriptor must first be created. The following deployment YAML file (isvaop-deployment.yaml) is a sample that references the configmaps and the secret created that was created in the previous section.

Use the following isvaop-deployment.yml to deploy the service.

## 
## A demo deployment description for the isvaop container. This deployment
## descriptor has dependencies on the file-based configuration.
##
## 
## A demo deployment description for the isvaop-new container. This deployment
## descriptor has dependencies on the file-based configuration.
##

apiVersion: apps/v1
kind: Deployment

metadata:
  name: isvaop
  labels:
    app: isvaop
spec:
  selector:
    matchLabels:
      app: isvaop
  replicas: 1
  template: 
    metadata:
      labels:
        app: isvaop
      annotations:
        version: "2.0"
        productName: "IBM Security Verify Access Virtual Edition Federation Module AOS"
        productId: "13ce5584032a42eab5704711369a11a4"
        productMetric: "PROCESSOR_VALUE_UNIT"
        productChargedContainers: "All"
    spec:
      # The name of the service account which has the required
      # capabilities enabled for the ISVAOP container.
      serviceAccountName: isvaop
      # Use volume to store the configuration data.
      volumes:
        - name: isvaop-config
          configMap:
            name: isvaop-config
    
      containers:
        - name: isvaop
          # The fully qualified name of the ISVAOP image.
          image: icr.io/isva/verify-access-oidc-provider:24.08
          # Mount our volumes to the expected configuration directory
          volumeMounts:
            - name: isvaop-config
              mountPath: /var/isvaop/config
           # The liveness and readiness probes are used by Kubernetes 
           # to obtain the health of the container.
          readinessProbe:
             httpGet:
                path: /healthcheck/ready
                port: 8436
                scheme: HTTPS
             initialDelaySeconds: 30
             timeoutSeconds: 30
             periodSeconds: 30
             successThreshold: 1
             failureThreshold: 2
          livenessProbe:
             httpGet:
                path: /healthcheck/alive
                port: 8436
                scheme: HTTPS
             initialDelaySeconds: 30
             timeoutSeconds: 30
             periodSeconds: 30
             successThreshold: 1
             failureThreshold: 10

The OpenShift pod can then be created using the following command:

[demouser@demovm ~]$ oc create -f isvaop-deployment.yml

Service

The isvaop container exposes a single port for each protocol that is enabled for the server. For the HTTPS protocol, the 8436 port is exposed. To make this port available from outside of the OpenShift cluster, a new service must be created. The following YAML file (isvaop-service.yaml) contains an example service definition.

## 
## The service description of the isvaop service.  
##

apiVersion: v1
kind: Service

metadata:
  name: isvaop
  labels:
    app: isvaop
spec:
  ports:
    - name: isvaop-https
      protocol: TCP
      port: 8436
      targetPort: 8436
  selector:
    app: isvaop
  type: ClusterIP

The service definition can then be created using the following command:

[demouser@demovm ~]$ oc create -f isvaop-service.yaml

Route

A Route in OpenShift provides an ingress point to the cluster which routes HTTP and HTTPS traffic to a Service based on requested Host and Path. This is a common way to publish services to the world from an OpenShift cluster.

apiVersion: route.openshift.io/v1
kind: Route
metadata:
  creationTimestamp: null
  name: isvaop-route
  labels:
    app: isvaop
spec:
  port:
    targetPort: isvaop-https
  tls:
    insecureEdgeTerminationPolicy: Redirect
    termination: passthrough
  to:
    kind: Service
    name: isvaop
    weight: 100
  wildcardPolicy: None 

Use the following command to create the route definition.

[demouser@demovm ~]$ oc create -f isvaop-route.yaml

Updating the Configmap

  • Modify the configuration directory, and use the following command to update the isvaop-config configmap.

    [demouser@demovm ~]$ oc create configmap isvaop-config --from-file=./config -o yaml --dry-run | oc apply -f -
    
  • Delete the existing pod.

    [demouser@demovm ~]$ oc delete pod <pod_name>
    

Use OpenShift Template

Instead of creating OpenShift deployment, service and route separately, use a OpenShift Template to deploy all of them in one go.

kind: Template
apiVersion: template.openshift.io/v1
metadata:
  name: verify-access-oidc-provider
  annotations:
    iconClass: icon-sso
    openshift.io/display-name: IBM Security Verify Access OIDC Provider
    openshift.io/documentation-url: 'https://ibm.biz/ibmsecurityoidcprovider'
    openshift.io/long-description: A OIDC Provider container which acts as the OpenID Connect provider.
    openshift.io/support-url: 'https://ibm.biz/ibmsecurityoidcprovider'
    productName: "IBM Security Verify Access Virtual Edition Federation Module AOS"
    productId: "13ce5584032a42eab5704711369a11a4"
    productMetric: "PROCESSOR_VALUE_UNIT"
    productChargedContainers: "All"
objects:
  - apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations:
        deployment.kubernetes.io/revision: '1'
      generation: 1
      labels:
        app: ${APP_NAME}
      name: ${APP_NAME}
    spec:
      replicas: 1
      progressDeadlineSeconds: 600
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: ${APP_NAME}
      strategy:
        rollingUpdate:
          maxSurge: 1
          maxUnavailable: 1
        type: RollingUpdate
      template:
        metadata:
          labels:
            app: ${APP_NAME}
        spec:
          serviceAccountName: ${SERVICE_ACCOUNT}
          volumes:
            - name: isvaop-config
              configMap:
                name: ${ISVAOP_CONFIGMAP}
          imagePullSecrets:
            - name: artifactory
          containers:
            - name: ${APP_NAME}
              image: >-
                icr.io/isva/verify-access-oidc-provider:${ISVAOP_VERSION}
              volumeMounts:
                - name: isvaop-config
                  mountPath: /var/isvaop/config
  - apiVersion: v1
    kind: Service
    metadata:
      name: ${APP_NAME}
      labels:
        app: ${APP_NAME}
    spec:
      ports:
        - name: ${APP_NAME}
          port: 8436
          protocol: TCP
          targetPort: 8436
      selector:
        app: ${APP_NAME}
      sessionAffinity: None
      type: ClusterIP
    status:
      loadBalancer: {}
  - apiVersion: v1
    kind: Route
    metadata:
      creationTimestamp: null
      name: ${APP_NAME}
      labels:
        app: ${APP_NAME}
    spec:
      port:
        targetPort: ${APP_NAME}
      tls:
        insecureEdgeTerminationPolicy: Redirect
        termination: passthrough
      to:
        kind: Service
        name: ${APP_NAME}
        weight: 100
      wildcardPolicy: None
parameters:
  - name: APP_NAME
    description: >-
      The name which will be given to the IBM Security Verify Access OIDC
      Provider application.
    value: isvaop
  - name: ISVAOP_VERSION
    description: The ISVAOP version/tag which is to be deployed.
    value: '24.08'
  - name: SERVICE_ACCOUNT
    description: The service account which will be used when running the pod.
    value: isvaop
  - name: REPLICAS
    description: The number of replicas of the application to create.
    value: '1'
  - name: ISVAOP_CONFIGMAP
    description: The ConfigMap which holds the configuration of the container.
    value: isvaop-23

Use the following command to create the objects defined in the OpenShift template:

oc process isvaop-template.yml | oc create -f -

Supported Tags

TagPurpose
YY.MMA particular release, of the format: {year}.{month}. For example 24.08.
YY.MM.RA particular revision of a release, of the format: {year}.{month}.{revision} For example 24.08.0.