@@ -3,6 +3,7 @@ package authorization
33import (
44 "context"
55 "errors"
6+ "fmt"
67 "strings"
78 "testing"
89
@@ -12,12 +13,13 @@ import (
1213 "k8s.io/apimachinery/pkg/api/meta/testrestmapper"
1314 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1415 "k8s.io/apimachinery/pkg/runtime"
15- featuregatetesting "k8s.io/component-base/featuregate/testing"
16+ "k8s.io/apiserver/pkg/authentication/user"
17+ "k8s.io/apiserver/pkg/endpoints/request"
18+ "k8s.io/kubernetes/pkg/registry/rbac/validation"
1619 "sigs.k8s.io/controller-runtime/pkg/client"
1720 "sigs.k8s.io/controller-runtime/pkg/client/fake"
1821
1922 ocv1 "github.com/operator-framework/operator-controller/api/v1"
20- "github.com/operator-framework/operator-controller/internal/operator-controller/features"
2123)
2224
2325var (
@@ -226,7 +228,6 @@ func setupFakeClient(role client.Object) client.Client {
226228
227229func TestPreAuthorize_Success (t * testing.T ) {
228230 t .Run ("preauthorize succeeds with no missing rbac rules" , func (t * testing.T ) {
229- featuregatetesting .SetFeatureGateDuringTest (t , features .OperatorControllerFeatureGate , features .PreflightPermissions , true )
230231 fakeClient := setupFakeClient (privilegedClusterRole )
231232 preAuth := NewRBACPreAuthorizer (fakeClient )
232233 missingRules , err := preAuth .PreAuthorize (context .TODO (), & exampleClusterExtension , strings .NewReader (testManifest ))
@@ -237,7 +238,6 @@ func TestPreAuthorize_Success(t *testing.T) {
237238
238239func TestPreAuthorize_Failure (t * testing.T ) {
239240 t .Run ("preauthorize fails with missing rbac rules" , func (t * testing.T ) {
240- featuregatetesting .SetFeatureGateDuringTest (t , features .OperatorControllerFeatureGate , features .PreflightPermissions , true )
241241 fakeClient := setupFakeClient (limitedClusterRole )
242242 preAuth := NewRBACPreAuthorizer (fakeClient )
243243 missingRules , err := preAuth .PreAuthorize (context .TODO (), & exampleClusterExtension , strings .NewReader (testManifest ))
@@ -248,7 +248,6 @@ func TestPreAuthorize_Failure(t *testing.T) {
248248
249249func TestPreAuthorizeMultiNamespace_Failure (t * testing.T ) {
250250 t .Run ("preauthorize fails with missing rbac rules in multiple namespaces" , func (t * testing.T ) {
251- featuregatetesting .SetFeatureGateDuringTest (t , features .OperatorControllerFeatureGate , features .PreflightPermissions , true )
252251 fakeClient := setupFakeClient (limitedClusterRole )
253252 preAuth := NewRBACPreAuthorizer (fakeClient )
254253 missingRules , err := preAuth .PreAuthorize (context .TODO (), & exampleClusterExtension , strings .NewReader (testManifestMultiNamespace ))
@@ -259,7 +258,6 @@ func TestPreAuthorizeMultiNamespace_Failure(t *testing.T) {
259258
260259func TestPreAuthorize_CheckEscalation (t * testing.T ) {
261260 t .Run ("preauthorize succeeds with no missing rbac rules" , func (t * testing.T ) {
262- featuregatetesting .SetFeatureGateDuringTest (t , features .OperatorControllerFeatureGate , features .PreflightPermissions , true )
263261 fakeClient := setupFakeClient (escalatingClusterRole )
264262 preAuth := NewRBACPreAuthorizer (fakeClient )
265263 missingRules , err := preAuth .PreAuthorize (context .TODO (), & exampleClusterExtension , strings .NewReader (testManifest ))
@@ -270,7 +268,7 @@ func TestPreAuthorize_CheckEscalation(t *testing.T) {
270268
271269// TestParseEscalationErrorForMissingRules Are tests with respect to https://github.com/kubernetes/api/blob/e8d4d542f6a9a16a694bfc8e3b8cd1557eecfc9d/rbac/v1/types.go#L49-L74
272270// Goal is: prove the regex works as planned AND that if the error messages ever change we'll learn about it with these tests
273- func TestParseEscalationErrorForMissingRules (t * testing.T ) {
271+ func TestParseEscalationErrorForMissingRules_ParsingLogic (t * testing.T ) {
274272 testCases := []struct {
275273 name string
276274 inputError error
@@ -279,7 +277,7 @@ func TestParseEscalationErrorForMissingRules(t *testing.T) {
279277 }{
280278 {
281279 name : "One Missing Resource Rule" ,
282- inputError : errors .New (`user "test-user" (groups=test) is attempting to grant RBAC permissions not currently held:
280+ inputError : errors .New (`user "test-user" (groups=[" test"] ) is attempting to grant RBAC permissions not currently held:
283281{APIGroups:["apps"], Resources:["deployments"], Verbs:["get"]}` ),
284282 expectedResult : & parseResult {
285283 MissingRules : []rbacv1.PolicyRule {
@@ -304,32 +302,32 @@ func TestParseEscalationErrorForMissingRules(t *testing.T) {
304302 {
305303 name : "One Missing Rule with Resolution Errors" ,
306304 inputError : errors .New (`user "test-admin" (groups=["system:masters"]) is attempting to grant RBAC permissions not currently held:
307- {APIGroups:["batch"], Resources:["jobs"], Verbs:["create"]}; resolution errors: role "missing-role" not found` ),
305+ {APIGroups:["batch"], Resources:["jobs"], Verbs:["create"]}; resolution errors: [ role "missing-role" not found] ` ),
308306 expectedResult : & parseResult {
309307 MissingRules : []rbacv1.PolicyRule {
310308 {APIGroups : []string {"batch" }, Resources : []string {"jobs" }, Verbs : []string {"create" }},
311309 },
312- ResolutionErrors : errors .New (`role "missing-role" not found` ),
310+ ResolutionErrors : errors .New (`[ role "missing-role" not found] ` ),
313311 },
314312 expectError : require .NoError ,
315313 },
316314 {
317315 name : "Multiple Missing Rules with Resolution Errors" ,
318316 inputError : errors .New (`user "another-user" (groups=[]) is attempting to grant RBAC permissions not currently held:
319317{APIGroups:[""], Resources:["secrets"], Verbs:["get"]}
320- {APIGroups:[""], Resources:["configmaps"], Verbs:["list"]}; resolution errors: clusterrole "missing-clusterrole" not found, role "other-missing" not found` ),
318+ {APIGroups:[""], Resources:["configmaps"], Verbs:["list"]}; resolution errors: [ clusterrole "missing-clusterrole" not found, role "other-missing" not found] ` ),
321319 expectedResult : & parseResult {
322320 MissingRules : []rbacv1.PolicyRule {
323321 {APIGroups : []string {"" }, Resources : []string {"secrets" }, Verbs : []string {"get" }},
324322 {APIGroups : []string {"" }, Resources : []string {"configmaps" }, Verbs : []string {"list" }},
325323 },
326- ResolutionErrors : errors .New (`clusterrole "missing-clusterrole" not found, role "other-missing" not found` ),
324+ ResolutionErrors : errors .New (`[ clusterrole "missing-clusterrole" not found, role "other-missing" not found] ` ),
327325 },
328326 expectError : require .NoError ,
329327 },
330328 {
331329 name : "Missing Rule (All Resource Fields)" ,
332- inputError : errors .New (`user "resource-name-user" (groups=test) is attempting to grant RBAC permissions not currently held:
330+ inputError : errors .New (`user "resource-name-user" (groups=[" test"] ) is attempting to grant RBAC permissions not currently held:
333331{APIGroups:["extensions"], Resources:["ingresses"], ResourceNames:["my-ingress"], Verbs:["update" "patch"]}` ),
334332 expectedResult : & parseResult {
335333 MissingRules : []rbacv1.PolicyRule {
@@ -340,7 +338,7 @@ func TestParseEscalationErrorForMissingRules(t *testing.T) {
340338 },
341339 {
342340 name : "Missing Rule (No ResourceNames)" ,
343- inputError : errors .New (`user "no-res-name-user" (groups=test) is attempting to grant RBAC permissions not currently held:
341+ inputError : errors .New (`user "no-res-name-user" (groups=[" test"] ) is attempting to grant RBAC permissions not currently held:
344342{APIGroups:["networking.k8s.io"], Resources:["networkpolicies"], Verbs:["watch"]}` ),
345343 expectedResult : & parseResult {
346344 MissingRules : []rbacv1.PolicyRule {
@@ -351,7 +349,7 @@ func TestParseEscalationErrorForMissingRules(t *testing.T) {
351349 },
352350 {
353351 name : "Missing Rule (NonResourceURLs only)" ,
354- inputError : errors .New (`user "url-user" (groups=test) is attempting to grant RBAC permissions not currently held:
352+ inputError : errors .New (`user "url-user" (groups=[" test"] ) is attempting to grant RBAC permissions not currently held:
355353{NonResourceURLs:["/version" "/apis"], Verbs:["get"]}` ),
356354 expectedResult : & parseResult {
357355 MissingRules : []rbacv1.PolicyRule {
@@ -370,7 +368,7 @@ func TestParseEscalationErrorForMissingRules(t *testing.T) {
370368 },
371369 {
372370 name : "Empty Permissions String" ,
373- inputError : errors .New (`user "empty-perms" (groups=test) is attempting to grant RBAC permissions not currently held:
371+ inputError : errors .New (`user "empty-perms" (groups=[" test"] ) is attempting to grant RBAC permissions not currently held:
374372` ),
375373 expectedResult : & parseResult {},
376374 expectError : func (t require.TestingT , err error , i ... interface {}) {
@@ -379,7 +377,7 @@ func TestParseEscalationErrorForMissingRules(t *testing.T) {
379377 },
380378 {
381379 name : "Rule with Empty Strings in lists" ,
382- inputError : errors .New (`user "empty-strings" (groups=test) is attempting to grant RBAC permissions not currently held:
380+ inputError : errors .New (`user "empty-strings" (groups=[" test"] ) is attempting to grant RBAC permissions not currently held:
383381{APIGroups:["" "apps"], Resources:["" "deployments"], Verbs:["get" ""]}` ),
384382 expectedResult : & parseResult {
385383 MissingRules : []rbacv1.PolicyRule {
@@ -390,7 +388,7 @@ func TestParseEscalationErrorForMissingRules(t *testing.T) {
390388 },
391389 {
392390 name : "Rule with Only Empty Verb" ,
393- inputError : errors .New (`user "empty-verb" (groups=test) is attempting to grant RBAC permissions not currently held:
391+ inputError : errors .New (`user "empty-verb" (groups=[" test"] ) is attempting to grant RBAC permissions not currently held:
394392{APIGroups:[""], Resources:["pods"], Verbs:[""]}` ),
395393 expectedResult : & parseResult {
396394 MissingRules : []rbacv1.PolicyRule {
@@ -401,16 +399,26 @@ func TestParseEscalationErrorForMissingRules(t *testing.T) {
401399 },
402400 {
403401 name : "Rule with no fields" ,
404- inputError : errors .New (`user "empty-verb" (groups=test) is attempting to grant RBAC permissions not currently held:
402+ inputError : errors .New (`user "empty-verb" (groups=[" test"] ) is attempting to grant RBAC permissions not currently held:
405403{}` ),
406404 expectedResult : & parseResult {
407405 MissingRules : []rbacv1.PolicyRule {{}},
408406 },
409407 expectError : require .NoError ,
410408 },
409+ {
410+ name : "Rule with no colon separator" ,
411+ inputError : errors .New (`user "empty-verb" (groups=["test"]) is attempting to grant RBAC permissions not currently held:
412+ {APIGroups:[""], Resources, Verbs:["get"]}
413+ ` ),
414+ expectedResult : & parseResult {},
415+ expectError : func (t require.TestingT , err error , i ... interface {}) {
416+ require .ErrorContains (t , err , `unexpected item "Resources": expected <Type>:[<values>...]` )
417+ },
418+ },
411419 {
412420 name : "Rule with unknown field" ,
413- inputError : errors .New (`user "empty-verb" (groups=test) is attempting to grant RBAC permissions not currently held:
421+ inputError : errors .New (`user "empty-verb" (groups=[" test"] ) is attempting to grant RBAC permissions not currently held:
414422{FooBar:["baz"]}
415423{APIGroups:[""], Resources:["secrets"], Verbs:["get"]}
416424` ),
@@ -428,9 +436,125 @@ func TestParseEscalationErrorForMissingRules(t *testing.T) {
428436 for _ , tc := range testCases {
429437 t .Run (tc .name , func (t * testing.T ) {
430438 rules , err := parseEscalationErrorForMissingRules (tc .inputError )
431-
432439 tc .expectError (t , err )
433440 require .Equal (t , tc .expectedResult , rules )
434441 })
435442 }
436443}
444+
445+ func TestParseEscalationErrorForMissingRules_KubernetesCompatibility (t * testing.T ) {
446+ testCases := []struct {
447+ name string
448+ ruleResolver validation.AuthorizationRuleResolver
449+ wantRules []rbacv1.PolicyRule
450+ expectedErrorString string
451+ expectedResult * parseResult
452+ }{
453+ {
454+ name : "missing rules" ,
455+ ruleResolver : mockRulesResolver {
456+ rules : []rbacv1.PolicyRule {},
457+ err : nil ,
458+ },
459+ wantRules : []rbacv1.PolicyRule {
460+ {APIGroups : []string {"" }, Resources : []string {"secrets" }, Verbs : []string {"get" }, ResourceNames : []string {"test-secret" }},
461+ {APIGroups : []string {"" }, Resources : []string {"configmaps" }, Verbs : []string {"get" , "list" , "watch" }},
462+ {APIGroups : []string {"apps" }, Resources : []string {"deployments" , "replicasets" }, Verbs : []string {"create" , "update" , "patch" , "delete" }},
463+ {NonResourceURLs : []string {"/healthz" , "/livez" }, Verbs : []string {"get" , "post" }},
464+ },
465+ expectedErrorString : `user "user" (groups=["a" "b"]) is attempting to grant RBAC permissions not currently held:
466+ {APIGroups:[""], Resources:["configmaps"], Verbs:["get" "list" "watch"]}
467+ {APIGroups:[""], Resources:["secrets"], ResourceNames:["test-secret"], Verbs:["get"]}
468+ {APIGroups:["apps"], Resources:["deployments"], Verbs:["create" "update" "patch" "delete"]}
469+ {APIGroups:["apps"], Resources:["replicasets"], Verbs:["create" "update" "patch" "delete"]}
470+ {NonResourceURLs:["/healthz"], Verbs:["get"]}
471+ {NonResourceURLs:["/healthz"], Verbs:["post"]}
472+ {NonResourceURLs:["/livez"], Verbs:["get"]}
473+ {NonResourceURLs:["/livez"], Verbs:["post"]}` ,
474+ expectedResult : & parseResult {
475+ MissingRules : []rbacv1.PolicyRule {
476+ {APIGroups : []string {"" }, Resources : []string {"configmaps" }, Verbs : []string {"get" , "list" , "watch" }},
477+ {APIGroups : []string {"" }, Resources : []string {"secrets" }, Verbs : []string {"get" }, ResourceNames : []string {"test-secret" }},
478+ {APIGroups : []string {"apps" }, Resources : []string {"deployments" }, Verbs : []string {"create" , "update" , "patch" , "delete" }},
479+ {APIGroups : []string {"apps" }, Resources : []string {"replicasets" }, Verbs : []string {"create" , "update" , "patch" , "delete" }},
480+ {NonResourceURLs : []string {"/healthz" }, Verbs : []string {"get" }},
481+ {NonResourceURLs : []string {"/healthz" }, Verbs : []string {"post" }},
482+ {NonResourceURLs : []string {"/livez" }, Verbs : []string {"get" }},
483+ {NonResourceURLs : []string {"/livez" }, Verbs : []string {"post" }},
484+ },
485+ },
486+ },
487+ {
488+ name : "resolution failure" ,
489+ ruleResolver : mockRulesResolver {
490+ rules : []rbacv1.PolicyRule {},
491+ err : errors .New ("resolution error" ),
492+ },
493+ wantRules : []rbacv1.PolicyRule {
494+ {APIGroups : []string {"" }, Resources : []string {"secrets" }, Verbs : []string {"get" }, ResourceNames : []string {"test-secret" }},
495+ {APIGroups : []string {"" }, Resources : []string {"configmaps" }, Verbs : []string {"get" , "list" , "watch" }},
496+ {APIGroups : []string {"apps" }, Resources : []string {"deployments" , "replicasets" }, Verbs : []string {"create" , "update" , "patch" , "delete" }},
497+ {NonResourceURLs : []string {"/healthz" , "/livez" }, Verbs : []string {"get" , "post" }},
498+ },
499+ expectedErrorString : `user "user" (groups=["a" "b"]) is attempting to grant RBAC permissions not currently held:
500+ {APIGroups:[""], Resources:["configmaps"], Verbs:["get" "list" "watch"]}
501+ {APIGroups:[""], Resources:["secrets"], ResourceNames:["test-secret"], Verbs:["get"]}
502+ {APIGroups:["apps"], Resources:["deployments"], Verbs:["create" "update" "patch" "delete"]}
503+ {APIGroups:["apps"], Resources:["replicasets"], Verbs:["create" "update" "patch" "delete"]}
504+ {NonResourceURLs:["/healthz"], Verbs:["get"]}
505+ {NonResourceURLs:["/healthz"], Verbs:["post"]}
506+ {NonResourceURLs:["/livez"], Verbs:["get"]}
507+ {NonResourceURLs:["/livez"], Verbs:["post"]}; resolution errors: [resolution error]` ,
508+ expectedResult : & parseResult {
509+ MissingRules : []rbacv1.PolicyRule {
510+ {APIGroups : []string {"" }, Resources : []string {"configmaps" }, Verbs : []string {"get" , "list" , "watch" }},
511+ {APIGroups : []string {"" }, Resources : []string {"secrets" }, Verbs : []string {"get" }, ResourceNames : []string {"test-secret" }},
512+ {APIGroups : []string {"apps" }, Resources : []string {"deployments" }, Verbs : []string {"create" , "update" , "patch" , "delete" }},
513+ {APIGroups : []string {"apps" }, Resources : []string {"replicasets" }, Verbs : []string {"create" , "update" , "patch" , "delete" }},
514+ {NonResourceURLs : []string {"/healthz" }, Verbs : []string {"get" }},
515+ {NonResourceURLs : []string {"/healthz" }, Verbs : []string {"post" }},
516+ {NonResourceURLs : []string {"/livez" }, Verbs : []string {"get" }},
517+ {NonResourceURLs : []string {"/livez" }, Verbs : []string {"post" }},
518+ },
519+ ResolutionErrors : errors .New ("[resolution error]" ),
520+ },
521+ },
522+ }
523+ for _ , tc := range testCases {
524+ t .Run (tc .name , func (t * testing.T ) {
525+ ctx := request .WithUser (request .WithNamespace (context .Background (), "namespace" ), & user.DefaultInfo {
526+ Name : "user" ,
527+ Groups : []string {"a" , "b" },
528+ })
529+
530+ // Let's actually call the upstream function that generates and returns the
531+ // error message that we are attempting to parse correctly. The hope is that
532+ // these tests will start failing if we bump to a new version of kubernetes
533+ // that causes our parsing logic to be incorrect.
534+ err := validation .ConfirmNoEscalation (ctx , tc .ruleResolver , tc .wantRules )
535+ require .Error (t , err )
536+ require .Equal (t , tc .expectedErrorString , err .Error ())
537+
538+ res , err := parseEscalationErrorForMissingRules (err )
539+ require .NoError (t , err )
540+ require .Equal (t , tc .expectedResult , res )
541+ })
542+ }
543+ }
544+
545+ type mockRulesResolver struct {
546+ rules []rbacv1.PolicyRule
547+ err error
548+ }
549+
550+ func (m mockRulesResolver ) GetRoleReferenceRules (ctx context.Context , roleRef rbacv1.RoleRef , namespace string ) ([]rbacv1.PolicyRule , error ) {
551+ panic ("unimplemented" )
552+ }
553+
554+ func (m mockRulesResolver ) RulesFor (ctx context.Context , user user.Info , namespace string ) ([]rbacv1.PolicyRule , error ) {
555+ return m .rules , m .err
556+ }
557+
558+ func (m mockRulesResolver ) VisitRulesFor (ctx context.Context , user user.Info , namespace string , visitor func (source fmt.Stringer , rule * rbacv1.PolicyRule , err error ) bool ) {
559+ panic ("unimplemented" )
560+ }
0 commit comments