Deploy Java RCS in a Docker container
You can deploy the Java Remote Connector Server (RCS) in a Docker container. This topic outlines the process to obtain, customize, configure, and run RCS using a Docker environment. The RCS download includes a sample dockerfile at path/to/openicf/docker/Dockerfile
.
Getting started
You can pull RCS images from the gcr.io/forgerock-io/rcs
image repository in the public Container Registry (browser access requires a Google account).
A public RCS image provides the default installation of the OpenICF (ICF) framework.
Customize the parent RCS image
To extend the parent image functionality, customize it by copying additional files to the ICF installation folder (/opt/openicf
) in the final image. Additional files can include connector packages, scripts, drivers, and so on.
Capture RCS image customizations by saving them in a custom Docker image using a custom Dockerfile
.
The following procedure includes the five example sections from the custom Dockerfile
included with RCS 1.5.20.30 and later:
-
Accept build arguments and select the parent image.
Dockerfile excerpt# 1. Accept build arguments in the FROM instruction. # @example ARG FROM_TAG=1.5.20.30 FROM gcr.io/forgerock-io/rcs:$FROM_TAG
During the
docker build
phase, use the--build-arg
flag to specify thegcr.io/forgerock-io/rcs
repository parent image tag for building the RCS image. For example:docker build --build-arg FROM_TAG=1.5.20.30 -t rcs .
-
Add additional files to the RCS installation.
Dockerfile excerpt# 2. Merge custom files with the RCS installation. # @example COPY openicf/conf conf COPY openicf/connectors connectors COPY openicf/lib lib COPY openicf/scripts scripts
Copy local files into the
/opt/openicf
location in the parent RCS image to extend or modify its functionality. Theopenicf
installation folder structure can be replicated locally to copy everything at once, or separateCOPY
instructions can be used for individual folders and files, which can help cache respective layers in the final image.The RCS parent image Dockerfile
specifies a working directory:WORKDIR /opt/openicf
. In theCOPY
instruction destination, use an absolute path or a path relative to theWORKDIR
location. -
Use root user for operations requiring escalated privileges.
Dockerfile excerpt# 3. Use root user for operations that require escalated permissions. # @example # USER root
By default, a Docker container runs as the root user. It’s recommended to run a Docker container as a non-root user, which is addressed in the RCS parent image
Dockerfile
that typically specifiesUSER 11111
.However, some instructions require elevated permissions. For example, adding an untrusted certificate to the Java truststore requires root user privileges.
-
Add certificates to RCS truststore.
Dockerfile excerpt# 4. Add untrusted public TLS certificate(s) to RCS `truststore` to allow for communications with unrecognized hosts. # Run `docker build` with the `--progress plain` option to check the outcome of the RUN instruction. # @example # COPY openicf/security/BadSSL-Untrusted-Root-Certificate-Authority.cer /opt/openicf/security # RUN keytool -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit -trustcacerts -import -file /opt/openicf/security/BadSSL-Untrusted-Root-Certificate-Authority.cer -alias badssl-com-untrusted-root-ca -noprompt
In the previous
Dockerfile
excerpt example, a public certificate is added to the Javatruststore
to allow RCS communications with an otherwise untrusted host, for instance, a third-party API. The destination of theCOPY
instruction, in this case, can be any accessible location within the image, because the change is applied using a command provided in theRUN
instruction, not directly by ICF.PingOne Advanced Identity Cloud certificates are signed by a trusted CA and don’t need to be added to the truststore
. -
Switch to a non-root user.
Dockerfile excerpt# 5. Switch back to a non-root user. # @example # USER 11111
After performing any specific instructions that require elevated permissions, switch back to the non-root user using the
USER
instruction.During development, you might want to continue as a root user. For example, root privileges are required to enable file sync when using a Docker image in Skaffold development mode. In this case, specify the user in the
docker run
command with the--user
or-u
flag.
Pushing the RCS image to a Docker repository
To share the RCS image and make it available for orchestration tools, push it to a Docker repository.
If the Docker repository is served from a private Docker registry, ensure Docker is configured with appropriate privileges to push to this repository. The Docker registry provider typically provides specific instructions on setting up authentication for Docker.
For example, documentation on setting up authentication for Docker describes how to use the gcloud
credential helper for configuring Docker with Google Cloud CLI session credentials. This can be used while developing RCS images and pushing them to a Google Cloud Artifact Registry.
The image must be tagged before pushing it to a repository. Tag the image with the reference to the repository in the docker build
command using the -t
or --tag
flag. For example:
# Build and tag the image with the repository reference
$ docker build --build-arg FROM_TAG=1.5.20.30 -t gcr.io/<organization>/<username>/rcs .
# Push the tagged image
$ docker push gcr.io/<organization>/<username>/rcs
Registering RCS
Configure the RCS in client mode to connect it to a managed environment, such as Advanced Identity Cloud.
In client mode, the connectorserver.connectorServerName
property must be provided in the RCS configuration. This property must match the registered name in IDM or Advanced Identity Cloud:
-
In Advanced Identity Cloud, a connector server can be registered using the Advanced Identity Cloud admin UI (refer to the documentation on syncing identities and registering a remote server). In the UI, the Name input for a connector server accepts a value containing lower-case alphanumeric characters, hyphens (
-
), and underscores (_
). Advanced Identity Cloud saves the Name value as theconnectorServerName
property in the connector server configuration. -
IDM saves the Name value as the
name
property of aremoteConnectorClients
entry in theprovisioner.openicf.connectorinfoprovider.json
file.
Configuring RCS
To configure RCS in client mode, define at least the following RCS configuration properties:
-
connectorserver.url
To specify more than one connectorserver.url
, separate each value using a comma (,
). Java RCS versions earlier than 1.5.20.26 don’t support multiple values forconnectorserver.url
when using a Docker container. -
connectorserver.connectorServerName
To connect to an Advanced Identity Cloud tenant, the following must also be specified:
-
connectorserver.tokenEndpoint
-
connectorserver.clientId
-
connectorserver.clientSecret
-
connectorserver.scope
To enable more controlled debug output, specify the RCS logger class:
-
connectorserver.loggerClass
Static connector server properties can be provided using instructions included in the openicf/conf/ConnectorServer.properties
file. In addition, the following sample configurations are available in openicf/conf/samples
:
-
ConnectorServer.properties.onprem-server
-
ConnectorServer.properties.onprem-client
-
ConnectorServer.properties.default-parameters
-
ConnectorServer.properties.cloud-client
For example, a ConnectorServer.properties
file could contain the following instructions for setting properties that are unlikely to change and carry no sensitive data and could, therefore, be embedded into the image:
conf/ConnectorServer.properties
# Set connectorserver properties.
# See OpenICF documentation for details:
# https://docs.pingidentity.com/openicf/connector-reference/configure-server.html#rcs-properties
# Set static properties.
connectorserver.scope=fr:idm:*
connectorserver.loggerClass=org.forgerock.openicf.common.logging.slf4j.SLF4JLog
To provide dynamic values in the connector server configuration, which is a suitable approach for secrets and environment specifics, define JVM system properties using the OPENICF_OPTS
environment variable. This variable needs to be exported into the JVM’s environment before the connector server starts. Provide this information when the container runs so it’s not embedded into the image.
Running RCS
Create and run an RCS container with the docker run
command.
In a standalone Docker container, environment variables can be set with one of the -e
, --env
, or --env-file
flags. For example:
-
Set environment variables with an
.env
file:.env file contentOPENICF_OPTS=-Dconnectorserver.url=wss://<your-tenant-url>/openicf/0 -Dconnectorserver.tokenEndpoint=https://<your-tenant-url>/am/oauth2/realms/root/realms/alpha/access_token -Dconnectorserver.connectorServerName=rcs-docker-1 -Dconnectorserver.clientId=RCSClient -Dconnectorserver.clientSecret=YA...H?
-
User
docker run
and supply the environment file:$ docker run --env-file .env rcs
A Docker environment file is limited to one-line variable definitions and can be difficult to read. An alternative approach is defining the environment variable on the host machine and then using the -e
or --env
flag. For example:
-
Define
OPENICF_OPTS
in a file (.env
in this example):# .env file content OPENICF_OPTS="-Dconnectorserver.url=wss://openam-dx-kl04.forgeblocks.com/openicf/0 \ -Dconnectorserver.tokenEndpoint=https://openam-dx-kl04.forgeblocks.com/am/oauth2/realms/root/realms/alpha/access_token \ -Dconnectorserver.connectorServerName=rcs-docker-1 \ -Dconnectorserver.clientId=RCSClient \ -Dconnectorserver.clientSecret=YA...H?"
-
Source the file and run the container:
# Export variables from .env file into the current shell $ set -a; source .env; set +a; # Run the container using the exported variable $ docker run -e OPENICF_OPTS rcs
This lets you set sensitive and dynamic properties without embedding them into the image.
You can substitute values using
OPENICF_OPTS
to address different environments or different connector server names registered in IDM or Advanced Identity Cloud. For example, you could run multiple containers referring to different connector server names registered in a server cluster.
Developing scripted connectors with Docker
The parent RCS image doesn’t ship with any Groovy scripts. While developing scripted connectors, use the docker run
flag -v
or --volume
as a convenient way of providing script content to the running RCS container. For example:
docker run --rm --env-file .env -v ./openicf/scripts:/opt/openicf/scripts rcs
Now, any updates to the scripts made in the ./openicf/scripts
folder on the host machine become available to the RCS running in the container.