Skip to content

ROX-33336: [Operator] Propagate cluster-wide TLS settings - #18864

Merged
vladbologa merged 18 commits into
masterfrom
vb/inherit-tls-settings
Apr 1, 2026
Merged

ROX-33336: [Operator] Propagate cluster-wide TLS settings#18864
vladbologa merged 18 commits into
masterfrom
vb/inherit-tls-settings

Conversation

@vladbologa

@vladbologa vladbologa commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

Description

When an OpenShift cluster has a cluster-wide TLS security profile configured via apiserver.config.openshift.io/cluster, the Operator now:

  1. Applies the TLS profile to its own metrics server (always, on OpenShift)
  2. Propagates the profile to all managed StackRox workloads via ROX_TLS_MIN_VERSION, ROX_TLS_CIPHER_SUITES, and ROX_OPENSSL_TLS_CIPHER_SUITES environment variables (when the spec.tlsAdherence policy requires it, or when FORCE_OPENSHIFT_TLS_PROFILE=true). The individual deployments can use the env var that is suitable for them (e.g. Go apps would use ROX_TLS_CIPHER_SUITES, C++/Rust/Postgres components would use ROX_OPENSSL_TLS_CIPHER_SUITES)
  3. Watches for changes to the TLS profile or adherence policy and restarts to apply them

The propagation uses customize.envVars in the Helm values, which would also allows users to set per-component overrides. The FORCE_OPENSHIFT_TLS_PROFILE Operator env var allows enforcement on clusters where spec.tlsAdherence is not yet available.

On non-OpenShift clusters, the feature is a no-op.

This PR follows the recommendations from this document, but adapted to the fact that we need to also support non-Openshift k8s. Note that in our implementation, we fetch the TLS settings only in the Operator. This avoids having multiple implementations in various languages for all our components and makes sure that the handling of these settings is consistent, by parsing them in a single place.

Related links:

User-facing documentation

Testing and quality

  • the change is production ready: the change is GA, or otherwise the functionality is gated by a feature flag
  • CI results are inspected

Automated testing

  • added unit tests
  • added e2e tests
  • added regression tests
  • added compatibility tests
  • modified existing tests

How I validated my change

Tested on an OpenShift 4.21 cluster with Central and SecuredCluster CRs deployed. Verified env vars on all 8 workloads: central, central-db, sensor, admission-control, scanner-v4-indexer, scanner-v4-matcher, scanner-v4-db, collector.

Default (Intermediate) profile with FORCE_OPENSHIFT_TLS_PROFILE=true:

  • Set FORCE_OPENSHIFT_TLS_PROFILE=true on the operator CSV
  • No explicit tlsSecurityProfile set on the cluster (defaults to Intermediate)
  • All workloads received: ROX_TLS_MIN_VERSION=TLSv1.2, 6 ECDHE ciphers in both IANA and OpenSSL formats
  • TLS 1.3 ciphers and DHE ciphers correctly filtered out

Modern profile:

  • Changed apiserver.config.openshift.io/cluster to type: Modern
  • Operator logs: cluster TLS profile changed, restarting Operator to apply new settings, oldMinTLSVersion=VersionTLS12, newMinTLSVersion=VersionTLS13
  • Graceful shutdown of all controllers, operator restarted automatically
  • All workloads updated: ROX_TLS_MIN_VERSION=TLSv1.3, empty cipher lists (TLS 1.3 ciphers handled separately by Go/OpenSSL)

Tried also tls-scanner, all pods look OK:

  • central 8443, 9091 - TLSv1.3
  • admission-control 8443, 9091 - TLSv1.3
  • sensor 9091, 9443 - TLSv1.3
  • scanner-v4-indexer 9091 - TLSv1.3
  • scanner-v4-matcher 9091 - TLSv1.3
  • scanner 8080 8443 - TLSv1.2, TLSv.13 (deviation is expected, feature is not implemented in Scanner V2, so it uses defaults)

However the DB pods (central-db, scanner-db, scanner-v4-db) were not tested properly (they show up as NO_TLS).

Full results here.

Custom profile:

  • Changed to Custom profile with 3 specific ciphers and minTLSVersion: VersionTLS12
  • Operator detected the change and restarted again
  • All workloads updated: ROX_TLS_MIN_VERSION=TLSv1.2, exactly the 3 specified ciphers in both IANA (TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) and OpenSSL format

Old profile:

  • Changed to Old profile, which sets minTLSVersion to 1.0
  • 8 unsupported cipher suites skipped by the Go services, but otherwise everything works as expected

