docker run -t -p 4456:4456 \
-v $PWD:/heimdall/conf \
-v /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro \
dadrus/heimdall:dev serve decision \
-c /heimdall/conf/heimdall.yaml
Security
To operate heimdall in a secure way, you should configure heimdall accordingly. Following sections address the corresponding areas.
Defaults
The following configurations and behaviors are enforced by default:
All inbound communication must use TLS. TLS configuration is required for all services and endpoints exposed by heimdall. This enforcement can be disabled (not recommended) by starting Heimdall with the
--insecure-skip-ingress-tls-enforcement
flag.All outbound communication must use TLS. TLS configuration is required for all services and endpoints heimdall communicates with. This enforcement can be disabled (not recommended) by starting Heimdall with the
--insecure-skip-egress-tls-enforcement
flag.If Heimdall is used in proxy mode, communication with upstream services while proxying requests must use TLS. This enforcement can be disabled (not recommended) by starting heimdall with the
--insecure-skip-upstream-tls-enforcement
flag.Configuring the
trusted_proxies
property to allow insecure networks (0.0.0.0/0
,0/0
,0000:0000:0000:0000:0000:0000:0000:0000/0
, and::/0
) is prohibited. See also HTTP Header Security Considerations. This enforcement can be disabled (not recommended) by starting heimdall with the--insecure-skip-secure-trusted-proxies-enforcement
flag.The authentication stage of the default rule cannot start with an insecure authenticator (i.e., authenticators that allow all requests to pass through). This enforcement can be disabled (not recommended) by starting heimdall with the
--insecure-skip-secure-default-rule-enforcement
flag.
For development purposes, all of the above settings can be disabled at once by starting heimdall with the If any of the above enforcement settings are disabled and an insecure configuration is used, warnings will be logged. |
HTTP Header Security Considerations
If trusted_proxies
property is configured (see also the corresponding configuration options) to let heimdall make use of different HTTP headers to build the URL for rule and HTTP method matching purposes, following logic apply:
The value for the used HTTP scheme is taken from the
X-Forwarded-Proto
header.The value for the used HTTP host and port is taken from the
X-Forwarded-Host
header.The value for the used HTTP path is taken from
X-Forwarded-Uri
header, which may also contain query parameters.The value for the used HTTP method is taken from the
X-Forwarded-Method
header.
If the evaluation result for any of the above said steps is empty, the corresponding value is taken from the actual request to heimdall. E.g. if X-Forwarded-Method
is set, the HTTP method used to communicate with heimdall is used for rule matching respectively evaluation purposes.
That means, if the client integrating with heimdall does not make use of the above said headers and does not drop them, a malicious actor could spoof them most probably leading to privileges escalation (depending on your rules). To avoid such situations, please adhere to the following practices:
If you can, try avoiding usage of
trusted_proxies
. Nothing can be spoofed then. However, you will lose the information about the used HTTP scheme, host and port and cannot rely on these in your rules.Configure all headers and use those taking precedence. That is, always set
X-Forwarded-Method
,X-Forwarded-Proto
,X-Forwarded-Host
,X-Forwarded-Uri
.If you cannot influence, which headers are set by your system, you’re integrating with heimdall, let it drop unused ones. E.g. If the proxy forwarding the request to heimdall by default sets only
X-Forwarded-Proto
andX-Forwarded-Host
, let it drop theX-Forwarded-Method
andX-Forwarded-Uri
headers.
The API Gateways & Proxies Guides follow these practices, respectively highlight where caution is required. So, you can find examples there.
Observability Information
Logs, metrics and profiling information is very valuable for operating heimdall. These are however also very valuable for any adversary. For this reason, the corresponding services, exposing such information are by default, if enabled, listening only on the loopback (127.0.0.1
) interface. If you have to configure them to listen to other interfaces, e.g. because you operate heimdall in a container, make sure, you don’t expose them publicly.
TLS Trust Store
As documented in Concepts section, the execution of heimdall’s pipeline typically includes communication to other systems. The endpoints of the corresponding systems should be TLS protected. This is however actually out of scope for heimdall. What is in scope, is the verification of the used TLS server certificate if TLS is used. This happens by making use of the operating system-wide trust store, containing the certificates of Root and Intermediate CAs (trust anchors) shipped with the OS. That means, you should
ensure this trust store contains the certificates of the Root CAs of your PKI hierarchy and
ensure the endpoints, heimdall communicates with over TLS, provide not only their own certificates, but also the intermediate certificates and cross certificates not included within the OS trust store
Both is required to enable heimdall building the certificate chain for TLS server certificate verification purpose. If heimdall fails doing so, the connection will be dropped.
As written above, heimdall makes use of the OS wide trust store to build the certificate chain. The most common installation directory on a Linux system for that trust store is the /etc/ssl/certs
directory. In addition to the separate root and intermediate CA certificates, it also contains a ca-certificates.crt
file, containing all installed certificates as well. This file is used by heimdall for the aforesaid purpose.
heimdall container image is shipped without any certificates by intention to ensure you take care about the up-to-date status of the trust store. This way, if you use heimdall in a container, you have to mount the OS trust store into heimdall’s container to enable its usage. E.g. |
The verification of TLS server certificates is not the single configuration option. You should also ensure heimdall’s services, you’re using, are configured to be available via TLS as well. See TLS Configuration for all available options.
Security Considerations
In a typical production scenario, there is a need for proper key and certificate management. This is supported by heimdall in the following way:
you can and should configure not only the private key for signature creation purposes, but also the corresponding certificate chain. This way your upstream services are able not only to verify the signatures of the signed objects for cryptographic validity, but also perform verification of the revocation status of used certificates and also their time validity. All of that is crucial for secure communication.
The cryptographic material for the above said verification purposes is available via the JWKS endpoint for the upstream services.
you can configure multiple keys in heimdall’s
key_store
and specify thekey_id
of the key to use. The easiest way to let heimdall use the key id, you need, is to setX-Key-ID
header in the PEM block of the corresponding private key (as also shown in the example above). Usage of key ids allows for seamless key rotation in setups which do not support or allow usage of secret management systems, respectively hot reloading of the corresponding updates by heimdall.
Secret Management & Rotation
When configuring heimdall, there are many places requiring secrets, like passwords, tokens, key material, etc. While you can directly configure these in heimdall’s config file, there is a huge chance for leaking them. Please reference the secrets in the config file via environment variables, or make use of external files where possible instead, and let the contents of these be managed by a secret management system.
Usage of external files can even allow you to rotate the configured secrets without the need to restart heimdall if desired. Watching for secrets rotation is however disabled by default, but can be enabled by setting the secrets_reload_enabled
property to true
on the top level of heimdall’s configuration.
As of today secret reloading is only supported for key stores and Redis cache backend credentials. |
Verification of Heimdall Artifacts
Heimdall releases include three types of artifacts: archived binaries, container images, and Helm Charts (as OCI images). Each is signed using Cosign with its keyless signing feature. Additionally, SLSA provenance is generated for all released artifacts, providing a higher level of assurance about the build process in accordance with SLSA Level 3 requirements. This chapter explains how to verify the signatures and provenance for each artifact type.
The Helm Chart is also released to gh-pages, but this version is neither signed nor accompanied by provenance. |
Prerequisites
To verify the artifacts, install the following tools:
crane (for Helm chart OCI image verification)
These tools are required for verifying signatures and provenance across all artifact types.
Container Image Verification
Signature Verification with Cosign
Signatures for container images are stored in dadrus/heimdall-signatures
. To verify a released container image, run:
COSIGN_REPOSITORY=dadrus/heimdall-signatures \
cosign verify dadrus/heimdall:<tag> \
--certificate-identity-regexp=https://github.com/dadrus/heimdall/.github/workflows/release.yaml* \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com | jq
For images from GHCR, use ghcr.io/dadrus/heimdall-signatures and ghcr.io/dadrus/heimdall:<tag> . For dev tagged images, adjust --certificate-identity-regexp to https://github.com/dadrus/heimdall/.github/workflows/ci.yaml* . |
On success, Cosign outputs JSON (similar to the example below) and exits with 0
.
[
{
"critical": {
"identity": {
"docker-reference": "index.docker.io/dadrus/heimdall"
},
"image": {
"docker-manifest-digest": "sha256:289b1a3eeeceeef08362a6fbcf4b95e726686d17998798e149c30b6974728eaf"
},
"type": "cosign container image signature"
},
"optional": {
"1.3.6.1.4.1.57264.1.1": "https://token.actions.githubusercontent.com",
"1.3.6.1.4.1.57264.1.2": "push",
"1.3.6.1.4.1.57264.1.3": "04379639dc5f3fbfc260e883ee4938a35076d63e",
"1.3.6.1.4.1.57264.1.4": "release",
"1.3.6.1.4.1.57264.1.5": "dadrus/heimdall",
"1.3.6.1.4.1.57264.1.6": "refs/tags/v0.16.0",
"Bundle": {
"SignedEntryTimestamp": "MEUCIFIvxs30zysroG6...tQ3U/2yx8Jqu8H75g6sihIcpg=",
"Payload": {
"body": "eyJhcGlWZXJzaW9uIjoi...xTMHRMUW89In19fX0=",
"integratedTime": 1692727396,
"logIndex": 32332529,
"logID": "c0d23d6ad406973f9559...d8ffc5b8445c224f98b9591801d"
}
},
"Issuer": "https://token.actions.githubusercontent.com",
"Subject": "https://github.com/dadrus/heimdall/.github/workflows/release.yaml@refs/tags/v0.16.0",
"githubWorkflowName": "release",
"githubWorkflowRef": "refs/tags/v0.16.0",
"githubWorkflowRepository": "dadrus/heimdall",
"githubWorkflowSha": "04379639dc5f3fbfc260e883ee4938a35076d63e",
"githubWorkflowTrigger": "push"
}
}
]
For released images, the Subject
value ends with @refs/tags/<release version>
, as indicated in the snippet above.
Provenance Verification with slsa-verifier
To verify the SLSA provenance of a container image, first obtain its digest:
IMAGE=$(docker inspect dadrus/heimdall:<tag> | jq -r '.[0].RepoDigests[0]')
# instead of docker, you can also use podman, crane, or similar tools
Then verify:
slsa-verifier verify-image "${IMAGE}" \
--source-uri github.com/dadrus/heimdall \
--source-tag v<tag>
Use ghcr.io/dadrus/heimdall:<tag> for GHCR images. |
On success, slsa-verifier
prints a success message and exits with 0
.
Helm Chart Verification
Signature Verification with Cosign
To verify the Helm Chart OCI image signature, run:
cosign verify ghcr.io/dadrus/heimdall/chart/heimdall:<tag> \
--certificate-identity-regexp=https://github.com/dadrus/heimdall/.github/workflows/release.yaml* \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com | jq
Replace <tag>
with the chart version (e.g., 0.15.0
). On success, Cosign outputs JSON similar to the container image example and exits with 0
.
Provenance Verification with slsa-verifier
To verify the Helm Chart’s provenance, obtain its digest:
IMAGE=ghcr.io/dadrus/heimdall/chart/heimdall:<tag>
DIGEST=$(crane digest "${IMAGE}")
Then verify:
slsa-verifier verify-image "${IMAGE}@${DIGEST}" \
--source-uri github.com/dadrus/heimdall \
--source-tag <heimdall release version>
Replace <tag>
with the chart version (e.g., 0.15.0
), and use --source-tag
matching the GitHub release. Please note that the <tag>
of the chart image does not correspond to the heimdall release version. On success, slsa-verifier
prints a success message and exits with 0
.
Release Binary Verification
Signature Verification with Cosign
Detached signatures and certificates for all released archives are published alongside each platform-specific archive (e.g., <archive>.sig
and <archive>.pem
). To verify the signature of an archive, including its platform-specific heimdall binary, run:
cosign verify-blob /path/to/the/downloaded/<archive> \
--certificate-identity-regexp=https://github.com/dadrus/heimdall/.github/workflows/release.yaml* \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
--signature /path/to/the/downloaded/<archive>.sig \
--certificate /path/to/the/downloaded/<archive>.pem
On successful verification, Cosign outputs Verified OK
and exits with 0
.
Provenance Verification with slsa-verifier
SLSA provenance is published as heimdall_<release version>.intoto.jsonl
for all released archives. To verify the provenance for a particular archive, run:
slsa-verifier verify-artifact \
--provenance-path /path/to/the/downloaded/heimdall_<release version>.intoto.jsonl \
--source-uri github.com/dadrus/heimdall \
--source-tag <release version> \
/path/to/the/downloaded/<archive>
Replace <release version>
with the specific version tag of the release (e.g., v0.16.0
) that corresponds to the archive.
On success, slsa-verifier
prints a success message and exits with 0
.
Software Bill of Material (SBOM)
Heimdall is shipped with an SBOM in CyclonDX (json) format.
If you use a released binary of heimdall, the corresponding file is part of the platform specific archive. That way, if you verify the signature of the archive (see above), you do also get evidence about the validity of the SBOM.
If you use a container image, the same SBOM is attached to the image as attestation signed with Cosign. These attestations are stored in the dadrus/heimdall-sbom
repository. To verify the attestation and retrieve the SBOM execute the following command once Cosign is installed:
COSIGN_REPOSITORY=dadrus/heimdall-sbom \
cosign verify-attestation dadrus/heimdall:<tag> \
--certificate-identity-regexp=https://github.com/dadrus/heimdall/.github/workflows/release.yaml* \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
--type=cyclonedx
If you pull heimdall images from GHCR, reference the ghcr.io registry while specifying the repository names. So dadrus/heimdall-sbom becomes ghcr.io/dadrus/heimdall-sbom and dadrus/heimdall:<tag> becomes ghcr.io/dadrus/heimdall:<tag> . |
In successful verification case, cosign will print similar output to the one shown below and exit with 0
.
{
"payloadType": "application/vnd.in-toto+json",
"payload": "eyJfdHlwZSI6Imh...LCJ2ZXJzaW9uIjoxfX0=",
"signatures": [
{
"keyid": "",
"sig": "MEQCICGdo9hmIUrBRzVQ23VS...6ToNGa5YrommZNCQ=="
}
]
}
Here, payload
is the base64 encoded attestation value embedding the SBOM.
As one-liner, you can verify the signature and extract the SBOM as follows:
COSIGN_REPOSITORY=dadrus/heimdall-sbom \
cosign verify-attestation dadrus/heimdall:<tag> \
--certificate-identity-regexp=https://github.com/dadrus/heimdall/.github/workflows/release.yaml* \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
--type=cyclonedx | jq -r ".payload" | base64 -d | jq -r ".predicate" > heimdall.sbom.json
The result will be the heimdall.sbom.json
SBOM document, which you can use with any SCA or monitoring tool of your choice, e.g. Dependency Track.
Last updated on Apr 8, 2025