Skip to content

feat: integrate with cluster TLS security profile - #812

Merged
ruivieira merged 1 commit into
trustyai-explainability:mainfrom
ugiordan:RHOAIENG-61068-tls-profile
Jul 7, 2026
Merged

ruivieira merged 1 commit into
trustyai-explainability:mainfrom
ugiordan:RHOAIENG-61068-tls-profile

Conversation

@ugiordan

@ugiordan ugiordan commented Jul 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Read the cluster TLS profile from apiservers.config.openshift.io/cluster at startup
  • TLS resolution code extracted into pkg/tls/ for reusability and testability
  • pkg/tls.Resolve() uses unstructured access (zero new dependencies, compatible with controller-runtime v0.17.0)
  • Apply MinVersion, CipherSuites, and NextProtos to metrics server TLS config
  • Fail closed on unexpected errors, use Intermediate defaults on non-OpenShift clusters
  • Transient API errors (ServiceUnavailable, Timeout, TooManyRequests) fall back to Intermediate defaults instead of crashing
  • 10s context timeout on APIServer fetch to avoid blocking startup indefinitely
  • Add config.openshift.io/apiservers to OPA policy allowlist
  • Add RBAC ClusterRole and ClusterRoleBinding for reading APIServer CR
  • ClusterRoleBinding and ClusterRole registered in config/rbac-base/kustomization.yaml
  • CRB added to OPA policy/rbac.rego allowlist (both prefixed and un-prefixed)

Files changed

  • cmd/main.go: Replaced inline TLS code with call to pkgtls.Resolve()
  • pkg/tls/tls.go: Reusable TLS profile resolution (unstructured APIServer read, cipher mapping, Intermediate defaults, transient error handling, 10s timeout)
  • pkg/tls/tls_test.go: Table-driven tests for all profile types
  • config/rbac-base/tls_profile_role.yaml: RBAC ClusterRole for reading APIServer
  • config/rbac-base/tls_profile_role_binding.yaml: RBAC ClusterRoleBinding for operator SA
  • config/rbac-base/kustomization.yaml: Added TLS RBAC resources
  • policy/clusterrole.rego: OPA allowlist update for config.openshift.io/apiservers
  • policy/rbac.rego: OPA allowlist update for TLS CRB (prefixed + un-prefixed)
  • Dockerfile: Added COPY pkg/ pkg/ for container builds

Test plan

  • Unit tests pass (go test ./pkg/tls/... -v)
  • Conftest RBAC policy passes
  • Operator starts on OpenShift with Intermediate profile
  • Operator starts on non-OpenShift with hardened defaults

Supersedes #774 (closed due to broken shallow clone force-push).

Ref: RHOAIENG-61068

Summary by CodeRabbit

  • New Features
    • Automatically resolves and applies TLS settings from the cluster’s security profile to both the metrics and webhook endpoints.
    • Added RBAC and policy updates to allow reading the cluster API server TLS profile.
  • Bug Fixes
    • Improves startup reliability by falling back to hardened Intermediate TLS settings when the profile is temporarily unavailable.
    • Adds “fail-closed” behavior for unexpected TLS profile read failures.
  • Tests
    • Added table-driven test coverage for TLS profile parsing, including custom/unsupported cipher handling.

@openshift-ci

openshift-ci Bot commented Jul 7, 2026

Copy link
Copy Markdown

Hi @ugiordan. Thanks for your PR.

I'm waiting for a trustyai-explainability member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work.

Tip

We noticed you've done this a few times! Consider joining the org to skip this step and gain /lgtm and other bot rights. We recommend asking approvers on your previous PRs to sponsor you.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions 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.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b49d0198-d574-4679-8fc4-e49bd4a9373c

📥 Commits

Reviewing files that changed from the base of the PR and between d8cbcde and 768f504.

📒 Files selected for processing (8)
  • cmd/main.go
  • config/rbac-base/kustomization.yaml
  • config/rbac-base/tls_profile_role.yaml
  • config/rbac-base/tls_profile_role_binding.yaml
  • pkg/tls/tls.go
  • pkg/tls/tls_test.go
  • policy/clusterrole.rego
  • policy/rbac.rego
🚧 Files skipped from review as they are similar to previous changes (7)
  • policy/rbac.rego
  • policy/clusterrole.rego
  • pkg/tls/tls_test.go
  • config/rbac-base/kustomization.yaml
  • config/rbac-base/tls_profile_role_binding.yaml
  • pkg/tls/tls.go
  • cmd/main.go

📝 Walkthrough

Walkthrough

This PR adds OpenShift APIServer-driven TLS resolution, wires the result into controller-manager metrics and webhook TLS settings, and adds the RBAC and policy updates needed to read the APIServer profile.

Changes

TLS Profile Resolution Feature

