IBM Security Verify Integration

IBM Security Verify SSO for JBoss / Wildfly using IBM Application Gateway

IBM Security Verify can be used to provide a cloud based identity to IBM Application Gateway (IAG) using the OIDC standard. IAG is a lightweight reverse proxy which provides authentication and authorization to web application servers. IAG can also be used to enforce additional path based authentication policies (such as 2FA) where required.

Assumed knowledge

This guide assumes that you are familiar with IBM Security Verify applications and managing a cloud based user registry. Users should also be familiar with IBM Application Gateway configuration. Specifically you should be able to:

  • Create a new IBM Security Verify application from the IAG template.
  • Configure an IAG identity source.
  • Configure an IAG resource server.
  • Set SSL configuration
    • SSL key/certificate for https traffic.
    • Mutual SSL for protected resource servers.
    • Strongly recommended for both JBoss and IAG web traffic.

Users should also be familiar with IBM Application Gateway (IAG) configuration. Specifically you should be able to configure an identity source and a resource server. You must also provided the required PKI to support SSL connections between IAG and the junctioned server.

Prerequisites

To use this this guide you should have:

  • A JBoss / Wildfly server configured for SSO authentication (this guide)
  • A IBM Security Verify subscription or valid trial account
  • PKI to secure connections to and from IAG and junctioned JBoss/Wildfly server

Configure IBM Security Verify

The verify scenario guide can be used to configure an IBM Security Verify tenant to provide SSO capabilities to IBM Application Gateway. An IAG application should be created or updated to support the new IAG instance. This will likely involve modifying the redirect_uri entries to include the DNS/hostname that the IAG instance is protecting.

The user registry should also be configured now (if not already done). IBM Security Verify supports cloud directory users as well as federated identity sources.

Deploying IBM Application Gateway

To configure IAG to pass-through identity information from IBM Security Verify to JBoss the resource_servers and identity configuration keys are used. The required configuration for each key is detailed below.

Resource servers

The resource server key is used to configure downstream applications which will be protected by IAG. At a minimum a junction path (prefixed with a /) and a resource server must be defined. The identity headers (or JWT) and additional security configuration is also defined here for the downstream JBoss server.

The target integration server can be identified by a DNS name or IP address, for Kubernetes environments this should be the service created for the target JBoss deployment. The X509 certificate (or a signer certificate) configured for mutual authentication (eg: iag.pem) must be a trusted certificate in the keystore used by JBoss.

The configured issuer (iss), audience (aud) and subject (sub) for the JWT must match the configuration set in the JBoss server's XML configuration. The PKI used to sign (and encrypt) the generated JWT must also be imported into the keystore used by the JBoss server. JBoss only supports using the Authorization header to supply JWT's and should be of the for Authorization: Bearer <j.w.t>.

resource_servers:
  - path: "/wildflysso"
    connection_type: ssl
    transparent_path: false
    sni: "demo.integration.server"
    mutual_auth:
      certificate_auth:
        certificate:
          - "@iag.pem"
          - "@iag.key"
    servers:
      - host: "wildfly.integration.server"
        port: 8443
        ssl:
          certificate:
            - "@integration.target.pem"
    identity_headers:
      jwt:
        hdr_name: "Authorization"
        certificate:
          - "@iag.pem"
          - "@iag.key"
        claims:
          - text: "www.ibm.com"
            name: iss
            type: string
          - attr: AZN_CRED_PRINCIPAL_NAME
            name: sub
            type: string
          - text: "demo.websphere.server"
            name: aud
            type: string

Identity

The identity key can be used to configure IAG as an OIDC RP. You can use the IBM Security Verify application created here to supply identity information to IAG. The provided example also makes use of special data types that IAG exposes to obfuscate sensitive information that may be required to define your deployment. In this case the client id and secret for the IBM Security Verify application is stored in a Kubernetes secret instead of a config map or set in the deployment yaml.

The OIDC definition also maps the preferred_username attribute instead of the sub attribute returned in the claims from Verify. This is done to return a human recognisable attribute as the Principal name available to the downstream application.

JBoss and Wildfly also make use of the kid field in a JWT header to identify the public key which should be used to verify supplied JWT. The kid value used by Elytron is set in the server's XML configuration file. In a verify deployment this is the distinguished name of the X509 certificate used to sign the JWT; in verify access this the key-label value from the SSL database.

identity:
  oidc:
    client_id: secret:ibm-verify-oidc-integration/client_id
    client_secret: secret:ibm-verify-oidc-integration/client_secret
    discovery_endpoint: https://your.tenant.ibmcloudsecurity.com/oidc/endpoint/default/.well-known/openid-configuration
    redirect_uri_host: ibm.security.integration.demo:30443
    mapped_identity: "{preferred_username}"
    ssl:
      certificate:
        - "@verify_tenant_ca.pem"
    response_type: code
    response_mode: query

