Skip to content

Commit 6ff0a72

Browse files
Merge pull request #1948 from tesshuflower/tls_profile_compliance
Controller setup & metrics - OpenShift Tls profile compliance
2 parents b4d1a84 + e08aa13 commit 6ff0a72

12 files changed

Lines changed: 780 additions & 88 deletions

File tree

.ci-scripts/yamlconfig.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ extends: default
55
ignore: |
66
bundle/**
77
config/**
8-
internal/controller/test/scc-crd.yml
9-
internal/controller/test/populator.storage.k8s.io_volumepopulators.yaml
8+
internal/controller/test/**
109
custom-scorecard-tests/**
1110
hack/crds/*
1211
helm/volsync/**

bundle/manifests/volsync.clusterserviceversion.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ metadata:
5555
}
5656
]
5757
capabilities: Basic Install
58-
createdAt: "2026-02-10T17:09:35Z"
58+
createdAt: "2026-03-13T15:41:32Z"
5959
olm.skipRange: '>=0.4.0 <0.16.0'
6060
operators.operatorframework.io/builder: operator-sdk-v1.42.0
6161
operators.operatorframework.io/project_layout: go.kubebuilder.io/v4
@@ -219,6 +219,14 @@ spec:
219219
- patch
220220
- update
221221
- watch
222+
- apiGroups:
223+
- config.openshift.io
224+
resources:
225+
- apiservers
226+
verbs:
227+
- get
228+
- list
229+
- watch
222230
- apiGroups:
223231
- populator.storage.k8s.io
224232
resources:

cmd/main.go

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737

3838
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1"
3939
volumepopulatorv1beta1 "github.com/kubernetes-csi/volume-data-source-validator/client/apis/volumepopulator/v1beta1"
40+
ocpconfigv1 "github.com/openshift/api/config/v1"
4041
ocpsecurityv1 "github.com/openshift/api/security/v1"
4142
"github.com/spf13/pflag"
4243
"github.com/spf13/viper"
@@ -80,6 +81,7 @@ func init() {
8081
utilruntime.Must(volsyncv1alpha1.AddToScheme(scheme))
8182
utilruntime.Must(ocpsecurityv1.AddToScheme(scheme))
8283
utilruntime.Must(volumepopulatorv1beta1.AddToScheme(scheme))
84+
utilruntime.Must(ocpconfigv1.AddToScheme(scheme))
8385
//+kubebuilder:scaffold:scheme
8486
}
8587

@@ -165,16 +167,10 @@ func addCommandFlags(probeAddr *string, metricsAddr *string, enableLeaderElectio
165167
}
166168

167169
// Prereq CRs we want to always be present in certain environments but do not want to reconcile often (just at startup)
168-
func ensureCRs(cfg *rest.Config) {
169-
setupClient, err := client.New(cfg, client.Options{Scheme: scheme})
170-
if err != nil {
171-
setupLog.Error(err, "error creating client")
172-
os.Exit(1)
173-
}
174-
170+
func ensureCRs(setupClient client.Client) {
175171
// Privileged mover SCC required in OpenShift envs
176172
setupLog.Info("Privileged Mover SCC", "scc-name", utils.SCCName)
177-
err = platform.EnsureVolSyncMoverSCCIfOpenShift(context.Background(), setupClient, setupLog,
173+
err := platform.EnsureVolSyncMoverSCCIfOpenShift(context.Background(), setupClient, setupLog,
178174
utils.SCCName, volsyncMoverSCCYamlRaw)
179175
if err != nil {
180176
setupLog.Error(err, "unable to reconcile volsync mover scc", "scc-name", utils.SCCName)
@@ -223,6 +219,18 @@ func main() {
223219
renewDeadline := 107 * time.Second
224220
retryPeriod := 26 * time.Second
225221

222+
cfg := ctrl.GetConfigOrDie()
223+
setupClient, err := client.New(cfg, client.Options{Scheme: scheme})
224+
if err != nil {
225+
setupLog.Error(err, "error creating client")
226+
os.Exit(1)
227+
}
228+
229+
// Create a context that can be cancelled when there is a need to shut down the manager .
230+
ctx, cancel := context.WithCancel(ctrl.SetupSignalHandler())
231+
// Ensure the context is cancelled when the program exits.
232+
defer cancel()
233+
226234
// if the enable-http2 flag is false (the default), http/2 should be disabled
227235
// due to its vulnerabilities. More specifically, disabling http/2 will
228236
// prevent from being vulnerable to the HTTP/2 Stream Cancellation and
@@ -233,11 +241,21 @@ func main() {
233241
setupLog.Info("disabling http/2")
234242
c.NextProtos = []string{"http/1.1"}
235243
}
236-
237244
if !enableHTTP2 {
238245
tlsOpts = append(tlsOpts, disableHTTP2)
239246
}
240247

248+
// Fetch the TLS profile from the APIServer resource (OpenShift only)
249+
tlsSecurityProfileSpec, err := platform.GetTLSProfileIfOpenShift(ctx, setupClient, setupLog)
250+
if err != nil {
251+
setupLog.Error(err, "Unable to get TLS Security Profile from OpenShift")
252+
os.Exit(1)
253+
}
254+
if tlsSecurityProfileSpec != nil {
255+
tlsConfig := platform.GetTLSConfigFromProfile(*tlsSecurityProfileSpec, setupLog)
256+
tlsOpts = append(tlsOpts, tlsConfig)
257+
}
258+
241259
// Create watchers for metrics and webhooks certificates
242260
var metricsCertWatcher *certwatcher.CertWatcher
243261
//var webhookCertWatcher *certwatcher.CertWatcher
@@ -320,7 +338,6 @@ func main() {
320338
})
321339
}
322340

323-
cfg := ctrl.GetConfigOrDie()
324341
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
325342
Scheme: scheme,
326343
Metrics: metricsServerOptions,
@@ -342,8 +359,20 @@ func main() {
342359
os.Exit(1)
343360
}
344361

362+
if tlsSecurityProfileSpec != nil {
363+
// Will only be true for OpenShift clusters
364+
// Setup TLS Security Profile Watcher to monitor for TLS profile changes.
365+
// When the cluster's TLS profile changes, the operator will gracefully shutdown
366+
// and restart to pick up the new configuration.
367+
err = platform.InitTLSSecurityProfileWatcherWithManager(mgr, *tlsSecurityProfileSpec, setupLog, cancel)
368+
if err != nil {
369+
setupLog.Error(err, "unable to set up TLS security profile watcher")
370+
os.Exit(1)
371+
}
372+
}
373+
345374
// Before starting controllers - create or patch volsync mover SCC and VolumePopulator CR if necessary
346-
ensureCRs(cfg)
375+
ensureCRs(setupClient)
347376

348377
initPodLogsClient(cfg)
349378

@@ -408,7 +437,7 @@ func main() {
408437
os.Exit(1)
409438
}
410439
setupLog.Info("starting manager")
411-
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
440+
if err := mgr.Start(ctx); err != nil {
412441
setupLog.Error(err, "problem running manager")
413442
os.Exit(1)
414443
}

config/rbac/role.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ rules:
8888
- patch
8989
- update
9090
- watch
91+
- apiGroups:
92+
- config.openshift.io
93+
resources:
94+
- apiservers
95+
verbs:
96+
- get
97+
- list
98+
- watch
9199
- apiGroups:
92100
- populator.storage.k8s.io
93101
resources:

go.mod

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ require (
1111
github.com/kubernetes-csi/volume-data-source-validator/client v0.0.0-20250919142814-90ffb8220766
1212
github.com/onsi/ginkgo/v2 v2.28.1
1313
github.com/onsi/gomega v1.39.1
14-
github.com/openshift/api v0.0.0-20230918105526-6488b1202507 // release-4.14
14+
github.com/openshift/api v0.0.0-20260213155647-8fe9fe363807 // release-4.14
15+
github.com/openshift/controller-runtime-common v0.0.0-20260307102856-5db94f69ad3a
1516
github.com/prometheus/client_golang v1.23.2
1617
github.com/robfig/cron/v3 v3.0.1
1718
github.com/spf13/cobra v1.10.2
@@ -28,7 +29,7 @@ require (
2829
k8s.io/component-helpers v0.35.2
2930
k8s.io/klog/v2 v2.130.1
3031
k8s.io/kubectl v0.35.2
31-
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4
32+
k8s.io/utils v0.0.0-20260108192941-914a6e750570
3233
sigs.k8s.io/controller-runtime v0.23.3
3334
)
3435

@@ -84,6 +85,7 @@ require (
8485
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
8586
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
8687
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
88+
github.com/openshift/library-go v0.0.0-20260213153706-03f1709971c5 // indirect
8789
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
8890
github.com/pierrec/lz4/v4 v4.1.22 // indirect
8991
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect

go.sum

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,12 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl
212212
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
213213
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
214214
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
215-
github.com/openshift/api v0.0.0-20230918105526-6488b1202507 h1:WcJnVswQUi7BEq1fsRkGU3iqVpID3lpOlYjFNND8tXI=
216-
github.com/openshift/api v0.0.0-20230918105526-6488b1202507/go.mod h1:yimSGmjsI+XF1mr+AKBs2//fSXIOhhetHGbMlBEfXbs=
215+
github.com/openshift/api v0.0.0-20260213155647-8fe9fe363807 h1:coR/haF16EW8KS1E/PwJfDzMSy4mU9K0H1rcHejqYDY=
216+
github.com/openshift/api v0.0.0-20260213155647-8fe9fe363807/go.mod h1:d5uzF0YN2nQQFA0jIEWzzOZ+edmo6wzlGLvx5Fhz4uY=
217+
github.com/openshift/controller-runtime-common v0.0.0-20260307102856-5db94f69ad3a h1:EQfdaEHOOBDkbvyHAn69u6eZDMuHPK3CTr1i89eEmss=
218+
github.com/openshift/controller-runtime-common v0.0.0-20260307102856-5db94f69ad3a/go.mod h1:9HQZbBpikedL8l9mQpaDB4C15FNgLlnNuLP5ADrkVOI=
219+
github.com/openshift/library-go v0.0.0-20260213153706-03f1709971c5 h1:9Pe6iVOMjt9CdA/vaKBNUSoEIjIe1po5Ha3ABRYXLJI=
220+
github.com/openshift/library-go v0.0.0-20260213153706-03f1709971c5/go.mod h1:K3FoNLgNBFYbFuG+Kr8usAnQxj1w84XogyUp2M8rK8k=
217221
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
218222
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
219223
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
@@ -479,8 +483,8 @@ k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZ
479483
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
480484
k8s.io/kubectl v0.35.2 h1:aSmqhSOfsoG9NR5oR8OD5eMKpLN9x8oncxfqLHbJJII=
481485
k8s.io/kubectl v0.35.2/go.mod h1:+OJC779UsDJGxNPbHxCwvb4e4w9Eh62v/DNYU2TlsyM=
482-
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
483-
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
486+
k8s.io/utils v0.0.0-20260108192941-914a6e750570 h1:JT4W8lsdrGENg9W+YwwdLJxklIuKWdRm+BC+xt33FOY=
487+
k8s.io/utils v0.0.0-20260108192941-914a6e750570/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
484488
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM=
485489
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
486490
sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80=

helm/volsync/templates/clusterrole-manager.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,14 @@ rules:
157157
- create
158158
- patch
159159
- update
160+
- apiGroups:
161+
- config.openshift.io
162+
resources:
163+
- apiservers
164+
verbs:
165+
- get
166+
- list
167+
- watch
160168
- apiGroups:
161169
- populator.storage.k8s.io
162170
resources:

internal/controller/platform/properties.go

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import (
2121
"context"
2222

2323
"github.com/go-logr/logr"
24+
ocpconfigv1 "github.com/openshift/api/config/v1"
2425
ocpsecurityv1 "github.com/openshift/api/security/v1"
2526
kerrors "k8s.io/apimachinery/pkg/api/errors"
26-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2727
"k8s.io/apimachinery/pkg/runtime/serializer"
2828
"k8s.io/apimachinery/pkg/types"
2929
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -32,42 +32,77 @@ import (
3232
)
3333

3434
// Properties contains properties about the environment in which we are running
35+
var properties *Properties
36+
3537
type Properties struct {
36-
IsOpenShift bool // True if we are running on OpenShift
37-
HasSCCRestrictedV2 bool // True if the SecurityContextConstraints "restricted-v2" exists
38+
IsOpenShift bool // True if we are running on OpenShift
39+
TLSSecurityProfileSpec *ocpconfigv1.TLSProfileSpec // Will be nil if not on OpenShift
3840
}
3941

4042
//nolint:lll
4143
//+kubebuilder:rbac:groups=security.openshift.io,resources=securitycontextconstraints,verbs=get;list;watch;create;patch;update
44+
//+kubebuilder:rbac:groups=config.openshift.io,resources=apiservers,verbs=get;list;watch
4245

4346
// Retrieves properties of the running cluster
44-
func GetProperties(ctx context.Context, client client.Client, logger logr.Logger) (Properties, error) {
45-
if err := ocpsecurityv1.AddToScheme(client.Scheme()); err != nil {
47+
func GetProperties(ctx context.Context, k8sClient client.Client, logger logr.Logger) (Properties, error) {
48+
if properties != nil {
49+
// Use cached value if it's set
50+
return *properties, nil
51+
}
52+
53+
if err := ocpsecurityv1.AddToScheme(k8sClient.Scheme()); err != nil {
4654
logger.Error(err, "unable to add scheme for security.openshift.io")
4755
return Properties{}, err
4856
}
57+
if err := ocpconfigv1.AddToScheme(k8sClient.Scheme()); err != nil {
58+
logger.Error(err, "unable to add scheme for config.openshift.io")
59+
return Properties{}, err
60+
}
4961

5062
var err error
5163
p := Properties{}
5264

53-
if p.IsOpenShift, err = isOpenShift(ctx, client, logger); err != nil {
65+
if p.IsOpenShift, err = isOpenShift(ctx, k8sClient, logger); err != nil {
5466
return Properties{}, err
5567
}
5668
if p.IsOpenShift {
57-
if p.HasSCCRestrictedV2, err = hasSCCRestrictedV2(ctx, client, logger); err != nil {
69+
if p.TLSSecurityProfileSpec, err = getTLSProfile(ctx, k8sClient, logger); err != nil {
5870
return Properties{}, err
5971
}
6072
}
73+
74+
// Cache properties for subsequent calls
75+
properties = &p
76+
6177
return p, nil
6278
}
6379

80+
// For test usage, clear out our cached properties
81+
func clearProperties() {
82+
properties = nil
83+
}
84+
85+
// Checks to determine whether this is OpenShift by looking for any SecurityContextConstraint objects
86+
func isOpenShift(ctx context.Context, k8sClient client.Client, logger logr.Logger) (bool, error) {
87+
SCCs := ocpsecurityv1.SecurityContextConstraintsList{}
88+
err := k8sClient.List(ctx, &SCCs)
89+
if len(SCCs.Items) > 0 {
90+
return true, nil
91+
}
92+
if err == nil || utils.IsCRDNotPresentError(err) {
93+
return false, nil
94+
}
95+
logger.Error(err, "error while looking for SCCs")
96+
return false, err
97+
}
98+
6499
func EnsureVolSyncMoverSCCIfOpenShift(ctx context.Context, k8sClient client.Client, logger logr.Logger,
65100
sccName string, sccRaw []byte) error {
66-
openShift, err := isOpenShift(ctx, k8sClient, logger)
101+
p, err := GetProperties(ctx, k8sClient, logger)
67102
if err != nil {
68103
return err
69104
}
70-
if !openShift {
105+
if !p.IsOpenShift {
71106
return nil // Not OpenShift, nothing to do here
72107
}
73108

@@ -115,35 +150,3 @@ func EnsureVolSyncMoverSCCIfOpenShift(ctx context.Context, k8sClient client.Clie
115150
// Patch currentScc with our volsync mover scc
116151
return k8sClient.Patch(ctx, volsyncMoverScc, client.MergeFrom(currentScc))
117152
}
118-
119-
// Checks to determine whether this is OpenShift by looking for any SecurityContextConstraint objects
120-
func isOpenShift(ctx context.Context, c client.Client, l logr.Logger) (bool, error) {
121-
SCCs := ocpsecurityv1.SecurityContextConstraintsList{}
122-
err := c.List(ctx, &SCCs)
123-
if len(SCCs.Items) > 0 {
124-
return true, nil
125-
}
126-
if err == nil || utils.IsCRDNotPresentError(err) {
127-
return false, nil
128-
}
129-
l.Error(err, "error while looking for SCCs")
130-
return false, err
131-
}
132-
133-
func hasSCCRestrictedV2(ctx context.Context, c client.Client, l logr.Logger) (bool, error) {
134-
scc := ocpsecurityv1.SecurityContextConstraints{
135-
ObjectMeta: metav1.ObjectMeta{
136-
Name: "restricted-v2",
137-
},
138-
}
139-
// The following assumes SCC is a valid type (i.e., it's OpenShift)
140-
err := c.Get(ctx, client.ObjectKeyFromObject(&scc), &scc)
141-
if err == nil {
142-
return true, nil
143-
}
144-
if kerrors.IsNotFound(err) {
145-
return false, nil
146-
}
147-
l.Error(err, "error while looking for restricted-v2 SCC")
148-
return false, err
149-
}

0 commit comments

Comments
 (0)