Layer / File(s) Summary
TLS resolution core logic
pkg/tls/tls.go
New Resolve logic reads the OpenShift APIServer TLS profile, falls back on transient errors, and maps profile types to TLS versions and cipher suites.
TLS parsing tests
pkg/tls/tls_test.go
Table-driven tests cover profile parsing and custom cipher handling.
Manager and server TLS wiring
cmd/main.go
main() now resolves TLS options from the cluster config and applies them to the metrics endpoint, webhook server, and manager construction.
RBAC manifests for APIServer read access
config/rbac-base/kustomization.yaml, config/rbac-base/tls_profile_role.yaml, config/rbac-base/tls_profile_role_binding.yaml
Adds the new ClusterRole and ClusterRoleBinding for apiservers, and includes them in kustomize resources.
Policy allowlist updates
policy/clusterrole.rego, policy/rbac.rego
Extends the allowlists to accept the new OpenShift API resource and TLS-profile RBAC bindings.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested reviewers: blastStu, RobGeada, nbs-rh, kpunwatk

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: integrating the operator with the cluster TLS security profile.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cmd/main.go (1)

150-154: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

EvalHub webhook server discards the resolved TLSOpts.

When serviceEvalHub is enabled, mgrOpts.WebhookServer is replaced with a new server that only sets Port: 9443 and omits TLSOpts. This silently drops the cluster TLS profile for the webhook server on EvalHub deployments, so the metrics server would honor the profile while the webhook server would not — an inconsistency that defeats the PR's goal for that configuration.

🔒 Proposed fix to preserve TLSOpts
 	if slices.Contains(enabledServices, serviceEvalHub) {
 		mgrOpts.WebhookServer = ctrlwebhook.NewServer(ctrlwebhook.Options{
-			Port: 9443,
+			Port:    9443,
+			TLSOpts: tlsOpts,
 		})
 	}

Since the only apparent difference between the two NewServer calls is this branch, consider dropping the duplicate construction entirely and keeping the single one at lines 143-146.

🤖 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 `@cmd/main.go` around lines 150 - 154, The EvalHub branch in main.go recreates
mgrOpts.WebhookServer with only Port set, which drops the previously resolved
TLSOpts. Update the serviceEvalHub conditional so it preserves the existing TLS
configuration from the earlier ctrlwebhook.NewServer setup, ideally by removing
the duplicate server construction and reusing the single mgrOpts.WebhookServer
initialization path.
🧹 Nitpick comments (3)
config/rbac-base/tls_profile_role.yaml (1)

6-13: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider scoping down permissions to least privilege.

Per the PR description, the operator performs a single Get on the cluster singleton APIServer object at startup, not a watch/list. Granting list/watch on all apiservers objects is broader than needed.

🔒 Suggested tightening
 rules:
   - apiGroups:
       - config.openshift.io
     resources:
       - apiservers
+    resourceNames:
+      - cluster
     verbs:
       - get
-      - list
-      - watch

Please confirm the exact API calls made against this resource in pkg/tls/tls.go (a Get-only client vs. a cached/watched client) before applying this change, since informer-backed clients would still require list/watch.

🤖 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 `@config/rbac-base/tls_profile_role.yaml` around lines 6 - 13, The RBAC rule
for the APIServer resource is broader than the current usage and should be
tightened only if pkg/tls/tls.go uses a direct Get call on the singleton cluster
APIServer object. Verify whether the tls package uses a plain client Get or an
informer/cached client, then update the tls_profile_role permissions
accordingly: keep only get for a direct read, or retain list/watch only if the
code वास्तव में relies on watching/caching that resource. Use the APIServer
access in pkg/tls/tls.go and the apiservers rule in tls_profile_role.yaml to
locate the change.
pkg/tls/tls.go (1)

145-148: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Modern/Custom TLS 1.3 cipher suites are silently ignored by Go.

For TLSProfileModernType you return nil ciphers (fine), but note that Go ignores CipherSuites entirely for TLS 1.3 connections. A Custom profile pinned to VersionTLS13 with explicit Ciphers will still have those ciphers accepted into c.CipherSuites yet have no runtime effect. This is acceptable behavior but worth a brief comment so future readers don't assume TLS 1.3 cipher selection is honored.

🤖 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 145 - 148, Add a brief comment in the TLS
profile/version mapping logic around TLSProfileModernType and any custom TLS 1.3
path in tls.go to note that Go ignores CipherSuites for TLS 1.3, so explicitly
configured ciphers are accepted in the config but have no runtime effect. Keep
the existing behavior in the version-returning code, and make the note near the
relevant switch/translation logic so future readers do not assume TLS 1.3 cipher
selection is honored.
pkg/tls/tls_test.go (1)

26-173: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider aligning with the repo's Ginkgo/Gomega test convention.

These are pure unit tests over parseProfile, so plain testing works fine, but the project convention is Ginkgo v2 + Gomega. Adopting Expect(...)-style assertions here would keep the test suite consistent and reuse existing tooling. Not blocking given this is a dependency-free pure function.

As per coding guidelines: "Use Ginkgo v2, Gomega, and controller-runtime envtest with K8s 1.29.0 binaries for unit tests".

🤖 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 26 - 173, The TestParseProfile function
uses the standard Go testing package with table-driven tests, but the project
convention is to use Ginkgo v2 and Gomega for unit tests. Convert this test to
use Ginkgo v2 style with Describe and It blocks, and replace the manual error
comparisons (t.Errorf, t.Fatal calls) with Gomega Expect assertions to align
with the repository's testing standards and maintain consistency across the test
suite.

