@@ -18,12 +18,15 @@ import (
18
18
corev1 "k8s.io/api/core/v1"
19
19
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
20
20
apimachyaml "k8s.io/apimachinery/pkg/util/yaml"
21
+ "k8s.io/client-go/rest"
21
22
"sigs.k8s.io/controller-runtime/pkg/client"
22
23
"sigs.k8s.io/controller-runtime/pkg/log"
23
24
24
25
helmclient "github.com/operator-framework/helm-operator-plugins/pkg/client"
26
+ authorizationv1client "k8s.io/client-go/kubernetes/typed/authorization/v1"
25
27
26
28
ocv1 "github.com/operator-framework/operator-controller/api/v1"
29
+ "github.com/operator-framework/operator-controller/internal/operator-controller/authorization"
27
30
"github.com/operator-framework/operator-controller/internal/operator-controller/features"
28
31
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/convert"
29
32
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/preflights/crdupgradesafety"
@@ -53,9 +56,38 @@ type Preflight interface {
53
56
Upgrade (context.Context , * release.Release ) error
54
57
}
55
58
59
+ type RestConfigMapper func (context.Context , client.Object , * rest.Config ) (* rest.Config , error )
60
+
61
+ type AuthClientMapper struct {
62
+ rcm RestConfigMapper
63
+ baseCfg * rest.Config
64
+ }
65
+
66
+ func (acm * AuthClientMapper ) GetAuthenticationClient (ctx context.Context , ext * ocv1.ClusterExtension ) (* authorizationv1client.AuthorizationV1Client , error ) {
67
+ authcfg , err := acm .rcm (ctx , ext , acm .baseCfg )
68
+ if err != nil {
69
+ return nil , err
70
+ }
71
+
72
+ authclient , err := authorizationv1client .NewForConfig (authcfg )
73
+ if err != nil {
74
+ return nil , err
75
+ }
76
+
77
+ return authclient , nil
78
+ }
79
+
56
80
type Helm struct {
57
81
ActionClientGetter helmclient.ActionClientGetter
58
82
Preflights []Preflight
83
+ AuthClientMapper AuthClientMapper
84
+ }
85
+
86
+ func NewAuthClientMapper (rcm RestConfigMapper , baseCfg * rest.Config ) AuthClientMapper {
87
+ return AuthClientMapper {
88
+ rcm : rcm ,
89
+ baseCfg : baseCfg ,
90
+ }
59
91
}
60
92
61
93
// shouldSkipPreflight is a helper to determine if the preflight check is CRDUpgradeSafety AND
@@ -79,7 +111,21 @@ func shouldSkipPreflight(ctx context.Context, preflight Preflight, ext *ocv1.Clu
79
111
}
80
112
81
113
func (h * Helm ) Apply (ctx context.Context , contentFS fs.FS , ext * ocv1.ClusterExtension , objectLabels map [string ]string , storageLabels map [string ]string ) ([]client.Object , string , error ) {
114
+
115
+ if features .OperatorControllerFeatureGate .Enabled (features .PreflightPermissions ) {
116
+ authclient , err := h .AuthClientMapper .GetAuthenticationClient (ctx , ext )
117
+ if err != nil {
118
+ return nil , "" , err
119
+ }
120
+
121
+ err = h .checkContentPermissions (ctx , contentFS , authclient , ext )
122
+ if err != nil {
123
+ return nil , "" , err
124
+ }
125
+ }
126
+
82
127
chrt , err := convert .RegistryV1ToHelmChart (ctx , contentFS , ext .Spec .Namespace , []string {corev1 .NamespaceAll })
128
+
83
129
if err != nil {
84
130
return nil , "" , err
85
131
}
@@ -152,8 +198,25 @@ func (h *Helm) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1.ClusterExte
152
198
return relObjects , state , nil
153
199
}
154
200
201
+ func (h * Helm ) checkContentPermissions (ctx context.Context , contentFS fs.FS , authcl * authorizationv1client.AuthorizationV1Client , ext * ocv1.ClusterExtension ) error {
202
+ reg , err := convert .ParseFS (ctx , contentFS )
203
+ if err != nil {
204
+ return err
205
+ }
206
+
207
+ plain , err := convert .Convert (reg , ext .Spec .Namespace , []string {corev1 .NamespaceAll })
208
+ if err != nil {
209
+ return err
210
+ }
211
+
212
+ err = authorization .CheckObjectPermissions (ctx , authcl , plain .Objects , ext )
213
+
214
+ return err
215
+ }
216
+
155
217
func (h * Helm ) getReleaseState (cl helmclient.ActionInterface , ext * ocv1.ClusterExtension , chrt * chart.Chart , values chartutil.Values , post postrender.PostRenderer ) (* release.Release , * release.Release , string , error ) {
156
218
currentRelease , err := cl .Get (ext .GetName ())
219
+
157
220
if errors .Is (err , driver .ErrReleaseNotFound ) {
158
221
desiredRelease , err := cl .Install (ext .GetName (), ext .Spec .Namespace , chrt , values , func (i * action.Install ) error {
159
222
i .DryRun = true
@@ -191,6 +254,11 @@ func (h *Helm) getReleaseState(cl helmclient.ActionInterface, ext *ocv1.ClusterE
191
254
return currentRelease , desiredRelease , relState , nil
192
255
}
193
256
257
+ // RulesAllow() checks expects resource names to be lowercase and plural, there's probably a better way to do this
258
+ func sanitizeResourceName (resourceName string ) string {
259
+ return strings .ToLower (resourceName ) + "s"
260
+ }
261
+
194
262
type postrenderer struct {
195
263
labels map [string ]string
196
264
cascade postrender.PostRenderer
0 commit comments