@@ -4,31 +4,79 @@ import (
44 "context"
55 "errors"
66 "fmt"
7+ "io/fs"
78 "slices"
89 "strings"
910
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"
1115 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"
1318 authorizationv1client "k8s.io/client-go/kubernetes/typed/authorization/v1"
19+ "k8s.io/client-go/rest"
1420 "sigs.k8s.io/controller-runtime/pkg/client"
15-
16- ocv1 "github.com/operator-framework/operator-controller/api/v1"
1721)
1822
1923const (
2024 SelfSubjectRulesReview string = "SelfSubjectRulesReview"
2125 SelfSubjectAccessReview string = "SelfSubjectAccessReview"
2226)
2327
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 {
2774 Namespace : ext .Spec .Namespace ,
2875 },
2976 }
3077
31- ssrr , err := authcl .SelfSubjectRulesReviews ().Create (ctx , ssrr , metav1.CreateOptions {})
78+ opts := v1.CreateOptions {}
79+ ssrr , err := authcl .SelfSubjectRulesReviews ().Create (ctx , ssrr , opts )
3280 if err != nil {
3381 return err
3482 }
@@ -50,14 +98,14 @@ func CheckObjectPermissions(ctx context.Context, authcl authorizationv1client.Au
5098 })
5199 }
52100
53- resAttrs := []authorizationv1.ResourceAttributes {}
54101 namespacedErrs := []error {}
55102 clusterScopedErrs := []error {}
56103 requiredVerbs := []string {"get" , "create" , "update" , "list" , "watch" , "delete" , "patch" }
104+ resAttrs := make ([]authv1.ResourceAttributes , 0 , len (requiredVerbs )* len (objects ))
57105
58106 for _ , o := range objects {
59107 for _ , verb := range requiredVerbs {
60- resAttrs = append (resAttrs , authorizationv1 .ResourceAttributes {
108+ resAttrs = append (resAttrs , authv1 .ResourceAttributes {
61109 Namespace : o .GetNamespace (),
62110 Verb : verb ,
63111 Resource : sanitizeResourceName (o .GetObjectKind ().GroupVersionKind ().Kind ),
@@ -70,7 +118,7 @@ func CheckObjectPermissions(ctx context.Context, authcl authorizationv1client.Au
70118 for _ , resAttr := range resAttrs {
71119 if ! canI (resAttr , rules ) {
72120 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 " ,
74122 resAttr .Verb ,
75123 strings .TrimSuffix (resAttr .Resource , "s" ),
76124 resAttr .Name ,
@@ -92,7 +140,7 @@ func CheckObjectPermissions(ctx context.Context, authcl authorizationv1client.Au
92140}
93141
94142// 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 {
96144 var canI bool
97145 for _ , rule := range rules {
98146 if (slices .Contains (rule .APIGroups , resAttr .Group ) || slices .Contains (rule .APIGroups , "*" )) &&
0 commit comments