Tutorials for deploying ForgeRock® Identity Gateway with Docker, with best practices for containerized deployment in production environments.

Preface

ForgeRock Identity Platform™ serves as the basis for our simple and comprehensive Identity and Access Management solution. We help our customers deepen their relationships with their customers, and improve the productivity and connectivity of their employees and partners. For more information about ForgeRock and about the platform, see https://www.forgerock.com.

1. About This Guide

This document describes how to deploy basic and customized configurations of Identity Gateway through Docker. To help you prepare for production deployments, it describes best practices for managing the secret and public configuration parameters that change from one deployment to another.

In progressive stages, you will configure the software to use OpenID Connect to authenticate to your Google login page, and then deploy that configuration through Docker.

This guide is for:

  • ForgeRock Identity Platform developers who want a first look and easy-to-use example of containerized deployment.

  • Identity Gateway developers who want to configure a production environment for containerized deployment.

Although full instructions are given in the tutorials, it will help to be familiar with the following subjects:

  • ForgeRock Identity Gateway, to edit the basic configuration and test the changes.

  • Docker, to build and run and Docker images. The provided Dockerfiles are extensively commented, and the tutorials contain the Docker instructions and options that you need to use.

  • Git, to clone a Git repository onto your local workspace so that you can download the example and files.

  • OpenID Connect 1.0 and Google Developer Console, to configure the tutorials.

2. Formatting Conventions

Most examples in the documentation are created in GNU/Linux or Mac OS X operating environments. If distinctions are necessary between operating environments, examples are labeled with the operating environment name in parentheses. To avoid repetition file system directory names are often given only in UNIX format as in /path/to/server, even if the text applies to C:\path\to\server as well.

Absolute path names usually begin with the placeholder /path/to/. This path might translate to /opt/, C:\Program Files\, or somewhere else on your system.

Command-line, terminal sessions are formatted as follows:

$ echo $JAVA_HOME
/path/to/jdk

Command output is sometimes formatted for narrower, more readable output even though formatting parameters are not shown in the command.

Program listings are formatted as follows:

class Test {
    public static void main(String [] args)  {
        System.out.println("This is a program listing.");
    }
}

3. Accessing Documentation Online

ForgeRock publishes comprehensive documentation online:

  • The ForgeRock Knowledge Base offers a large and increasing number of up-to-date, practical articles that help you deploy and manage ForgeRock software.

    While many articles are visible to community members, ForgeRock customers have access to much more, including advanced information for customers using ForgeRock software in a mission-critical capacity.

  • ForgeRock product documentation, such as this document, aims to be technically accurate and complete with respect to the software documented. It is visible to everyone and covers all product features and examples of how to use them.

4. Using the ForgeRock.org Site

The ForgeRock.org site has links to source code for ForgeRock open source software, as well as links to the ForgeRock forums and technical blogs.

If you are a ForgeRock customer, raise a support ticket instead of using the forums. ForgeRock support professionals will get in touch to help you.

5. Getting Support and Contacting ForgeRock

ForgeRock provides support services, professional services, training through ForgeRock University, and partner services to assist you in setting up and maintaining your deployments. For a general overview of these services, see https://www.forgerock.com.

ForgeRock has staff members around the globe who support our international customers and partners. For details on ForgeRock's support offering, including support plans and service level agreements (SLAs), visit https://www.forgerock.com/support.

Chapter 1. Before You Start

This guide describes how to deploy IG with Docker, using a set of sample files provided in https://github.com/ForgeRock/openig-devops-guide GitHub.

For information about deploying IG using DevOps techniques, where an IG runs in Kubernetes, see Deploying the IG Example in the ForgeRock Identity Platform Devops Guide.

Using containers and Docker to deploy IG simplifies deployment, especially when you deploy multiple instances.

1.1. About the Sample Files

The sample files and IG configurations used in this guide are available for you to clone or download from a Git repository. This section describes the repository and files, and describes how to get a local copy of the files.

The sample files are stored in https://github.com/ForgeRock/openig-devops-guide. The repository contains a folder for each tutorial:

  • docker/sample1-base contains the Dockerfile you need to create and run an IG base image. "Deploying a Base Image in Docker" describes how to build and run the image.

  • docker/sample2-config contains an IG configuration to display a simple "Hello World" page, and a Dockerfile that refers to the base image. "Deploying a Basic Configuration in Docker" describes how to add the IG configuration, and build and run a new image.

  • docker/sample3-oidc contains an IG configuration to use a social login to access a page and a Dockerfile that refers to the base image. "Deploying a Configuration With OpenID Connect 1.0 in Docker" describes how to create and use client data in the configuration, and build and run a new image.

