Skip to content

Commit 6c119ce

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. [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 6c119ce

32 files changed

Lines changed: 1034 additions & 41 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)