Advanced configuration:

IAG requires some additional advanced configuration parameters in order to supply a JWT in the correct format. The header format needs to be modified to include the static string Bearer. The name of the stanza for this property is dependant on the junction name to the JBoss server. If a different junction name is used then the stanza key should be updated to jwt:/<junction name>.

    advanced:
      configuration:
        - stanza: "jwt:/wildflysso"
          entry: "hdr-format"
          operation: set
          value: "Bearer %TOKEN%"

Return to JBoss/Wildfly integration guide

Demo Wildfly Application server: "hello world" integration example

This guide can be used to deploy a simple demonstration of the identity capabilities available from IBM Security Verify and IBM Application Gateway (IAG). This demo provides configuration for two containers: One IAG container setup to authenticate users with IBM Security Verify; and one Wildfly container with a demo java application.

This demo is deployed on Kubernetes but could be modified for OpenShift or another container orchestration platform. The source code for this demonstration is available at IBM Security Integrations.

Assumed knowledge

To successfully deploy this demonstration there is some assumed knowledge. A user should be familiar with:

  • Deploying containers, configuration maps and secrets to Kubernetes.
  • Creating and managing IBM Security Verify tenants.

Prerequisites

To deploy this demo a user should first:

  • Retrieve the integration artifacts required from release artifacts or build them from source code
  • Configure your environment to connect to the Kubernetes (or equivalent) cluster being used to host this demo.

Configuring IBM Security Verify

Identity for this demo is provided by IBM Security Verify. A guide for configuring IBM Security Verify as an OP for IAG is available in the IAG Readme

Create/Request PKI

Asymmetric keys are required for SSL connections and to sign/verify JWT's. The following openssl commands can be used to generate RSA keys and self-signed X509 certificates for Wildfly and IBM Application Gateway. The X509 Certificate/Public Key used by IBM Application Gateway for connections to junctioned servers should also be imported to the keystore (.p12file) used by Wildfly. For production environments the PKI used should be signed by a suitable certificate authority.

# Create IAG certificates/keys
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:4096 -keyout iag.key -out iag.pem \
        -subj "/C=AU/ST=QLD/L=Gold Coast/O=IBM/CN=demo.iag.server"

# Create Wildfly certificae/keys/pcsk12
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:4096 -keyout wildfly.key -out wildfly.pem \
        -subj "/C=AU/ST=QLD/L=Gold Coast/O=IBM/CN=demo.integration.server"

# Import IAG X509 into the Wildfly keystore
openssl pkcs12 -export -out application.keystore -inkey wildfly.key -in wildfly.pem -passout pass:demokeystore -name server
keytool -importcert -keystore application.keystore -file iag.pem -alias isvajwt -storepass demokeystore -noprompt

Deploying IBM Application Gateway

Once the IBM Security Verify application has been created and PKI generated the Application can be deployed to your container orchestration platform (OpenShift/Kubernetes). There are two containers required for this demonstration: the IAG container is configured as an OIDC RP for the previously configured IBM Security Verify OP; and a Wildfly application server which is the target of the integration. The IAG deployment requires three Kubernetes Objects: A secret map for sensitive data; a config map with the IAG configuration; and a deployment which defines the IAG containers to be deployed. The following sections detail how these objects are created.

IAG Secrets map

Kubernetes secrets are used to obfuscate sensitive data such as the client id and secret of the IBM Security Verify Application. Additional non-sensitive information such as the config.yaml file and any X509 Certificates / Keys should be added using Config Maps.

apiVersion: v1
kind: Secret
metadata:
  name: ibm-verify-oidc-integration
type: Opaque
data:
  client_id: "change this"
  client_secret: "change this"

IAG Config Map

The core of an IAG deployment is the yaml configuration file which defines protected resources and access policies. The following example sets a junction to a Wildfly application server as well as defining the JWT supplied to the server. IBM Security Verify identity configuration s also defined in this file. If a configuration option is not able to be set with the documented configuration options, the advanced/configuration entry can be used to define reverse proxy daemon configuration entries.

apiVersion: v1
kind: ConfigMap
metadata:
  name: ibm-verify-wildfly-integration-config
data:
  iag.pem: |
%%IAG_CERTIFICATE%%
  iag.key: |
%%IAG_KEY%%
  integration.target.pem: |
%%INTEGRATION_SERVER_CERTIFICATE%%
  verify_tenant_ca.pem: |
