Skip to content

Add interface IPs from Calico annotation to node certificates - #371

Open
fwiesel wants to merge 1 commit into
mainfrom
certificate-interface-ips
Open

fwiesel wants to merge 1 commit into
mainfrom
certificate-interface-ips

Conversation

@fwiesel

@fwiesel fwiesel commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

What

Adds IP SANs from Calico's projectcalico.org/Interfaces node annotation to the hypervisor certificate, alongside the existing node.Status.Addresses SANs.

Why

The libvirt certificate only covered the node's status addresses, so connections over other host interfaces (e.g. vlan networks reported by Calico) failed TLS validation.

How to configure

Which interfaces are admitted is configurable via two new flags (and the matching Helm values):

  • --certificate-interface-include-regex (default ^vlan_[0-9]+$) — only matching interface names are considered; an empty expression includes all interfaces
  • --certificate-interface-exclude-regex (default "") — matching interfaces are excluded; the exclude expression wins over the include one

Addresses are normalized (IPv6 canonical form, IPv4-mapped IPv6) and non-routable entries (loopback, link-local, unspecified, multicast, zoned) are skipped, so a malformed or unexpected annotation cannot make cert-manager reject the whole certificate. Only plain IP addresses are accepted — Calico validates addresses with net.ParseIP before writing the annotation, so CIDR notation and anything else is simply skipped.

Notes

  • Calico prerequisite: the projectcalico.org/Interfaces annotation is populated by calico-node's interface/IP autodetection at startup (the default IP_AUTODETECTION_METHOD behavior; nothing is written when detection is disabled, e.g. IP=none). That detection also skips virtual and CNI interfaces (lo, cali.*, tunl.*, vxlan.calico, docker.*, veth.*, ...), so only real host interfaces appear in the annotation. The annotation was introduced with Calico v3.31 — on older Calico, or where it is not written, this feature is a silent no-op.
  • Stacked on top of ssa-node-certificate — merge that PR first.
  • With the default include regex the feature is a no-op on nodes without vlan_<digits> interfaces; the primary interface is already represented by the node status addresses.

@fwiesel
fwiesel added this pull request to stack #372 October 28, 2026 11:58
@fwiesel
fwiesel force-pushed the certificate-interface-ips branch 2 times, most recently from c1d8132 to 7fb675e Compare October 28, 2026 12:06
@fwiesel
fwiesel marked this pull request as ready for review October 28, 2026 12:10
@fwiesel
fwiesel force-pushed the certificate-interface-ips branch from 7fb675e to ffe1904 Compare October 28, 2026 12:10
@fwiesel
fwiesel requested a balanced review from Copilot October 28, 2026 12:10

Copilot AI 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.

🟡 Changes recommended

Tests are missing for CIDR parsing, IPv6 canonicalization, IPv4-mapped IPv6 unmapping, cross-source SAN deduplication, and rejection of mapped loopback/link-local addresses.

1 open issue
What changed in this PR

Adds Calico-reported interface IPs to hypervisor certificate SANs so TLS connections can use additional host interfaces.

Changes:

  • Merges selected interface addresses with node-status addresses, normalizing and deduplicating IPs while filtering invalid or non-routable entries.
  • Adds include/exclude regex flags and matching Helm values, defaulting to numbered VLAN interfaces.
  • Adds tests for interface filtering, address merging, malformed annotations, and annotation removal.
File Description
internal/​controller/​node_certificate_controller.go Parses Calico annotations, filters interfaces, and normalizes certificate IP SANs.
internal/​controller/​node_certificate_controller_test.go Adds annotation processing and certificate reconciliation tests.
cmd/​main.go Defines interface filter flags and passes them to the controller.
charts/​openstack-hypervisor-operator/​values.yaml Adds filter defaults and controller arguments.
charts/​openstack-hypervisor-operator/​templates/​deployment.yaml Exposes filter values through environment variables.

Review effort: Balanced

Comment thread internal/controller/node_certificate_controller.go Outdated
@notandy
notandy self-requested a review October 28, 2026 14:01

@notandy notandy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can't you just use the downward api to pass down the calico projectcalico.org/Interfaces annotation? 300+ lines for just adding another IP to the certificate?

Base automatically changed from ssa-node-certificate to main October 29, 2026 09:05
@fwiesel
fwiesel force-pushed the certificate-interface-ips branch 5 times, most recently from 33bfdfd to a6c2e9f Compare October 29, 2026 09:42
The certificate only covered the node's status addresses, so
connections over other host interfaces (e.g. vlan networks reported
by Calico) failed TLS validation. Which interfaces to admit is
configurable via --certificate-interface-{include,exclude}-regex.

Signed-off-by: Fabian Wiesel <[email protected]>
@fwiesel
fwiesel force-pushed the certificate-interface-ips branch from a6c2e9f to f118bff Compare October 29, 2026 09:53
@github-actions

Copy link
Copy Markdown

Merging this branch will decrease overall coverage

Impacted Packages Coverage Δ 🤖
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller 74.31% (-0.20%) 👎
Coverage details

Compared to commit cbd917d (run #40846960949)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/cobaltcore-dev/openstack-hypervisor-operator/cmd/main.go 0.00% (ø) 0 0 0
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/node_certificate_controller.go 75.68% (-5.28%) 74 (+32) 56 (+22) 18 (+10) 👎

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files:

  • github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/node_certificate_controller_test.go

@fwiesel

fwiesel commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

Can't you just use the downward api to pass down the calico projectcalico.org/Interfaces annotation?

How can I use the downward api to transport a value from a node to a crd from the certificate-manager? I thought, it was only to get values from nodes to pods/containers.

300+ lines for just adding another IP to the certificate?

Half of which were tests... and 70 lines of logic. Rest is passing values through the stack (Chart->CLI->Controller)

If LoC are the problem, I tried to compress it.

Now ~50 lines of logic, ~50 lines of setup, ~130 lines test.

@fwiesel
fwiesel requested a review from notandy October 29, 2026 09:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants