Skip to content

Commit c9405d0

Browse files
Merge pull request #1629 from matskiv/unique-binding-names
Bug 1855088: generate unique (Cluster)RoleBinding names
2 parents 205f53d + b262c0b commit c9405d0

File tree

2 files changed

+175
-5
lines changed

2 files changed

+175
-5
lines changed

pkg/controller/registry/resolver/rbac.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri
9393
// Create Role
9494
role := &rbacv1.Role{
9595
ObjectMeta: metav1.ObjectMeta{
96-
Name: generateName(csv.GetName(), permission.Rules),
96+
Name: generateName(fmt.Sprintf("%s-%s", csv.GetName(), permission.ServiceAccountName), []interface{}{csv.GetName(), permission}),
9797
Namespace: csv.GetNamespace(),
9898
OwnerReferences: []metav1.OwnerReference{ownerutil.NonBlockingOwner(csv)},
9999
Labels: ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
@@ -105,7 +105,7 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri
105105
// Create RoleBinding
106106
roleBinding := &rbacv1.RoleBinding{
107107
ObjectMeta: metav1.ObjectMeta{
108-
Name: generateName(role.GetName(), role),
108+
Name: role.GetName(),
109109
Namespace: csv.GetNamespace(),
110110
OwnerReferences: []metav1.OwnerReference{ownerutil.NonBlockingOwner(csv)},
111111
Labels: ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
@@ -137,7 +137,7 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri
137137
// Create ClusterRole
138138
role := &rbacv1.ClusterRole{
139139
ObjectMeta: metav1.ObjectMeta{
140-
Name: generateName(csv.GetName(), permission.Rules),
140+
Name: generateName(csv.GetName(), []interface{}{csv.GetName(), csv.GetNamespace(), permission}),
141141
Labels: ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
142142
},
143143
Rules: permission.Rules,
@@ -147,7 +147,7 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri
147147
// Create ClusterRoleBinding
148148
roleBinding := &rbacv1.ClusterRoleBinding{
149149
ObjectMeta: metav1.ObjectMeta{
150-
Name: generateName(role.GetName(), role),
150+
Name: role.GetName(),
151151
Namespace: csv.GetNamespace(),
152152
Labels: ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
153153
},

pkg/controller/registry/resolver/rbac_test.go

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
package resolver
22

33
import (
4-
"github.com/stretchr/testify/require"
54
"math/rand"
65
"reflect"
76
"strings"
87
"testing"
98
"testing/quick"
9+
10+
"github.com/stretchr/testify/require"
11+
12+
rbacv1 "k8s.io/api/rbac/v1"
13+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
15+
"github.com/operator-framework/api/pkg/operators/v1alpha1"
1016
)
1117

1218
func TestGenerateName(t *testing.T) {
@@ -63,3 +69,167 @@ func TestGeneratesWithinRange(t *testing.T) {
6369
}
6470
require.NoError(t, quick.Check(f, nil))
6571
}
72+
73+
func TestRBACForClusterServiceVersion(t *testing.T) {
74+
serviceAccount1 := "test-service-account"
75+
serviceAccount2 := "second-service-account"
76+
csvName := "test-csv.v1.1.0"
77+
78+
rules := []rbacv1.PolicyRule{
79+
{
80+
Verbs: []string{"get"},
81+
APIGroups: []string{""},
82+
Resources: []string{"pods"},
83+
},
84+
}
85+
86+
// Note: two CSVs have same name and permissions for a cluster role, this is chosen intentionally,
87+
// to verify that ClusterRole and ClusterRoleBinding have different names when the same CSV is installed
88+
// twice in the same cluster, but in different namespaces.
89+
tests := []struct {
90+
name string
91+
csv v1alpha1.ClusterServiceVersion
92+
want map[string]*OperatorPermissions
93+
}{
94+
{
95+
name: "RoleBindings and one ClusterRoleBinding",
96+
csv: v1alpha1.ClusterServiceVersion{
97+
ObjectMeta: metav1.ObjectMeta{
98+
Name: csvName,
99+
Namespace: "test-namespace",
100+
},
101+
Spec: v1alpha1.ClusterServiceVersionSpec{
102+
InstallStrategy: v1alpha1.NamedInstallStrategy{
103+
StrategyName: v1alpha1.InstallStrategyNameDeployment,
104+
StrategySpec: v1alpha1.StrategyDetailsDeployment{
105+
Permissions: []v1alpha1.StrategyDeploymentPermissions{
106+
{
107+
ServiceAccountName: serviceAccount1,
108+
Rules: rules,
109+
},
110+
{
111+
ServiceAccountName: serviceAccount1,
112+
Rules: []rbacv1.PolicyRule{
113+
{
114+
Verbs: []string{"get"},
115+
APIGroups: []string{""},
116+
Resources: []string{"deployments"},
117+
},
118+
},
119+
},
120+
{
121+
ServiceAccountName: serviceAccount2,
122+
Rules: rules,
123+
},
124+
},
125+
ClusterPermissions: []v1alpha1.StrategyDeploymentPermissions{
126+
{
127+
ServiceAccountName: serviceAccount1,
128+
Rules: rules,
129+
},
130+
},
131+
},
132+
},
133+
},
134+
},
135+
want: map[string]*OperatorPermissions{
136+
serviceAccount1: {
137+
RoleBindings: []*rbacv1.RoleBinding{{}, {}},
138+
ClusterRoleBindings: []*rbacv1.ClusterRoleBinding{{}},
139+
},
140+
serviceAccount2: {
141+
RoleBindings: []*rbacv1.RoleBinding{{}},
142+
},
143+
},
144+
},
145+
{
146+
name: "ClusterRoleBinding",
147+
csv: v1alpha1.ClusterServiceVersion{
148+
ObjectMeta: metav1.ObjectMeta{
149+
Name: csvName,
150+
Namespace: "second-namespace",
151+
},
152+
Spec: v1alpha1.ClusterServiceVersionSpec{
153+
InstallStrategy: v1alpha1.NamedInstallStrategy{
154+
StrategyName: v1alpha1.InstallStrategyNameDeployment,
155+
StrategySpec: v1alpha1.StrategyDetailsDeployment{
156+
ClusterPermissions: []v1alpha1.StrategyDeploymentPermissions{
157+
{
158+
ServiceAccountName: serviceAccount1,
159+
Rules: rules,
160+
},
161+
{
162+
ServiceAccountName: serviceAccount2,
163+
Rules: rules,
164+
},
165+
},
166+
},
167+
},
168+
},
169+
},
170+
want: map[string]*OperatorPermissions{
171+
serviceAccount1: {
172+
ClusterRoleBindings: []*rbacv1.ClusterRoleBinding{{}},
173+
},
174+
serviceAccount2: {
175+
ClusterRoleBindings: []*rbacv1.ClusterRoleBinding{{}},
176+
},
177+
},
178+
},
179+
}
180+
181+
// declared here to verify that names are unique when same csv is install in different namespaces
182+
clusterRoleBindingNames := map[string]bool{}
183+
clusterRolesNames := map[string]bool{}
184+
185+
for _, tt := range tests {
186+
t.Run(tt.name, func(t *testing.T) {
187+
result, err := RBACForClusterServiceVersion(&tt.csv)
188+
require.NoError(t, err)
189+
190+
roleBindingNames := map[string]bool{}
191+
rolesNames := map[string]bool{}
192+
for serviceAccount, permissions := range tt.want {
193+
// Check that correct number of bindings is created
194+
require.Equal(t, len(permissions.RoleBindings), len(result[serviceAccount].RoleBindings))
195+
require.Equal(t, len(permissions.ClusterRoleBindings), len(result[serviceAccount].ClusterRoleBindings))
196+
197+
// Check that testing ServiceAccount is the Subject of RoleBindings
198+
for _, roleBinding := range result[serviceAccount].RoleBindings {
199+
require.Len(t, roleBinding.Subjects, 1)
200+
require.Equal(t, serviceAccount, roleBinding.Subjects[0].Name)
201+
202+
// Check that RoleBindings are created with unique names
203+
_, rbWithNameExists := roleBindingNames[roleBinding.Name]
204+
require.False(t, rbWithNameExists, "RoleBinding with the same name already generated")
205+
roleBindingNames[roleBinding.Name] = true
206+
}
207+
208+
// Check that testing ServiceAccount is the Subject of ClusterrRoleBindings
209+
for _, clusterRoleBinding := range result[serviceAccount].ClusterRoleBindings {
210+
require.Len(t, clusterRoleBinding.Subjects, 1)
211+
require.Equal(t, serviceAccount, clusterRoleBinding.Subjects[0].Name)
212+
213+
// Check that ClusterRoleBindings are created with unique names
214+
_, crbWithNameExists := clusterRoleBindingNames[clusterRoleBinding.Name]
215+
require.False(t, crbWithNameExists, "ClusterRoleBinding with the same name already generated")
216+
clusterRoleBindingNames[clusterRoleBinding.Name] = true
217+
}
218+
219+
// Check that Roles are created with unique names
220+
for _, role := range result[serviceAccount].Roles {
221+
_, roleWithNameExists := rolesNames[role.Name]
222+
require.False(t, roleWithNameExists, "Role with the same name already generated")
223+
rolesNames[role.Name] = true
224+
}
225+
226+
// Check that ClusterRoles are created with unique names
227+
for _, clusterRole := range result[serviceAccount].ClusterRoles {
228+
_, crWithNameExists := clusterRolesNames[clusterRole.Name]
229+
require.False(t, crWithNameExists, "ClusterRole with the same name already generated")
230+
clusterRolesNames[clusterRole.Name] = true
231+
}
232+
}
233+
})
234+
}
235+
}

0 commit comments

Comments
 (0)