Skip to content

OCPBUGS-77056: Make external cert validation asynchronous (Resurrection) - #822

Merged
openshift-merge-bot[bot] merged 13 commits into
openshift:masterfrom
bentito:OCPBUGS-77056-async-sar-resurrect
Jul 24, 2026
Merged

OCPBUGS-77056: Make external cert validation asynchronous (Resurrection)#822
openshift-merge-bot[bot] merged 13 commits into
openshift:masterfrom
bentito:OCPBUGS-77056-async-sar-resurrect

Conversation

@bentito

@bentito bentito commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

This PR is a resurrection of PR #745 ("Make external cert validation asynchronous") which was reverted in PR #817 due to a regression in the RouteExternalCertificate hypershift conformance tests.

What PR #745 Did

It implemented semaphore-throttled, cached, asynchronous checks using SubjectAccessReview for route spec.tls.externalCertificate during router startup. This maintains full RBAC security checks while executing them asynchronously in the background, avoiding the O(N * API_latency) startup Probe delays causing CrashLoopBackOff when scaling to thousands of routes.

Reversion Root Cause

When a referenced certificate secret was deleted, the route's ingress condition stayed in the successful ExternalCertificateSARCompleted/True state instead of transitioning to ExternalCertificateValidationFailed/False. The e2e conformance tests checked for this transition and timed out. This was due to:

  1. conditionsEqual in master ignoring status transitions when one of the reasons belonged to the ignored set.
  2. The DeleteFunc of the secret handler recording a transient ExternalCertificateSecretDeleted/False status and relying on a separate watch-triggered re-evaluation cycle to hit validate() and record the final ExternalCertificateValidationFailed state. This multi-step process was race-prone and didn't reliably complete before the test polled.

What This Resurrection Adds (Robustness & Bug Fixes)

  1. Immediate Final Failed State (Fail-Closed): Updated DeleteFunc in route_secret_manager.go to directly and immediately record ExternalCertificateValidationFailed/False status upon secret deletion. This satisfies the E2E test assertions instantly, avoids a secondary status update, and eliminates any race conditions.
  2. Standard Service Account Groups in SubjectAccessReview (SAR) checks: Populated the Groups field on all SAR requests with standard service account groups (system:serviceaccounts, system:serviceaccounts:openshift-ingress, and system:authenticated). This ensures correct RBAC evaluation on clusters where permissions are granted via group-level roles, preventing false-negative denials.
  3. Improved Testing Hygiene: Replaced global os.Setenv mutations with t.Setenv in factory_endpointslices_test.go to avoid process-wide test environment pollution.
  4. Corrected Ingress Condition Comparison: Preserved the fix to conditionsEqual() to ensure it correctly compares Type and Status before ignoring reasons.
  5. Message Semantic Consistency: Refined the secret deletion status message to say "external certificate validation failed: secret ... deleted" to keep it consistent with the rejection reason.

All unit tests compiled, executed, and passed cleanly with Go 1.26 and Kubernetes 1.36.2.

Summary by CodeRabbit

  • New Features

    • Improved handling of external TLS certificates, including permission checks, result caching, and controlled concurrency.
    • Added more efficient secret monitoring across routes and namespaces.
    • Increased Kubernetes client request capacity for improved responsiveness.
    • Added support for concurrent status processing workers.
  • Bug Fixes

    • Prevented route status flapping and unnecessary leadership loss during update conflicts.
    • Improved handling of deleted or recreated TLS secrets.
    • Corrected architecture selection for debug image builds.
    • Refined TLS validation behavior for malformed certificate data.

@openshift-ci-robot openshift-ci-robot added jira/severity-critical Referenced Jira bug's severity is critical for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Jul 22, 2026
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@bentito: This pull request references Jira Issue OCPBUGS-77056, which is invalid:

  • expected the bug to be in one of the following states: NEW, ASSIGNED, POST, but it is Verified instead

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