The samples are supported on macOS and native Linux hosts, and are tested on Docker 17.06.

Some operating systems require you create a docker group or to run the commands with sudo.

1.2. Getting the Sample Files

Commands used in this guide assume that you store the sample files in /path/to/openig-devops-guide. Adapt the commands if you use a different directory.

Clone or download the sample files:

  • To clone the files, go to your installation directory and run this command:

    $ git clone https://github.com/ForgeRock/openig-devops-guide.git

    The sample directories and files are copied into /path/to/openig-devops-guide.

  • To download the files, go to the Git repository on https://github.com/ForgeRock/openig-devops-guide and select Clone or Download > Download ZIP.

    Move and unzip the downloaded folder into your installation directory. The tutorial folders are in /path/to/openig-devops-guide.

1.3. Getting the IG .war File

Download IG-5.5.2.war from the ForgeRock BackStage download site .

Copy (or move) and rename the .war file to the sample directories:

$ cp IG-5.5.2.war /path/to/openig-devops-guide/docker/sample1-base/openig.war

1.4. Configuring the Network

The samples in /path/to/openig-devops-guide/docker run Docker on your local machine, where the IP address is usually 127.0.0.1. Add the following entry to your /etc/hosts file:

127.0.0.1  localhost  openig.example.com

1.5. Choosing a Port

The samples in this guide run IG on port 8080. Before you run any Docker images, make sure that port 8080 is available. Alternatively, use a different port and adjust the commands accordingly.

To run a Docker image on a port other than 8080, in the Docker run command replace my-port with the other port number:

$ docker run -p <my-port>:8080 <docker-image>

Chapter 2. Deploying a Base Image in Docker

This chapter describes how to deploy IG by building and running a Docker image. At the end of this chapter, you can access the IG welcome page.

2.1. Understanding the Configuration

The Dockerfile for sample1-base is in /path/to/openig-devops-guide/docker/sample1-base. It contains a series of instructions to specify the installation environment for IG, the location of the IG .war file, the web container, installation directories, environment variables, and port numbers to use.

OPENIG_BASE and the IG configuration files are in the following directories:

  • OPENIG_BASE in /var/openig

  • CATALINA_HOME in /usr/local/tomcat

The Dockerfile uses the IG .war file to build the base image. The Dockerfiles in the other samples build on this base image.

To help you to customize your installation, the Dockerfile is commented with information about the configuration options that you can change. Read the Dockerfile to understand the configuration options.

2.2. Building and Running the IG Base Image

Before you start:

  • Read and follow the instructions in "Before You Start". You should have Docker installed, the sample files and the IG .war file downloaded, and the network configured.

  • Make sure that port 8080 is not being used, or, alternatively, replace port 8080 as described in "Choosing a Port".

  • Start Docker or make sure it is running.

After running the procedure, remember to stop the IG instance by pressing CTRL-C in the terminal that is running Tomcat.

To Build and Run a Docker Image
  1. In a terminal window, go to /path/to/openig-devops-guide/docker/sample1-base.

    Take a moment to review the Dockerfile in that directory. The commands and options in the Dockerfile are used to build the IG image.

  2. Run the Docker instruction to build a Docker image called forgerock/openig-base:

    $ docker build -t forgerock/openig-base .

    It takes a few minutes to build a base image. While it is building, the status is displayed. When it is built, a success message is displayed along with the ID of the image.

  3. Check that the base image is built:

    $ docker images
    REPOSITORY                  TAG                  IMAGE ID            CREATED             SIZE
    forgerock/openig-base       latest               5a063649fc87        57 seconds ago      428 MB

    The forgerock/openig-base image should be listed in the repository.

  4. Run the Docker image on port 8080:

    $ docker run -p 8080:8080 forgerock/openig-base

    Tomcat starts up and the console displays the IG message log. Read the message log to see the progress of the startup. When the startup is complete, a message similar to this is displayed:

    org.apache.catalina.startup.Catalina.start Server startup in 8385 ms

  5. Go to http://openig.example.com:8080 to view the IG welcome page and confirm that your IG image is running.

  6. In the terminal that is running the Docker image, press CTRL-C to stop the image.

2.3. Stopping a Docker Image

If a Docker image is running in the foreground, press CTRL-C in the terminal that is running Tomcat.