Note that for the OpenShift 4.11 tests I had to use FORCE_OPENSHIFT_TLS_PROFILE=true, as the tlsAdherence field will only be available in OpenShift 4.22.

Test on OCP 4.22 (dev preview) with native tlsAdherence support

Deployed on OCP 4.22.0-ec.4 with DevPreviewNoUpgrade feature gate to enable the TLSAdherence feature.

StrictAllComponents + Modern profile:

oc patch apiserver cluster --type merge -p \
  '{"spec":{"tlsSecurityProfile":{"type":"Modern","modern":{}},"tlsAdherence":"StrictAllComponents"}}'
The operator picked up the profile without FORCE_OPENSHIFT_TLS_PROFILE and set ROX_TLS_MIN_VERSION=TLSv1.3 on all deployments (central, central-db, sensor, admission-control, scanner, scanner-db, scanner-v4-db,
 scanner-v4-indexer, scanner-v4-matcher, config-controller).

LegacyAdheringComponentsOnly:
oc patch apiserver cluster --type merge -p \
  '{"spec":{"tlsAdherence":"LegacyAdheringComponentsOnly"}}'
The operator removed ROX_TLS_MIN_VERSION, ROX_TLS_CIPHER_SUITES, and ROX_OPENSSL_TLS_CIPHER_SUITES from all deployments, reverting to defaults.

@openshift-ci

openshift-ci Bot commented Feb 5, 2026

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@rhacs-bot

rhacs-bot commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

Images are ready for the commit at b411ea4.

To use with deploy scripts, first export MAIN_IMAGE_TAG=4.11.x-542-gb411ea4ca9.

@codecov

codecov Bot commented Feb 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 63.63636% with 40 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.60%. Comparing base (2837c9b) to head (b411ea4).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
operator/internal/tlsprofile/watch.go 0.00% 29 Missing ⚠️
operator/internal/tlsprofile/provider.go 66.66% 8 Missing and 3 partials ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##           master   #18864    +/-   ##
========================================
  Coverage   49.59%   49.60%            
========================================
  Files        2756     2760     +4     
  Lines      208036   208144   +108     
========================================
+ Hits       103183   103246    +63     
- Misses      97192    97232    +40     
- Partials     7661     7666     +5     
Flag Coverage Δ
go-unit-tests 49.60% <63.63%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@vladbologa
vladbologa force-pushed the vb/inherit-tls-settings branch from 65477e3 to 1947c4e Compare February 5, 2026 12:37
@vladbologa vladbologa added the konflux-build Run Konflux in PR. Push commit to trigger it. label Feb 6, 2026
@vladbologa
vladbologa force-pushed the vb/inherit-tls-settings branch 3 times, most recently from 5f90175 to 67aa3a3 Compare February 27, 2026 11:02
@vladbologa
vladbologa force-pushed the vb/inherit-tls-settings branch 2 times, most recently from 0f9fa38 to be483be Compare March 2, 2026 09:53
@vladbologa
vladbologa force-pushed the vb/inherit-tls-settings branch from be483be to 8a708ee Compare March 12, 2026 11:29
@vladbologa vladbologa changed the title Log TLS ciphers Honor cluster-wide TLS settings Mar 12, 2026
@stackrox stackrox deleted a comment from openshift-ci Bot Mar 12, 2026
@stackrox stackrox deleted a comment from github-actions Bot Mar 12, 2026
@vladbologa
vladbologa force-pushed the vb/inherit-tls-settings branch 2 times, most recently from b3d11f9 to 6c56818 Compare March 12, 2026 14:50
@vladbologa vladbologa changed the title Honor cluster-wide TLS settings [wip] Honor cluster-wide TLS settings Mar 12, 2026
@vladbologa
vladbologa force-pushed the vb/inherit-tls-settings branch from 6c56818 to 25bf072 Compare March 13, 2026 10:34
@vladbologa
vladbologa force-pushed the vb/inherit-tls-settings branch from 25bf072 to b75703a Compare March 13, 2026 12:29
@vladbologa
vladbologa force-pushed the vb/inherit-tls-settings branch from b75703a to 43f247e Compare March 24, 2026 13:13
@vladbologa
vladbologa force-pushed the vb/inherit-tls-settings branch 3 times, most recently from 0023d83 to 7f73d85 Compare March 25, 2026 15:04
@stackrox stackrox deleted a comment from github-actions Bot Mar 25, 2026
@stackrox stackrox deleted a comment from github-actions Bot Mar 25, 2026

@porridge porridge left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM overall, just a bunch of nitpicks.