This PR is a resurrection of PR #745 ("Make external cert validation asynchronous") which was reverted in PR #817 due to a regression in the RouteExternalCertificate hypershift conformance tests.

What PR #745 Did

It implemented semaphore-throttled, cached, asynchronous checks using SubjectAccessReview for route spec.tls.externalCertificate during router startup. This maintains full RBAC security checks while executing them asynchronously in the background, avoiding the O(N * API_latency) startup Probe delays causing CrashLoopBackOff when scaling to thousands of routes.

Reversion Root Cause

When a referenced certificate secret was deleted, the route's ingress condition stayed in the successful ExternalCertificateSARCompleted/True state instead of transitioning to ExternalCertificateValidationFailed/False. The e2e conformance tests checked for this transition and timed out. This was due to:

  1. conditionsEqual in master ignoring status transitions when one of the reasons belonged to the ignored set.
  2. The DeleteFunc of the secret handler recording a transient ExternalCertificateSecretDeleted/False status and relying on a separate watch-triggered re-evaluation cycle to hit validate() and record the final ExternalCertificateValidationFailed state. This multi-step process was race-prone and didn't reliably complete before the test polled.

What This Resurrection Adds (Robustness & Bug Fixes)

  1. Immediate Final Failed State (Fail-Closed): Updated DeleteFunc in route_secret_manager.go to directly and immediately record ExternalCertificateValidationFailed/False status upon secret deletion. This satisfies the E2E test assertions instantly, avoids a secondary status update, and eliminates any race conditions.
  2. Standard Service Account Groups in SubjectAccessReview (SAR) checks: Populated the Groups field on all SAR requests with standard service account groups (system:serviceaccounts, system:serviceaccounts:openshift-ingress, and system:authenticated). This ensures correct RBAC evaluation on clusters where permissions are granted via group-level roles, preventing false-negative denials.
  3. Improved Testing Hygiene: Replaced global os.Setenv mutations with t.Setenv in factory_endpointslices_test.go to avoid process-wide test environment pollution.
  4. Corrected Ingress Condition Comparison: Preserved the fix to conditionsEqual() to ensure it correctly compares Type and Status before ignoring reasons.
  5. Message Semantic Consistency: Refined the secret deletion status message to say "external certificate validation failed: secret ... deleted" to keep it consistent with the rejection reason.

All unit tests compiled, executed, and passed cleanly with Go 1.26 and Kubernetes 1.36.2.

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 openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@bentito, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 25 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 58477ac0-a6fe-466d-a00f-044285327ee7

📥 Commits

Reviewing files that changed from the base of the PR and between 357b83b and da1c969.

⛔ Files ignored due to path filters (3)
  • vendor/github.com/openshift/library-go/pkg/authorization/authorizationutil/subject.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/pkg/authorization/authorizationutil/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (17)
  • hack/Makefile.debug
  • pkg/cmd/infra/router/clientcmd.go
  • pkg/cmd/infra/router/template.go
  • pkg/router/controller/contention.go
  • pkg/router/controller/factory/factory_endpointslices_test.go
  • pkg/router/controller/route_secret_manager.go
  • pkg/router/controller/route_secret_manager_test.go
  • pkg/router/controller/shared_secret_manager.go
  • pkg/router/controller/shared_secret_manager_test.go
  • pkg/router/controller/status.go
  • pkg/router/controller/status_test.go
  • pkg/router/routeapihelpers/validation.go
  • pkg/router/routeapihelpers/validation_test.go
  • pkg/router/router_test.go
  • pkg/router/template/configmanager/haproxy/testing/haproxy.go
  • pkg/router/writerlease/writerlease.go
  • pkg/router/writerlease/writerlease_test.go

Walkthrough

The PR adds shared Secret informer management, throttled and cached external-certificate SAR validation, SAR completion status reporting, concurrent writer lease workers, and related controller, build, and test-harness updates.

Changes

External certificate processing

Layer / File(s) Summary
Throttled external certificate validation
pkg/router/routeapihelpers/validation.go, pkg/router/routeapihelpers/validation_test.go
External certificate validation adds direct SAR checks, concurrency limiting, successful-result caching, invalidation helpers, and revised PEM validation expectations.
Shared Secret informer management
pkg/router/controller/shared_secret_manager.go, pkg/router/controller/shared_secret_manager_test.go
Routes use namespace-wide or per-secret informers based on RBAC restrictions, with event dispatch, cache/API retrieval, route lookup, and informer cleanup.
Route Secret status and handlers
pkg/router/controller/route_secret_manager.go, pkg/router/controller/route_secret_manager_test.go
Secret events invalidate SAR cache entries, deletion handles tombstones, successful processing records SAR completion, and tests use synchronous handler invocation with update assertions.
Controller and client integration
pkg/cmd/infra/router/clientcmd.go, pkg/cmd/infra/router/template.go
Kubernetes client rate limits increase, startup uses SharedSecretManager, and status writer concurrency uses the SAR limit.
Concurrent status writing and lease workers
pkg/router/writerlease/*, pkg/router/controller/status.go, pkg/router/controller/status_test.go, pkg/router/router_test.go
Writer leases support multiple workers and delayed requeueing; status handling preserves ignored reasons and retains the lease on conflicts.
Build and test harness adjustments
hack/Makefile.debug, pkg/router/controller/factory/factory_endpointslices_test.go, pkg/router/template/configmanager/haproxy/testing/haproxy.go
Debug image builds specify architecture, endpoint-slice tests scope environment changes, and fake HAProxy startup handles temporary sockets and listener failures differently.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RouteSecretManager
  participant SharedSecretManager
  participant ValidateTLSExternalCertificate
  participant KubernetesAPI
  RouteSecretManager->>SharedSecretManager: Register route and referenced Secret
  SharedSecretManager->>KubernetesAPI: Probe permissions and watch Secrets
  RouteSecretManager->>ValidateTLSExternalCertificate: Validate external certificate
  ValidateTLSExternalCertificate->>KubernetesAPI: Create SARs and fetch TLS Secret
  KubernetesAPI-->>ValidateTLSExternalCertificate: Authorization and Secret results
  ValidateTLSExternalCertificate-->>RouteSecretManager: Validation result
  RouteSecretManager->>RouteSecretManager: Record SAR completion status
Loading

Possibly related PRs

  • openshift/router#811: Updates the same fake HAProxy test server’s temporary socket and listener error handling.

Suggested reviewers: knobunc, miciah, redhat-chai-bot

🚥 Pre-merge checks | ✅ 14 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (14 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: resurrecting asynchronous external certificate validation for OCPBUGS-77056.
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.
Stable And Deterministic Test Names ✅ Passed No Ginkgo titles were added; the changed tests use plain testing.T and static subtest names, with no dynamic identifiers in the diff.
Test Structure And Quality ✅ Passed No Ginkgo tests were added/modified; the touched tests are standard Go unit tests, and cluster-interaction cases already use explicit timeouts and cleanup.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; changed tests are plain testing.T unit tests and I found no unsupported MicroShift APIs/features.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the touched tests are plain unit tests and contain no SNO-sensitive node/topology assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed Modified files only adjust secret validation, writer-lease concurrency, tests, and build flags; no nodeSelector, affinity, spread, PDB, or topology-based replica logic was added.
Ote Binary Stdout Contract ✅ Passed Only TestMain was touched, and the diff there changes a constructor call; no new stdout writes were added in process-level setup.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e specs were added; the touched tests are unit tests, and I found no external connectivity requirements.
No-Weak-Crypto ✅ Passed Changed code only references SHA1/MD5 to reject unsupported certs; no weak crypto implementations or secret/token comparisons were added.
Container-Privileges ✅ Passed PASS: master..HEAD changes no K8s/container manifests with privileged/hostPID/hostNetwork/hostIPC, allowPrivilegeEscalation, SYS_ADMIN, or runAsUser:0; only vendor config YAMLs changed.
No-Sensitive-Data-In-Logs ✅ Passed No added logs expose secret contents, tokens, keys, PII, or hostnames; changed messages only include route/secret names and resource versions.
✨ 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.

@openshift-ci
openshift-ci Bot requested review from Miciah and knobunc July 22, 2026 14:33
@bentito

bentito commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

/test verify-deps

@bentito

bentito commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

/payload-aggregate periodic-ci-openshift-hypershift-release-5.0-periodics-e2e-aws-ovn-conformance 10

@openshift-ci

openshift-ci Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@bentito: trigger 1 job(s) for the /payload-(with-prs|job|aggregate|job-with-prs|aggregate-with-prs) command

  • periodic-ci-openshift-hypershift-release-5.0-periodics-e2e-aws-ovn-conformance

See details on https://pr-payload-tests.ci.openshift.org/runs/ci/d2e30930-85e7-11f1-9f54-ba31857f6125-0

@bentito

bentito commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

/test e2e-agnostic

@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
pkg/router/writerlease/writerlease_test.go (1)

9-9: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add coverage for multiple workers.

All updated tests use workers=1; add a bounded workers=2 test that verifies two distinct keys execute concurrently and shutdown waits for both workers.

Also applies to: 33-33, 53-53, 75-75, 115-115

🤖 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/router/writerlease/writerlease_test.go` at line 9, Add a bounded test
alongside the existing New calls in the writerlease tests using workers=2, with
two distinct keys whose work blocks until both have started to prove concurrent
execution. Release the work, shut down the writer lease, and assert shutdown
does not return until both workers finish.
pkg/router/template/configmanager/haproxy/testing/haproxy.go (1)

110-110: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Resolve the noctx lint finding.

golangci-lint reports direct net.Listen usage here; use net.ListenConfig.Listen with an appropriate context, or add a narrow documented exception if this synchronous test-only bind is intentionally exempt.

🤖 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/router/template/configmanager/haproxy/testing/haproxy.go` at line 110,
Replace the direct net.Listen call in the test setup with
net.ListenConfig.Listen using an appropriate context, preserving the existing
network and socket behavior; only add a narrow documented noctx exception if
this synchronous test-only bind is intentionally exempt.

Sources: Path instructions, Linters/SAST tools

pkg/cmd/infra/router/template.go (1)

818-818: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Decouple writer-lease worker count from the SAR throttle constant, and review write amplification.

Passing routeapihelpers.MaxConcurrentSARChecks as the writer-lease workers argument ties status-write parallelism to an unrelated SAR-concurrency limit—future tuning of one silently changes the other. It also raises status-write concurrency to 50 workers, which combined with the client-side QPS=50/Burst=100 could saturate the client rate limiter and increase status-update conflicts under scale. Consider a dedicated named constant and validating the API write load.

🤖 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/cmd/infra/router/template.go` at line 818, Update the writer-lease
initialization in the route template generation flow to use a dedicated named
worker-count constant instead of routeapihelpers.MaxConcurrentSARChecks. Choose
a conservative value for status writes, define it alongside the related
configuration constants, and keep SAR concurrency tuning independent from
writer-lease parallelism.
pkg/router/controller/shared_secret_manager.go (1)

111-118: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Fast-path caches all namespace secrets in router memory.

Using fields.Everything() makes the shared informer list/watch and cache every Secret (including Data) in each namespace that has an external-cert route. In namespaces with many/large secrets this increases the router's memory footprint and the amount of secret material held in-process. Consider bounding memory (or documenting expected footprint) for high-secret-count namespaces.

🤖 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/router/controller/shared_secret_manager.go` around lines 111 - 118,
Update the unrestricted selector logic in the shared-secret manager’s informer
setup so it does not use fields.Everything() to cache every namespace Secret.
Bound the list/watch to only the secrets required by external-cert routes, or
otherwise apply an explicit memory-limiting strategy while preserving the
restricted secretName behavior.
🤖 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/router/controller/shared_secret_manager.go`:
- Around line 108-109: The map lookup in the informer-management flow assigns
infState before it is used, then overwrites it in the !exists branch. Remove the
unused infState assignment from the initial lookup while preserving the exists
check and subsequent informer-state initialization behavior.

In `@pkg/router/template/configmanager/haproxy/testing/haproxy.go`:
- Around line 109-112: Update fake HAProxy Start’s listener goroutine to report
net.Listen and unexpected listener.Accept failures through a test-visible error
mechanism instead of panicking or silently exiting; ensure startup failure still
signals completion appropriately, and treat the expected
shutdown/closed-listener error as non-fatal while propagating other accept
errors.

---

Nitpick comments:
In `@pkg/cmd/infra/router/template.go`:
- Line 818: Update the writer-lease initialization in the route template
generation flow to use a dedicated named worker-count constant instead of
routeapihelpers.MaxConcurrentSARChecks. Choose a conservative value for status
writes, define it alongside the related configuration constants, and keep SAR
concurrency tuning independent from writer-lease parallelism.

In `@pkg/router/controller/shared_secret_manager.go`:
- Around line 111-118: Update the unrestricted selector logic in the
shared-secret manager’s informer setup so it does not use fields.Everything() to
cache every namespace Secret. Bound the list/watch to only the secrets required
by external-cert routes, or otherwise apply an explicit memory-limiting strategy
while preserving the restricted secretName behavior.

In `@pkg/router/template/configmanager/haproxy/testing/haproxy.go`:
- Line 110: Replace the direct net.Listen call in the test setup with
net.ListenConfig.Listen using an appropriate context, preserving the existing
network and socket behavior; only add a narrow documented noctx exception if
this synchronous test-only bind is intentionally exempt.

In `@pkg/router/writerlease/writerlease_test.go`:
- Line 9: Add a bounded test alongside the existing New calls in the writerlease
tests using workers=2, with two distinct keys whose work blocks until both have
started to prove concurrent execution. Release the work, shut down the writer
lease, and assert shutdown does not return until both workers finish.
🪄 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: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8dee1794-61fa-4494-ba5e-5ede45df1b01

📥 Commits

Reviewing files that changed from the base of the PR and between 0c4063d and 357b83b.

⛔ Files ignored due to path filters (3)
  • vendor/github.com/openshift/library-go/pkg/authorization/authorizationutil/subject.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/pkg/authorization/authorizationutil/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (17)
  • hack/Makefile.debug
  • pkg/cmd/infra/router/clientcmd.go
  • pkg/cmd/infra/router/template.go
  • pkg/router/controller/contention.go
  • pkg/router/controller/factory/factory_endpointslices_test.go
  • pkg/router/controller/route_secret_manager.go
  • pkg/router/controller/route_secret_manager_test.go
  • pkg/router/controller/shared_secret_manager.go
  • pkg/router/controller/shared_secret_manager_test.go
  • pkg/router/controller/status.go
  • pkg/router/controller/status_test.go
  • pkg/router/routeapihelpers/validation.go
  • pkg/router/routeapihelpers/validation_test.go
  • pkg/router/router_test.go
  • pkg/router/template/configmanager/haproxy/testing/haproxy.go
  • pkg/router/writerlease/writerlease.go
  • pkg/router/writerlease/writerlease_test.go

Comment thread pkg/router/controller/shared_secret_manager.go
Comment thread pkg/router/template/configmanager/haproxy/testing/haproxy.go
bentito added 13 commits July 23, 2026 10:29
This prevents the router from dropping its leader lease under high concurrency when updating route statuses, which was causing a 60-second stall in scale tests.
This commit modifies DeleteFunc inside route_secret_manager.go to transition the route's ingress condition to ExternalCertificateValidationFailed on secret deletion, rather than the transient ExternalCertificateSecretDeleted status.

Reasoning and Analysis:
- The RouteExternalCertificate e2e conformance tests in hypershift expect the route to transition to 'ExternalCertificateValidationFailed' (with ConditionFalse) when a referenced TLS secret is deleted.
- Previously, when DeleteFunc fired, it recorded the intermediate reason 'ExternalCertificateSecretDeleted'. It was expected that the subsequent standard route controller Modified reconciliation would trigger validate(), which would then transition to the final 'ExternalCertificateValidationFailed' reason.
- However, relying on this multi-step watch-triggered transition is race-prone and does not guarantee completion before the test polls.
- By immediately and directly recording 'ExternalCertificateValidationFailed' on secret deletion, we satisfy the E2E test assertion requirements instantly, unblocking hypershift conformance payload nightlies.

Related Changes:
- Updated pkg/router/controller/route_secret_manager_test.go unit tests (TestSecretDelete and TestSecretRecreation) to expect the updated rejection reason.
This commit adds 'system:serviceaccounts', 'system:serviceaccounts:openshift-ingress', and 'system:authenticated' standard service account groups to all SubjectAccessReviewSpecs.

Previously, only the routerServiceAccount name was passed, leading to false-negative denials if permissions are granted via standard service account group roles on the target cluster. Specifying the standard groups ensures complete and correct RBAC evaluation.
…ests

This commit improves testing hygiene in factory_endpointslices_test.go by replacing the global os.Setenv call with t.Setenv.

Using t.Setenv ensures that the KUBE_FEATURE_WatchListClient environment override is automatically scoped and cleanly torn down after each test execution, avoiding potential side effects or pollution on other test suites.
This commit refines the deletion message inside DeleteFunc to say 'external certificate validation failed: secret ... deleted for route ...'

This ensures complete semantic consistency with the ExternalCertificateValidationFailed rejection reason, providing clear and non-contradictory diagnostic information for operators inspecting the route condition.
…ence

This commit updates vendor/modules.txt to remove the reference to github.com/openshift/library-go/pkg/authorization/authorizationutil, which is no longer used by the router following our asynchronous external certificate validation refactoring.
This commit modifies StartFakeServerForTest in pkg/router/template/configmanager/haproxy/testing/haproxy.go to use the pattern 'fake-haproxy-*' instead of combining the long test name in the prefix.

This avoids reaching the hard 104-character limit on Darwin (macOS) Unix socket paths when running local tests, ensuring all tests compile and execute successfully on both macOS and Linux environments.
@bentito
bentito force-pushed the OCPBUGS-77056-async-sar-resurrect branch from 357b83b to da1c969 Compare July 23, 2026 14:30
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 23, 2026
@bentito

bentito commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

/retest

@bentito

bentito commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

/payload-aggregate-with-prs periodic-ci-openshift-hypershift-release-5.0-periodics-e2e-aws-ovn-conformance 10 #822

conn, err := listener.Accept()
if err != nil {
return err
return

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.

minor: maybe this should be a panic as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah let's not wait on a cycle of testing for this. I'll make a note for small follow up PR. thanks

@jcmoraisjr

Copy link
Copy Markdown
Member

/approve
/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jul 24, 2026
@openshift-ci

openshift-ci Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: jcmoraisjr

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

The pull request process is described 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

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 24, 2026
@jcmoraisjr

Copy link
Copy Markdown
Member

@bentito I compared this PR with the former one, changes sounds good. Just found a hidden error message, but it was being hidden before this change as well, so it doesn't worth to run all the CI because of that, and future updates should remove that test as well. Approved, lgtm-ed.

@bentito

bentito commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

@bentito: This PR was included in a payload test run from #822 trigger 1 job(s) for the /payload-(with-prs|job|aggregate|job-with-prs|aggregate-with-prs) command

* periodic-ci-openshift-hypershift-release-5.0-periodics-e2e-aws-ovn-conformance

See details on https://pr-payload-tests.ci.openshift.org/runs/ci/a0c769f0-86d7-11f1-92e7-546aa0840be4-0

All 10 runs of the HyperShift AWS OVN Conformance suite built with our PR #822 payload completed successfully. Previously had a flaky 40% failure rate (4/10 runs) on PR #745

@melvinjoseph86

Copy link
Copy Markdown

the functionality is already verified with #745 (comment), but seems one more check can be done, hence will verify again after the merge..
/verified later @mjoseph

@openshift-ci-robot openshift-ci-robot added verified-later verified Signifies that the PR passed pre-merge verification criteria labels Jul 24, 2026
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@melvinjoseph86: This PR has been marked to be verified later by @mjoseph.

Details

In response to this:

the functionality is already verified with #745 (comment), but seems one more check can be done, hence will verify again after the merge..
/verified later @mjoseph

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 openshift-eng/jira-lifecycle-plugin repository.

@melvinjoseph86

Copy link
Copy Markdown

/jira refresh

@openshift-ci-robot openshift-ci-robot added jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. and removed jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Jul 24, 2026
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@melvinjoseph86: This pull request references Jira Issue OCPBUGS-77056, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)

Requesting review from QA contact:
/cc @melvinjoseph86

Details

In response to this:

/jira refresh

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 openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci
openshift-ci Bot requested a review from melvinjoseph86 July 24, 2026 17:48
@bentito

bentito commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

all tests were passed before verify later which, surprisingly, triggering all checks again. unit and several others tests are failing on pod scheduling timeouts. Since no new commits, and we've got the HyperShift AWS OVN Conformance suite which passed 10/10, I am overriding all outstanding tests, so this can get merged:

/override ci/prow/e2e-agnostic
/override ci/prow/e2e-aws-fips
/override ci/prow/e2e-aws-serial-1of2
/override ci/prow/e2e-aws-serial-2of2
/override ci/prow/e2e-upgrade
/override ci/prow/unit

@openshift-ci

openshift-ci Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

@bentito: Overrode contexts on behalf of bentito: ci/prow/e2e-agnostic, ci/prow/e2e-aws-fips, ci/prow/e2e-aws-serial-1of2, ci/prow/e2e-aws-serial-2of2, ci/prow/e2e-upgrade, ci/prow/unit

Details

In response to this:

all tests were passed before verify later which, surprisingly, triggering all checks again. unit and several others tests are failing on pod scheduling timeouts. Since no new commits, and we've got the HyperShift AWS OVN Conformance suite which passed 10/10, I am overriding all outstanding tests, so this can get merged:

/override ci/prow/e2e-agnostic
/override ci/prow/e2e-aws-fips
/override ci/prow/e2e-aws-serial-1of2
/override ci/prow/e2e-aws-serial-2of2
/override ci/prow/e2e-upgrade
/override ci/prow/unit

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.

@openshift-merge-bot
openshift-merge-bot Bot merged commit 13f62cb into openshift:master Jul 24, 2026
13 checks passed
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@bentito: Jira Issue OCPBUGS-77056: All pull requests linked via external trackers have merged:

This pull request has the verified-later tag and will need to be manually moved to VERIFIED after testing. Jira Issue OCPBUGS-77056 has been moved to the MODIFIED state.

Details

In response to this:

This PR is a resurrection of PR #745 ("Make external cert validation asynchronous") which was reverted in PR #817 due to a regression in the RouteExternalCertificate hypershift conformance tests.

What PR #745 Did

It implemented semaphore-throttled, cached, asynchronous checks using SubjectAccessReview for route spec.tls.externalCertificate during router startup. This maintains full RBAC security checks while executing them asynchronously in the background, avoiding the O(N * API_latency) startup Probe delays causing CrashLoopBackOff when scaling to thousands of routes.

Reversion Root Cause

When a referenced certificate secret was deleted, the route's ingress condition stayed in the successful ExternalCertificateSARCompleted/True state instead of transitioning to ExternalCertificateValidationFailed/False. The e2e conformance tests checked for this transition and timed out. This was due to:

  1. conditionsEqual in master ignoring status transitions when one of the reasons belonged to the ignored set.
  2. The DeleteFunc of the secret handler recording a transient ExternalCertificateSecretDeleted/False status and relying on a separate watch-triggered re-evaluation cycle to hit validate() and record the final ExternalCertificateValidationFailed state. This multi-step process was race-prone and didn't reliably complete before the test polled.

What This Resurrection Adds (Robustness & Bug Fixes)

  1. Immediate Final Failed State (Fail-Closed): Updated DeleteFunc in route_secret_manager.go to directly and immediately record ExternalCertificateValidationFailed/False status upon secret deletion. This satisfies the E2E test assertions instantly, avoids a secondary status update, and eliminates any race conditions.
  2. Standard Service Account Groups in SubjectAccessReview (SAR) checks: Populated the Groups field on all SAR requests with standard service account groups (system:serviceaccounts, system:serviceaccounts:openshift-ingress, and system:authenticated). This ensures correct RBAC evaluation on clusters where permissions are granted via group-level roles, preventing false-negative denials.
  3. Improved Testing Hygiene: Replaced global os.Setenv mutations with t.Setenv in factory_endpointslices_test.go to avoid process-wide test environment pollution.
  4. Corrected Ingress Condition Comparison: Preserved the fix to conditionsEqual() to ensure it correctly compares Type and Status before ignoring reasons.
  5. Message Semantic Consistency: Refined the secret deletion status message to say "external certificate validation failed: secret ... deleted" to keep it consistent with the rejection reason.

All unit tests compiled, executed, and passed cleanly with Go 1.26 and Kubernetes 1.36.2.

Summary by CodeRabbit

  • New Features

  • Improved handling of external TLS certificates, including permission checks, result caching, and controlled concurrency.

  • Added more efficient secret monitoring across routes and namespaces.

  • Increased Kubernetes client request capacity for improved responsiveness.

  • Added support for concurrent status processing workers.

  • Bug Fixes

  • Prevented route status flapping and unnecessary leadership loss during update conflicts.

  • Improved handling of deleted or recreated TLS secrets.

  • Corrected architecture selection for debug image builds.

  • Refined TLS validation behavior for malformed certificate data.

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 openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci

openshift-ci Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

@bentito: all tests passed!

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-merge-robot

Copy link
Copy Markdown
Contributor

Fix included in release 5.0.0-0.nightly-2026-07-25-032712

bentito added a commit to bentito/router that referenced this pull request Jul 27, 2026
…ert validation

Three tests that prove the bugs causing the x509: ECDSA verification
failure after PR openshift#822 merged:

1. TestPopulateRouteTLSRace: fails with -race, proving
   populateRouteTLSFromSecret mutates the shared informer cache object
   while the informer goroutine concurrently reads it via DeepCopy.

2. TestWriteCertificateAtomicity: fails consistently, proving
   os.WriteFile truncates the PEM file before writing — concurrent
   readers (HAProxy during reload) observe empty files 3% of the time.

3. TestSARCompletedFeedbackLoop: passes, documenting that every
   HandleRoute unconditionally emits RecordRouteUpdate(SARCompleted),
   creating a re-enqueue loop that doubles cert writes and reloads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bentito added a commit to bentito/router that referenced this pull request Jul 30, 2026
…ert validation

Three tests that prove the bugs causing the x509: ECDSA verification
failure after PR openshift#822 merged:

1. TestPopulateRouteTLSRace: fails with -race, proving
   populateRouteTLSFromSecret mutates the shared informer cache object
   while the informer goroutine concurrently reads it via DeepCopy.

2. TestWriteCertificateAtomicity: fails consistently, proving
   os.WriteFile truncates the PEM file before writing — concurrent
   readers (HAProxy during reload) observe empty files 3% of the time.

3. TestSARCompletedFeedbackLoop: passes, documenting that every
   HandleRoute unconditionally emits RecordRouteUpdate(SARCompleted),
   creating a re-enqueue loop that doubles cert writes and reloads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/severity-critical Referenced Jira bug's severity is critical for the branch this PR is targeting. jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. verified Signifies that the PR passed pre-merge verification criteria verified-later

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants