-
-
Notifications
You must be signed in to change notification settings - Fork 28
Using keystores without a private key entry for tls results in panic #2833
Description
Preflight checklist
- I agree to follow this project's Code of Conduct.
- I have read and am following this repository's Contribution Guidelines."
- I could not find a solution in the existing issues, docs, nor discussions.
Describe the bug
I was playing around with heimdall on kubernetes and wanted to use a certificate managed by cert-manager for the endpoints that heimdall exposes. (Management, Ingress & Webhook).
Note: If you have a similar setup, you might be interested in: #2834
Not thinking too much about it, I passed the tls.crt contained in the cert-manager secret to .tls.key_store. This however caused a go panic - see the logs below.
Of course, the primary problem here is that I did not pass a "complete" keystore to heimdall. But I suspect I won't be the last one to make that mistake, so it's probably better to have a more instructive error message for this case.
Note: Heimdall already does provide a more instructive error message if one passes a file that contains no pem-encoded certificate at all.
heimdall-1 | 2025-10-24T09:49:09Z ERR OnStart hook failed error="internal error: Could not create listener for Management service: configuration error: key store entry is not suitable for TLS: no certificate present" _caller=go.uber.org/fx.(*lifecycleHookAnnotation).buildHookInstaller.func1 _functionName=go.uber.org/fx.(*lifecycleHookAnnotation).buildHookInstaller.func1.1()
heimdall-1 | 2025-10-24T09:49:09Z ERR Start failed, rolling back error="internal error: Could not create listener for Management service: configuration error: key store entry is not suitable for TLS: no certificate present"
How can the bug be reproduced
Reproduction (certs included):
https://github.com/NiklasBeierl/heimdall/tree/cert-file-panic
docker compose -f docker-compose.yaml -f docker-compose-tls-error.yaml up
Relevant log output
panic: runtime error: index out of range [0] with length 0
goroutine 66 [running]:
github.com/dadrus/heimdall/internal/x/tlsx.(*keyStore).load(0xc001222000)
github.com/dadrus/heimdall/internal/x/tlsx/key_store.go:90 +0xa31
github.com/dadrus/heimdall/internal/x/tlsx.newTLSKeyStore({0xc000b3efa8, 0x14}, {0x0, 0x0}, {0x0, 0x0})
github.com/dadrus/heimdall/internal/x/tlsx/key_store.go:54 +0xa6
github.com/dadrus/heimdall/internal/x/tlsx.ToTLSConfig(0xc000b9fb30, {0xc000e3f2c0, 0x3, 0x7f4ae7b24d58?})
github.com/dadrus/heimdall/internal/x/tlsx/tls.go:38 +0xe5
github.com/dadrus/heimdall/internal/handler/listener.newTLSListener({0x37704d1?, 0x3e26f60?}, 0xc000dd0b60?, {0x3e15890, 0xc00121c010}, {0x3de1860?, 0x5df6440?}, {0x0?, 0x0?})
github.com/dadrus/heimdall/internal/handler/listener/listener.go:126 +0xd5
github.com/dadrus/heimdall/internal/handler/listener.New({0x3e26f60?, 0xc000dd0b60?}, {0x37704d1, 0xa}, {0xc000dc4468?, 0x47edc5?}, 0xc000b9fb30, {0x3de1860, 0x5df6440}, {0x0, ...})
github.com/dadrus/heimdall/internal/handler/listener/listener.go:113 +0x134
github.com/dadrus/heimdall/internal/handler/fxlcm.(*LifecycleManager).Start(0xc000d75ad0, {0x3e26f60, 0xc000dd0b60})
github.com/dadrus/heimdall/internal/handler/fxlcm/lifecycle_manager.go:53 +0xa5
github.com/dadrus/heimdall/internal/handler/management.init.func1({0x3e26f60?, 0xc000dd0b60?}, 0x0?)
github.com/dadrus/heimdall/internal/handler/management/module.go:31 +0x2c
reflect.Value.call({0x3092dc0?, 0x3908a08?, 0x0?}, {0x375e4dd, 0x4}, {0xc000dde6f0, 0x2, 0xc000f86410?})
reflect/value.go:581 +0xcc6
reflect.Value.Call({0x3092dc0?, 0x3908a08?, 0x7f4aa0b32cc0?}, {0xc000dde6f0?, 0x50?, 0xc0000d1008?})
reflect/value.go:365 +0xb9
go.uber.org/fx.(*lifecycleHookAnnotation).buildHookInstaller.func1.1({0x3e26f60?, 0xc000dd0b60})
go.uber.org/fx@v1.24.0/annotated.go:842 +0x2c5
go.uber.org/fx/internal/lifecycle.(*Lifecycle).runStartHook(0xc000000540, {0x3e26f60, 0xc000dd0b60}, {0xc000dd0230, 0x0, {0x0, 0x0}, {0x0, 0x0}, {{0xc000dd43c0, ...}, ...}})
go.uber.org/fx@v1.24.0/internal/lifecycle/lifecycle.go:256 +0x1f2
go.uber.org/fx/internal/lifecycle.(*Lifecycle).Start(0xc000000540, {0x3e26f60, 0xc000dd0b60})
go.uber.org/fx@v1.24.0/internal/lifecycle/lifecycle.go:216 +0x468
go.uber.org/fx.(*App).start-fm.(*App).start.func1({0x3e26f60?, 0xc000dd0b60?})
go.uber.org/fx@v1.24.0/app.go:702 +0x31
go.uber.org/fx.(*App).withRollback(0xc000656dc0, {0x3e26f60, 0xc000dd0b60}, 0x0?)
go.uber.org/fx@v1.24.0/app.go:684 +0x32
go.uber.org/fx.(*App).start(...)
go.uber.org/fx@v1.24.0/app.go:701
go.uber.org/fx.withTimeout.func1()
go.uber.org/fx@v1.24.0/app.go:801 +0x6b
created by go.uber.org/fx.withTimeout in goroutine 1
go.uber.org/fx@v1.24.0/app.go:789 +0xc5Relevant configuration
serve:
tls:
key_store:
path: /etc/secrets/tls.crt
management:
tls:
key_store:
path: /etc/secrets/tls.crt
providers:
file_system:
src: /etc/heimdall/rules.yaml
watch: true
# Probably requires kubernetes to test
# kubernetes:
# tls:
# key_store:
# path: /etc/secrets/heimdall-cert/tls.crtVersion
heimdall version v0.17.3
On which operating system are you observing this issue?
Linux
In which environment are you deploying?
Docker Compose
Additional Context
No response