If a Docker image is running in the background:

  • List the Docker images that are running:

    $ docker ps
    CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS . . .
    fe3768b9c55f        forgerock/openig-base   "/usr/local/tomcat/bi"   11 minutes ago      Up 11 minutes . . .

  • If an image has the status Up, use the container ID to stop the image:

    docker stop fe3768b9c55f

Chapter 3. Deploying a Basic Configuration in Docker

This chapter describes how to make a small change to the configuration of IG and then build and run a new Docker image with the changed configuration. This chapter demonstrates how easy it is to propagate a configuration change into a Docker image.

3.1. Understanding the Configuration

The Dockerfile for sample2-config uses the base image created in "Deploying a Base Image in Docker", and specifies the location of the IG configuration files.

The IG configuration file configures a static response handler to return a simple "Hello World" page when the URI of a request finishes with /hello.

3.2. Customizing IG and Building a New Docker Image

Before you start:

To Customize IG and Build a New Docker Image
  1. In a terminal window, go to /path/to/openig-devops-guide/docker/sample2-config.

    Take a moment to review the Dockerfile in that directory. The Dockerfile refers to base image you built in "Deploying a Base Image in Docker", and adds the new IG configuration.

  2. Review the IG configuration file custom-config/config/routes/01-hello.json:

    {
      "handler": {
        "type": "StaticResponseHandler",
        "config" : {
          "status": 200,
          "reason": "OK",
          "entity": "Hello, world! Your route is ${request.uri.path}"
        }
      },
      "condition": "${matches(request.uri.path, '^/hello')}"
    }

    This configuration contains a static response handler to return a "Hello World" statement when the URI of a request finishes with /hello.

  3. From /path/to/openig-devops-guide/docker/sample2-config, run the Docker instruction to build a new Docker image called sample2-config:

    $ docker build -t sample2-config .
    Step 1 : FROM forgerock/openig-base:latest
     ---> a93fdd6074b8
    Step 2 : ADD custom-config /var/openig
     ---> a720e5472a76
    Removing intermediate container 1507feec0b39

    When the image is built, a success message is displayed along with the ID of the image.

  4. Check that the new image is built:

    $ docker images
    REPOSITORY              TAG                 IMAGE ID            CREATED              SIZE
    sample2-config          latest              a720e5472a76        About a minute ago   428 MB
    forgerock/openig-base   latest              a93fdd6074b8        3 minutes ago        428 MB

    The sample2-config image should be in the list of repositories.

  5. Run the Docker image on port 8080:

    $ docker run -p 8080:8080 sample2-config

    Tomcat starts up and the console displays the IG message log. Read the message log to see the progress of the startup. When the startup is complete, a message similar to this is displayed:

    org.apache.catalina.startup.Catalina.start Server startup in 8385 ms

  6. Test that IG is running on http://openig.example.com:8080/hello.

    A page displaying the "Hello World" statement is displayed.

  7. In the terminal that is running the Docker image, press CTRL-C to stop the image.

Chapter 4. Deploying a Configuration With OpenID Connect 1.0 in Docker

This chapter describes how to set up a more complex configuration of IG that uses OpenID Connect 1.0 and Google credentials to log you in to a web page.

4.1. Understanding the Configuration

The Dockerfile for sample3-oidc refers to the base image from "Deploying a Base Image in Docker", and specifies the location of the IG configuration files. The OAuth 2.0 credentials you add to this file are referenced in the IG configuration.

The IG configuration file is described in "Reviewing the IG Configuration".

4.2. Setting Up OAuth 2.0 Credentials

To Set Up OAuth 2.0 Credentials
  1. Browse to https://console.cloud.google.com/apis/credentials.

  2. Create credentials for an OAuth 2.0 client ID with the following options:

    • Application type: Web application

    • Authorized redirect URI: http://openig.example.com:8080/openid/callback

    A client ID and a client secret are created. Make a note of their values or keep the site open for the next step.

4.3. Preparing the Dockerfile

To Prepare the Dockerfile
  1. In a terminal window, go to /path/to/openig-devops-guide/docker/sample3-oidc.

  2. Edit the Dockerfile to replace <your-client-ID> and <your-client-secret> with the values you created in "Setting Up OAuth 2.0 Credentials":

    FROM forgerock/openig-base:latest
    
    #  Replace <your-client-ID> and <your-client-secret> with your own values.
    ENV CLIENT_ID <your-client-ID>
    ENV CLIENT_SECRET <your-client-secret>
    #  These environment variables are referenced in the openid.json config file.
    #  To override these values, pass them as environment variables in the docker run command.
    
    ADD custom-config /var/openig

