Configuring Moderne DX
Moderne DX is a secure, fully on-premises, enterprise-level automated code remediation solution. At its heart is a central service that must be configured for everything to work correctly. This guide will walk you through how to do that.
Moderne DX setup instructions
Step 1: Determine how you will run the service
There are two ways you can run the DX service:
- You can use Java to run a Spring Boot executable JAR
- You can create a Docker image that downloads and runs the executable JAR
Regardless of which option you pick, we recommend that you dedicate a minimum of 2 CPU cores, 8 GB of memory, and at least 10 GB of persistent storage.
Moderne DX can be found on Maven Central. From there, you can select the latest version and download the appropriate JAR to either run or to configure your image with.
If you deploy to Kubernetes or any other containerized environment like AWS ECS, you'll want to create a Docker image to run the service.
If you deploy to a PaaS environment such Cloud Foundry, you'll want to use the JAR to run the service.
The table below provides some core information for running the service. However, in order for the service to function correctly, additional variables will need to be added based on your environment (such as what artifact repositories you have configured, and whether or not you've configured an Organizations service). We'll walk through each of those in the following steps.
- Docker image
- Executable JAR
How to build the Docker image
docker build -t moderne-dx:latest .
How to run the image with an environment file
docker run --env-file=moderne-dx.env moderne-dx:latest
How to run the image with command line arguments
# Please note that if you create environment variables for secrets, you still need to let Docker
# know that these variables exist by including it via: `-e ENV_VAR_NAME`.
export MODERNE_DX_TOKEN_0=...
export MODERNE_DX_ARTIFACTORY_0_USERNAME=...
export MODERNE_DX_ARTIFACTORY_0_PASSWORD=...
export MODERNE_DX_MAVEN_0_USERNAME=...
export MODERNE_DX_MAVEN_0_PASSWORD=...
docker run \
-e MODERNE_DX_TOKEN_0 \
-e MODERNE_DX_ARTIFACTORY_0_URL=https://myartifactory.example.com/artifactory/ \
-e MODERNE_DX_ARTIFACTORY_0_USERNAME \
-e MODERNE_DX_ARTIFACTORY_0_PASSWORD \
-e MODERNE_DX_ARTIFACTORY_0_ASTQUERYFILTERS_0='"name":{"$match":"*-ast.jar"}' \
-e MODERNE_DX_ARTIFACTORY_0_ASTQUERYFILTERS_1='"repo":{"$eq":"example-maven"}' \
-e MODERNE_DX_MAVEN_0_URL=https://myartifactory.example.com/artifactory/libs-releases-local \
-e MODERNE_DX_MAVEN_0_LOCALREPOSITORY=~/.moderne-maven \
-e MODERNE_DX_MAVEN_0_USERNAME \
-e MODERNE_DX_MAVEN_0_PASSWORD \
# ... Additional variables to come
-p 8080:8080
moderne-dx:latest
Example Dockerfile
You are responsible for creating this Dockerfile and your own base image. It is your responsibility to keep this up-to-date when vulnerabilities arise. The below one is a suggestion for getting started - but yours will differ from this as it should point to and use your own tools and services.
FROM eclipse-temurin:17-jdk
RUN apt-get update && apt-get install -y libxml2-utils
# Set the environment variable MODERNE_DX_VERSION
ARG MODERNE_DX_VERSION
ENV MODERNE_DX_VERSION=${MODERNE_DX_VERSION}
WORKDIR /app
USER root
RUN groupadd -r app && useradd --no-log-init -r -m -g app app && chown -R app:app /app
USER app
# Download the specified version of moderne-dx JAR file if MODERNE_DX_VERSION is provided,
# otherwise download the latest version
RUN if [ -n "${MODERNE_DX_VERSION}" ]; then \
echo "Downloading version: ${MODERNE_DX_VERSION}"; \
curl -s --insecure --request GET --url "https://repo1.maven.org/maven2/io/moderne/moderne-dx/${MODERNE_DX_VERSION}/moderne-dx-${MODERNE_DX_VERSION}.jar" --output dx.jar; \
else \
LATEST_VERSION=$(curl -s --insecure --request GET --url "https://repo1.maven.org/maven2/io/moderne/moderne-dx/maven-metadata.xml" | xmllint --xpath 'string(/metadata/versioning/latest)' -); \
if [ -z "${LATEST_VERSION}" ]; then \
echo "Failed to get latest version"; \
exit 1; \
fi; \
echo "Downloading latest version: ${LATEST_VERSION}"; \
curl -s --insecure --request GET --url "https://repo1.maven.org/maven2/io/moderne/moderne-dx/${LATEST_VERSION}/moderne-dx-${LATEST_VERSION}.jar" --output dx.jar; \
fi
ENTRYPOINT ["java"]
CMD ["-XX:-OmitStackTraceInFastThrow", "-XX:MaxRAMPercentage=65.0", "-XX:MaxDirectMemorySize=2G", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:+UseStringDeduplication", "-jar", "/app/dx.jar"]
EXPOSE 8080
Example environment variables file
MODERNE_DX_TOKEN_0=${MODERNE_TOKEN}
MODERNE_DX_ARTIFACTORY_0_URL=https://myartifactory.example.com/artifactory/
MODERNE_DX_ARTIFACTORY_0_USERNAME=${ARTIFACTORY_USER}
MODERNE_DX_ARTIFACTORY_0_PASSWORD=${ARTIFACTORY_PASSWORD}
MODERNE_DX_ARTIFACTORY_0_ASTQUERYFILTERS_0='"name":{"$match":"*-ast.jar"}'
MODERNE_DX_ARTIFACTORY_0_ASTQUERYFILTERS_1='"repo":{"$eq":"example-maven"}'
MODERNE_DX_MAVEN_0_URL=https://myartifactory.example.com/artifactory/libs-releases-local
MODERNE_DX_MAVEN_0_LOCALREPOSITORY=~/.moderne-maven
MODERNE_DX_MAVEN_0_USERNAME=${MAVEN_USER}
MODERNE_DX_MAVEN_0_PASSWORD=${MAVEN_PASSWORD}
How to run the service:
Use java
to run a jar in combination with arguments that you'll add in the subsequent steps. The final command will look similar to:
java -jar moderne-dx-{version}.jar \
# ... Additional arguments explained in the following steps
Step 2: Configure the service to connect to your artifact repositories
The Moderne DX service needs to connect to your artifact repositories for two reasons:
- To obtain information about your LST artifacts so that the CLI can list and potentially grab them.
- To obtain your recipe artifacts (if any exist). These recipe artifacts contain custom recipes, defined by your team, that perform transformations against your LST artifacts.
Your company might have many artifact repositories, potentially in different products, that you wish to connect the Moderne DX service to. Each of these artifact repositories could contain LST artifacts, recipe artifacts, or a combination of both. The setup instructions differ based on what product you use to store your artifact repositories and what artifacts you wish to send to Moderne.
The Moderne DX service can only talk to Maven formatted artifact repositories. There are a variety of open-source and commercial products that exist that can serve artifacts in this format (such as Artifactory and Sonatype Nexus). A single instance of one of these products may contain multiple Maven repositories.
Moderne offers two options for connecting to your artifact repository: a generic Maven connection that can connect to any Maven formatted repository regardless of vendor and an Artifactory-specific connection that is optimized to serve LST artifacts more quickly.
If you do not plan on using Artifactory to store LST or recipe artifacts, please follow the Maven repository configuration instructions and then jump to Step 4.
If you do plan on using Artifactory to store artifacts, you have two options:
- Use the Artifactory LST configuration instructions to set up a connection that gets the list of LST artifacts. Then, if you plan on creating custom recipes, you would follow the Artifactory recipe configuration instructions to set up a connection in Artifactory to serve recipe artifacts. (recommended)
- Use the Maven repository configuration instructions to set up a connection that serves both LST artifacts and recipe artifacts to Moderne. This is not recommended as LST artifacts will have a considerable delay between being published and being available in the CLI. However, if for some reason you can not use AQL queries, this approach is necessary.
The below table shows the key differences between the two types of configuration:
Maven repository configuration | Artifactory repository configuration |
---|---|
Is not tied to a particular vendor. | Can only be used with Artifactory. |
Serves BOTH recipe artifacts and LST artifacts. | Serves ONLY LST artifacts. Requires Maven configuration to serve recipe artifacts. |
Recipe artifacts are immediately available for deployment to Moderne upon publishing to the Maven formatted repository. | Can not serve recipe artifacts without Maven configuration. |
LST artifacts may be served if an index in the Maven Indexer format is regularly published to the repository. There will be a considerable delay between when an LST is published to the Maven repository and when it is available in the Moderne CLI. This delay is approximately the delay between updates to the index – which is controlled by a batch process that your artifact repository executes on a schedule. | LST artifacts will be available in near-real time (within a minute or two) in the Moderne CLI when they are published to Artifactory. This is because Artifactory configuration uses Artifactory Query Language (AQL) to identify recently published artifacts. AQL queries Artifactory's internal relational database for information about artifacts rather than using an index produced in a batch process. |
Please ensure you've followed either the Maven or Artifactory instructions before continuing.
Below is an example of what the Moderne DX service run command might look like at the end of this step.
token[N]
/ TOKEN_N
is used to specify one or more tokens that can be used by admins.
- Docker image
- Executable JAR
# Please note that if you create environment variables for secrets, you still need to let Docker
# know that these variables exist by including it via: `-e ENV_VAR_NAME`.
export MODERNE_DX_TOKEN_0=...
export MODERNE_DX_ARTIFACTORY_0_USERNAME=...
export MODERNE_DX_ARTIFACTORY_0_PASSWORD=...
export MODERNE_DX_MAVEN_0_USERNAME=...
export MODERNE_DX_MAVEN_0_PASSWORD=...
docker run \
-e MODERNE_DX_TOKEN_0 \
-e MODERNE_DX_ARTIFACTORY_0_URL=https://myartifactory.example.com/artifactory/ \
-e MODERNE_DX_ARTIFACTORY_0_USERNAME \
-e MODERNE_DX_ARTIFACTORY_0_PASSWORD \
-e MODERNE_DX_ARTIFACTORY_0_ASTQUERYFILTERS_0='"name":{"$match":"*-ast.jar"}' \
-e MODERNE_DX_ARTIFACTORY_0_ASTQUERYFILTERS_1='"repo":{"$eq":"example-maven"}' \
-e MODERNE_DX_MAVEN_0_URL=https://myartifactory.example.com/artifactory/libs-releases-local \
-e MODERNE_DX_MAVEN_0_LOCALREPOSITORY=~/.moderne-maven \
-e MODERNE_DX_MAVEN_0_USERNAME \
-e MODERNE_DX_MAVEN_0_PASSWORD \
# ... Additional variables to come
-p 8080:8080
moderne-dx:latest
# Exporting environment variables with the exact same structure as the parameter in the Java command makes it so you no longer need to include them in the below Java command. For instance, the first export below is equivalent to including this parameter in the Java command:
# --moderne.dx.token[0]=...
export MODERNE_DX_TOKEN_0=...
export MODERNE_DX_ARTIFACTORY_0_USERNAME=...
export MODERNE_DX_ARTIFACTORY_0_PASSWORD=...
export MODERNE_DX_MAVEN_0_USERNAME=...
export MODERNE_DX_MAVEN_0_PASSWORD=...
java -jar moderne-dx-{version}.jar \
--moderne.dx.artifactory[0].url=https://myartifactory.example.com/artifactory/ \
--moderne.dx.artifactory[0].astQueryFilters[0]='"name":{"$match":"*-ast.jar"}' \
--moderne.dx.artifactory[0].astQueryFilters[1]='"repo":{"$eq":"example-maven"}' \
--moderne.dx.maven[0].url=https://myartifactory.example.com/artifactory/libs-releases-local \
--moderne.dx.maven[0].localRepository=~/.moderne-maven \
# ... Additional arguments to come
Step 3: Set up Moderne DX License
In order for your developers to run recipes using the CLI, they will need a license. Moderne DX provides a convenient mechanism for distributing license keys. Moderne will send a license key to your admin, and you will provide that license key to DX's startup configuration. When CLI users configure the DX connection with mod config moderne edit
, the CLI will retrieve the license from Moderne DX.
- Docker image
- Executable JAR
export MODERNE_DX_LICENSEKEY=...
docker run \
# ... other arguments
-e MODERNE_DX_LICENSEKEY
# ... Additional variables to come
-p 8080:8080
moderne-dx:latest
# Exporting environment variables with the exact same structure as the parameter in the Java command makes it so you no longer need to include them in the below Java command. For instance, the first export below is equivalent to including this parameter in the Java command:
# --moderne.dx.licenseKey=...
export MODERNE_DX_LICENSEKEY=...
java -jar moderne-dx-{version}.jar \
# ... other arguments
Step 4: (Optionally) Configure an organization structure
Many organizations desire the ability to control the organizational structure of their repositories within the Moderne Platform in a dynamic way. To facilitate this need, Moderne provides two approaches: a file-based one or a service-based one (where you configure an Organizations service that is hosted inside of your environment).
If you want to set up this integration, please follow the instructions in our configuring Organizations with Moderne DX doc.
Below is an example of what the Moderne DX service run command might look like at the end of this step if you set up the Organizations service.
- Docker image
- Executable JAR
export MODERNE_DX_TOKEN_0=...
export MODERNE_DX_ARTIFACTORY_0_USERNAME=...
export MODERNE_DX_ARTIFACTORY_0_PASSWORD=...
export MODERNE_DX_MAVEN_0_USERNAME=...
export MODERNE_DX_MAVEN_0_PASSWORD=...
docker run \
-e MODERNE_DX_TOKEN_0 \
-e MODERNE_DX_ARTIFACTORY_0_URL=https://myartifactory.example.com/artifactory/ \
-e MODERNE_DX_ARTIFACTORY_0_USERNAME \
-e MODERNE_DX_ARTIFACTORY_0_PASSWORD \
-e MODERNE_DX_ARTIFACTORY_0_ASTQUERYFILTERS_0='"name":{"$match":"*-ast.jar"}' \
-e MODERNE_DX_ARTIFACTORY_0_ASTQUERYFILTERS_1='"repo":{"$eq":"example-maven"}' \
-e MODERNE_DX_MAVEN_0_URL=https://myartifactory.example.com/artifactory/libs-releases-local \
-e MODERNE_DX_MAVEN_0_LOCALREPOSITORY=~/.moderne-maven \
-e MODERNE_DX_MAVEN_0_USERNAME \
-e MODERNE_DX_MAVEN_0_PASSWORD \
-e MODERNE_DX_ORGANIZATION_URL=http://localhost:8091 \
-e MODERNE_DX_ORGANIZATION_UPDATE_INTERVAL_SECONDS=600 \
-e MODERNE_DX_ORGANIZATION_DEFAULTCOMMITOPTIONS=PullRequest,Branch,Direct \
# ... Additional variables to come
-p 8080:8080
moderne-dx:latest
# Exporting environment variables with the exact same structure as the parameter in the Java command makes it so you no longer need to include them in the below Java command. For instance, the first export below is equivalent to including this parameter in the Java command:
# --moderne.dx.token[0]=...
export MODERNE_DX_TOKEN_0=...
export MODERNE_DX_ARTIFACTORY_0_USERNAME=...
export MODERNE_DX_ARTIFACTORY_0_PASSWORD=...
export MODERNE_DX_MAVEN_0_USERNAME=...
export MODERNE_DX_MAVEN_0_PASSWORD=...
java -jar moderne-dx-{version}.jar \
--moderne.dx.artifactory[0].url=https://myartifactory.example.com/artifactory/ \
--moderne.dx.artifactory[0].astQueryFilters[0]='"name":{"$match":"*-ast.jar"}' \
--moderne.dx.artifactory[0].astQueryFilters[1]='"repo":{"$eq":"example-maven"}' \
--moderne.dx.maven[0].url=https://myartifactory.example.com/artifactory/libs-releases-local \
--moderne.dx.maven[0].localRepository=~/.moderne-maven \
--moderne.dx.organization.url=http://localhost:8091 \
--moderne.dx.organization.updateIntervalSeconds=600 \
--moderne.dx.organization.defaultCommitOptions=PullRequest,Branch,Direct \
Step 5: (Optionally) Use strict recipe sources.
Some organizations want recipe artifacts to only come from locations configured in the Moderne DX service. If you want to configure that, please follow the strict recipe sources instructions.
Below is an example of what the Moderne DX service run command might look like at the end of this step if you configured the service to use only configured recipe sources.
- Docker image
- Executable JAR
# Please note that if you create environment variables for secrets, you still need to let Docker
# know that these variables exist by including it via: `-e ENV_VAR_NAME`.
export MODERNE_DX_TOKEN_0=...
export MODERNE_DX_ARTIFACTORY_0_USERNAME=...
export MODERNE_DX_ARTIFACTORY_0_PASSWORD=...
export MODERNE_DX_MAVEN_0_USERNAME=...
export MODERNE_DX_MAVEN_0_PASSWORD=...
docker run \
-e MODERNE_DX_TOKEN_0 \
-e MODERNE_DX_ARTIFACTORY_0_URL=https://myartifactory.example.com/artifactory/ \
-e MODERNE_DX_ARTIFACTORY_0_USERNAME \
-e MODERNE_DX_ARTIFACTORY_0_PASSWORD \
-e MODERNE_DX_ARTIFACTORY_0_ASTQUERYFILTERS_0='"name":{"$match":"*-ast.jar"}' \
-e MODERNE_DX_ARTIFACTORY_0_ASTQUERYFILTERS_1='"repo":{"$eq":"example-maven"}' \
-e MODERNE_DX_MAVEN_0_URL=https://myartifactory.example.com/artifactory/libs-releases-local \
-e MODERNE_DX_MAVEN_0_LOCALREPOSITORY=~/.moderne-maven \
-e MODERNE_DX_MAVEN_0_USERNAME \
-e MODERNE_DX_MAVEN_0_PASSWORD \
-e MODERNE_DX_ORGANIZATION_URL=http://localhost:8091 \
-e MODERNE_DX_ORGANIZATION_UPDATE_INTERVAL_SECONDS=600 \
-e MODERNE_DX_RECIPE_USEONLYCONFIGURED=true \
-e MODERNE_DX_ORGANIZATION_DEFAULTCOMMITOPTIONS=PullRequest,Branch,Direct \
-p 8080:8080
moderne-dx:latest
# Exporting environment variables with the exact same structure as the parameter in the Java command makes it so you no longer need to include them in the below Java command. For instance, the first export below is equivalent to including this parameter in the Java command:
# --moderne.dx.token[0]=...
export MODERNE_DX_TOKEN_0=...
export MODERNE_DX_ARTIFACTORY_0_USERNAME=...
export MODERNE_DX_ARTIFACTORY_0_PASSWORD=...
export MODERNE_DX_MAVEN_0_USERNAME=...
export MODERNE_DX_MAVEN_0_PASSWORD=...
java -jar moderne-dx-{version}.jar \
--moderne.dx.artifactory[0].url=https://myartifactory.example.com/artifactory/ \
--moderne.dx.artifactory[0].astQueryFilters[0]='"name":{"$match":"*-ast.jar"}' \
--moderne.dx.artifactory[0].astQueryFilters[1]='"repo":{"$eq":"example-maven"}' \
--moderne.dx.maven[0].url=https://myartifactory.example.com/artifactory/libs-releases-local \
--moderne.dx.maven[0].localRepository=~/.moderne-maven \
--moderne.dx.organization.url=http://localhost:8091 \
--moderne.dx.organization.updateIntervalSeconds=600 \
--moderne.dx.organization.defaultCommitOptions=PullRequest,Branch,Direct \
--moderne.dx.recipe.useOnlyConfigured=true
Step 6: (Optionally) Provide SSL client keystore
If you have configured any services that require client SSL certificates (such as Maven or Artifactory), you will need to provide a KeyStore with these certificates. Please see the configure DX with SSL certificate instructions.
Step 7: Run the service
At this point, you should have configured everything needed to run the Moderne DX service. If you run into issues running the command, please don't hesitate to reach out.
Below is a table that has instructions for how to run the service in combination with some examples of the variables/arguments provided in the previous steps:
- Docker image
- Executable JAR
- Rebuild your Docker image with the latest JAR and any other changes you need to make.
- Run the
docker run
command in combination with all of the environment variables you've added in the previous steps:
# Please note that if you create environment variables for secrets, you still need to let Docker
# know that these variables exist by including it via: `-e ENV_VAR_NAME`.
export MODERNE_DX_TOKEN_0=...
export MODERNE_DX_ARTIFACTORY_0_USERNAME=...
export MODERNE_DX_ARTIFACTORY_0_PASSWORD=...
export MODERNE_DX_MAVEN_0_USERNAME=...
export MODERNE_DX_MAVEN_0_PASSWORD=...
docker run \
-e MODERNE_DX_TOKEN_0 \
-e MODERNE_DX_ARTIFACTORY_0_URL=https://myartifactory.example.com/artifactory/ \
-e MODERNE_DX_ARTIFACTORY_0_USERNAME \
-e MODERNE_DX_ARTIFACTORY_0_PASSWORD \
-e MODERNE_DX_ARTIFACTORY_0_ASTQUERYFILTERS_0='"name":{"$match":"*-ast.jar"}' \
-e MODERNE_DX_ARTIFACTORY_0_ASTQUERYFILTERS_1='"repo":{"$eq":"example-maven"}' \
-e MODERNE_DX_MAVEN_0_URL=https://myartifactory.example.com/artifactory/libs-releases-local \
-e MODERNE_DX_MAVEN_0_LOCALREPOSITORY=~/.moderne-maven \
-e MODERNE_DX_MAVEN_0_USERNAME \
-e MODERNE_DX_MAVEN_0_PASSWORD \
-e MODERNE_DX_ORGANIZATION_URL=http://localhost:8091 \
-e MODERNE_DX_ORGANIZATION_UPDATE_INTERVAL_SECONDS=600 \
-e MODERNE_DX_ORGANIZATION_DEFAULTCOMMITOPTIONS=PullRequest,Branch,Direct \
-p 8080:8080
moderne-dx:latest
Use java
to run a jar in combination with arguments that you've added in the previous steps:
# Exporting environment variables with the exact same structure as the parameter in the Java command makes it so you no longer need to include them in the below Java command. For instance, the first export below is equivalent to including this parameter in the Java command:
# --moderne.dx.token[0]=...
export MODERNE_DX_TOKEN_0=...
export MODERNE_DX_ARTIFACTORY_0_USERNAME=...
export MODERNE_DX_ARTIFACTORY_0_PASSWORD=...
export MODERNE_DX_MAVEN_0_USERNAME=...
export MODERNE_DX_MAVEN_0_PASSWORD=...
java -jar moderne-dx-{version}.jar \
--moderne.dx.artifactory[0].url=https://myartifactory.example.com/artifactory/ \
--moderne.dx.artifactory[0].astQueryFilters[0]='"name":{"$match":"*-ast.jar"}' \
--moderne.dx.artifactory[0].astQueryFilters[1]='"repo":{"$eq":"example-maven"}' \
--moderne.dx.maven[0].url=https://myartifactory.example.com/artifactory/libs-releases-local \
--moderne.dx.maven[0].localRepository=~/.moderne-maven \
--moderne.dx.organization.url=http://localhost:8091 \
--moderne.dx.organization.updateIntervalSeconds=600 \
--moderne.dx.organization.defaultCommitOptions=PullRequest,Branch,Direct \
- Note: System properties can be used in place of arguments. For example, you can use
-Dmoderne.dx.token={token_value}
as an argument instead of--moderne.dx.token={token_value}
.
Updating your service
If you want to update the Moderne DX service over time, please follow the instructions in the table below:
- Docker image
- Executable JAR
Update your Dockerfile to contain the latest DX JAR. Then rebuild your Docker image and restart your Docker instance by running the docker run ...
command again.
To update your version of the Executable JAR, change the {version}
in java -jar moderne-dx-{version}.jar
to be the latest DX JAR.