OpenMRS Supply-Chain Security Features
Three features protect the OpenMRS build and release pipeline. Together, they cover the
full chain: artifacts are signed when published, verified when consumed, and
Docker images are signed so deployers can prove where an image came from.
Feature | What it protects | Where it lives |
|---|---|---|
Artifact signing & checksums | Maven artifacts ( | This parent POM ( |
PGP verification | Downloaded |
|
Cosign for Docker | Reference Application release images |
|
1. Artifact signing & checksums (Maven / GPG)
What it does
When a module built on this parent POM is released, maven-gpg-plugin signs every
published artifact with the OpenMRS Bot code-signing key, producing a detached .asc
signature next to each file. Maven also publishes the standard .md5 / .sha1
checksums. This is what PGP verification (below) later checks against.
Signing is off by default (gpg.skip=true) so ordinary local builds don't need a
key. It turns on automatically when a passphrase is supplied.
How to use it
Inherit this parent POM in your module (no extra config needed):
<parent>
<groupId>org.openmrs.maven.parents</groupId>
<artifactId>maven-parent-openmrs-module</artifactId>
<version><!-- latest --></version>
</parent>Signing activates when you release with a passphrase, via either:
# environment variable (used in CI)
MAVEN_GPG_PASSPHRASE=... mvn deploy
# or a Maven property
mvn deploy -Dgpg.passphrase=...Both switch gpg.skip to false automatically. The openmrs-module-signing
integration test in this repo exercises the whole flow with an ephemeral key.
Backfilling old artifacts
Artifacts published before signing existed can be covered by a script that downloads
existing artifacts and generates the missing .md5, .sha1, .sha256, and .asc
files:
backfill-gpg-signatures.sh.
2. PGP verification (openmrs-pgpverify-maven-plugin)
What it does
Verifies that resolved org.openmrs artifacts were signed by the OpenMRS Bot key
before the build proceeds. It only checks a whitelist of groupIds (defaultorg.openmrs, verified against key CA12619FDE8CD6A93FAFE458A6F9608DCC73473F) and
ignores everything else, so it stays version-independent and doesn't need every
third-party dependency enumerated.
The signing key is pinned by fingerprint: a key fetched from a keyserver or keyring
is trusted only if its fingerprint (or its master key's) matches the allowed set, so no
server can swap in a different key under the same id.
It has two goals:
verify: checks the resolved dependency tree; bound to theverifyphase.verify-files: checks an explicit list of files you already downloaded (used by
the SDK when it fetches modules/WARs into a distribution).
How to use it
In a module build (already wired into this parent POM, nothing to add). To use it
standalone:
<plugin>
<groupId>org.openmrs.maven.plugins</groupId>
<artifactId>openmrs-pgpverify-maven-plugin</artifactId>
<version><!-- latest release --></version>
<executions>
<execution>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>With no configuration it verifies org.openmrs.* against the Bot key.
Useful parameters:
Parameter | Default | Purpose |
|---|---|---|
|
| Whitelisted groupIds and their allowed fingerprints. |
| none | External keys file (local path or |
|
| Where keys are fetched by id. |
| none | Local/remote public key rings, consulted before the key server (enables offline verification). |
|
| Fail when a whitelisted artifact has no |
|
| Verify SNAPSHOT artifacts too. |
|
| Skip the check. |
In the SDK (work in progress): support for the SDK to call verify-files on theorg.openmrs artifacts it downloads during openmrs-sdk:setup andopenmrs-sdk:build-distro is under development and not yet released.
3. Cosign for Docker (Reference Application images)
What it does
Every Reference Application release image is signed with
cosign using keyless (OIDC) signing, where GitHub
Actions' identity is the signer and the signature is recorded in the public
Sigstore transparency log. There is no private key to manage. Signed images include the backend
(and its DB / no-demo / nightly-with-data variants), frontend, gateway, certbot, and
monitoring-init.
How it's produced
Each build-* workflow in openmrs-distro-referenceapplication runs, after pushing the
image:
permissions:
id-token: write # required for keyless signing via OIDC
- name: Install cosign
uses: sigstore/cosign-installer@... # v3.9.2
- name: Sign the image (keyless)
run: cosign sign --yes "${IMAGE}@${DIGEST}"Signing uses the image digest, not the tag, so it always signs exactly what was
pushed.
How to verify an image
Anyone pulling an image can confirm it came from the OpenMRS release pipeline:
cosign verify openmrs/openmrs-reference-application-3-backend:<version> \
--certificate-identity-regexp 'https://github.com/openmrs/openmrs-distro-referenceapplication/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.comThe command succeeds only if the image was signed by that repository's workflow.