%%VERIFY_TENANT_CERT%%
  config.yaml: |
    version: 21.09
    server:
      ssl:
        front_end:
          certificate:
            - "@iag.pem"
            - "@iag.key"
    resource_servers:
      - path: "/wildflysso"
        connection_type: ssl
        transparent_path: false
        sni: "demo.wildfly.server"
        mutual_auth:
          certificate_auth:
            certificate:
              - "@iag.pem"
              - "@iag.key"
        servers:
          - host: "wildfly-integration"
            port: 8443
            ssl:
              certificate:
                - "@integration.target.pem"
        identity_headers:
          jwt:
            hdr_name: "Authorization"
            certificate:
              - "@iag.pem"
              - "@iag.key"
            claims:
              - text: "www.ibm.com"
                name: iss
                type: string
              - attr: AZN_CRED_PRINCIPAL_NAME
                name: sub
                type: string
              - text: "demo.integration.server"
                name: aud
                type: string
    advanced:
      configuration:
        - stanza: "jwt:/wildflysso"
          entry: "hdr-format"
          operation: set
          value: "Bearer %TOKEN%"
    identity:
      oidc:
        client_id: secret:ibm-verify-oidc-integration/client_id
        client_secret: secret:ibm-verify-oidc-integration/client_secret
        discovery_endpoint: https://iag-dev.pre1.idng.ibmcloudsecurity.com/oidc/endpoint/default/.well-known/openid-configuration
        redirect_uri_host: ibm.security.integration.demo:30443
        #mapped_identity: "{sub}"
        ssl:
          certificate:
            - "@verify_tenant_ca.pem"
        response_type: code
        response_mode: query

IBM Application Gateway deployment

Next we need to define the IBM Application Gateway container and connect it to the Kubernetes service layer so it is reachable from network addresses outside to the Kubernetes cluster. The container version used should match the version set in the ConfigMap config.yaml. Container health checks are also defined to enable Kubernetes to respond if the IBM Application gateway container stops responding.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: iag-instance
  labels:
    app: iag-instance
spec:
  selector:
    matchLabels:
      app: iag-instance
  replicas: 1
  template:
    metadata:
      labels:
        app: iag-instance
    spec:
      #serviceAccountName: ibm-application-gateway
      imagePullSecrets:
        - name: iag-login
      volumes:
        - name: integration-config
          configMap:
            name: ibm-verify-wildfly-integration-config
      containers:
        - name: iag-instance
          image: ibmcom/ibm-application-gateway:21.09.0
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - name: integration-config
              mountPath: /var/iag/config
          readinessProbe:
            exec:
              command:
              - /sbin/health_check.sh
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            exec:
              command:
              - /sbin/health_check.sh
            initialDelaySeconds: 120
            periodSeconds: 20
---
apiVersion: v1
kind: Service
metadata:
  name: iag-instance
  labels:
    app: iag-instance
spec:
  ports:
    - port: 8443
      name: iag
      protocol: TCP
      nodePort: 30443
  selector:
    app: iag-instance
  type: NodePort

Deploying the demo JBoss Wildfly server

The final step of this demo is to deploy the Wildfly server which is the target of this integration. A simple Wildfly container is provided as part of the demo resources. This container is already configured to use the JWT token-realm feature to supply identity information to Java application.

The demo application deployed to the Wildfly container is configured to reflect the identity information supplied in the java Principal object. A PCKS12 keystore is also mounted to the Wildfly default keystore file which ensures the SSL certificate provided by IBM Application Gateway can be validated by Wildfly (mutual TLS).

apiVersion: v1
kind: ConfigMap
metadata:
  name: wildfly-config
binaryData:
  application.keystore: %%WILDFLY_KEYSTORE%%
  SecTestWeb.war: %%DEMO_APPLICATION%%
  standalone.xml: |
    %%STANDALONE_XML%%
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wildfly-integration
  labels:
    app: wildfly-integration
spec:
  selector:
    matchLabels:
      app: wildfly-integration
  replicas: 1
  template:
    metadata:
      labels:
        app: wildfly-integration
    spec:
      volumes:
        - name: wildfly-config
          configMap:
            name: wildfly-config
      containers:
        - name: wildfly-integration
          image: jboss/wildfly:latest
          imagePullPolicy: IfNotPresent
          args: ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0"]
          ports:
            - containerPort: 8443
          volumeMounts:
            - mountPath: /opt/jboss/wildfly/standalone/configuration/application.keystore
              subPath: application.keystore
              name: keystore-volume
            - mountPath: /opt/jboss/wildfly/standalone/deployments/SecTestWeb.war
              subPath: SecTestWeb.war
              name: wildfly-config
            - mountPath: /opt/jboss/wildfly/standalone/configuration/standalone.xml
              subPath: standalone.xml
              name: wildfly-config
---
apiVersion: v1
kind: Service
metadata:
  name: wildfly-integration
  labels:
    app: wildfly-integration
spec:
  ports:
    - port: 8443
      name: wildfly-integration
  selector:
    app: wildfly-integration
  type: NodePort