ICF 1.5.20.30

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:

  1. 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 the gcr.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 .
  2. 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. The openicf installation folder structure can be replicated locally to copy everything at once, or separate COPY 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 the COPY instruction destination, use an absolute path or a path relative to the WORKDIR location.
    Files and directories
    • openicf/conf

      Provide a custom version of the openicf/conf/ConnectorServer.properties file. Specify all or some RCS configuration properties in this file, as described in Configure a remote connector server (RCS).

    • openicf/connectors

      Add custom or downloaded connectors packaged in JAR files into this sub-directory.

    • openicf/lib

      Add any additional dependencies used by connectors into this sub-directory. For example, required database drivers.

      Provide a customized version of the openicf/conf/logback.xml file to overwrite the default one. This adjusts the detail of logs produced by the RCS, as described in Connector logs.

      You can find the resulting log files in a running container within the /opt/openicf/logs folder. Logs are printed to standard output by the container in the default attached mode or can be requested explicitly from the container with the docker logs command.

    • openicf/scripts

      Add scripted connector Groovy scripts to this directory.

    • openicf/security

      Contains the default RCS keystore and truststore.

    You can copy any other content the connectors need to any other accessible location within the connector server image.
  3. 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 specifies USER 11111.

    However, some instructions require elevated permissions. For example, adding an untrusted certificate to the Java truststore requires root user privileges.

  4. 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 Java truststore to allow RCS communications with an otherwise untrusted host, for instance, a third-party API. The destination of the COPY instruction, in this case, can be any accessible location within the image, because the change is applied using a command provided in the RUN 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.
  5. 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 the connectorServerName property in the connector server configuration.

  • IDM saves the Name value as the name property of a remoteConnectorClients entry in the provisioner.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 for connectorserver.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:

  1. Set environment variables with an .env file:

    .env file content
    OPENICF_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?
  2. 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:

  1. 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?"
  2. 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.