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.32 FROM gcr.io/forgerock-io/rcs:$FROM_TAGDuring the
docker buildphase, use the--build-argflag to specify thegcr.io/forgerock-io/rcsrepository parent image tag for building the RCS image. For example:docker build --build-arg FROM_TAG=1.5.20.32 -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 scriptsCopy local files into the
/opt/openicflocation in the parent RCS image to extend or modify its functionality. Theopenicfinstallation folder structure can be replicated locally to copy everything at once, or separateCOPYinstructions can be used for individual folders and files, which can help cache respective layers in the final image.The RCS parent image Dockerfilespecifies a working directory:WORKDIR /opt/openicf. In theCOPYinstruction destination, use an absolute path or a path relative to theWORKDIRlocation. -
Use root user for operations requiring escalated privileges.
Dockerfile excerpt# 3. Use root user for operations that require escalated permissions. # @example # USER rootBy 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
Dockerfilethat 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
Dockerfileexcerpt example, a public certificate is added to the Javatruststoreto allow RCS communications with an otherwise untrusted host, for instance, a third-party API. The destination of theCOPYinstruction, in this case, can be any accessible location within the image, because the change is applied using a command provided in theRUNinstruction, 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 11111After performing any specific instructions that require elevated permissions, switch back to the non-root user using the
USERinstruction.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 runcommand with the--useror-uflag.
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.32 -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 theconnectorServerNameproperty in the connector server configuration. -
IDM saves the Name value as the
nameproperty of aremoteConnectorClientsentry in theprovisioner.openicf.connectorinfoprovider.jsonfile.
Configuring RCS
To configure RCS in client mode, define at least the following RCS configuration properties:
-
connectorserver.urlTo 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.urlwhen 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
.envfile:.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 runand 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_OPTSin a file (.envin 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 rcsThis lets you set sensitive and dynamic properties without embedding them into the image.
You can substitute values using
OPENICF_OPTSto 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.