fix(config): reject unusable APP_ENCRYPTION_KEY at startup - #1201
fix(config): reject unusable APP_ENCRYPTION_KEY at startup#1201nbmaiti wants to merge 2 commits into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1201 +/- ##
==========================================
+ Coverage 50.09% 50.28% +0.19%
==========================================
Files 146 147 +1
Lines 13552 13635 +83
==========================================
+ Hits 6789 6857 +68
- Misses 6171 6183 +12
- Partials 592 595 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Tightens startup validation around APP_ENCRYPTION_KEY so invalid or dangerously weak keys are caught early (with clearer operator guidance), and adds validation when loading keys from the secret store/keyring to avoid runtime encryption failures.
Changes:
- Introduces
ValidateEncryptionKeywith length + strength checks and unit tests for common weak patterns and generated keys. - Validates hand-supplied keys during
config.NewConfig()and surfaces actionable errors (including anopenssl rand -base64 24suggestion). - Validates stored keys on load in
cmd/app, treating wrong-sized keys as fatal and weak keys as a warning; documents requirements in.env.example.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| config/encryption_key.go | Adds encryption-key validation logic (length + strength heuristics). |
| config/encryption_key_test.go | Adds unit tests for the validator and NewConfig() behavior with env-supplied keys. |
| config/config.go | Enforces validation of non-empty APP_ENCRYPTION_KEY at config load time with a clearer error message. |
| cmd/app/main.go | Validates keys loaded from secret store/keyring; fatal on unusable size, warn on weak-but-usable. |
| cmd/app/main_test.go | Adds coverage for checkStoredEncryptionKey warning/success paths. |
| .env.example | Documents encryption key expectations and generation guidance. |
Suppressed comments (1)
config/encryption_key.go:92
for i := range len(key)does not compile in Go. This loop should iterate over the string indices.
counts := make(map[byte]int, len(key))
for i := range len(key) {
counts[key[i]]++
}
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| seen := make(map[byte]struct{}, len(key)) | ||
| for i := range len(key) { | ||
| seen[key[i]] = struct{}{} | ||
| } |
| for _, tc := range tests { | ||
| t.Run(tc.name, func(t *testing.T) { | ||
| t.Parallel() |
A hand-supplied APP_ENCRYPTION_KEY was accepted without any check, so a
key of the wrong size only failed at first use, as an opaque HTTP 500
("crypto/aes: invalid key size 15") that the web UI never surfaced. A
key with no entropy ("aaaaaaaaaaaaaaaa") was accepted outright and
silently negated the encryption of device credentials.
Validate the key in config.NewConfig instead, so Console refuses to
start and names the offending setting. The key must be 16, 24 or 32
characters (AES-128/192/256) and must not be repetitive: at least 8
distinct characters, 3 bits of Shannon entropy per character, no
whole-key repetition and no run of 6 sequential code points. The
thresholds clear the generated key (24 random bytes, base64-encoded)
and any random 16-character key with margin.
Keys read back from the secret store or the OS keyring may predate this
check, so they are validated where they are loaded: a wrong-sized key is
fatal because it can never encrypt anything, while a weak but usable key
only warns - exiting would leave the operator unable to start Console
and read credentials already encrypted with it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Nabendu Maiti <nabendu.bikash.maiti@intel.com>
ee74bb6 to
0a09e19
Compare
Iterate key bytes explicitly in distinctChars and entropyBitsPerChar, rebind the loop variable in table-driven subtests per repo convention, and correct the paralleltest suppressions that golangci-lint reported as unused. Signed-off-by: Nabendu Maiti <nabendu.bikash.maiti@intel.com>
Issue
A hand-supplied
APP_ENCRYPTION_KEYwas never checked. A wrong-sized key onlyfailed at first use — an opaque HTTP 500 (
crypto/aes: invalid key size 15)that the web UI never surfaced to the user — and a zero-entropy key like
aaaaaaaaaaaaaaaawas accepted outright, silently negating the encryption ofdevice credentials.
Changes
config.NewConfignow validates a non-empty key and refuses to start, namingthe offending setting and suggesting
openssl rand -base64 24.≥3 bits of Shannon entropy per character, no whole-key repetition, no run of
6 sequential code points. Thresholds clear the key Console generates for
itself (24 random bytes → 32 base64 chars) and any random 16-char key with
margin.
are validated where they are loaded: wrong size is fatal (it can never
encrypt), weak-but-usable only warns — exiting would lock the operator out of
credentials already encrypted with that key.
.env.exampledocuments the requirement.Testing
go test -race -count=1 ./...green;go vetclean. Validator tests cover thethree
aaaa…examples from the report and assert 100 generated keys pass.Fixes: #NNNN