Skip to content

Commit ac43416

Browse files
committed
Add tests for authorization/rbac.go
Signed-off-by: Tayler Geiger <[email protected]>
1 parent 484061d commit ac43416

File tree

1 file changed

+181
-0
lines changed

1 file changed

+181
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package authorization
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
"testing"
8+
9+
"github.com/operator-framework/operator-controller/internal/operator-controller/features"
10+
"github.com/stretchr/testify/require"
11+
corev1 "k8s.io/api/core/v1"
12+
rbacv1 "k8s.io/api/rbac/v1"
13+
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
14+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+
"k8s.io/apimachinery/pkg/runtime"
16+
"k8s.io/apiserver/pkg/authentication/user"
17+
featuregatetesting "k8s.io/component-base/featuregate/testing"
18+
"sigs.k8s.io/controller-runtime/pkg/client"
19+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
20+
)
21+
22+
var (
23+
testManifest = `apiVersion: v1
24+
kind: Service
25+
metadata:
26+
name: test-service
27+
namespace: test-namespace
28+
spec:
29+
clusterIP: None
30+
---
31+
apiVersion: rbac.authorization.k8s.io/v1
32+
kind: Role
33+
metadata:
34+
name: test-extension-role
35+
namespace: test-namespace
36+
rules:
37+
- apiGroups: [""]
38+
resources: [serviceaccounts]
39+
verbs: [watch]
40+
- apiGroups: ["*"]
41+
resources: [services]
42+
verbs: [create]
43+
---
44+
apiVersion: rbac.authorization.k8s.io/v1
45+
kind: RoleBinding
46+
metadata:
47+
name: test-extension-binding
48+
namespace: test-namespace
49+
roleRef:
50+
apiGroup: rbac.authorization.k8s.io
51+
kind: Role
52+
name: test-extension-role
53+
subjects:
54+
- kind: ServiceAccount
55+
name: test-serviceaccount
56+
namespace: test-namespace
57+
`
58+
59+
saName = "test-serviceaccount"
60+
ns = "test-namespace"
61+
62+
objects = []client.Object{
63+
&corev1.Namespace{
64+
ObjectMeta: metav1.ObjectMeta{
65+
Name: "test-namespace",
66+
},
67+
},
68+
&rbacv1.ClusterRoleBinding{
69+
ObjectMeta: metav1.ObjectMeta{
70+
Name: "admin-clusterrole-binding",
71+
},
72+
Subjects: []rbacv1.Subject{
73+
{
74+
Kind: "ServiceAccount",
75+
Name: saName,
76+
Namespace: ns,
77+
},
78+
},
79+
RoleRef: rbacv1.RoleRef{
80+
Name: "admin-clusterrole",
81+
Kind: "ClusterRole",
82+
},
83+
},
84+
&corev1.ServiceAccount{
85+
ObjectMeta: metav1.ObjectMeta{
86+
Name: "test-serviceaccount",
87+
Namespace: "test-namespace",
88+
},
89+
},
90+
}
91+
92+
privilegedClusterRole = &rbacv1.ClusterRole{
93+
ObjectMeta: metav1.ObjectMeta{
94+
Name: "admin-clusterrole",
95+
},
96+
Rules: []rbacv1.PolicyRule{
97+
{
98+
APIGroups: []string{"*"},
99+
Resources: []string{"*"},
100+
Verbs: []string{"*"},
101+
},
102+
},
103+
}
104+
105+
limitedClusterRole = &rbacv1.ClusterRole{
106+
ObjectMeta: metav1.ObjectMeta{
107+
Name: "admin-clusterrole",
108+
},
109+
Rules: []rbacv1.PolicyRule{
110+
{
111+
APIGroups: []string{""},
112+
Resources: []string{""},
113+
Verbs: []string{""},
114+
},
115+
},
116+
}
117+
118+
escalatingClusterRole = &rbacv1.ClusterRole{
119+
ObjectMeta: metav1.ObjectMeta{
120+
Name: "admin-clusterrole",
121+
},
122+
Rules: []rbacv1.PolicyRule{
123+
{
124+
APIGroups: []string{"*"},
125+
Resources: []string{"serviceaccounts"},
126+
Verbs: []string{"*"},
127+
},
128+
{
129+
APIGroups: []string{"rbac.authorization.k8s.io"},
130+
Resources: []string{"roles", "clusterroles"},
131+
Verbs: []string{"escalate", "bind"},
132+
},
133+
},
134+
}
135+
)
136+
137+
func setupFakeClient(role client.Object) client.Client {
138+
s := runtime.NewScheme()
139+
_ = corev1.AddToScheme(s)
140+
_ = rbacv1.AddToScheme(s)
141+
restMapper := testrestmapper.TestOnlyStaticRESTMapper(s)
142+
// restMapper := meta.NewDefaultRESTMapper(nil)
143+
fakeClientBuilder := fake.NewClientBuilder().WithObjects(append(objects, role)...).WithRESTMapper(restMapper)
144+
return fakeClientBuilder.Build()
145+
}
146+
147+
func TestPreAuthorize_Success(t *testing.T) {
148+
t.Run("preauthorize succeeds with no missing rbac rules", func(t *testing.T) {
149+
featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.PreflightPermissions, true)
150+
fakeClient := setupFakeClient(privilegedClusterRole)
151+
preAuth := NewRBACPreAuthorizer(fakeClient)
152+
testServiceAccount := user.DefaultInfo{Name: fmt.Sprintf("system:serviceaccount:%s:%s", ns, saName)}
153+
missingRules, err := preAuth.PreAuthorize(context.TODO(), &testServiceAccount, strings.NewReader(testManifest))
154+
require.NoError(t, err)
155+
require.Equal(t, map[string][]rbacv1.PolicyRule{}, missingRules)
156+
})
157+
}
158+
159+
func TestPreAuthorize_Failure(t *testing.T) {
160+
t.Run("preauthorize failes with missing rbac rules", func(t *testing.T) {
161+
featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.PreflightPermissions, true)
162+
fakeClient := setupFakeClient(limitedClusterRole)
163+
preAuth := NewRBACPreAuthorizer(fakeClient)
164+
testServiceAccount := user.DefaultInfo{Name: fmt.Sprintf("system:serviceaccount:%s:%s", ns, saName)}
165+
missingRules, err := preAuth.PreAuthorize(context.TODO(), &testServiceAccount, strings.NewReader(testManifest))
166+
require.Error(t, err)
167+
require.NotEqual(t, map[string][]rbacv1.PolicyRule{}, missingRules)
168+
})
169+
}
170+
171+
func TestPreAuthorize_CheckEscalation(t *testing.T) {
172+
t.Run("preauthorize succeeds with no missing rbac rules", func(t *testing.T) {
173+
featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.PreflightPermissions, true)
174+
fakeClient := setupFakeClient(escalatingClusterRole)
175+
preAuth := NewRBACPreAuthorizer(fakeClient)
176+
testServiceAccount := user.DefaultInfo{Name: fmt.Sprintf("system:serviceaccount:%s:%s", ns, saName)}
177+
missingRules, err := preAuth.PreAuthorize(context.TODO(), &testServiceAccount, strings.NewReader(testManifest))
178+
require.NoError(t, err)
179+
require.NotEqual(t, map[string][]rbacv1.PolicyRule{}, missingRules)
180+
})
181+
}

0 commit comments

Comments
 (0)