Comment thread operator/cmd/main.go Outdated
Comment thread operator/cmd/main.go Outdated
Comment thread operator/cmd/main.go Outdated
Comment thread operator/internal/tlsprofile/convert.go Outdated
Comment thread operator/internal/tlsprofile/convert.go Outdated
Comment thread operator/internal/tlsprofile/enricher.go Outdated
Comment thread operator/cmd/main.go Outdated
Comment thread operator/internal/tlsprofile/watch.go Outdated
Comment thread operator/internal/tlsprofile/watch.go Outdated
Comment thread operator/internal/tlsprofile/provider.go Outdated
@vladbologa
vladbologa force-pushed the vb/inherit-tls-settings branch 3 times, most recently from ce6b24d to 63200ee Compare March 31, 2026 14:26
@vladbologa

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 1, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Apr 1, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The pull request introduces OpenShift cluster-wide TLS profile support to the Operator. The Operator now reads the cluster TLS profile from apiserver.config.openshift.io/cluster, monitors it for changes via a watcher, and propagates it to Central and SecuredCluster reconcilers through TLS profile enrichers. Supporting infrastructure includes profile fetching, conversion utilities, and dependency updates.

Changes

Cohort / File(s) Summary
Documentation & Dependencies
CHANGELOG.md, go.mod
Added changelog entry for TLS profile propagation feature; updated Go module dependencies including OpenShift API, controller-runtime-common, and library-go.
Helm Template Integration
image/templates/helm/stackrox-central/templates/01-central-12-central-db.yaml
Added TLS profile environment variable injection to central-db container via Helm template inclusion.
Operator Initialization & Metrics
operator/cmd/main.go
Implemented cluster TLS profile fetching during startup, added metrics server TLS configuration helper, registered OpenShift config API, and introduced TLS profile watcher with cancelable context management. New env var FORCE_OPENSHIFT_TLS_PROFILE controls profile enforcement.
Reconciler Registration
operator/internal/central/reconciler/reconciler.go, operator/internal/securedcluster/reconciler/reconciler.go
Updated RegisterNewReconciler signatures to accept tlsProfile *tlsprofile.TLSProfile parameter and integrated TLS profile enricher into reconciliation pipeline.
TLS Profile Provider & Tests
operator/internal/tlsprofile/provider.go, operator/internal/tlsprofile/provider_test.go
New module providing FetchProfile to retrieve OpenShift APIServer TLS configuration and ConvertProfile to transform it into operator-consumable format; comprehensive test coverage for fetch, conversion, and adherence policy handling.
TLS Profile Conversion & Tests
operator/internal/tlsprofile/convert.go, operator/internal/tlsprofile/convert_test.go
Utilities for converting OpenShift TLS protocol versions and cipher suites to Go/OpenSSL formats; handles TLS 1.3 cipher filtering and unmapped cipher handling with logging.
TLS Profile Enrichment & Tests
operator/internal/tlsprofile/enricher.go, operator/internal/tlsprofile/enricher_test.go
Implements translation.Enricher to inject TLS environment variables (ROX_TLS_MIN_VERSION, cipher suites) into Helm values; respects user-provided overrides via coalescing.
TLS Profile Watcher
operator/internal/tlsprofile/watch.go
Sets up OpenShift TLS profile change detection; triggers operator restart via context cancellation when cluster TLS settings change.
TLS Profile Library
pkg/tlsprofile/profile.go, pkg/tlsprofile/profile_test.go
Updated minimum version parsing to accept "TLSv1" alias; modified cipher suite parsing to gracefully skip unknown suites rather than fail, logging warnings for ignored entries.

Sequence Diagram

sequenceDiagram
    participant Operator as Operator<br/>(main.go)
    participant BootClient as Bootstrap<br/>Controller Client
    participant OSAPIServer as OpenShift<br/>APIServer API
    participant TLSProfile as TLS Profile<br/>Provider
    participant Reconcilers as Central &<br/>SecuredCluster<br/>Reconcilers
    participant Enricher as TLS Profile<br/>Enricher
    participant HelmValues as Helm<br/>Values

    Operator->>BootClient: Create bootstrap client
    Operator->>OSAPIServer: Fetch cluster TLS profile
    OSAPIServer-->>TLSProfile: Return APIServer resource
    TLSProfile->>TLSProfile: Convert profile spec<br/>(minVersion, ciphers)
    TLSProfile-->>Operator: ClusterTLSProfile
    Operator->>Operator: Setup TLS profile<br/>watcher (callbacks)
    Operator->>Reconcilers: Pass tlsProfile to<br/>RegisterNewReconciler
    Reconcilers->>Enricher: Create with tlsProfile
    Reconcilers->>HelmValues: Enrich Helm values<br/>with TLS env vars
    HelmValues-->>Reconcilers: Merged values<br/>(user overrides<br/>preserved)
    Operator->>Operator: Start manager with<br/>cancelable context
    Operator->>OSAPIServer: Monitor TLS changes
    OSAPIServer-->>Operator: TLS config changed
    Operator->>Operator: Trigger cancel(),<br/>operator restarts
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: implementing operator-side propagation of cluster-wide TLS settings on OpenShift.
Description check ✅ Passed The pull request description follows the template structure with all required sections completed: detailed explanation of changes, user-facing documentation checklist (CHANGELOG.md updated), testing and quality checklist (production-ready, CI inspected, unit tests added), and comprehensive validation methodology with specific test scenarios.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch vb/inherit-tls-settings

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
pkg/tlsprofile/profile.go (1)

