Skip to content

OCPBUGS-57437: Always validate EgressIPs - #309

Open
mdbooth wants to merge 5 commits into
openshift:mainfrom
mdbooth:OCPBUGS-57437
Open

OCPBUGS-57437: Always validate EgressIPs#309
mdbooth wants to merge 5 commits into
openshift:mainfrom
mdbooth:OCPBUGS-57437

Conversation

@mdbooth

@mdbooth mdbooth commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

EgressIPs manifest as additional IP addresses on a Node. They are dynamic, so can be added and removed. Even though they cannot be used to serve incoming traffic, CCMs cannot currently distinguish EgressIPs and they will typically be added to a Node's Addresses. Consequently kubelet will typically request a CSR containing EgressIPs when they are present on a Node.

We had some existing code to make the approver aware of OpenShiftSDN egress IPs, but no equivalent for OVN Kubernetes.

This change fixes 2 aspects of validating a Node with EgressIPs:

  • Extend support for EgressIP matching to OVN Kubernetes
  • Ensure that a Node cannot continue to request an EgressIP which it no longer has

For the first, we also fetch OVNKubernetes EgressIP based on the infrastructure's networkType.

For the second, we can only do this for IPI clusters as we don't know the complete set of permitted address in a UPI cluster. To enable this for IPI clusters, we deterministically split the authorisation path chosen based on the presence of a Machine object for a Node. We no longer permit fall-through authentication. A side benefit of this is that the error messages reported on authentication failures become shorter. However, note from the test changes that this doesn't result in any additional failure modes.

Summary by CodeRabbit

  • New Features
    • CSR approval now considers node egress IPs and CIDRs when validating serving certificate requests, including egress-aware SAN handling.
    • Added support for EgressIP custom resources during controller startup and authorization flows.
  • Bug Fixes
    • Improved CSR authorization behavior and error reporting by clearly separating non-retryable validation failures from retriable issues.
    • Serving-certificate renewal validation now allows SANs that match the node’s egress IP/CIDR constraints rather than requiring exact IP equality.
  • Chores
    • Updated dependencies to newer versions.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 3, 2026
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@mdbooth: This pull request references Jira Issue OCPBUGS-57437, which is invalid:

  • expected the bug to target the "5.0.0" version, but no target version was set

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:

EgressIPs manifest as additional IP addresses on a Node. They are dynamic, so can be added and removed. Even though they cannot be used to serve incoming traffic, CCMs cannot currently distinguish EgressIPs and they will typically be added to a Node's Addresses. Consequently kubelet will typically request a CSR containing EgressIPs when they are present on a Node.

We had some existing code to make the approver aware of OpenShiftSDN egress IPs, but no equivalent for OVN Kubernetes.

This change fixes 2 aspects of validating a Node with EgressIPs:

  • Extend support for EgressIP matching to OVN Kubernetes
  • Ensure that a Node cannot continue to request an EgressIP which it no longer has

For the first, we also fetch OVNKubernetes EgressIP based on the infrastructure's networkType.

For the second, we can only do this for IPI clusters as we don't know the complete set of permitted address in a UPI cluster. To enable this for IPI clusters, we deterministically split the authorisation path chosen based on the presence of a Machine object for a Node. We no longer permit fall-through authentication. A side benefit of this is that the error messages reported on authentication failures become shorter. However, note from the test changes that this doesn't result in any additional failure modes.

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-robot openshift-ci-robot added the jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. label Jul 3, 2026
@mdbooth

mdbooth commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

/jira refresh

@openshift-ci

openshift-ci Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign joelspeed for approval. For more information see the Code Review Process.

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

@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 3, 2026
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@mdbooth: This pull request references Jira Issue OCPBUGS-57437, which is valid. The bug has been moved to the POST state.

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 ASSIGNED, which is one of the valid states (NEW, ASSIGNED, POST)

Requesting review from QA contact:
/cc @sunzhaohua2

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.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 48b78546-9275-4886-b5b4-840a2a5837ce

📥 Commits

Reviewing files that changed from the base of the PR and between a870966 and 0db2470.

⛔ Files ignored due to path filters (154)
  • go.sum is excluded by !**/*.sum
  • vendor/go.opentelemetry.io/otel/.golangci.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/AGENTS.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/CHANGELOG.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/CLAUDE.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/CONTRIBUTING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/Makefile is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/RELEASING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/encoder.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/hash.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/internal/attribute.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/key.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/kv.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/set.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/type_string.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/value.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/baggage/baggage.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/dependencies.Dockerfile is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/asyncfloat64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/asyncint64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/instrument.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/syncfloat64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/syncint64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/propagation/baggage.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/propagation/trace_context.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/requirements.txt is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/internal/x/features.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/container.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/host_id_exec.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/host_id_readfile.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/os.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/os_unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/os_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/process.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/resource.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/batch_span_processor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/simple_span_processor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/tracer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/provider.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/span.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.26.0/attribute_group.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.37.0/attribute_group.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/MIGRATION.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/attribute_group.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/error_type.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/exception.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/otelconv/metric.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/schema.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/auto.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/internal/telemetry/span.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/trace.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/tracestate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/versions.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/plan9/syscall_plan9.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/affinity_linux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ioctl_signed.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ioctl_unsigned.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/mkall.sh is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/mkerrors.sh is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/readv_unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_darwin.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_linux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_linux_arm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_linux_arm64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_linux_loong64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_openbsd.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_solaris.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_386.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_arm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_mips.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_linux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_386.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_386.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_arm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_mips.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/aliases.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/dll_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/registry/key.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/security_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/syscall_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/types_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/zsyscall_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (5)
  • go.mod
  • main.go
  • pkg/controller/controller.go
  • pkg/controller/csr_check.go
  • pkg/controller/csr_check_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • main.go
  • pkg/controller/controller.go
  • go.mod
  • pkg/controller/csr_check_test.go

Walkthrough

This PR registers the OVN EgressIP CRD, adds egress-aware CSR authorization and serving-cert validation, updates retry handling for validation errors, and refreshes tests and indirect dependencies.

Changes

Egress-aware CSR authorization

Layer / File(s) Summary
Dependencies and scheme
go.mod, main.go
Adds the EgressIP controller dependency, refreshes indirect modules, registers the EgressIP API during manager startup, and stops on scheme registration failure.
Reconcile and retry handling
pkg/controller/controller.go
Threads context through CSR reconciliation and treats validation failures as non-retryable while keeping other authorization errors retryable.
Egress-aware CSR checks
pkg/controller/csr_check.go
Loads node egress data, reads kubelet CA and serving certs with context, and updates machine-based and renewal-based serving CSR validation to allow egress-aware IP matching.
CSR tests
pkg/controller/csr_check_test.go
Registers EgressIP types in tests, adds OVN EgressIP fixtures and cases, and updates harness calls and expected errors for the new authorization paths.

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


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error PR adds logs that print node names, SANs, and machine/egress IPs, exposing internal hostnames/IPs in validation failures. Redact or remove node name/SAN/address details from logs; log only non-sensitive context or counts, and avoid printing full IP/DNS lists.
Ipv6 And Disconnected Network Test Compatibility ⚠️ Warning Changed tests hardcode IPv4 loopback and addresses (127.0.0.1, 10.0.0.1) and build 127.0.0.1:25544 directly, so they're not IPv6-safe. Use IPv6/dual-stack test inputs and net.JoinHostPort or IP-family detection for socket addresses, then verify under the IPv6 CI job.
✅ Passed checks (13 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: adding always-on EgressIP validation.
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.
Stable And Deterministic Test Names ✅ Passed PASS: The affected test file uses fixed string names in table-driven t.Run cases; no fmt.Sprintf, IPs, timestamps, UUIDs, or runtime-derived values appear in titles.
Test Structure And Quality ✅ Passed No Ginkgo tests here; the modified subtests use isolated setup/cleanup, explicit TLS dial timeout, and clear failure messages.
Microshift Test Compatibility ✅ Passed No new Ginkgo/e2e tests were added; the modified file is standard Go unit tests and contains no MicroShift-unsafe API/resource usage.
Single Node Openshift (Sno) Test Compatibility ✅ Passed Only unit tests changed; no new Ginkgo e2e tests or SNO-specific multi-node assumptions were added.
Topology-Aware Scheduling Compatibility ✅ Passed Only pkg/controller/csr_check_test.go changed; no manifests or runtime code were modified, and no scheduling/topology constraints were introduced.
Ote Binary Stdout Contract ✅ Passed No process-level stdout writes were added; main/init only register schemes, and vendored klog defaults to stderr.
No-Weak-Crypto ✅ Passed No weak ciphers/hashes or custom crypto were added; changed code uses standard tls/x509 and compares public SAN/address slices only.
Container-Privileges ✅ Passed Only pkg/controller/csr_check_test.go changed, and it contains no privileged/hostPID/hostNetwork/hostIPC/SYS_ADMIN/allowPrivilegeEscalation settings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@openshift-ci

openshift-ci Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

@openshift-ci-robot: GitHub didn't allow me to request PR reviews from the following users: sunzhaohua2.

Note that only openshift members and repo collaborators can review this PR, and authors cannot review their own PRs.

Details

In response to this:

@mdbooth: This pull request references Jira Issue OCPBUGS-57437, which is valid. The bug has been moved to the POST state.

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 ASSIGNED, which is one of the valid states (NEW, ASSIGNED, POST)

Requesting review from QA contact:
/cc @sunzhaohua2

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.

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

Copy link
Copy Markdown
Contributor

@mdbooth: This pull request references Jira Issue OCPBUGS-57437, 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 @sunzhaohua2

Details

In response to this:

EgressIPs manifest as additional IP addresses on a Node. They are dynamic, so can be added and removed. Even though they cannot be used to serve incoming traffic, CCMs cannot currently distinguish EgressIPs and they will typically be added to a Node's Addresses. Consequently kubelet will typically request a CSR containing EgressIPs when they are present on a Node.

We had some existing code to make the approver aware of OpenShiftSDN egress IPs, but no equivalent for OVN Kubernetes.

This change fixes 2 aspects of validating a Node with EgressIPs:

  • Extend support for EgressIP matching to OVN Kubernetes
  • Ensure that a Node cannot continue to request an EgressIP which it no longer has

For the first, we also fetch OVNKubernetes EgressIP based on the infrastructure's networkType.

For the second, we can only do this for IPI clusters as we don't know the complete set of permitted address in a UPI cluster. To enable this for IPI clusters, we deterministically split the authorisation path chosen based on the presence of a Machine object for a Node. We no longer permit fall-through authentication. A side benefit of this is that the error messages reported on authentication failures become shorter. However, note from the test changes that this doesn't result in any additional failure modes.

Summary by CodeRabbit

  • New Features

  • CSR approval now accounts for node egress IPs and CIDRs when validating serving certificate requests.

  • Support was added for additional network-related resources used during certificate approval.

  • Bug Fixes

  • Improved handling of certificate signing requests so validation failures are reported more clearly.

  • Serving certificate renewal checks now allow valid IP ranges instead of requiring exact IP matches, reducing false rejections.

  • Chores

  • Updated several dependencies to newer versions.

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 3, 2026

Copy link
Copy Markdown
Contributor

@openshift-ci-robot: GitHub didn't allow me to request PR reviews from the following users: sunzhaohua2.

Note that only openshift members and repo collaborators can review this PR, and authors cannot review their own PRs.

Details

In response to this:

@mdbooth: This pull request references Jira Issue OCPBUGS-57437, 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 @sunzhaohua2

In response to this:

EgressIPs manifest as additional IP addresses on a Node. They are dynamic, so can be added and removed. Even though they cannot be used to serve incoming traffic, CCMs cannot currently distinguish EgressIPs and they will typically be added to a Node's Addresses. Consequently kubelet will typically request a CSR containing EgressIPs when they are present on a Node.

We had some existing code to make the approver aware of OpenShiftSDN egress IPs, but no equivalent for OVN Kubernetes.

This change fixes 2 aspects of validating a Node with EgressIPs:

  • Extend support for EgressIP matching to OVN Kubernetes
  • Ensure that a Node cannot continue to request an EgressIP which it no longer has

For the first, we also fetch OVNKubernetes EgressIP based on the infrastructure's networkType.

For the second, we can only do this for IPI clusters as we don't know the complete set of permitted address in a UPI cluster. To enable this for IPI clusters, we deterministically split the authorisation path chosen based on the presence of a Machine object for a Node. We no longer permit fall-through authentication. A side benefit of this is that the error messages reported on authentication failures become shorter. However, note from the test changes that this doesn't result in any additional failure modes.

Summary by CodeRabbit

  • New Features

  • CSR approval now accounts for node egress IPs and CIDRs when validating serving certificate requests.

  • Support was added for additional network-related resources used during certificate approval.

  • Bug Fixes

  • Improved handling of certificate signing requests so validation failures are reported more clearly.

  • Serving certificate renewal checks now allow valid IP ranges instead of requiring exact IP matches, reducing false rejections.

  • Chores

  • Updated several dependencies to newer versions.

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.

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 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: 4

🤖 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`:
- Line 48: The dependency on go.opentelemetry.io/otel/sdk is still pinned to
v1.39.0, which needs to be raised to a safe version. Update the OpenTelemetry
module set in go.mod to v1.40.0 or later, and make sure any related go.sum
entries are refreshed so the dependency graph stays consistent.

In `@pkg/controller/csr_check_test.go`:
- Line 82: The init path in csr_check_test.go is ignoring the error from
egressipv1.AddToScheme(scheme.Scheme), which is inconsistent with the existing
panic-on-failure pattern in init(). Update the init() setup around AddToScheme
to handle its returned error explicitly, using a panic or equivalent hard-fail
consistent with generateCertKeyPair, so golangci-lint errcheck is satisfied. Use
the AddToScheme call and init() as the key symbols to locate the change.

In `@pkg/controller/csr_check.go`:
- Around line 94-164: getNodeEgressIPs and getKubeletCA are still making API
requests with context.Background(), so they can hang without a deadline. Replace
the internal background context usage in getNodeEgressIPs (for the network,
EgressIP list, and HostSubnet reads) and in getKubeletCA with a bounded context
created locally with a timeout, and ensure it is canceled after each call. Keep
the fix localized to these two functions and preserve their existing error
handling.
- Around line 381-400: In authorizeServingRenewal, stop wrapping every
verifyCertificateCommonName failure as CSRValidationError so that cert-chain and
expiry verification failures from currentCert.Verify(options) can propagate back
to reconcileCSR as retryable errors. Keep the SAN/CN comparison checks in
authorizeServingRenewal as validation errors, but only convert the specific
mismatch cases to newCSRValidationError and let non-validation errors from
verifyCertificateCommonName pass through unchanged.
🪄 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: Enterprise

Run ID: be9227c1-af7b-4382-934e-d0a7667dc34b

📥 Commits

Reviewing files that changed from the base of the PR and between 1ae3f15 and fc72252.

⛔ Files ignored due to path filters (249)
  • go.sum is excluded by !**/*.sum
  • vendor/cel.dev/expr/BUILD.bazel is excluded by !**/vendor/**, !vendor/**
  • vendor/cel.dev/expr/MODULE.bazel is excluded by !**/vendor/**, !vendor/**
  • vendor/cel.dev/expr/checked.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/cel.dev/expr/eval.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/cel.dev/expr/explain.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/cel.dev/expr/syntax.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/cel.dev/expr/value.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/.golangci.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/errors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/pointer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/.golangci.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/errors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/json.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/loading.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/yaml.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/mailru/easyjson/jlexer/bytestostr.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/mailru/easyjson/jlexer/lexer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/mailru/easyjson/jwriter/writer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ovn-kubernetes/ovn-kubernetes/go-controller/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ovn-kubernetes/ovn-kubernetes/go-controller/pkg/crd/egressip/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ovn-kubernetes/ovn-kubernetes/go-controller/pkg/crd/egressip/v1/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ovn-kubernetes/ovn-kubernetes/go-controller/pkg/crd/egressip/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/ovn-kubernetes/ovn-kubernetes/go-controller/pkg/crd/egressip/v1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/spf13/afero/.editorconfig is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/spf13/afero/.golangci.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/spf13/afero/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/spf13/afero/copyOnWriteFs.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/spf13/afero/iofs.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/spf13/afero/lstater.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/spf13/afero/mem/file.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/spf13/afero/unionFile.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/spf13/afero/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/internal/telemetry/id.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/internal/telemetry/number.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/internal/telemetry/span.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/internal/telemetry/status.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/internal/telemetry/traces.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/internal/telemetry/value.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/span.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/tracer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/.clomonitor.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/.codespellignore is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/.golangci.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/.lycheeignore is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/CHANGELOG.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/CODEOWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/CONTRIBUTING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/Makefile is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/RELEASING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/SECURITY-INSIGHTS.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/VERSIONING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/encoder.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/filter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/hash.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/internal/attribute.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/internal/xxhash/xxhash.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/iterator.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/key.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/kv.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/set.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/type_string.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/value.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/baggage/baggage.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/codes/codes.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/dependencies.Dockerfile is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/internal/global/handler.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/internal/global/instruments.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/internal/global/internal_logging.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/internal/global/meter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/internal/global/state.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/internal/global/trace.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/asyncfloat64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/asyncint64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/meter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/noop/noop.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/syncfloat64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/syncint64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/propagation/baggage.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/propagation/propagation.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/propagation/trace_context.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/internal/x/features.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/container.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/host_id_bsd.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/host_id_linux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/host_id_unsupported.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/host_id_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/os.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/os_release_unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/os_unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/os_unsupported.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/process.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/resource.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/id_generator.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/internal/env/env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/batch_span_processor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/simple_span_processor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/tracer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/provider.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/span.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/tracer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.37.0/MIGRATION.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.37.0/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.37.0/attribute_group.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.37.0/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.37.0/error_type.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.37.0/exception.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.37.0/otelconv/metric.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.37.0/schema.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/MIGRATION.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/attribute_group.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/error_type.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/exception.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/schema.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/auto.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/hex.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/internal/telemetry/attr.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/internal/telemetry/id.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/internal/telemetry/value.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/noop.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/noop/noop.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/span.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/trace.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/tracestate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/versions.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/oauth2/deviceauth.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/oauth2/oauth2.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/oauth2/pkce.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/oauth2/token.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/oauth2/transport.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/time/rate/rate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gomodules.xyz/jsonpatch/v2/jsonpatch.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/genproto/googleapis/api/expr/v1alpha1/checked.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/google.golang.org/genproto/googleapis/api/expr/v1alpha1/eval.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/google.golang.org/genproto/googleapis/api/expr/v1alpha1/explain.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/google.golang.org/genproto/googleapis/api/expr/v1alpha1/syntax.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/google.golang.org/genproto/googleapis/api/expr/v1alpha1/value.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/google.golang.org/genproto/googleapis/api/httpbody/httpbody.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/CONTRIBUTING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/MAINTAINERS.md is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/balancer/balancer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/balancer/pickfirst/internal/internal.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/balancer/subconn.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/balancer_wrapper.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/clientconn.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/credentials/credentials.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/credentials/insecure/insecure.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/credentials/tls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/dialoptions.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/encoding/encoding.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/encoding/gzip/gzip.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/encoding/internal/internal.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/encoding/proto/proto.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/experimental/stats/metricregistry.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/experimental/stats/metrics.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/interceptor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/balancer/weight/weight.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/buffer/unbounded.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/channelz/trace.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/credentials/credentials.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/envconfig/envconfig.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/envconfig/xds.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/experimental.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/grpcsync/event.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/idle/idle.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/internal.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/resolver/delegatingresolver/delegatingresolver.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/stats/metrics_recorder_list.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/stats/stats.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/status/status.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/transport/client_stream.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/transport/controlbuf.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/transport/flowcontrol.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/transport/handler_server.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/transport/http2_client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/transport/http2_server.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/transport/http_util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/transport/server_stream.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/internal/transport/transport.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/mem/buffer_pool.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/mem/buffer_slice.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/mem/buffers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/picker_wrapper.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/preloader.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/resolver/resolver.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/resolver_wrapper.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/rpc_util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/server.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/stats/handlers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/stats/stats.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/stream.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/grpc/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/internal/editionssupport/editions.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/internal/encoding/text/decode.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/internal/filedesc/desc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/internal/filedesc/desc_init.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/internal/filedesc/editions.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/internal/impl/codec_map.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/internal/impl/decode.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/internal/impl/validate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/internal/version/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/proto/decode.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/reflect/protodesc/desc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/reflect/protodesc/desc_init.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/reflect/protodesc/editions.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/reflect/protodesc/proto.go is excluded by !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/kube-openapi/pkg/validation/spec/ref.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (5)
  • go.mod
  • main.go
  • pkg/controller/controller.go
  • pkg/controller/csr_check.go
  • pkg/controller/csr_check_test.go

Comment thread go.mod Outdated
Comment thread pkg/controller/csr_check_test.go Outdated
Comment thread pkg/controller/csr_check.go Outdated
Comment thread pkg/controller/csr_check.go
Comment thread pkg/controller/controller.go
// getNodeEgressIPs returns the egress IPs assigned to the given node.
// It determines the network type and queries the appropriate CRD:
// - OVNKubernetes: queries EgressIP objects from k8s.ovn.org/v1
// - OpenShiftSDN: queries HostSubnet objects

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.

SDN hasn't been supported since ~4.17 IIRC. We should verify this and remove any SDN references now

@mdbooth mdbooth Jul 6, 2026

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.

If you go back to the Jira that was my original plan. But @sdodson had asked for a 4.16 backport where it is required, and the code was already there so I left it in. I'm inclined to follow up with another patch removing SDN support back to 4.17.

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.

That comment is a year old, do we still intend to backport this all the way to 4.16? I would expect us to only backport this as far as 4.18 which is the oldest, currently in maintenance release.

Sustaining may wish to backport to 4.16 to support the EUS term 2 customers that are using 4.16 there, perhaps we should get their impression on whether this woud be something they want to backport?

// No error, the renewal is authorized.
return true, nil
// Use machine API authorization if the node has a machine.
machine, machineErr := machinehandlerpkg.FindMatchingMachineFromNodeRef(machines, nodeAsking)

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.

Why are we reversing this order of machine vs renewing against existing SANs? Seems like an unrelated change we don't necessarily need to include here?

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.

We're not reversing it. We're eliminating it. There is no fallback any more. Either we have a Machine, in which case we do the Machine validation flow, or we don't, in which case we do the existing SAN validation flow.

This is relevant to EgressIPs because the IPI flow can reject a CSR with an EgressIP which was formerly present but is no longer present, but the existing SAN validation can't. If we allow a fallback back we remove that ability.

It's also interesting to note that if you look carefully at the tests, we haven't altered any existing test cases with this change, except by removing unrelated information from their error messages.

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.

We discussed this. @JoelSpeed additionally raised the question of whether this could impact platforms which use keepalived to manage a VIP, e.g. metal, vSphere, OpenStack.

To verify this, I checked the state of all e2e jobs running against the installer. I noted that, as expected, all UPI jobs implement an approve_csrs method to 'manually' approve CSRs. In contrast, only 1 IPI job currently does this: openshift-e2e-vsphere-hybrid-env. This job adds 2 BM nodes to a vSphere cluster. As the additional nodes will not be auto-approved, it approves the additional nodes.

We know that SAN-reapproval is not relevant to joining nodes, so this means that all IPI platforms under test are approved by CMA using the Machine-backed flow.

As for keepalived specifically, I checked what actually happens here. I created a vsphere cluster and found the control plane node which currently owned the external api VIP. I confirmed that the API VIP was added to br-ex as an additional IP address. I deleted kubelet's serving cert and restarted it, which caused it to request a new one. The new CSR:

  • Did not include the api server VIP
  • Was automatically approved

The reason was that the CCM had not added the VIP to the Node. The reason for this is that the CCM is only aware of IPs which have been added via infrastructure API calls. Keepalived is moving the VIP through L2 network shenanigans, and therefore isn't visible to the CCM.

By contrast, EgressIPs are added via infrastructure API calls, and are visible to the CCM. Therefore they must either be picked up by (ideally) the {Machine,Cluster}API provider, or CMA must be explicitly aware of them.

Comment thread pkg/controller/csr_check.go
Comment thread go.mod
github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1
github.com/openshift/controller-runtime-common v0.0.0-20260428152732-64ee174f5e2e
github.com/openshift/library-go v0.0.0-20260318142011-72bf34f474bc
github.com/ovn-kubernetes/ovn-kubernetes/go-controller v0.0.0-20260703130629-a6c3ed490571

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.

This is an unfortunate dependency, is it necessary? Is it worth looking at unstructured instead?

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.

Hah, that's exactly what the bot said. I said no. I think the ovn-kubernetes api package was fairly well isolated, no? IIRC this doesn't pull in anything other than apimachinery, which we've already got.

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.

I think Unstructured was viable here, I just prefer the relative safety of structured types whenever possible. I can look at this again, but IIRC it was just apimachinery, which I felt was safe enough.

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.

We discussed this. The resolution: on my recognizance 😅 I'm going to double check my assertion that the api-only import from ovn-kubernetes is as clean as I'm claiming, but if so then I'm ok with it.

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.

@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: 3

🧹 Nitpick comments (1)
pkg/controller/csr_check.go (1)

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

Update the stale requeue comment.

This now returns CSRValidationError, which downstream reconciliation handles without retry, so the comment says the opposite of the current behavior.

🧹 Proposed comment fix
-			// return error so we requeue, in case machine network is out of date
-			// for some reason
+			// Return a validation error so invalid CSRs are not retried automatically.

Based on learnings, keep documentation aligned with actual behavior.

🤖 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/controller/csr_check.go` around lines 435 - 439, The requeue comment in
the CSR validation path is stale and contradicts the current behavior in the CSR
check logic. Update the comment near the code that logs the DNS name mismatch
and returns newCSRValidationError so it accurately states that this path returns
CSRValidationError and is handled by downstream reconciliation without retry,
rather than implying it will requeue; keep the wording aligned with the behavior
of csr_check.go and the validation flow.

Source: Learnings

🤖 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/controller/csr_check.go`:
- Line 603: The deferred conn.Close() in the CSR check flow is ignoring a
returned error, which violates the never-ignore-errors rule and the errcheck
hint. Update the cleanup in the function that opens conn so the close error is
handled explicitly, either by logging it or by propagating it through the
surrounding error path, while keeping the connection lifecycle in this same
function.
- Line 596: The log in csr_check.go currently exposes the kubelet endpoint via
the klog.Infof call in the serving-cert retrieval path. Update the logging
around the retrieval flow (near the existing nodeName/kubelet message) to omit
the kubelet value and keep only non-sensitive context such as the node name.
Make sure any related log statements in this code path follow the same rule and
do not print internal hostnames, addresses, or ports.
- Around line 310-315: Propagate the serving-cert lookup failure from the CSR
check path instead of swallowing it: in the getServingCert call site inside
csr_check logic, and any related reconcileCSR handling, return the actual error
when Node GET or internal-IP lookup fails so the reconciliation loop retries.
Keep only explicit validation/approval failures as non-retryable, and preserve
the existing logging around the getServingCert error path.

---

Nitpick comments:
In `@pkg/controller/csr_check.go`:
- Around line 435-439: The requeue comment in the CSR validation path is stale
and contradicts the current behavior in the CSR check logic. Update the comment
near the code that logs the DNS name mismatch and returns newCSRValidationError
so it accurately states that this path returns CSRValidationError and is handled
by downstream reconciliation without retry, rather than implying it will
requeue; keep the wording aligned with the behavior of csr_check.go and the
validation flow.
🪄 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: Enterprise

Run ID: ed680079-9f81-4e5a-9061-3a0a3a1e5554

📥 Commits

Reviewing files that changed from the base of the PR and between fc72252 and a870966.

⛔ Files ignored due to path filters (154)
  • go.sum is excluded by !**/*.sum
  • vendor/go.opentelemetry.io/otel/.golangci.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/AGENTS.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/CHANGELOG.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/CLAUDE.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/CONTRIBUTING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/Makefile is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/RELEASING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/encoder.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/hash.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/internal/attribute.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/key.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/kv.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/set.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/type_string.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/value.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/baggage/baggage.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/dependencies.Dockerfile is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/asyncfloat64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/asyncint64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/instrument.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/syncfloat64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/syncint64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/propagation/baggage.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/propagation/trace_context.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/requirements.txt is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/internal/x/features.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/builtin.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/container.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/host_id.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/host_id_exec.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/host_id_readfile.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/os.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/os_unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/os_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/process.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/resource/resource.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/batch_span_processor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/simple_span_processor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/tracer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/provider.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/sampling.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/span.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/sdk/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.26.0/attribute_group.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.37.0/attribute_group.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/MIGRATION.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/attribute_group.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/error_type.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/exception.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/otelconv/metric.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.41.0/schema.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/auto.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/internal/telemetry/span.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/trace.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/tracestate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/versions.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/plan9/syscall_plan9.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/affinity_linux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ioctl_signed.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ioctl_unsigned.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/mkall.sh is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/mkerrors.sh is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/readv_unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_darwin.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_linux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_linux_arm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_linux_arm64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_linux_loong64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_openbsd.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_solaris.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/syscall_unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_386.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_arm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_mips.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_linux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_386.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_386.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_arm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_mips.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/aliases.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/dll_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/registry/key.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/security_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/syscall_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/types_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/sys/windows/zsyscall_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (5)
  • go.mod
  • main.go
  • pkg/controller/controller.go
  • pkg/controller/csr_check.go
  • pkg/controller/csr_check_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • main.go
  • pkg/controller/controller.go
  • go.mod
  • pkg/controller/csr_check_test.go

