feat: implement TLS groups/curve preferences support - #22
Conversation
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: damdo The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
/hold This PR depends on openshift/library-go#2347 merging upstream. Once that PR is merged and released, we can drop the temporary replace directive and revendor to use the official library-go version. |
d584c5e to
79a541a
Compare
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe project now targets Go 1.26.0 and uses updated OpenShift, Kubernetes, controller-runtime, Prometheus, protobuf, and related module versions. Suggested reviewers: 🚥 Pre-merge checks | ✅ 14 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (14 passed)
✨ Finishing Touches 💡 2⚔️ Resolve merge conflicts 💡
🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
pkg/tls/tls_test.go (1)
357-371: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winStrengthen the conditional assertion in the Intermediate-profile Groups test.
The test only asserts
CurvePreferencesis setif len(profile.Groups) > 0; if the Intermediate profile definition ever ships with an emptyGroupslist (e.g., upstream API regression), this test silently passes without verifying anything.✅ Proposed fix to make the test deterministic
It("should set CurvePreferences from the profile", func() { profile := *configv1.TLSProfiles[configv1.TLSProfileIntermediateType] + Expect(profile.Groups).NotTo(BeEmpty(), "Intermediate profile is expected to define Groups") tlsConfigFn, _ := NewTLSConfigFromProfile(profile) tlsConf := &tls.Config{} tlsConfigFn(tlsConf) - // Intermediate profile now includes Groups - if len(profile.Groups) > 0 { - Expect(tlsConf.CurvePreferences).NotTo(BeNil()) - } + Expect(tlsConf.CurvePreferences).NotTo(BeNil()) })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/tls/tls_test.go` around lines 357 - 371, The Intermediate profile Groups test in NewTLSConfigFromProfile is conditional on len(profile.Groups), so it can pass without checking anything if Groups is empty. Make the test deterministic by asserting the expected Intermediate profile data explicitly before calling tlsConfigFn, then always verify tlsConf.CurvePreferences is populated from the profile’s Groups rather than skipping the assertion.pkg/tls/tls.go (1)
119-121: 🧹 Nitpick | 🔵 TrivialPost-quantum curve gap noted and tracked.
The TODO correctly flags that post-quantum hybrid curves (SecP256r1MLKEM768, SecP384r1MLKEM1024) are not supported in Go 1.25 and are gracefully filtered as unsupported. Since this shared TLS helper may end up protecting long-lived secrets across consuming controller-runtime projects, worth ensuring downstream consumers are aware of the current PQ gap until Go 1.26+ lands support.
As per path instructions for files matching
**/*{crypt,cipher,sign,hash,tls,ssl,cert,key,token}*, "Post-quantum: flag if protecting long-lived secrets."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/tls/tls.go` around lines 119 - 121, The TLS helper in CurveIDsForTLSGroups already filters unsupported post-quantum hybrid curves, but the comment needs to make the downstream exposure explicit for consumers handling long-lived secrets. Update the TODO/documentation around curvePrefs and unsupportedGroups in tls.go to clearly call out that SecP256r1MLKEM768 and SecP384r1MLKEM1024 are currently unavailable in Go 1.25, that they are being dropped by CurveIDsForTLSGroups, and that controller-runtime consumers should not rely on PQ protection until Go 1.26+ support is available.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pkg/tls/tls.go`:
- Around line 116-137: Normalize the unsupported group names returned from
NewTLSConfigFromProfile so they match the expected lowercase underscore format
instead of the raw enum string. Update the unsupported-group handling in
CurveIDsForTLSGroups (or immediately after its result is used in
NewTLSConfigFromProfile) to map values like SecP256r1MLKEM768 to
secp256r1_mlkem768 before appending to unsupported, while keeping
unsupportedCiphers behavior unchanged.
---
Nitpick comments:
In `@pkg/tls/tls_test.go`:
- Around line 357-371: The Intermediate profile Groups test in
NewTLSConfigFromProfile is conditional on len(profile.Groups), so it can pass
without checking anything if Groups is empty. Make the test deterministic by
asserting the expected Intermediate profile data explicitly before calling
tlsConfigFn, then always verify tlsConf.CurvePreferences is populated from the
profile’s Groups rather than skipping the assertion.
In `@pkg/tls/tls.go`:
- Around line 119-121: The TLS helper in CurveIDsForTLSGroups already filters
unsupported post-quantum hybrid curves, but the comment needs to make the
downstream exposure explicit for consumers handling long-lived secrets. Update
the TODO/documentation around curvePrefs and unsupportedGroups in tls.go to
clearly call out that SecP256r1MLKEM768 and SecP384r1MLKEM1024 are currently
unavailable in Go 1.25, that they are being dropped by CurveIDsForTLSGroups, and
that controller-runtime consumers should not rely on PQ protection until Go
1.26+ support is available.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
| func NewTLSConfigFromProfile(profile configv1.TLSProfileSpec) (tlsConfig func(*tls.Config), unsupported []string) { | ||
| minVersion := libgocrypto.TLSVersionOrDie(string(profile.MinTLSVersion)) | ||
| cipherSuites, unsupportedCiphers := cipherCodes(profile.Ciphers) | ||
| // TODO: post-quantum hybrid curves (SecP256r1MLKEM768, SecP384r1MLKEM1024) are not supported in Go 1.25. | ||
| // These will be returned as unsupported and gracefully filtered. Update this when Go 1.26+ support is available. | ||
| curvePrefs, unsupportedGroups := libgocrypto.CurveIDsForTLSGroups(profile.Groups) | ||
|
|
||
| unsupported = append(unsupportedCiphers, unsupportedGroups...) | ||
|
|
||
| return func(tlsConf *tls.Config) { | ||
| tlsConf.MinVersion = minVersion | ||
| // TODO: add curve preferences from profile once https://github.com/openshift/api/pull/2583 merges. | ||
| // tlsConf.CurvePreferences <<<<<< profile.Curves | ||
| if len(curvePrefs) > 0 { | ||
| tlsConf.CurvePreferences = curvePrefs | ||
| } | ||
|
|
||
| // TLS 1.3 cipher suites are not configurable in Go (https://github.com/golang/go/issues/29349), so only set CipherSuites accordingly. | ||
| // TODO: revisit this once we get an answer on the best way to handle this here: | ||
| // https://docs.google.com/document/d/1cMc9E8psHfnoK06ntR8kHSWB8d3rMtmldhnmM4nImjs/edit?disco=AAABu_nPcYg | ||
| if minVersion != tls.VersionTLS13 { | ||
| tlsConf.CipherSuites = cipherSuites | ||
| } | ||
| }, unsupportedCiphers | ||
| }, unsupported |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Locate the vendored library-go crypto package and inspect CurveIDsForTLSGroups signature
fd -a 'crypto.go' --path '*library-go/pkg/crypto*'
rg -n -A 15 'func CurveIDsForTLSGroups' -g '*.go'Repository: openshift/controller-runtime-common
Length of output: 405
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '== go.mod references =='
rg -n 'library-go|CurveIDsForTLSGroups|TLSGroup|TLSProfileSpec' go.mod go.sum vendor . || true
echo
echo '== locate tls.go =='
fd -a 'tls.go' pkg || true
echo
echo '== outline pkg/tls/tls.go =='
if command -v ast-grep >/dev/null 2>&1; then
ast-grep outline pkg/tls/tls.go --view expanded || true
fi
echo
echo '== relevant lines in pkg/tls/tls.go =='
nl -ba pkg/tls/tls.go | sed -n '1,220p'Repository: openshift/controller-runtime-common
Length of output: 26899
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '== dependency metadata =='
rg -n 'openshift/library-go|library-go' go.mod go.sum vendor . || true
echo
echo '== search for CurveIDsForTLSGroups in repo =='
rg -n 'CurveIDsForTLSGroups|TLSGroup' . || true
echo
echo '== inspect pkg/tls tests =='
fd -a 'tls_test.go' pkg || true
if [ -f pkg/tls/tls_test.go ]; then
nl -ba pkg/tls/tls_test.go | sed -n '1,260p'
fiRepository: openshift/controller-runtime-common
Length of output: 9811
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '== vendor CurveIDsForTLSGroups implementation =='
sed -n '392,420p' vendor/github.com/openshift/library-go/pkg/crypto/crypto.go
echo
echo '== tls tests around unsupported groups =='
sed -n '286,360p' pkg/tls/tls_test.goRepository: openshift/controller-runtime-common
Length of output: 3714
Normalize unsupported group names
CurveIDsForTLSGroups appends string(group) for unsupported entries, so configv1.TLSGroupSecP256r1MLKEM768 is reported as SecP256r1MLKEM768, not secp256r1_mlkem768. If the lowercase underscore form is required here, normalize before returning.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@pkg/tls/tls.go` around lines 116 - 137, Normalize the unsupported group names
returned from NewTLSConfigFromProfile so they match the expected lowercase
underscore format instead of the raw enum string. Update the unsupported-group
handling in CurveIDsForTLSGroups (or immediately after its result is used in
NewTLSConfigFromProfile) to map values like SecP256r1MLKEM768 to
secp256r1_mlkem768 before appending to unsupported, while keeping
unsupportedCiphers behavior unchanged.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
pkg/tls/tls_test.go (1)
357-371: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winWeak assertion: test can pass without exercising anything.
The assertion is gated behind
if len(profile.Groups) > 0, so if the Intermediate profile'sGroupsfield is ever empty (e.g., due to anopenshift/apiregression), this test silently passes without validating any behavior.🧪 Proposed fix to assert the precondition
Context("when using Intermediate profile with Groups", func() { It("should set CurvePreferences from the profile", func() { profile := *configv1.TLSProfiles[configv1.TLSProfileIntermediateType] + Expect(profile.Groups).NotTo(BeEmpty()) tlsConfigFn, _ := NewTLSConfigFromProfile(profile) tlsConf := &tls.Config{} tlsConfigFn(tlsConf) - // Intermediate profile now includes Groups - if len(profile.Groups) > 0 { - Expect(tlsConf.CurvePreferences).NotTo(BeNil()) - } + Expect(tlsConf.CurvePreferences).NotTo(BeNil()) }) })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/tls/tls_test.go` around lines 357 - 371, The test in tls_test.go has a weak assertion because it only checks CurvePreferences when profile.Groups is non-empty, so it can silently pass without validating behavior. In the Context for NewTLSConfigFromProfile with configv1.TLSProfileIntermediateType, assert the precondition on profile.Groups directly (for example, require it to be non-empty before checking tlsConf.CurvePreferences) so the test fails if the Intermediate profile no longer includes groups, and keep the existing CurvePreferences expectation tied to that same setup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@pkg/tls/tls_test.go`:
- Around line 357-371: The test in tls_test.go has a weak assertion because it
only checks CurvePreferences when profile.Groups is non-empty, so it can
silently pass without validating behavior. In the Context for
NewTLSConfigFromProfile with configv1.TLSProfileIntermediateType, assert the
precondition on profile.Groups directly (for example, require it to be non-empty
before checking tlsConf.CurvePreferences) so the test fails if the Intermediate
profile no longer includes groups, and keep the existing CurvePreferences
expectation tied to that same setup.
79a541a to
fc0245f
Compare
|
/assign @joelanford |
| cipherSuites, unsupportedCiphers := cipherCodes(profile.Ciphers) | ||
| curvePrefs, unsupportedGroups := libgocrypto.CurveIDsForTLSGroups(profile.Groups) | ||
|
|
||
| unsupported = append(unsupportedCiphers, unsupportedGroups...) |
There was a problem hiding this comment.
Is there any value in separating the two types here?
There was a problem hiding this comment.
I think merging is fine here. The caller only uses unsupported for logging ("unsupported ciphers/groups that will be ignored: %v"). Separating them would change the function signature (e.g., return two slices, or a struct) for no practical benefit, the caller doesn't need to handle them differently. If a consumer ever needs to distinguish, libgocrypto.CurveIDsForTLSGroups and cipherCodes are individually callable.
fc0245f to
2e66fc2
Compare
2e66fc2 to
1e752ab
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
pkg/tls/tls_test.go (1)
338-353: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a nil
Groupstest case.This test covers only a non-nil empty slice. The contract also requires nil
Groupsto leavetls.Config.CurvePreferencesunset. Add a case withGroupsomitted or set tonil, and assert emptyunsupportedand nilCurvePreferences.As per the PR objectives, both empty and nil
Groupsmust preserve the default curve preferences.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/tls/tls_test.go` around lines 338 - 353, Extend the “when profile has empty Groups” tests around NewTLSConfigFromProfile with a separate case where TLSProfileSpec.Groups is nil or omitted. Assert unsupported is empty and tls.Config.CurvePreferences remains nil, preserving the existing non-nil empty-slice coverage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@go.mod`:
- Around line 85-86: Review and verify maintainer approval and provenance for
fork commit fceccb2c136d4e52ad826c78141e6081aa95ffb9 before merging. Keep the
github.com/openshift/library-go replacement temporarily, then remove that
replace directive and revendor once upstream pull request `#2347` is merged and
its release is available.
- Around line 17-83: Update the indirect golang.org/x/net dependency in go.mod
to at least v0.56.0 and golang.org/x/text to at least v0.39.0, then regenerate
go.sum consistently with those versions and rerun the OSV vulnerability scan to
confirm both advisories are resolved.
In `@Makefile`:
- Line 21: Update the Go version directive in tools/go.tool.mod to match the
GO_DIRECTIVE_VERSION value of 1.26.0, so verify-go-directive sees consistent
versions.
---
Nitpick comments:
In `@pkg/tls/tls_test.go`:
- Around line 338-353: Extend the “when profile has empty Groups” tests around
NewTLSConfigFromProfile with a separate case where TLSProfileSpec.Groups is nil
or omitted. Assert unsupported is empty and tls.Config.CurvePreferences remains
nil, preserving the existing non-nil empty-slice coverage.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Central YAML (inherited)
Review profile: CHILL
Plan: Enterprise
Run ID: 83b2db0d-01d8-4a0b-889f-4f3f4b69a6c5
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (4)
Makefilego.modpkg/tls/tls.gopkg/tls/tls_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
- pkg/tls/tls.go
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
pkg/tls/tls_test.go (1)
336-351: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd explicit coverage for nil
Groups.The contract covers both nil and empty
Groups, but this test uses only[]configv1.TLSGroup{}. Add a case that omitsGroupsand verifies thattls.Config.CurvePreferencesremains nil.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/tls/tls_test.go` around lines 336 - 351, Add a separate test case in the existing empty-Groups context that constructs TLSProfileSpec without setting Groups, invokes NewTLSConfigFromProfile and the returned configurator, and explicitly verifies tls.Config.CurvePreferences remains nil.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pkg/tls/tls_test.go`:
- Around line 353-366: Update the “should set CurvePreferences from the profile”
test to derive the expected count from the profile’s supported groups only,
rather than subtracting the combined unsupported count. Use the group-specific
filtering or supported-group result associated with NewTLSConfigFromProfile,
then compare tlsConf.CurvePreferences against that exact expected value.
---
Nitpick comments:
In `@pkg/tls/tls_test.go`:
- Around line 336-351: Add a separate test case in the existing empty-Groups
context that constructs TLSProfileSpec without setting Groups, invokes
NewTLSConfigFromProfile and the returned configurator, and explicitly verifies
tls.Config.CurvePreferences remains nil.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Central YAML (inherited)
Review profile: CHILL
Plan: Enterprise
Run ID: a34d4867-3e36-435d-b843-640cf6127e76
📒 Files selected for processing (1)
pkg/tls/tls_test.go
1e752ab to
59f72c1
Compare
59f72c1 to
c12349a
Compare
|
@damdo: all tests passed! Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
Enforce the cluster-wide TLS security profile on the WMCO metrics server, gated on the TLS adherence policy. WMCO was not previously honoring the cluster TLS profile, so enforcement only applies when the adherence policy is StrictAllComponents, per the centralized TLS config enhancement. Changes: - Fetch TLS profile and adherence policy from apiserver.config.openshift.io/cluster - Gate enforcement using library-go's ShouldHonorClusterTLSProfile - Disable HTTP/2 (HTTP/1.1 only) as defense-in-depth against CVE-2023-44487 - Watch for TLS profile and adherence policy changes, restart on change - Add controller-runtime-common to hack/update_submodules.sh CurvePreferences with X25519MLKEM768 for post-quantum key exchange will be added in a follow-up once openshift/controller-runtime-common#22 lands.
Enforce the cluster-wide TLS security profile on the WMCO metrics server, gated on the TLS adherence policy. WMCO was not previously honoring the cluster TLS profile, so enforcement only applies when the adherence policy is StrictAllComponents, per the centralized TLS config enhancement. Changes: - Fetch TLS profile and adherence policy from apiserver.config.openshift.io/cluster - Gate enforcement using library-go's ShouldHonorClusterTLSProfile - Disable HTTP/2 (HTTP/1.1 only) as defense-in-depth against CVE-2023-44487 - Watch for TLS profile and adherence policy changes, restart on change - Add controller-runtime-common to hack/update_submodules.sh CurvePreferences with X25519MLKEM768 for post-quantum key exchange will be added in a follow-up once openshift/controller-runtime-common#22 lands.
Summary
Implements TLS groups/curve preferences support in
NewTLSConfigFromProfile()by leveraging the library-go crypto package.Fixes #20
libgocrypto.CurveIDsForTLSGroups()to map TLS groups/curve preferences to Go curve IDsSample PR that leverages this is here: openshift/cluster-machine-approver#308
Test plan
TODO
replace github.com/openshift/library-godirective in go.mod and revendor once crypto: add TLS group/curve mapping support library-go#2347 merges