88-88: Consider keeping TLSv1.0 as a backward-compatible alias.

Line 88 now accepts TLSv1 only. This can break existing manual ROX_TLS_MIN_VERSION=TLSv1.0 configurations by silently falling back to default.

Suggested compatibility patch
 var supportedVersions = map[string]uint16{
 	"TLSv1":   tls.VersionTLS10,
+	"TLSv1.0": tls.VersionTLS10,
 	"TLSv1.1": tls.VersionTLS11,
 	"TLSv1.2": tls.VersionTLS12,
 	"TLSv1.3": tls.VersionTLS13,
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/tlsprofile/profile.go` at line 88, Add a backward-compatible alias for
TLSv1.0 by mapping the string "TLSv1.0" to tls.VersionTLS10 in the same TLS
version lookup used in pkg/tlsprofile/profile.go (i.e., alongside the existing
"TLSv1": tls.VersionTLS10 entry); ensure the parser or lookup that reads
ROX_TLS_MIN_VERSION accepts the new "TLSv1.0" key so existing env values
continue to be recognized without changing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@operator/internal/tlsprofile/provider.go`:
- Around line 55-58: The code currently treats
discovery.IsGroupDiscoveryFailedError(err) the same as IsNotFound/IsNoMatchError
and returns (nil, nil), which silently skips cluster-profile enforcement; change
the logic in the block that calls c.Get(ctx, NamespacedName{Name:
apiserverClusterName}, apiServer) so that IsNotFound and meta.IsNoMatchError
still return (nil, nil) but discovery.IsGroupDiscoveryFailedError(err) is
handled differently: log a warning (including err) and return the error (not
nil) so the caller can retry and clusterTLS in watch.go is not left nil; update
handling around c.Get, apiServer, and any caller expectations in watch.go to
ensure the restart watcher is armed when appropriate.

---

Nitpick comments:
In `@pkg/tlsprofile/profile.go`:
- Line 88: Add a backward-compatible alias for TLSv1.0 by mapping the string
"TLSv1.0" to tls.VersionTLS10 in the same TLS version lookup used in
pkg/tlsprofile/profile.go (i.e., alongside the existing "TLSv1":
tls.VersionTLS10 entry); ensure the parser or lookup that reads
ROX_TLS_MIN_VERSION accepts the new "TLSv1.0" key so existing env values
continue to be recognized without changing behavior.
🪄 Autofix (Beta)

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: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f485a3a2-a5e1-4eb4-9172-e48c17c4fea9

📥 Commits

Reviewing files that changed from the base of the PR and between 79baa11 and 63200ee.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (15)
  • CHANGELOG.md
  • go.mod
  • image/templates/helm/stackrox-central/templates/01-central-12-central-db.yaml
  • operator/cmd/main.go
  • operator/internal/central/reconciler/reconciler.go
  • operator/internal/securedcluster/reconciler/reconciler.go
  • operator/internal/tlsprofile/convert.go
  • operator/internal/tlsprofile/convert_test.go
  • operator/internal/tlsprofile/enricher.go
  • operator/internal/tlsprofile/enricher_test.go
  • operator/internal/tlsprofile/provider.go
  • operator/internal/tlsprofile/provider_test.go
  • operator/internal/tlsprofile/watch.go
  • pkg/tlsprofile/profile.go
  • pkg/tlsprofile/profile_test.go

Comment thread operator/internal/tlsprofile/provider.go
@vladbologa
vladbologa force-pushed the vb/inherit-tls-settings branch from 63200ee to b411ea4 Compare April 1, 2026 14:46
@vladbologa
vladbologa merged commit f8de23e into master Apr 1, 2026
119 checks passed
@vladbologa
vladbologa deleted the vb/inherit-tls-settings branch April 1, 2026 19:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants