Skip to content

Commit 1ced423

Browse files
committed
Add OVN RBAC support with per-node ovn-controller certificates
Enable OVN role-based access control (RBAC) on the Southbound database so that ovn-controller nodes can only modify their own chassis rows. When the openstack-operator provides an RBAC issuer name (from a dedicated rootca-ovn-rbac CA, see patch [1]), this patch: * Creates per-node cert-manager Certificate CRs for each ovn-controller pod, with CN set to a deterministic UUID5 system-id derived from the node name (ComputeSystemID). This CN must match the chassis system-id for RBAC to authorize operations. * Copies the RBAC client cert/key into /etc/openvswitch/ on each node via the config job, and switches ovn-controller to use these dedicated paths instead of the shared OVN DB cert. * Mounts the RBAC CA certificate into ovsdbserver-sb pods and builds a combined CA bundle (regular CA + RBAC CA) so the SB database can verify ovn-controller client certificates. * Sets role=ovn-controller on the SB DB connection (port 6642) to enforce RBAC. * Creates a second SB DB listener on port 16642 with full (unrestricted) access, used by ovn-northd. * Updates inactivity probe handling in setup.sh and runtime-config.sh to iterate over all connections, since SB now has two listeners. * ovn-controller POD now waits for the Northd to be ready before start, it is done to avoid race condition when ovn-controller POD could be started before Northd would populate RBAC rules in the SB DB and that could cause issues with connection of the ovn-controller to the SB DB. * remove OVS DaemonSet readiness gate in the ovncontroller controller - it was there to make sure that local ovsdb is up so that config job would be able to store config values in it. But init scripts are already waiting actively for the ovsdb to become active before it anything else will be done. This check is also causing deadlock with deploying ovs and ovn-controller PODs now with RBAC enabled as ovn-controller needs to have certificates ready to start and create br-int brigde. That can't be done if the config job is not started and config job couldn't be started because ovncontroller controller was waiting for the OVS DaemonSet to be ready. * Remove OVS DaemonSet readiness gate from the ovncontroller controller - the gate ensured that the local ovsdb was running before the config job attempted to store configuration values. However, the init scripts already poll for ovsdb availability before doing anything else, making the gate redundant. With RBAC enabled, this gate also causes a deadlock: ovn-controller needs its RBAC certificates to start and create the br-int bridge, but those certificates are deployed by the config job, which cannot run until the OVS DaemonSet is ready — and the OVS DaemonSet cannot become ready without br-int. [1] openstack-k8s-operators/openstack-operator#1906 Related: #OSPRH-1921 Closes: #OSPRH-1922 Signed-off-by: Slawek Kaplonski <skaplons@redhat.com>
1 parent 55b3554 commit 1ced423

32 files changed

Lines changed: 1037 additions & 45 deletions

api/bases/ovn.openstack.org_ovncontrollers.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,13 @@ spec:
178178
- info
179179
- dbg
180180
type: string
181+
rbacIssuerName:
182+
description: |-
183+
RbacIssuerName - The name of the cert-manager Issuer used to sign
184+
per-node ovn-controller RBAC certificates. When set, the controller
185+
creates cert-manager Certificate resources for each node instead of
186+
signing certificates locally with the CA key.
187+
type: string
181188
resources:
182189
description: |-
183190
Resources - Compute Resources required by this service (Limits/Requests).

api/bases/ovn.openstack.org_ovndbclusters.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,12 @@ spec:
274274
Active probe interval from standby to active ovsdb-server remote
275275
format: int32
276276
type: integer
277+
rbacCACertSecretName:
278+
description: |-
279+
RbacCACertSecretName - The name of the K8s Secret containing the RBAC
280+
PKI CA certificate (tls.crt). Used by the SB database to verify
281+
ovn-controller client certificates when RBAC is enabled.
282+
type: string
277283
replicas:
278284
default: 1
279285
description: Replicas of OVN DBCluster to run
@@ -438,6 +444,11 @@ spec:
438444
description: InternalDBAddress - DB IP address used by other Pods
439445
in the cluster
440446
type: string
447+
internalDbAddressRbacFullAccess:
448+
description: |-
449+
InternalDBAddressRbacFullAccess - DB IP address for full-access (non-RBAC)
450+
connections, used by ovn-northd when RBAC is enabled on SB DB
451+
type: string
441452
lastAppliedTopology:
442453
description: LastAppliedTopology - the last applied Topology
443454
properties:

