@@ -6,11 +6,11 @@ import (
6
6
"fmt"
7
7
"io"
8
8
"maps"
9
- "reflect"
10
9
"regexp"
11
10
"sort"
12
11
"strings"
13
12
13
+ ocv1 "github.com/operator-framework/operator-controller/api/v1"
14
14
corev1 "k8s.io/api/core/v1"
15
15
rbacv1 "k8s.io/api/rbac/v1"
16
16
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -34,7 +34,7 @@ import (
34
34
)
35
35
36
36
type PreAuthorizer interface {
37
- PreAuthorize (ctx context.Context , manifestManager user. Info , manifestReader io.Reader ) ([]ScopedPolicyRules , error )
37
+ PreAuthorize (ctx context.Context , ext * ocv1. ClusterExtension , manifestReader io.Reader ) ([]ScopedPolicyRules , error )
38
38
}
39
39
40
40
type ScopedPolicyRules struct {
@@ -69,13 +69,14 @@ func NewRBACPreAuthorizer(cl client.Client) PreAuthorizer {
69
69
// completes successfully but identifies missing rules, then a nil error is returned along with
70
70
// the list (or slice) of missing rules. Note that in some cases the error may encapsulate multiple
71
71
// evaluation failures
72
- func (a * rbacPreAuthorizer ) PreAuthorize (ctx context.Context , manifestManager user. Info , manifestReader io.Reader ) ([]ScopedPolicyRules , error ) {
72
+ func (a * rbacPreAuthorizer ) PreAuthorize (ctx context.Context , ext * ocv1. ClusterExtension , manifestReader io.Reader ) ([]ScopedPolicyRules , error ) {
73
73
var allMissingPolicyRules = []ScopedPolicyRules {}
74
74
dm , err := a .decodeManifest (manifestReader )
75
75
if err != nil {
76
76
return nil , err
77
77
}
78
- attributesRecords := dm .asAuthorizationAttributesRecordsForUser (manifestManager )
78
+ manifestManager := & user.DefaultInfo {Name : fmt .Sprintf ("system:serviceaccount:%s:%s" , ext .Spec .Namespace , ext .Spec .ServiceAccount .Name )}
79
+ attributesRecords := dm .asAuthorizationAttributesRecordsForUser (manifestManager , ext )
79
80
80
81
var preAuthEvaluationErrors []error
81
82
missingRules , err := a .authorizeAttributesRecords (ctx , attributesRecords )
@@ -92,14 +93,8 @@ func (a *rbacPreAuthorizer) PreAuthorize(ctx context.Context, manifestManager us
92
93
93
94
for _ , obj := range dm .rbacObjects () {
94
95
if err := ec .checkEscalation (ctx , manifestManager , obj ); err != nil {
95
- missingEscalationRules , namespace := parseEscalationErrorForMissingRules (err )
96
- // Check if we already have these escalation PolicyRules, if so don't append
97
- for i , rule := range missingEscalationRules {
98
- previousRule := missingRules [namespace ][len (missingRules [namespace ])- len (missingEscalationRules )+ i ]
99
- if ! arePolicyRulesEqual (previousRule , rule ) {
100
- missingRules [namespace ] = append (missingRules [namespace ], missingEscalationRules ... )
101
- }
102
- }
96
+ missingEscalationRules , err := parseEscalationErrorForMissingRules (err )
97
+ missingRules [obj .GetNamespace ()] = append (missingRules [obj .GetNamespace ()], missingEscalationRules ... )
103
98
preAuthEvaluationErrors = append (preAuthEvaluationErrors , err )
104
99
}
105
100
}
@@ -112,7 +107,20 @@ func (a *rbacPreAuthorizer) PreAuthorize(ctx context.Context, manifestManager us
112
107
if compactMissingRules , err := validation .CompactRules (nsMissingRules ); err == nil {
113
108
missingRules [ns ] = compactMissingRules
114
109
}
115
- sortableRules := rbacv1helpers .SortableRuleSlice (missingRules [ns ])
110
+
111
+ missingRulesWithDeduplicatedVerbs := []rbacv1.PolicyRule {}
112
+ for _ , rule := range missingRules [ns ] {
113
+ verbSet := sets .New [string ](rule .Verbs ... )
114
+ if verbSet .Has ("*" ) {
115
+ rule .Verbs = []string {"*" }
116
+ } else {
117
+ rule .Verbs = sets .List (verbSet )
118
+ }
119
+ missingRulesWithDeduplicatedVerbs = append (missingRulesWithDeduplicatedVerbs , rule )
120
+ }
121
+
122
+ sortableRules := rbacv1helpers .SortableRuleSlice (missingRulesWithDeduplicatedVerbs )
123
+
116
124
sort .Sort (sortableRules )
117
125
allMissingPolicyRules = append (allMissingPolicyRules , ScopedPolicyRules {Namespace : ns , MissingRules : sortableRules })
118
126
}
@@ -284,7 +292,7 @@ func (dm *decodedManifest) rbacObjects() []client.Object {
284
292
return objects
285
293
}
286
294
287
- func (dm * decodedManifest ) asAuthorizationAttributesRecordsForUser (manifestManager user.Info ) []authorizer.AttributesRecord {
295
+ func (dm * decodedManifest ) asAuthorizationAttributesRecordsForUser (manifestManager user.Info , ext * ocv1. ClusterExtension ) []authorizer.AttributesRecord {
288
296
var attributeRecords []authorizer.AttributesRecord
289
297
290
298
// Here we are splitting collection verbs based on required scope
@@ -338,6 +346,18 @@ func (dm *decodedManifest) asAuthorizationAttributesRecordsForUser(manifestManag
338
346
Verb : v ,
339
347
})
340
348
}
349
+
350
+ for _ , verb := range []string {"update" , "patch" } {
351
+ attributeRecords = append (attributeRecords , authorizer.AttributesRecord {
352
+ User : manifestManager ,
353
+ Name : ext .Name ,
354
+ APIGroup : ext .GroupVersionKind ().Group ,
355
+ APIVersion : ext .GroupVersionKind ().Version ,
356
+ Resource : "clusterextensions/finalizers" ,
357
+ ResourceRequest : true ,
358
+ Verb : verb ,
359
+ })
360
+ }
341
361
}
342
362
return attributeRecords
343
363
}
@@ -518,17 +538,14 @@ var fullAuthority = []rbacv1.PolicyRule{
518
538
{Verbs : []string {"*" }, NonResourceURLs : []string {"*" }},
519
539
}
520
540
521
- func parseEscalationErrorForMissingRules (ecError error ) ([]rbacv1.PolicyRule , string ) {
522
- // Regex to capture namespace and serviceaccount
523
- userRegex := regexp .MustCompile (`system:serviceaccount:(?P<Namespace>[^:]+):(?P<ServiceAccount>[^"]+)` )
524
- // Regex to capture missing permissions
541
+ func parseEscalationErrorForMissingRules (ecError error ) ([]rbacv1.PolicyRule , error ) {
542
+ errRegex := regexp .MustCompile (`(?s)^(user \".*\" \(groups=.*\) is attempting to grant RBAC permissions not currently held):.*?$` )
525
543
permRegex := regexp .MustCompile (`{APIGroups:\[("[^"]*")\], Resources:\[("[^"]*")\], Verbs:\[("[^"]*")\]}` )
526
544
527
- userMatches := userRegex .FindStringSubmatch (ecError .Error ())
528
- namespace := userMatches [1 ]
545
+ errMatches := errRegex .FindAllStringSubmatch (ecError .Error (), - 1 )
529
546
530
547
// Extract permissions
531
- var permissions []rbacv1.PolicyRule
548
+ permissions := []rbacv1.PolicyRule {}
532
549
permMatches := permRegex .FindAllStringSubmatch (ecError .Error (), - 1 )
533
550
for _ , match := range permMatches {
534
551
permissions = append (permissions , rbacv1.PolicyRule {
@@ -538,20 +555,7 @@ func parseEscalationErrorForMissingRules(ecError error) ([]rbacv1.PolicyRule, st
538
555
})
539
556
}
540
557
541
- return permissions , namespace
542
- }
543
-
544
- func arePolicyRulesEqual (rule1 rbacv1.PolicyRule , rule2 rbacv1.PolicyRule ) bool {
545
- sort .Strings (rule1 .Verbs )
546
- sort .Strings (rule2 .Verbs )
547
- sort .Strings (rule1 .APIGroups )
548
- sort .Strings (rule2 .APIGroups )
549
- sort .Strings (rule1 .Resources )
550
- sort .Strings (rule2 .Resources )
551
- sort .Strings (rule1 .ResourceNames )
552
- sort .Strings (rule2 .ResourceNames )
553
-
554
- return reflect .DeepEqual (rule1 , rule2 )
558
+ return permissions , errors .New (errMatches [0 ][1 ])
555
559
}
556
560
557
561
func hasAggregationRule (clusterRole * rbacv1.ClusterRole ) bool {
0 commit comments