@@ -4,31 +4,79 @@ import (
4
4
"context"
5
5
"errors"
6
6
"fmt"
7
+ "io/fs"
7
8
"slices"
8
9
"strings"
9
10
10
- authorizationv1 "k8s.io/api/authorization/v1"
11
+ ocv1 "github.com/operator-framework/operator-controller/api/v1"
12
+ "github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/convert"
13
+ authv1 "k8s.io/api/authorization/v1"
14
+ corev1 "k8s.io/api/core/v1"
11
15
rbacv1 "k8s.io/api/rbac/v1"
12
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16
+
17
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13
18
authorizationv1client "k8s.io/client-go/kubernetes/typed/authorization/v1"
19
+ "k8s.io/client-go/rest"
14
20
"sigs.k8s.io/controller-runtime/pkg/client"
15
-
16
- ocv1 "github.com/operator-framework/operator-controller/api/v1"
17
21
)
18
22
19
23
const (
20
24
SelfSubjectRulesReview string = "SelfSubjectRulesReview"
21
25
SelfSubjectAccessReview string = "SelfSubjectAccessReview"
22
26
)
23
27
24
- func CheckObjectPermissions (ctx context.Context , authcl authorizationv1client.AuthorizationV1Interface , objects []client.Object , ext * ocv1.ClusterExtension ) error {
25
- ssrr := & authorizationv1.SelfSubjectRulesReview {
26
- Spec : authorizationv1.SelfSubjectRulesReviewSpec {
28
+ type RestConfigMapper func (context.Context , client.Object , * rest.Config ) (* rest.Config , error )
29
+
30
+ type NewForConfigFunc func (* rest.Config ) (authorizationv1client.AuthorizationV1Interface , error )
31
+
32
+ type AuthorizationClientMapper struct {
33
+ rcm RestConfigMapper
34
+ baseCfg * rest.Config
35
+ NewForConfig NewForConfigFunc
36
+ }
37
+
38
+ func NewAuthorizationClientMapper (rcm RestConfigMapper , baseCfg * rest.Config ) AuthorizationClientMapper {
39
+ return AuthorizationClientMapper {
40
+ rcm : rcm ,
41
+ baseCfg : baseCfg ,
42
+ }
43
+ }
44
+
45
+ func (acm * AuthorizationClientMapper ) GetAuthorizationClient (ctx context.Context , ext * ocv1.ClusterExtension ) (authorizationv1client.AuthorizationV1Interface , error ) {
46
+ authcfg , err := acm .rcm (ctx , ext , acm .baseCfg )
47
+ if err != nil {
48
+ return nil , err
49
+ }
50
+
51
+ return acm .NewForConfig (authcfg )
52
+ }
53
+
54
+ // Check if RBAC allows the installer service account necessary permissions on the objects in the contentFS
55
+ func (acm * AuthorizationClientMapper ) CheckContentPermissions (ctx context.Context , contentFS fs.FS , authcl authorizationv1client.AuthorizationV1Interface , ext * ocv1.ClusterExtension ) error {
56
+ reg , err := convert .ParseFS (ctx , contentFS )
57
+ if err != nil {
58
+ return err
59
+ }
60
+
61
+ plain , err := convert .Convert (reg , ext .Spec .Namespace , []string {corev1 .NamespaceAll })
62
+ if err != nil {
63
+ return err
64
+ }
65
+
66
+ err = checkObjectPermissions (ctx , authcl , plain .Objects , ext )
67
+
68
+ return err
69
+ }
70
+
71
+ func checkObjectPermissions (ctx context.Context , authcl authorizationv1client.AuthorizationV1Interface , objects []client.Object , ext * ocv1.ClusterExtension ) error {
72
+ ssrr := & authv1.SelfSubjectRulesReview {
73
+ Spec : authv1.SelfSubjectRulesReviewSpec {
27
74
Namespace : ext .Spec .Namespace ,
28
75
},
29
76
}
30
77
31
- ssrr , err := authcl .SelfSubjectRulesReviews ().Create (ctx , ssrr , metav1.CreateOptions {})
78
+ opts := v1.CreateOptions {}
79
+ ssrr , err := authcl .SelfSubjectRulesReviews ().Create (ctx , ssrr , opts )
32
80
if err != nil {
33
81
return err
34
82
}
@@ -50,14 +98,14 @@ func CheckObjectPermissions(ctx context.Context, authcl authorizationv1client.Au
50
98
})
51
99
}
52
100
53
- resAttrs := []authorizationv1.ResourceAttributes {}
54
101
namespacedErrs := []error {}
55
102
clusterScopedErrs := []error {}
56
103
requiredVerbs := []string {"get" , "create" , "update" , "list" , "watch" , "delete" , "patch" }
104
+ resAttrs := make ([]authv1.ResourceAttributes , 0 , len (requiredVerbs )* len (objects ))
57
105
58
106
for _ , o := range objects {
59
107
for _ , verb := range requiredVerbs {
60
- resAttrs = append (resAttrs , authorizationv1 .ResourceAttributes {
108
+ resAttrs = append (resAttrs , authv1 .ResourceAttributes {
61
109
Namespace : o .GetNamespace (),
62
110
Verb : verb ,
63
111
Resource : sanitizeResourceName (o .GetObjectKind ().GroupVersionKind ().Kind ),
@@ -70,7 +118,7 @@ func CheckObjectPermissions(ctx context.Context, authcl authorizationv1client.Au
70
118
for _ , resAttr := range resAttrs {
71
119
if ! canI (resAttr , rules ) {
72
120
if resAttr .Namespace != "" {
73
- namespacedErrs = append (namespacedErrs , fmt .Errorf ("cannot %s %s %s in namespace %s " ,
121
+ namespacedErrs = append (namespacedErrs , fmt .Errorf ("cannot %q %q %q in namespace %q " ,
74
122
resAttr .Verb ,
75
123
strings .TrimSuffix (resAttr .Resource , "s" ),
76
124
resAttr .Name ,
@@ -92,7 +140,7 @@ func CheckObjectPermissions(ctx context.Context, authcl authorizationv1client.Au
92
140
}
93
141
94
142
// Checks if the rules allow the verb on the GroupVersionKind in resAttr
95
- func canI (resAttr authorizationv1 .ResourceAttributes , rules []rbacv1.PolicyRule ) bool {
143
+ func canI (resAttr authv1 .ResourceAttributes , rules []rbacv1.PolicyRule ) bool {
96
144
var canI bool
97
145
for _ , rule := range rules {
98
146
if (slices .Contains (rule .APIGroups , resAttr .Group ) || slices .Contains (rule .APIGroups , "*" )) &&
0 commit comments