Skip to content

Commit b97a361

Browse files
committed
ACM-30179: Use TLS configuration from the APIServer when available
1 parent 99a951c commit b97a361

5,736 files changed

Lines changed: 655400 additions & 738006 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
annotations:
5+
service.beta.openshift.io/serving-cert-secret-name: ibi-metrics-serving-certs
6+
creationTimestamp: null
7+
name: image-based-install-metrics
8+
spec:
9+
ports:
10+
- port: 8080
11+
protocol: TCP
12+
targetPort: 8080
13+
selector:
14+
app: image-based-install-operator
15+
status:
16+
loadBalancer: {}

bundle/manifests/image-based-install-operator.clusterserviceversion.yaml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ metadata:
3636
}
3737
]
3838
capabilities: Basic Install
39-
createdAt: "2026-02-05T10:59:19Z"
39+
createdAt: "2026-04-19T15:02:51Z"
4040
operators.operatorframework.io/builder: operator-sdk-v1.30.0
4141
operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
4242
name: image-based-install-operator.v0.0.1
@@ -82,6 +82,26 @@ spec:
8282
- patch
8383
- update
8484
- watch
85+
- apiGroups:
86+
- authentication.k8s.io
87+
resources:
88+
- tokenreviews
89+
verbs:
90+
- create
91+
- apiGroups:
92+
- authorization.k8s.io
93+
resources:
94+
- subjectaccessreviews
95+
verbs:
96+
- create
97+
- apiGroups:
98+
- config.openshift.io
99+
resources:
100+
- apiservers
101+
verbs:
102+
- get
103+
- list
104+
- watch
85105
- apiGroups:
86106
- extensions.hive.openshift.io
87107
resources:
@@ -226,6 +246,8 @@ spec:
226246
name: data
227247
- mountPath: /webhook-certs
228248
name: webhook-certs
249+
- mountPath: /metrics-certs
250+
name: metrics-certs
229251
- command:
230252
- /usr/local/bin/server
231253
env:
@@ -279,6 +301,9 @@ spec:
279301
- name: webhook-certs
280302
secret:
281303
secretName: ibi-webhook-serving-certs
304+
- name: metrics-certs
305+
secret:
306+
secretName: ibi-metrics-serving-certs
282307
permissions:
283308
- rules:
284309
- apiGroups:

cmd/manager/main.go

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package main
1818