Source: Coding guidelines

🤖 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 `@cmd/main.go`:
- Around line 121-123: The metrics server configuration in ctrl.Options is
mixing TLSOpts with plain HTTP, so either enable SecureServing for the metrics
endpoint and switch it to HTTPS, or remove TLSOpts entirely if metrics should
stay unencrypted. Update the metrics server setup in main by adjusting the
ctrl.Options/Metrics configuration so it matches the intended serving mode.

---

Outside diff comments:
In `@cmd/main.go`:
- Around line 150-154: The EvalHub branch in main.go recreates
mgrOpts.WebhookServer with only Port set, which drops the previously resolved
TLSOpts. Update the serviceEvalHub conditional so it preserves the existing TLS
configuration from the earlier ctrlwebhook.NewServer setup, ideally by removing
the duplicate server construction and reusing the single mgrOpts.WebhookServer
initialization path.

---

Nitpick comments:
In `@config/rbac-base/tls_profile_role.yaml`:
- Around line 6-13: The RBAC rule for the APIServer resource is broader than the
current usage and should be tightened only if pkg/tls/tls.go uses a direct Get
call on the singleton cluster APIServer object. Verify whether the tls package
uses a plain client Get or an informer/cached client, then update the
tls_profile_role permissions accordingly: keep only get for a direct read, or
retain list/watch only if the code वास्तव में relies on watching/caching that
resource. Use the APIServer access in pkg/tls/tls.go and the apiservers rule in
tls_profile_role.yaml to locate the change.

In `@pkg/tls/tls_test.go`:
- Around line 26-173: The TestParseProfile function uses the standard Go testing
package with table-driven tests, but the project convention is to use Ginkgo v2
and Gomega for unit tests. Convert this test to use Ginkgo v2 style with
Describe and It blocks, and replace the manual error comparisons (t.Errorf,
t.Fatal calls) with Gomega Expect assertions to align with the repository's
testing standards and maintain consistency across the test suite.

In `@pkg/tls/tls.go`:
- Around line 145-148: Add a brief comment in the TLS profile/version mapping
logic around TLSProfileModernType and any custom TLS 1.3 path in tls.go to note
that Go ignores CipherSuites for TLS 1.3, so explicitly configured ciphers are
accepted in the config but have no runtime effect. Keep the existing behavior in
the version-returning code, and make the note near the relevant
switch/translation logic so future readers do not assume TLS 1.3 cipher
selection is honored.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2d0a4c3b-4ad1-4a7c-90f8-92c837fea4a5

📥 Commits

Reviewing files that changed from the base of the PR and between 9520041 and d8cbcde.

📒 Files selected for processing (8)
  • cmd/main.go
  • config/rbac-base/kustomization.yaml
  • config/rbac-base/tls_profile_role.yaml
  • config/rbac-base/tls_profile_role_binding.yaml
  • pkg/tls/tls.go
  • pkg/tls/tls_test.go
  • policy/clusterrole.rego
  • policy/rbac.rego

Comment thread cmd/main.go
@ruivieira ruivieira self-assigned this Jul 7, 2026
@ruivieira
ruivieira self-requested a review July 7, 2026 10:17
@ruivieira ruivieira moved this to In Progress in TrustyAI planning Jul 7, 2026
@ruivieira ruivieira moved this from In Progress to In Review in TrustyAI planning Jul 7, 2026
@ugiordan

ugiordan commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

/ok-to-test

@ruivieira ruivieira left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@ugiordan LGTM, thanks! Just an inlined question.

Comment thread config/rbac-base/tls_profile_role.yaml Outdated
Read the cluster TLS profile from apiservers.config.openshift.io/cluster
at startup via pkg/tls.Resolve(). Apply MinVersion, CipherSuites, and
NextProtos to metrics server TLS config. Fail closed on unexpected errors.
Use Intermediate defaults on non-OpenShift clusters.

TLS code extracted into pkg/tls/ for reusability and testability.

Signed-off-by: Ugo Giordano <ugiordan@redhat.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Ugo Giordano <ugiordan@redhat.com>
@ugiordan
ugiordan force-pushed the RHOAIENG-61068-tls-profile branch from d8cbcde to 768f504 Compare July 7, 2026 14:50
@openshift-ci openshift-ci Bot removed the lgtm label Jul 7, 2026
@openshift-ci

openshift-ci Bot commented Jul 7, 2026

Copy link
Copy Markdown

@ugiordan: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/trustyai-service-operator-e2e 768f504 link true /test trustyai-service-operator-e2e

Full PR test history. Your PR dashboard.

Details

Instructions 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.

@openshift-ci openshift-ci Bot added the lgtm label Jul 7, 2026
@openshift-ci

openshift-ci Bot commented Jul 7, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: ruivieira

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ruivieira
ruivieira merged commit b7f3922 into trustyai-explainability:main Jul 7, 2026
12 of 13 checks passed
@ruivieira ruivieira moved this from In Review to Done in TrustyAI planning Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants