From 3fcbd8ffc5828666447256f52abdf592ff3bfd4d Mon Sep 17 00:00:00 2001 From: Will Mooreston Date: Thu, 28 May 2026 11:03:21 -0700 Subject: [PATCH 1/2] Migrate credentials to LabKey native SSM integration (26.6+) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace ECS-injected credential secrets (POSTGRES_USER, POSTGRES_PASSWORD, LABKEY_EK, SMTP_USER, SMTP_PASSWORD) with LabKey's native SSM integration via AwsParameterStoreEnvironmentPostProcessor: - application.properties: add context.awsParameterStore.prefix and ssm: references for the 5 credentials; old @@placeholder@@ lines kept as comments for non-AWS reference - entrypoint.sh: add SSM prefix normalization and non-AWS fallback (replaces ssm: references with direct env var values when LABKEY_SSM_PREFIX is unset); remove AWS credential unset so JVM can reach SSM; remove credential sed/unset - docker-compose.yml: add LABKEY_SSM_PREFIX, LABKEY_VPC_SSM_PREFIX, AWS credential forwarding, and direct credential fallbacks for non-AWS local use - README.md, CLAUDE.md: document SSM integration, updated env var tables, updated runtime flow description ⚠️ HOLD until LabKey/server#1388 merges. Targets develop / LabKey 26.6+. Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 76 ++++++++++++++++++++++++++++++++++++++++ README.md | 33 +++++++++++++++++- application.properties | 21 ++++++++---- docker-compose.yml | 78 +++++++++++++++++++++++++++++++++--------- entrypoint.sh | 44 +++++++++++++++++------- quickstart_envs.sh | 2 +- 6 files changed, 217 insertions(+), 37 deletions(-) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..2993b62 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,76 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What This Repo Does + +Builds and publishes Docker images for LabKey Server (a biomedical data management platform) to AWS ECR. A single `Dockerfile` produces multiple distributions (`community`, `enterprise`, `lims_starter`, `allpg`) via the `LABKEY_DISTRIBUTION` build arg. + +## Common Commands + +```bash +# Local development cycle +make build # Build image locally (uses local .jar if present) +make up # Run community via docker-compose (https://localhost:8443) +make up-enterprise # Run enterprise distribution +make up-lims_starter +make down # Tear down containers +make test # Run smoke.bash health check against running container + +# Lint +# Hadolint runs in CI; run locally via: +docker run --rm -i hadolint/hadolint < Dockerfile + +# AWS ECR workflow +make login # Authenticate to ECR +make tag # Tag image for ECR +make push # Push to ECR +make all # login → build → tag → push (default) +``` + +## Architecture + +### Build Flow + +`Dockerfile` downloads the LabKey `.tar.gz` from a URL (or uses a local `.jar` file placed in the repo root for development). The `LABKEY_VERSION` and `LABKEY_DISTRIBUTION` build args control which artifact is fetched. Base image is `eclipse-temurin:25-jre-noble` (Debian); Alpine variant is also supported. + +### Runtime + +`entrypoint.sh` is the container entry point. It: +1. Validates required `LABKEY_*` env vars (excludes `*SSM*`, `*GUID*`, `*MEK*`, initial-user vars) +2. Optionally downloads startup properties from S3 +3. Handles SSM vs. non-AWS mode: if `LABKEY_SSM_PREFIX` is set, normalizes trailing slashes on both prefix vars; otherwise removes the `context.awsParameterStore.prefix` line and substitutes `ssm:` references in `application.properties` with direct env var values +4. Runs `envsubst` on all `.properties` files, then `sed` to substitute `@@placeholder@@` values +5. Generates a self-signed TLS keystore via `openssl` +6. Unsets connection/SMTP env vars, then `exec`s `java -jar labkeyServer.jar` + +### Multi-Distribution + +The `startup/` directory contains per-distribution `.properties` files (`community.properties`, `enterprise.properties`, etc.). The `LABKEY_DISTRIBUTION` env var selects which file is copied in at build time and passed to the JVM. + +### Configuration Surface + +Almost all runtime behavior is controlled via environment variables. The major groups are documented in `README.md`: +- **DB**: `POSTGRES_*` — connection, pooling +- **App**: `LABKEY_*` — version, distribution, base URL, encryption key, initial user +- **SSM (AWS, 26.6+)**: `LABKEY_SSM_PREFIX` (app-level prefix) and `LABKEY_VPC_SSM_PREFIX` (VPC-level prefix) — when set, DB credentials (`database_user`, `database_password`), encryption key (`ek`), and SMTP credentials (`smtp_user`, `smtp_password`) are fetched from SSM instead of env vars; see `application.properties` for the `ssm:` references and `README.md` for the full SSM parameter table +- **JVM**: `JAVA_*`, `MAX_JVM_RAM_PERCENT`, `JAVA_PRE_JAR_EXTRA` / `JAVA_POST_JAR_EXTRA` +- **SSL**: `CERT_*`, `TOMCAT_KEYSTORE_*` +- **Observability**: Datadog APM (`dd-java-agent.jar` baked in), `LOG_LEVEL_*`, `LOGGER_PATTERN` +- **Debug**: `DEBUG=1` installs extra tools (ping, netcat, vim, etc.) at runtime + +### CI/CD (GitHub Actions) + +| Workflow | Trigger | +|----------|---------| +| `hadolint.yml` | Push to `fb_*` / `*_fb_*`; PRs to develop/release* | +| `validate_pr.yml` | PR opened/ready for review | +| `merge_release.yml` | PR review approved (auto-merges release branches) | +| `dockle_xeol.yml` | Security scanning | +| `branch_release.yml` | Release branch automation | + +Feature branches follow the pattern `fb_` or `_fb_`. + +### Local JAR Development + +Place a `labkeyServer.jar.*` file in the repo root (already gitignored). The `Makefile` detects it and uses it as the build artifact instead of downloading from a remote URL, enabling local iteration without publishing. \ No newline at end of file diff --git a/README.md b/README.md index b6f9b7a..8fef138 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,7 @@ A better description of the LabKey settings can be found in the LabKey docs [her | LABKEY_DISTRIBUTION | "flavor" of labkey; | `community` | | LABKEY_FILES_ROOT | path within which will serve as the root of the "files" directory | `/labkey/files` | | LABKEY_GUID | LabKey [server GUID](https://www.labkey.org/Documentation/wiki-page.view?name=stagingServerTips#guid) | `` | -| LABKEY_EK | LabKey [encryption key](https://www.labkey.org/Documentation/wiki-page.view?name=cpasxml#encrypt) | `123abc456` | +| LABKEY_EK | LabKey [encryption key](https://www.labkey.org/Documentation/wiki-page.view?name=cpasxml#encrypt); not needed when using AWS SSM integration (see below) | `123abc456` | | LABKEY_PORT | port to which labkey will bind within the container | `8443` | | LABKEY_SYSTEM_DESCRIPTION | brief description of server; appears in emails | `Sirius Cybernetics` | | LABKEY_SYSTEM_EMAIL_ADDRESS | email address system email will be sent "from" | `do_not_reply@localhost` | @@ -216,6 +216,8 @@ Initial user API key creation was implemented in LabKey Server 20.11. The `POSTGRES_*` default values are meant to match those of the [library/postgres](https://hub.docker.com/_/postgres) containers. +`POSTGRES_USER` and `POSTGRES_PASSWORD` are not needed when using AWS SSM integration (see below). + | name | purpose | default | | ------------------- | ------------------------------------------------------------------------- | ----------- | | POSTGRES_DB | "name" of database; compounds to URI connection string | `postgres` | @@ -229,6 +231,8 @@ The `POSTGRES_*` default values are meant to match those of the [library/postgre These replace values previously housed in `context.xml` (`ROOT.xml` or `labkey.xml`) governing `mail/Session` resources. +`SMTP_USER` and `SMTP_PASSWORD` are not needed when using AWS SSM integration (see below). + | name | purpose | default | | ------------- | --------------------------- | ----------- | | SMTP_HOST | SMTP host configuration | `localhost` | @@ -239,6 +243,33 @@ These replace values previously housed in `context.xml` (`ROOT.xml` or `labkey.x | SMTP_AUTH | SMTP Auth flag | `false` | | SMTP_STARTTLS | SMTP STARTTLS flag | `` | +## AWS SSM Integration (LabKey 26.6+) + +For AWS deployments on LabKey 26.6+, DB credentials, the encryption key, and SMTP credentials can be resolved directly from AWS SSM Parameter Store by the JVM at startup, rather than being injected as container env vars. This uses LabKey's `AwsParameterStoreEnvironmentPostProcessor`. + +Set two path-prefix env vars and create the corresponding SSM parameters: + +| name | purpose | example | +| ---------------------- | ----------------------------------------------------- | -------------------------- | +| `LABKEY_SSM_PREFIX` | App-specific SSM prefix (DB creds, encryption key) | `/myapp/myenv/` | +| `LABKEY_VPC_SSM_PREFIX`| VPC-level shared SSM prefix (SMTP credentials) | `/shared/vpc/myvpc/` | + +Trailing slashes on both prefixes are normalized automatically by `entrypoint.sh`. + +**Expected SSM parameters:** + +| SSM path | replaces env var | +| ----------------------------------------- | ------------------- | +| `${LABKEY_SSM_PREFIX}database_user` | `POSTGRES_USER` | +| `${LABKEY_SSM_PREFIX}database_password` | `POSTGRES_PASSWORD` | +| `${LABKEY_SSM_PREFIX}ek` | `LABKEY_EK` | +| `${LABKEY_VPC_SSM_PREFIX}smtp_user` | `SMTP_USER` | +| `${LABKEY_VPC_SSM_PREFIX}smtp_password` | `SMTP_PASSWORD` | + +When `LABKEY_SSM_PREFIX` is set, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `LABKEY_EK`, `SMTP_USER`, and `SMTP_PASSWORD` env vars are not used. When `LABKEY_SSM_PREFIX` is unset (local / non-AWS), the container falls back to those env vars as before. + +In ECS, the container task role provides credentials via IMDS — no AWS credential env vars needed. For local testing with SSM, export `AWS_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN` (or use aws-vault) so the JVM can reach SSM. + ## SSL/Keystore/Self-signed Cert The `CERT_*` ENVs should look familiar to anyone that has used the `openssl` command to generate a pkcs12 keystore. diff --git a/application.properties b/application.properties index 795b4d2..0f2084d 100644 --- a/application.properties +++ b/application.properties @@ -18,10 +18,15 @@ context.resources.jdbc.labkeyDataSource.driverClassName=org.postgresql.Driver # context.resources.jdbc.labkeyDataSource.username=${POSTGRES_USER:-postgres} # context.resources.jdbc.labkeyDataSource.password=${POSTGRES_PASSWORD:-} -context.resources.jdbc.labkeyDataSource.url=@@jdbcUrl@@ -context.resources.jdbc.labkeyDataSource.username=@@jdbcUser@@ -context.resources.jdbc.labkeyDataSource.password=@@jdbcPassword@@ +# AWS SSM prefix for resolving ssm: references below. Set LABKEY_SSM_PREFIX to /${app_param_path} (e.g. /myapp/myenv/). +# Leave unset for non-AWS deployments as the post-processor is a no-op when no ssm: values are present. +context.awsParameterStore.prefix=${LABKEY_SSM_PREFIX} +context.resources.jdbc.labkeyDataSource.url=@@jdbcUrl@@ +# context.resources.jdbc.labkeyDataSource.username=@@jdbcUser@@ +# context.resources.jdbc.labkeyDataSource.password=@@jdbcPassword@@ +context.resources.jdbc.labkeyDataSource.username=ssm:database_user +context.resources.jdbc.labkeyDataSource.password=ssm:database_password context.resources.jdbc.labkeyDataSource.maxTotal=${POSTGRES_MAX_TOTAL_CONNECTIONS} context.resources.jdbc.labkeyDataSource.maxIdle=${POSTGRES_MAX_IDLE_CONNECTIONS} context.resources.jdbc.labkeyDataSource.maxWaitMillis=${POSTGRES_MAX_WAIT_MILLIS} @@ -57,7 +62,8 @@ server.ssl.key-store=${LABKEY_HOME}/${TOMCAT_KEYSTORE_FILENAME} # server.ssl.key-store-password=${TOMCAT_KEYSTORE_PASSWORD} server.ssl.key-store-type=${TOMCAT_KEYSTORE_FORMAT} -context.encryptionKey=@@encryptionKey@@ +# context.encryptionKey=@@encryptionKey@@ +context.encryptionKey=ssm:ek # @@ -69,9 +75,12 @@ server.servlet.context-path=/_ server.error.whitelabel.enabled=false mail.smtpHost=@@smtpHost@@ -mail.smtpUser=@@smtpUser@@ +# mail.smtpUser=@@smtpUser@@ +# LABKEY_VPC_SSM_PREFIX is the VPC-level shared SSM path prefix (e.g. /shared/vpc/myvpc/), expanded by envsubst at startup. +mail.smtpUser=ssm:${LABKEY_VPC_SSM_PREFIX}smtp_user mail.smtpPort=@@smtpPort@@ -mail.smtpPassword=@@smtpPassword@@ +# mail.smtpPassword=@@smtpPassword@@ +mail.smtpPassword=ssm:${LABKEY_VPC_SSM_PREFIX}smtp_password mail.smtpAuth=@@smtpAuth@@ mail.smtpFrom=@@smtpFrom@@ mail.smtpStartTlsEnable=@@smtpStartTlsEnable@@ diff --git a/docker-compose.yml b/docker-compose.yml index dadad2d..e715f6a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,7 +36,6 @@ services: - LOGGER_PATTERN=%-80.80logger{79} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-a"placeholder#'password} - POSTGRES_HOST=pg-community - MAX_JVM_RAM_PERCENT=${MAX_JVM_RAM_PERCENT:-75.0} @@ -48,13 +47,24 @@ services: - SMTP_HOST=${SMTP_HOST} - SMTP_AUTH=true - SMTP_PORT=587 - - SMTP_USER=${SMTP_USER} - - SMTP_PASSWORD=${SMTP_PASSWORD} - SMTP_STARTTLS=true - LABKEY_SYSTEM_EMAIL_ADDRESS=${SMTP_FROM} # - SMTP_FROM= + - LABKEY_SSM_PREFIX=${LABKEY_SSM_PREFIX} + - LABKEY_VPC_SSM_PREFIX=${LABKEY_VPC_SSM_PREFIX} + - AWS_REGION=${AWS_REGION} + - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} + - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} + - AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} + # non-AWS: set these to supply credentials directly instead of via SSM + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-} + - POSTGRES_USER=${POSTGRES_USER:-} + - LABKEY_EK=${LABKEY_EK:-} + - SMTP_USER=${SMTP_USER:-} + - SMTP_PASSWORD=${SMTP_PASSWORD:-} + # uncomment to enable CAS against labkey.org # - | # LABKEY_STARTUP_BASIC_EXTRA=' @@ -83,7 +93,7 @@ services: - LOG4J_CONFIG_FILE=${LOG4J_CONFIG_FILE-log4j2.xml} - LOG4J_CONFIG_OVERRIDE=${LOG4J_CONFIG_OVERRIDE} - JSON_OUTPUT=${JSON_OUTPUT-false} - - DD_COLLECT_APM=${DD_COLLECT_APM-false} + - DD_COLLECT_APM=${DD_COLLECT_APM-false} - SLEEP=${SLEEP:-0} pg-community: @@ -99,7 +109,8 @@ services: - "-c" - "docker-entrypoint.sh postgres >/dev/null 2>&1" environment: - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-a"placeholder#'password} + - POSTGRES_USER=${POSTGRES_USER:-postgres} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-localdevpassword} healthcheck: test: ["CMD", "pg_isready", "-U", "postgres"] interval: 30s @@ -148,7 +159,6 @@ services: - LOGGER_PATTERN=%-80.80logger{79} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-a"placeholder#'password} - POSTGRES_HOST=pg-allpg - MAX_JVM_RAM_PERCENT=${MAX_JVM_RAM_PERCENT:-75.0} @@ -160,13 +170,24 @@ services: - SMTP_HOST=${SMTP_HOST} - SMTP_AUTH=true - SMTP_PORT=587 - - SMTP_USER=${SMTP_USER} - - SMTP_PASSWORD=${SMTP_PASSWORD} - SMTP_STARTTLS=true - LABKEY_SYSTEM_EMAIL_ADDRESS=${SMTP_FROM} # - SMTP_FROM= + - LABKEY_SSM_PREFIX=${LABKEY_SSM_PREFIX} + - LABKEY_VPC_SSM_PREFIX=${LABKEY_VPC_SSM_PREFIX} + - AWS_REGION=${AWS_REGION} + - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} + - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} + - AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} + # non-AWS: set these to supply credentials directly instead of via SSM + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-} + - POSTGRES_USER=${POSTGRES_USER:-} + - LABKEY_EK=${LABKEY_EK:-} + - SMTP_USER=${SMTP_USER:-} + - SMTP_PASSWORD=${SMTP_PASSWORD:-} + # uncomment to enable CAS against labkey.org # - | # LABKEY_STARTUP_BASIC_EXTRA=' @@ -211,7 +232,8 @@ services: - "-c" - "docker-entrypoint.sh postgres >/dev/null 2>&1" environment: - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-a"placeholder#'password} + - POSTGRES_USER=${POSTGRES_USER:-postgres} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-localdevpassword} healthcheck: test: ["CMD", "pg_isready", "-U", "postgres"] interval: 30s @@ -258,7 +280,6 @@ services: - LOGGER_PATTERN=%-80.80logger{79} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-a"placeholder#'password} - POSTGRES_HOST=pg-enterprise - MAX_JVM_RAM_PERCENT=${MAX_JVM_RAM_PERCENT:-75.0} @@ -270,13 +291,24 @@ services: - SMTP_HOST=${SMTP_HOST} - SMTP_AUTH=true - SMTP_PORT=587 - - SMTP_USER=${SMTP_USER} - - SMTP_PASSWORD=${SMTP_PASSWORD} - SMTP_STARTTLS=true - LABKEY_SYSTEM_EMAIL_ADDRESS=${SMTP_FROM} # - SMTP_FROM= + - LABKEY_SSM_PREFIX=${LABKEY_SSM_PREFIX} + - LABKEY_VPC_SSM_PREFIX=${LABKEY_VPC_SSM_PREFIX} + - AWS_REGION=${AWS_REGION} + - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} + - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} + - AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} + # non-AWS: set these to supply credentials directly instead of via SSM + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-} + - POSTGRES_USER=${POSTGRES_USER:-} + - LABKEY_EK=${LABKEY_EK:-} + - SMTP_USER=${SMTP_USER:-} + - SMTP_PASSWORD=${SMTP_PASSWORD:-} + # uncomment to enable CAS against labkey.org # - | # LABKEY_STARTUP_BASIC_EXTRA=' @@ -321,7 +353,8 @@ services: - "-c" - "docker-entrypoint.sh postgres >/dev/null 2>&1" environment: - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-a"placeholder#'password} + - POSTGRES_USER=${POSTGRES_USER:-postgres} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-localdevpassword} healthcheck: test: ["CMD", "pg_isready", "-U", "postgres"] interval: 30s @@ -369,7 +402,6 @@ services: - LOGGER_PATTERN=%-80.80logger{79} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-a"placeholder#'password} - POSTGRES_HOST=pg-lims_starter - MAX_JVM_RAM_PERCENT=${MAX_JVM_RAM_PERCENT:-75.0} @@ -381,13 +413,24 @@ services: - SMTP_HOST=${SMTP_HOST} - SMTP_AUTH=true - SMTP_PORT=587 - - SMTP_USER=${SMTP_USER} - - SMTP_PASSWORD=${SMTP_PASSWORD} - SMTP_STARTTLS=true - LABKEY_SYSTEM_EMAIL_ADDRESS=${SMTP_FROM} # - SMTP_FROM= + - LABKEY_SSM_PREFIX=${LABKEY_SSM_PREFIX} + - LABKEY_VPC_SSM_PREFIX=${LABKEY_VPC_SSM_PREFIX} + - AWS_REGION=${AWS_REGION} + - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} + - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} + - AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} + # non-AWS: set these to supply credentials directly instead of via SSM + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-} + - POSTGRES_USER=${POSTGRES_USER:-} + - LABKEY_EK=${LABKEY_EK:-} + - SMTP_USER=${SMTP_USER:-} + - SMTP_PASSWORD=${SMTP_PASSWORD:-} + # uncomment to enable CAS against labkey.org # - | # LABKEY_STARTUP_BASIC_EXTRA=' @@ -435,7 +478,8 @@ services: - "-c" - "docker-entrypoint.sh postgres >/dev/null 2>&1" environment: - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-a"placeholder#'password} + - POSTGRES_USER=${POSTGRES_USER:-postgres} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-localdevpassword} healthcheck: test: ["CMD", "pg_isready", "-U", "postgres"] interval: 30s diff --git a/entrypoint.sh b/entrypoint.sh index e05c7c0..0e4e3fc 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -88,6 +88,7 @@ main() { | grep -vE 'MEK' \ | grep -vE 'STARTUP' \ | grep -vE 'INITIAL_USER' \ + | grep -vE 'SSM' \ ; ); do if [ -z "${key_value#*=}" ]; then @@ -153,11 +154,27 @@ main() { # echo "deleting awscli and unsetting AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, & AWS_SESSION_TOKEN, if set..." # rm -rf awsclibin aws-cli - unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN + # Note: AWS credential env vars are intentionally NOT unset here — they are needed by the + # Java process for SSM resolution at startup. In ECS they are not present as env vars + # (the JVM uses the container role via IMDS), so not unsetting them there is harmless. # echo "sleeping for $SLEEP seconds..." # sleep $SLEEP + if [ -n "${LABKEY_SSM_PREFIX:-}" ]; then + # AWS SSM mode: normalize trailing slashes so both /prefix and /prefix/ forms work + LABKEY_SSM_PREFIX="${LABKEY_SSM_PREFIX%/}/" + export LABKEY_SSM_PREFIX + if [ -n "${LABKEY_VPC_SSM_PREFIX:-}" ]; then + LABKEY_VPC_SSM_PREFIX="${LABKEY_VPC_SSM_PREFIX%/}/" + export LABKEY_VPC_SSM_PREFIX + fi + else + # Non-AWS mode: remove the SSM prefix property before envsubst so LabKey doesn't + # error on an empty context.awsParameterStore.prefix value + sed -i '/context.awsParameterStore.prefix=/d' config/application.properties + fi + for prop_file in startup/*.properties config/application.properties; do envsubst < "$prop_file" > "${prop_file}.tmp" \ && mv "${prop_file}.tmp" "$prop_file" @@ -210,21 +227,24 @@ main() { -passin "pass:${keystore_pass}" fi - echo "Adding secrets to config/application.properties from environment variables..." - sed -i "s/@@jdbcUrl@@/jdbc:postgresql:\/\/${POSTGRES_HOST:-localhost}:${POSTGRES_PORT:-5432}\/${POSTGRES_DB:-${POSTGRES_USER}}${POSTGRES_PARAMETERS:-}/" config/application.properties - sed -i "s/@@jdbcUser@@/${POSTGRES_USER:-postgres}/" config/application.properties - sed -i "s/@@jdbcPassword@@/${POSTGRES_PASSWORD:-}/" config/application.properties + echo "Substituting placeholders in config/application.properties..." + if [ -z "${LABKEY_SSM_PREFIX:-}" ]; then + # Non-AWS mode: replace ssm: references with direct values from environment variables + sed -i "s|ssm:database_user|${POSTGRES_USER:-postgres}|" config/application.properties + sed -i "s|ssm:database_password|${POSTGRES_PASSWORD:-}|" config/application.properties + sed -i "s|ssm:ek|${LABKEY_EK:-}|" config/application.properties + sed -i "s|ssm:smtp_user|${SMTP_USER:-}|" config/application.properties + sed -i "s|ssm:smtp_password|${SMTP_PASSWORD:-}|" config/application.properties + fi + + sed -i "s/@@jdbcUrl@@/jdbc:postgresql:\/\/${POSTGRES_HOST:-localhost}:${POSTGRES_PORT:-5432}\/${POSTGRES_DB}${POSTGRES_PARAMETERS:-}/" config/application.properties sed -i "s/@@smtpHost@@/${SMTP_HOST}/" config/application.properties - sed -i "s/@@smtpUser@@/${SMTP_USER}/" config/application.properties sed -i "s/@@smtpPort@@/${SMTP_PORT}/" config/application.properties - sed -i "s/@@smtpPassword@@/${SMTP_PASSWORD}/" config/application.properties sed -i "s/@@smtpAuth@@/${SMTP_AUTH}/" config/application.properties sed -i "s/@@smtpFrom@@/${SMTP_FROM}/" config/application.properties sed -i "s/@@smtpStartTlsEnable@@/${SMTP_STARTTLS}/" config/application.properties - sed -i "s/@@encryptionKey@@/${LABKEY_EK}/" config/application.properties - # Check if we want JSON output, and/or if we are using the base log4j2.xml config export LOG4J_CONFIG_OPTION="" if [ "${JSON_OUTPUT}" = "true" ] && [ "${LOG4J_CONFIG_FILE}" = "log4j2.xml" ]; then @@ -283,10 +303,10 @@ main() { sleep $SLEEP echo "Purging secrets and other bits from environment variables..." - unset POSTGRES_USER POSTGRES_PASSWORD POSTGRES_HOST POSTGRES_PORT POSTGRES_DB POSTGRES_PARAMETERS - unset SMTP_HOST SMTP_USER SMTP_PORT SMTP_PASSWORD SMTP_AUTH SMTP_FROM SMTP_STARTTLS + unset POSTGRES_HOST POSTGRES_PORT POSTGRES_DB POSTGRES_PARAMETERS + unset SMTP_HOST SMTP_PORT SMTP_AUTH SMTP_FROM SMTP_STARTTLS unset LABKEY_CREATE_INITIAL_USER LABKEY_CREATE_INITIAL_USER_APIKEY LABKEY_INITIAL_USER_APIKEY LABKEY_INITIAL_USER_EMAIL LABKEY_INITIAL_USER_GROUP LABKEY_INITIAL_USER_ROLE - unset LABKEY_EK SLEEP CONTAINER_PRIVATE_IP + unset SLEEP CONTAINER_PRIVATE_IP # shellcheck disable=SC2086 exec java \ diff --git a/quickstart_envs.sh b/quickstart_envs.sh index f36a061..eb97930 100644 --- a/quickstart_envs.sh +++ b/quickstart_envs.sh @@ -3,7 +3,7 @@ # example minimal set of environment variables to get started - see readme for additional envs you may wish to set # embedded tomcat LabKey .jar version to build container with -export LABKEY_VERSION="26.3" +export LABKEY_VERSION="26.6" # minimal SMTP settings export SMTP_HOST="localhost" From dbb4407eaf9c026cd2a354ff9d9c40f600fb8063 Mon Sep 17 00:00:00 2001 From: Will Mooreston Date: Mon, 1 Jun 2026 10:06:50 -0700 Subject: [PATCH 2/2] Fix non-AWS default credentials to match postgres service defaults POSTGRES_PASSWORD and POSTGRES_USER in LabKey services now default to localdevpassword/postgres, matching the postgres service defaults, so make up works without setting any env vars. Co-Authored-By: Claude Sonnet 4.6 --- docker-compose.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index e715f6a..f40a403 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -59,8 +59,8 @@ services: - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} - AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} # non-AWS: set these to supply credentials directly instead of via SSM - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-} - - POSTGRES_USER=${POSTGRES_USER:-} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-localdevpassword} + - POSTGRES_USER=${POSTGRES_USER:-postgres} - LABKEY_EK=${LABKEY_EK:-} - SMTP_USER=${SMTP_USER:-} - SMTP_PASSWORD=${SMTP_PASSWORD:-} @@ -182,8 +182,8 @@ services: - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} - AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} # non-AWS: set these to supply credentials directly instead of via SSM - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-} - - POSTGRES_USER=${POSTGRES_USER:-} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-localdevpassword} + - POSTGRES_USER=${POSTGRES_USER:-postgres} - LABKEY_EK=${LABKEY_EK:-} - SMTP_USER=${SMTP_USER:-} - SMTP_PASSWORD=${SMTP_PASSWORD:-} @@ -303,8 +303,8 @@ services: - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} - AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} # non-AWS: set these to supply credentials directly instead of via SSM - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-} - - POSTGRES_USER=${POSTGRES_USER:-} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-localdevpassword} + - POSTGRES_USER=${POSTGRES_USER:-postgres} - LABKEY_EK=${LABKEY_EK:-} - SMTP_USER=${SMTP_USER:-} - SMTP_PASSWORD=${SMTP_PASSWORD:-} @@ -425,8 +425,8 @@ services: - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} - AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} # non-AWS: set these to supply credentials directly instead of via SSM - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-} - - POSTGRES_USER=${POSTGRES_USER:-} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-localdevpassword} + - POSTGRES_USER=${POSTGRES_USER:-postgres} - LABKEY_EK=${LABKEY_EK:-} - SMTP_USER=${SMTP_USER:-} - SMTP_PASSWORD=${SMTP_PASSWORD:-}