4.4. Reviewing the IG Configuration

To Review the IG Configuration
  • Review the IG configuration file /custom-config/config/routes/07-openid.json:

    {
      "heap": [
        {
          "name": "accounts.google.com",
          "type": "Issuer",
          "config": {
            "wellKnownEndpoint": "https://accounts.google.com/.well-known/openid-configuration"
          }
        },
        {
          "name": "OidcRelyingParty",
          "type": "ClientRegistration",
          "config": {
            "clientId": "${env['CLIENT_ID']}",
            "clientSecret": "${env['CLIENT_SECRET']}",
            "issuer": "accounts.google.com",
            "scopes": [
              "openid",
              "profile"
            ]
          }
        },
        {
          "name": "capture",
          "type": "CaptureDecorator",
          "config": {
            "captureEntity": true,
            "_captureContext": true
          }
        }
      ],
      "handler": {
        "type": "Chain",
        "capture": "all",
        "config": {
          "filters": [
            {
              "type": "OAuth2ClientFilter",
              "config": {
                "clientEndpoint": "/openid",
                "requireHttps": false,
                "requireLogin": true,
                "registrations": "OidcRelyingParty",
                "target": "${attributes.openid}",
                "failureHandler": {
                  "type": "StaticResponseHandler",
                  "config": {
                    "comment": "Trivial failure handler for debugging only",
                    "status": 500,
                    "reason": "Error",
                    "entity": "${attributes.openid}"
                  }
                }
              }
            }
          ],
          "handler": {
            "type": "StaticResponseHandler",
            "config": {
              "status": 200,
              "entity": "<html><h1>Welcome to the OIDC Test Page</h1><body><p><b>Your are:</b> ${attributes.openid.user_info.name}</p><p><b>Working on host:</b> ${env['HOSTNAME']}</p></body></html>"
            }
          }
        }
      },
      "condition": "${matches(request.uri.path, '^/openid')}"
    }

    Notice the following features of the route:

    • The Issuer and ClientRegistration are defined in the heap. The registration refers to the issuer accounts.google.com as as the OpenID provider.

      For more information, see Issuer(5) in the Configuration Reference and ClientRegistration(5) in the Configuration Reference.

    • The OAuth2ClientFilter enables IG to act as a relying party, referring to the client registration.

      The client endpoint /openid causes requests to /openid start the delegated authorization process.

      For convenience in this test, "requireHttps" is false. In production environments, set it to true. So that you see the delegated authorization process when you make a request, "requireLogin" is true.

      The target for storing authorization state information is ${attributes.openid}. This is where subsequent filters and handlers can find access tokens and user information.

      If the request fails, the failureHandler, in this case a StaticResponseHandler, dumps the information in the context into a web page response. While this is helpful for debugging, in production environments consider returning a more user-friendly failure page.

      The StaticResponseHandler retrieves the user name and host from the context and displays them on a test page.

      For more information, see OAuth2ClientFilter(5) in the Configuration Reference.

    • The route matches requests to /openid.

4.5. Building and Running the OpenID Connect 1.0 Sample

Before you start:

After running the procedure, remember to stop the IG instance by pressing CTRL-C in the terminal that is running Tomcat.

To Build and Run the OpenID Connect 1.0 Sample
  1. In a terminal window, go to /path/to/openig-devops-guide/docker/sample3-oidc.

  2. Run the Docker instruction to build a new Docker image called sample3-oidc:

    $ docker build -t sample3-oidc .
    Sending build context to Docker daemon 14.34 kB
    Step 1 : FROM forgerock/openig-base:latest
     ---> a385ade7625e
    Step 2 : ENV CLIENT_ID . . .
     ---> Running in 14c20dec7d5c
     ---> b8e4ccefbc83
    Removing intermediate container 14c20dec7d5c
    Step 3 : ENV CLIENT_SECRET . . .
     ---> Running in 36eae9fb75c9
     ---> f485785a8a0c
    Removing intermediate container 36eae9fb75c9
    Step 4 : ADD custom-config /var/openig
     ---> fb3e4fdd24fb
    Removing intermediate container 8ce983caface
    Successfully built fb3e4fdd24fb

    The build uses the base image from "Deploying a Base Image in Docker", adds the OAuth 2.0 credentials to the image, and then adds the new IG configuration to the image.

  3. Check that the new image is built:

    $ docker images
    REPOSITORY              TAG                 IMAGE ID            CREATED              SIZE
    sample3-oidc            latest              fb3e4fdd24fb        About a minute ago   428 MB
    sample2-config          latest              a720e5472a76        10 minutes ago       428 MB
    forgerock/openig-base   latest              a93fdd6074b8        20 minutes ago       428 MB

    The sample3-oidc image should be in the list of repositories.

  4. Run the Docker image on port 8080:

    $ docker run -p 8080:8080 sample3-oidc

    Tomcat starts up and the console displays the IG message log. Read the message log to see the progress of the startup. When the startup is complete, a message similar to this is displayed:

    org.apache.catalina.startup.Catalina.start Server startup in 8385 ms

  5. Test the setup on http://openig.example.com:8080/openid.

    Depending on whether you logged out of Google, you might need to authenticate.

    The Google login is used to give you access to the OIDC Test Page, and you are asked to allow access. You should see a screen showing something like this:

    Welcome to the OIDC Test Page
    
    Howdy George Costanza
    You are working on host a0b1c2345d67

    What is happening behind the scenes:

    • After IG gets the browser request, the OAuth2ClientFilter redirects you to authenticate with Google. After authentication, Google returns an access token to the filter.

    • The OAuth2ClientFilter uses the access token to get the user information, and then injects the authorization state information into attributes.openid. The outermost chain then calls the static response handler.

  6. In the terminal that is running the Docker image, press CTRL-C to stop the image.

Chapter 5. Preparing For Production Deployment With Docker

This chapter sets out considerations for deploying IG in multiple containers in a production environment.

5.1. Separating Configuration From Code

Many of the configuration parameters in "Deploying a Configuration With OpenID Connect 1.0 in Docker" are hard-coded into the configuration files. The client ID and client secret, for example, are hard-coded in the Dockerfile. The identity issuer is hard-coded in the IG route.

Although this setup works fine for our example, it has limited use in a production environment, where the values for client ID, client secret, and issuer would probably change from one deploy to another.

Separating configuration parameters from the code has many advantages, including flexibility and security. When the configuration parameters are defined outside the code, the same code can be used in multiple deployments with less need for reconfiguration. When confidential information, such as a client ID or secret, are provided separately to the code, they are less likely to be checked in to version control.

5.1.1. Configuration Parameters to Consider Storing as Environment Variables

This section lists some of the IG configuration parameters that you should consider storing in environment variables instead of in the code.

This list includes secret configuration parameters:

  • Key pair for JWTSession encryption/decryption

  • OIDC client ID and secret

  • AM agent password

  • CryptoHeaderFilter keys

  • KeyStore credentials

This list includes other, non-secret configuration parameters:

  • Host names

  • Port numbers

  • Configuration base

  • baseUri values

  • URLs

  • Redirect URIs

  • SQL data source strings

  • JDBC URL for JDBC audit event handlers

5.1.2. Removing Configuration Parameters from the Dockerfile

In "Deploying a Configuration With OpenID Connect 1.0 in Docker" the client ID and client secret are hard-coded in the Dockerfile, and the identity issuer, Google, is hard-coded in the IG route.

To override the credentials in the Dockerfile, or to set them in the command instead of in the Dockerfile, include the credentials when you run the docker image:

$ docker run --env CLIENT_ID=your-client-ID --env CLIENT_SECRET=your-client-secret -it -p 8080:8080 sample3-oidc

5.2. Making the Deployment Immutable

IG operates in development mode (mutable mode) and production mode (immutable mode):

Development mode

Use development mode to evaluate or demo IG, or to develop configurations on a single instance. This mode is not suitable for production.

In development mode, by default all endpoints are open and accessible. You can create, edit, and deploy routes through IG Studio, and manage routes through Common REST, without authentication or authorization.

To protect specific endpoints in development mode, configure an ApiProtectionFilter in admin.json and add it to the IG configuration.

Production mode

After you have developed your configuration, switch to production mode to test the configuration, to run the software in pre-production or production, or to run multiple instances of the software with the same configuration.

In production mode, the /routes endpoint is not exposed or accessible. IG Studio is effectively disabled, and you cannot manage, list, or even read routes through Common REST.

By default, other endpoints, such as /monitoring, /share, and api/info are exposed to the loopback address only. To change the default protection for specific endpoints, configure an ApiProtectionFilter in admin.json and add it to the IG configuration.

The default mode is development. For information about making the configuration immutable, see "To Switch From Development Mode to Production Mode" in the Gateway Guide.

Read a different version of :