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, visit https://www.forgerock.com, or send an email to ForgeRock at info@forgerock.com.
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-6.1.0.war
from the
ForgeRock BackStage download site
.
Copy (or move) and rename the .war file to the sample directories:
$ cp IG-6.1.0.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.
The following directories are used:
IG_INSTANCE_DIR is
/var/openig
CATALINA_HOME is
/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.
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.
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.
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.
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
Go to http://openig.example.com:8080 to view the IG welcome page and confirm that your IG image is running.
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:
Complete the tutorial in "Deploying a Base Image in Docker".
If an IG image is still running, stop it as described in "Stopping a Docker Image".
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.
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
.From
/path/to/openig-devops-guide/docker/sample2-config
, run the Docker instruction to build a new Docker image calledsample2-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.
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.
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
Test that IG is running on http://openig.example.com:8080/hello.
A page displaying the "Hello World" statement is displayed.
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
Browse to https://console.cloud.google.com/apis/credentials.
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
In a terminal window, go to
/path/to/openig-devops-guide/docker/sample3-oidc
.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
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
andClientRegistration
are defined in the heap. The registration refers to the issueraccounts.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 aStaticResponseHandler
, 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:
Complete the tutorial in "Deploying a Base Image in Docker".
If an IG image is still running, stop it as described in "Stopping a Docker Image".
After running the procedure, remember to stop the IG instance by pressing CTRL-C in the terminal that is running Tomcat.
In a terminal window, go to
/path/to/openig-devops-guide/docker/sample3-oidc
.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.
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.
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
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 intoattributes.openid
. The outermost chain then calls the static response handler.
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 (mutable 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 (immutable 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. Studio is effectively disabled, and you cannot manage, list, or even read routes through Common REST.By default, other endpoints, such as
/monitoring
,/share
, andapi/info
are exposed to the loopback address only. To change the default protection for specific endpoints, configure an ApiProtectionFilter inadmin.json
and add it to the IG configuration.
The default mode is development. For information about making the configuration immutable, see "To Make the Configuration Immutable" in the Gateway Guide.