1919
import (
2020
"context"
21+
"crypto/tls"
2122
"flag"
2223
"fmt"
2324
"net/http"
@@ -26,11 +27,13 @@ import (
2627
"os"
2728
"time"
2829

30+
crtls "github.com/openshift/controller-runtime-common/pkg/tls"
2931
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
3032
// to ensure that exec-entrypoint and run can make use of them.
3133
_ "k8s.io/client-go/plugin/pkg/client/auth"
3234
"sigs.k8s.io/controller-runtime/pkg/manager"
3335

36+
configv1 "github.com/openshift/api/config/v1"
3437
corev1 "k8s.io/api/core/v1"
3538
"k8s.io/apimachinery/pkg/labels"
3639
"k8s.io/apimachinery/pkg/runtime"
@@ -41,6 +44,7 @@ import (
4144
"sigs.k8s.io/controller-runtime/pkg/client"
4245
"sigs.k8s.io/controller-runtime/pkg/healthz"
4346
"sigs.k8s.io/controller-runtime/pkg/log/zap"
47+
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
4448
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
4549
"sigs.k8s.io/controller-runtime/pkg/webhook"
4650

@@ -54,6 +58,7 @@ import (
5458
"github.com/openshift/image-based-install-operator/internal/credentials"
5559
"github.com/openshift/image-based-install-operator/internal/installer"
5660
"github.com/openshift/image-based-install-operator/internal/monitor"
61+
"github.com/openshift/image-based-install-operator/internal/tlsconfig"
5762
//+kubebuilder:scaffold:imports
5863
)
5964

@@ -67,6 +72,7 @@ func init() {
6772
utilruntime.Must(v1alpha1.AddToScheme(scheme))
6873
utilruntime.Must(bmh_v1alpha1.AddToScheme(scheme))
6974
utilruntime.Must(hivev1.AddToScheme(scheme))
75+
utilruntime.Must(configv1.AddToScheme(scheme))
7076
//+kubebuilder:scaffold:scheme
7177
}
7278

@@ -96,17 +102,32 @@ func main() {
96102
go startPPROF(logger)
97103
}
98104

99-
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
105+
ctx, cancel := context.WithCancel(ctrl.SetupSignalHandler())
106+
defer cancel()
107+
108+
restCfg := ctrl.GetConfigOrDie()
109+
tlsResult, err := tlsconfig.ResolveTLSConfig(context.Background(), restCfg)
110+
if err != nil {
111+
setupLog.Error(err, "unable to resolve TLS config")
112+
os.Exit(1)
113+
}
114+
115+
mgr, err := ctrl.NewManager(restCfg, ctrl.Options{
100116
Scheme: scheme,
101117
Metrics: metricsserver.Options{
102-
BindAddress: metricsAddr,
118+
BindAddress: metricsAddr,
119+
SecureServing: true,
120+
CertDir: "/metrics-certs",
121+
FilterProvider: filters.WithAuthenticationAndAuthorization,
122+
TLSOpts: []func(*tls.Config){tlsResult.TLSConfig},
103123
},
104124
HealthProbeBindAddress: probeAddr,
105125
LeaderElection: enableLeaderElection,
106126
LeaderElectionID: "e21b2704.openshift.io",
107127
WebhookServer: webhook.NewServer(webhook.Options{
108128
Port: 9443,
109129
CertDir: "/webhook-certs",
130+
TLSOpts: []func(*tls.Config){tlsResult.TLSConfig},
110131
}),
111132
Cache: cache.Options{
112133
ByObject: map[client.Object]cache.ByObject{
@@ -179,6 +200,25 @@ func main() {
179200
os.Exit(1)
180201
}
181202

203+
if err := (&crtls.SecurityProfileWatcher{
204+
Client: mgr.GetClient(),
205+
InitialTLSAdherencePolicy: tlsResult.TLSAdherencePolicy,
206+
InitialTLSProfileSpec: tlsResult.TLSProfileSpec,
207+
OnAdherencePolicyChange: func(_ context.Context, oldPolicy, newPolicy configv1.TLSAdherencePolicy) {
208+
logger.Infof("TLS adherence policy has changed, shutting down to reload, oldPolicy: %v, newPolicy: %v",
209+
oldPolicy, newPolicy)
210+
cancel()
211+
},
212+
OnProfileChange: func(_ context.Context, oldProfile, newProfile configv1.TLSProfileSpec) {
213+
logger.Infof("TLS profile has changed, shutting down to reload, oldProfile: %v, newProfile: %v",
214+
oldProfile, newProfile)
215+
cancel()
216+
},
217+
}).SetupWithManager(mgr); err != nil {
218+
setupLog.Error(err, "unable to create TLS security profile watcher")
219+
os.Exit(1)
220+
}
221+
182222
if err = (&v1alpha1.ImageClusterInstall{}).SetupWebhookWithManager(mgr); err != nil {
183223
setupLog.Error(err, "unable to create webhook", "webhook", "ImageClusterInstall")
184224
os.Exit(1)
@@ -197,7 +237,7 @@ func main() {
197237
go EnqueueExistingImageClusterInstall(mgr)
198238

199239
setupLog.Info("starting manager")
200-
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
240+
if err := mgr.Start(ctx); err != nil {
201241
setupLog.Error(err, "problem running manager")
202242
os.Exit(1)
203243
}

cmd/server/main.go

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package main
22

33
import (
44
"context"
5+
"crypto/tls"
6+
"flag"
57
"fmt"
68
"net/http"
79
"os"
@@ -11,8 +13,21 @@ import (
1113
"time"
1214

1315
"github.com/kelseyhightower/envconfig"
14-
"github.com/openshift/image-based-install-operator/internal/imageserver"
16+
configv1 "github.com/openshift/api/config/v1"
17+
configclientset "github.com/openshift/client-go/config/clientset/versioned"
18+
crtls "github.com/openshift/controller-runtime-common/pkg/tls"
1519
"github.com/sirupsen/logrus"
20+
"k8s.io/apimachinery/pkg/api/equality"
21+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+
"k8s.io/apimachinery/pkg/watch"
23+
24+
"github.com/openshift/image-based-install-operator/internal/imageserver"
25+
"github.com/openshift/image-based-install-operator/internal/tlsconfig"
26+
27+
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
28+
_ "k8s.io/client-go/plugin/pkg/client/auth"
29+
ctrl "sigs.k8s.io/controller-runtime"
30+
"sigs.k8s.io/controller-runtime/pkg/log/zap"
1631
)
1732

1833
var Options struct {
@@ -23,6 +38,13 @@ var Options struct {
2338
}
2439

2540
func main() {
41+
opts := zap.Options{
42+
Development: true,
43+
}
44+
opts.BindFlags(flag.CommandLine)
45+
flag.Parse()
46+
47+
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
2648
log := logrus.New()
2749
log.SetReportCaller(true)
2850

@@ -50,8 +72,23 @@ func main() {
5072
go func() {
5173
var err error
5274
if Options.HTTPSKeyFile != "" && Options.HTTPSCertFile != "" {
75+
var tlsResult tlsconfig.TLSConfigResult
76+
var cert tls.Certificate
5377
log.Infof("Starting https handler on %s...", server.Addr)
54-
err = server.ListenAndServeTLS(Options.HTTPSCertFile, Options.HTTPSKeyFile)
78+
79+
restCfg := ctrl.GetConfigOrDie()
80+
tlsResult, err = tlsconfig.ResolveTLSConfig(context.Background(), restCfg)
81+
if err != nil {
82+
log.WithError(err).Fatal("unable to configure HTTPS TLS")
83+
}
84+
go watchAndExitOnTLSChange(context.Background(), log, configclientset.NewForConfigOrDie(restCfg), tlsResult)
85+
86+
cert, err = tls.LoadX509KeyPair(Options.HTTPSCertFile, Options.HTTPSKeyFile)
87+
if err != nil {
88+
log.WithError(err).Fatal("failed to load HTTPS certificate")
89+
}
90+
server.TLSConfig = tlsconfig.ServingTLSConfig(tlsResult, cert)
91+
err = server.ListenAndServeTLS("", "")
5592
} else {
5693
log.Infof("Starting http handler on %s...", server.Addr)
5794
err = server.ListenAndServe()
@@ -75,3 +112,40 @@ func main() {
75112
log.Info("server terminated gracefully")
76113
}
77114
}
115+
116+
func watchAndExitOnTLSChange(ctx context.Context, log *logrus.Logger, configClient configclientset.Interface, current tlsconfig.TLSConfigResult) {
117+
w, err := configClient.ConfigV1().APIServers().Watch(ctx, metav1.ListOptions{
118+
FieldSelector: "metadata.name=cluster",
119+
})
120+
if err != nil {
121+
return
122+
}
123+
defer w.Stop()
124+
125+
for event := range w.ResultChan() {
126+
if event.Type != watch.Modified {
127+
continue
128+
}
129+
updated, ok := event.Object.(*configv1.APIServer)
130+
if !ok {
131+
continue
132+
}
133+
134+
if current.TLSAdherencePolicy != updated.Spec.TLSAdherence {
135+
log.Infof("TLS adherence policy has changed, shutting down to reload, oldPolicy: %v, newPolicy: %v",
136+
current.TLSAdherencePolicy, updated.Spec.TLSAdherence)
137+
os.Exit(0)
138+
}
139+
140+
profile, err := crtls.GetTLSProfileSpec(updated.Spec.TLSSecurityProfile)
141+
if err != nil {
142+
log.WithError(err).Error("failed to load TLS profile spec after APIServer update, ignoring")
143+
continue
144+
}
145+
if !equality.Semantic.DeepEqual(current.TLSProfileSpec, profile) {
146+
log.Infof("TLS profile has changed, shutting down to reload, oldProfile: %v, newProfile: %v",
147+
current.TLSProfileSpec, profile)
148+
os.Exit(0)
149+
}
150+
}
151+
}

config/manager/manager.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ spec:
7777
mountPath: /data
7878
- name: webhook-certs
7979
mountPath: /webhook-certs
80+
- name: metrics-certs
81+
mountPath: /metrics-certs
8082
- command:
8183
- /usr/local/bin/server
8284
image: controller:latest
@@ -124,6 +126,9 @@ spec:
124126
- name: webhook-certs
125127
secret:
126128
secretName: ibi-webhook-serving-certs
129+
- name: metrics-certs
130+
secret:
131+
secretName: ibi-metrics-serving-certs
127132
serviceAccountName: image-based-install-operator
128133
terminationGracePeriodSeconds: 10
129134
---
@@ -141,3 +146,18 @@ spec:
141146
name: config-server
142147
selector:
143148
app: image-based-install-operator
149+
---
150+
apiVersion: v1
151+
kind: Service
152+
metadata:
153+
name: image-based-install-metrics
154+
namespace: image-based-install-operator
155+
annotations:
156+
service.beta.openshift.io/serving-cert-secret-name: ibi-metrics-serving-certs
157+
spec:
158+
ports:
159+
- port: 8080
160+
protocol: TCP
161+
targetPort: 8080
162+
selector:
163+
app: image-based-install-operator

config/rbac/role.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,26 @@ rules:
2626
- patch
2727
- update
2828
- watch
29+
- apiGroups:
30+
- authentication.k8s.io
31+
resources:
32+
- tokenreviews
33+
verbs:
34+
- create
35+
- apiGroups:
36+
- authorization.k8s.io
37+
resources:
38+
- subjectaccessreviews
39+
verbs:
40+
- create
41+
- apiGroups:
42+
- config.openshift.io
43+
resources:
44+
- apiservers
45+
verbs:
46+
- get
47+
- list
48+
- watch
2949
- apiGroups:
3050
- extensions.hive.openshift.io
3151
resources:

controllers/imageclusterinstall_controller.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package controllers
1919
import (
2020
"bytes"
2121
"context"
22-
2322
// These are required for image parsing to work correctly with digest-based pull specs
2423
// See: https://github.com/opencontainers/go-digest/blob/v1.0.0/README.md#usage
2524
_ "crypto/sha256"
@@ -129,6 +128,9 @@ const (
129128
//+kubebuilder:rbac:groups=hive.openshift.io,resources=clusterdeployments/finalizers,verbs=update
130129
//+kubebuilder:rbac:groups=hive.openshift.io,resources=clusterimagesets,verbs=get;list;watch
131130
//+kubebuilder:rbac:groups=metal3.io,resources=dataimages,verbs=get;list;watch;create;update;patch;delete
131+
//+kubebuilder:rbac:groups=config.openshift.io,resources=apiservers,verbs=get;list;watch
132+
//+kubebuilder:rbac:groups=authentication.k8s.io,resources=tokenreviews,verbs=create
133+
//+kubebuilder:rbac:groups=authorization.k8s.io,resources=subjectaccessreviews,verbs=create
132134

133135
func (r *ImageClusterInstallReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
134136
log := r.Log.WithFields(logrus.Fields{"name": req.Name, "namespace": req.Namespace})

0 commit comments

Comments
 (0)