api/v1beta1/client.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,27 @@ func GetOVNController(
7272
return nil, nil
7373
}
7474

75+
// GetOVNNorthd - return OVNNorthd instance in the given namespace
76+
func GetOVNNorthd(
77+
ctx context.Context,
78+
h *helper.Helper,
79+
namespace string,
80+
) (*OVNNorthd, error) {
81+
ovnNorthdList := &OVNNorthdList{}
82+
listOpts := []client.ListOption{
83+
client.InNamespace(namespace),
84+
}
85+
err := h.GetClient().List(ctx, ovnNorthdList, listOpts...)
86+
if err != nil {
87+
return nil, err
88+
}
89+
if len(ovnNorthdList.Items) > 0 {
90+
return &ovnNorthdList.Items[0], nil
91+
}
92+
93+
return nil, nil
94+
}
95+
7596
// GetDBClusterByType - return OVNDBCluster for the given dbType
7697
func GetDBClusterByType(
7798
ctx context.Context,

api/v1beta1/ovncontroller_types.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,13 @@ type OVNControllerSpecCore struct {
124124
// +kubebuilder:validation:Optional
125125
// MetricsTLS - Parameters related to TLS for metrics daemonset
126126
MetricsTLS tls.SimpleService `json:"metricsTLS,omitempty"`
127+
128+
// +kubebuilder:validation:Optional
129+
// RbacIssuerName - The name of the cert-manager Issuer used to sign
130+
// per-node ovn-controller RBAC certificates. When set, the controller
131+
// creates cert-manager Certificate resources for each node instead of
132+
// signing certificates locally with the CA key.
133+
RbacIssuerName string `json:"rbacIssuerName,omitempty"`
127134
}
128135

129136
// OVNControllerStatus defines the observed state of OVNController

api/v1beta1/ovndbcluster_types.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ type OVNDBClusterSpecCore struct {
146146
// +kubebuilder:validation:Optional
147147
// MetricsTLS - Parameters related to TLS for metrics sidecar
148148
MetricsTLS tls.SimpleService `json:"metricsTLS,omitempty"`
149+
150+
// +kubebuilder:validation:Optional
151+
// RbacCACertSecretName - The name of the K8s Secret containing the RBAC
152+
// PKI CA certificate (tls.crt). Used by the SB database to verify
153+
// ovn-controller client certificates when RBAC is enabled.
154+
RbacCACertSecretName string `json:"rbacCACertSecretName,omitempty"`
149155
}
150156

151157
// OVNDBClusterOverrideSpec to override the generated manifest of several child resources.
@@ -171,6 +177,10 @@ type OVNDBClusterStatus struct {
171177
// InternalDBAddress - DB IP address used by other Pods in the cluster
172178
InternalDBAddress string `json:"internalDbAddress,omitempty"`
173179

180+
// InternalDBAddressRbacFullAccess - DB IP address for full-access (non-RBAC)
181+
// connections, used by ovn-northd when RBAC is enabled on SB DB
182+
InternalDBAddressRbacFullAccess string `json:"internalDbAddressRbacFullAccess,omitempty"`
183+
174184
// NetworkAttachments status of the deployment pods
175185
NetworkAttachments map[string][]string `json:"networkAttachments,omitempty"`
176186

@@ -239,6 +249,18 @@ func (instance OVNDBCluster) GetInternalEndpoint() (string, error) {
239249
return instance.Status.InternalDBAddress, nil
240250
}
241251

252+
// GetInternalEndpointRbacFullAccess - return the full-access (non-RBAC) internal endpoint for SB DB.
253+
// Falls back to GetInternalEndpoint if the DB is not SB or TLS is not enabled.
254+
func (instance OVNDBCluster) GetInternalEndpointRbacFullAccess() (string, error) {
255+
if instance.Spec.DBType != SBDBType || !instance.Spec.TLS.Enabled() {
256+
return instance.GetInternalEndpoint()
257+
}
258+
if instance.Status.InternalDBAddressRbacFullAccess == "" {
259+
return "", fmt.Errorf("internal RBAC full-access DBEndpoint not ready yet for %s", instance.Spec.DBType)
260+
}
261+
return instance.Status.InternalDBAddressRbacFullAccess, nil
262+
}
263+
242264
// GetExternalEndpoint - return the DNS that openstack dnsmasq can resolve
243265
func (instance OVNDBCluster) GetExternalEndpoint() (string, error) {
244266
if (instance.Spec.NetworkAttachment != "" || instance.Spec.Override.Service != nil) && instance.Status.DBAddress == "" {

cmd/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import (
4646

4747
// +kubebuilder:scaffold:imports
4848

49+
certmgrv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
4950
networkv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
5051
infranetworkv1 "github.com/openstack-k8s-operators/infra-operator/apis/network/v1beta1"
5152
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
@@ -66,6 +67,7 @@ func init() {
6667
utilruntime.Must(networkv1.AddToScheme(scheme))
6768
utilruntime.Must(infranetworkv1.AddToScheme(scheme))
6869
utilruntime.Must(topologyv1.AddToScheme(scheme))
70+
utilruntime.Must(certmgrv1.AddToScheme(scheme))
6971
//+kubebuilder:scaffold:scheme
7072
}
7173

config/crd/bases/ovn.openstack.org_ovncontrollers.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,13 @@ spec:
178178
- info
179179
- dbg
180180
type: string
181+
rbacIssuerName:
182+
description: |-
183+
RbacIssuerName - The name of the cert-manager Issuer used to sign
184+
per-node ovn-controller RBAC certificates. When set, the controller
185+
creates cert-manager Certificate resources for each node instead of
186+
signing certificates locally with the CA key.
187+
type: string
181188
resources:
182189
description: |-
183190
Resources - Compute Resources required by this service (Limits/Requests).

config/crd/bases/ovn.openstack.org_ovndbclusters.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,12 @@ spec:
274274
Active probe interval from standby to active ovsdb-server remote
275275
format: int32
276276
type: integer
277+
rbacCACertSecretName:
278+
description: |-
279+
RbacCACertSecretName - The name of the K8s Secret containing the RBAC
280+
PKI CA certificate (tls.crt). Used by the SB database to verify
281+
ovn-controller client certificates when RBAC is enabled.
282+
type: string
277283
replicas:
278284
default: 1
279285
description: Replicas of OVN DBCluster to run
@@ -438,6 +444,11 @@ spec:
438444
description: InternalDBAddress - DB IP address used by other Pods
439445
in the cluster
440446
type: string
447+
internalDbAddressRbacFullAccess:
448+
description: |-
449+
InternalDBAddressRbacFullAccess - DB IP address for full-access (non-RBAC)
450+
connections, used by ovn-northd when RBAC is enabled on SB DB
451+
type: string
441452
lastAppliedTopology:
442453
description: LastAppliedTopology - the last applied Topology
443454
properties:

config/rbac/role.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,26 @@ rules:
6565
- patch
6666
- update
6767
- watch
68+
- apiGroups:
69+
- cert-manager.io
70+
resources:
71+
- certificates
72+
verbs:
73+
- create
74+
- delete
75+
- get
76+
- list
77+
- patch
78+
- update
79+
- watch
80+
- apiGroups:
81+
- cert-manager.io
82+
resources:
83+
- issuers
84+
verbs:
85+
- get
86+
- list
87+
- watch
6888
- apiGroups:
6989
- k8s.cni.cncf.io
7090
resources:

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/openstack-k8s-operators/ovn-operator
33
go 1.24.4
44

55
require (
6+
github.com/cert-manager/cert-manager v1.16.5
67
github.com/go-logr/logr v1.4.3
78
github.com/google/uuid v1.6.0
89
github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.7.7
@@ -65,7 +66,7 @@ require (
6566
github.com/prometheus/procfs v0.16.1 // indirect
6667
github.com/spf13/cobra v1.9.1 // indirect
6768
github.com/spf13/pflag v1.0.7 // indirect
68-
github.com/stoewer/go-strcase v1.2.0 // indirect
69+
github.com/stoewer/go-strcase v1.3.0 // indirect
6970
github.com/x448/float16 v0.8.4 // indirect
7071
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
7172
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
@@ -103,6 +104,7 @@ require (
103104
k8s.io/klog/v2 v2.130.1 // indirect
104105
k8s.io/kube-openapi v0.0.0-20250902184714-7fc278399c7f // indirect
105106
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect
107+
sigs.k8s.io/gateway-api v1.1.0 // indirect
106108
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
107109
sigs.k8s.io/randfill v1.0.0 // indirect
108110
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect

0 commit comments

Comments
 (0)