Comment thread pkg/controller/csr_check.go Outdated
Comment thread pkg/controller/csr_check.go
Comment thread pkg/controller/csr_check.go
mdbooth added 4 commits July 7, 2026 10:17
EgressIPs manifest as additional IP addresses on a Node. They are
dynamic, so can be added and removed. Even though they cannot be used to
serve incoming traffic, CCMs cannot currently distinguish EgressIPs and
they will typically be added to a Node's Addresses. Consequently kubelet
will typically request a CSR containing EgressIPs when they are present
on a Node.

We had some existing code to make the approver aware of OpenShiftSDN
egress IPs, but no equivalent for OVN Kubernetes.

This change fixes 2 aspects of validating a Node with EgressIPs:
* Extend support for EgressIP matching to OVN Kubernetes
* Ensure that a Node cannot continue to request an EgressIP which it no
  longer has

For the first, we also fetch OVNKubernetes EgressIP based on the
infrastructure's networkType.

For the second, we can only do this for IPI clusters as we don't know
the complete set of permitted address in a UPI cluster. To enable this
for IPI clusters, we deterministically split the authorisation path
chosen based on the presence of a Machine object for a Node. We no
longer permit fall-through authentication. A side benefit of this is
that the error messages reported on authentication failures become
shorter. However, note from the test changes that this doesn't result in
any additional failure modes.
@mdbooth

mdbooth commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

/retest-required

@openshift-ci

openshift-ci Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

@mdbooth: The following tests 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/e2e-aws-operator 0db2470 link true /test e2e-aws-operator
ci/prow/e2e-aws-techpreview-post-install 0db2470 link true /test e2e-aws-techpreview-post-install

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.

Comment on lines +104 to +107
egressIPList := &egressipv1.EgressIPList{}
if err := c.List(ctx, egressIPList); err != nil {
return result, fmt.Errorf("could not list EgressIP objects: %v", err)
}

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.

Do you have RBAC for egressIP?

klog.Errorf("%v: IP address '%s' not in machine addresses: %s", req.Name, san, strings.Join(attemptedAddresses, " "))
return fmt.Errorf("IP address '%s' not in machine addresses: %s", san, strings.Join(attemptedAddresses, " "))
klog.Errorf("%v: IP address '%s' not in machine addresses or egress IPs: %s", req.Name, san, strings.Join(attemptedAddresses, " "))
return newCSRValidationError("IP address '%s' not in machine addresses or egress IPs: %s", san, strings.Join(attemptedAddresses, " "))

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.

Are the IPs and DNS already available when the CSR is first reconciled? CSRValidationError is being handled as permanent failure. Previously this returned error and requeued.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants