Skip to content

Commit b4a23e3

Browse files
committed
Fix conversion for role binding to cluster role
This change makes it so that the conversion for authorization policy correctly handles when a RBAC role binding references a cluster role. The code incorrectly assumed that the role binding's namespace was the referenced role's namespace as well. Now we use the role's kind to determine its namespace. This was missed by the fuzzer tests because they only made role bindings to roles. The tests have been updated to create bindings to both types of roles. Signed-off-by: Monis Khan <[email protected]>
1 parent 12575c5 commit b4a23e3

File tree

2 files changed

+55
-11
lines changed

2 files changed

+55
-11
lines changed

pkg/authorization/apis/authorization/conversion.go

+21-9
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ func Convert_authorization_Role_To_rbac_Role(in *Role, out *rbac.Role, _ convers
4141
}
4242

4343
func Convert_authorization_ClusterRoleBinding_To_rbac_ClusterRoleBinding(in *ClusterRoleBinding, out *rbac.ClusterRoleBinding, _ conversion.Scope) error {
44+
if len(in.RoleRef.Namespace) != 0 {
45+
return fmt.Errorf("invalid origin cluster role binding %s: attempts to reference role in namespace %q instead of cluster scope", in.Name, in.RoleRef.Namespace)
46+
}
4447
var err error
4548
if out.Subjects, err = convert_api_Subjects_To_rbac_Subjects(in.Subjects); err != nil {
4649
return err
@@ -166,7 +169,9 @@ func Convert_rbac_ClusterRoleBinding_To_authorization_ClusterRoleBinding(in *rba
166169
if out.Subjects, err = convert_rbac_Subjects_To_authorization_Subjects(in.Subjects); err != nil {
167170
return err
168171
}
169-
out.RoleRef = convert_rbac_RoleRef_To_authorization_RoleRef(&in.RoleRef, "")
172+
if out.RoleRef, err = convert_rbac_RoleRef_To_authorization_RoleRef(&in.RoleRef, ""); err != nil {
173+
return err
174+
}
170175
out.ObjectMeta = in.ObjectMeta
171176
return nil
172177
}
@@ -176,7 +181,9 @@ func Convert_rbac_RoleBinding_To_authorization_RoleBinding(in *rbac.RoleBinding,
176181
if out.Subjects, err = convert_rbac_Subjects_To_authorization_Subjects(in.Subjects); err != nil {
177182
return err
178183
}
179-
out.RoleRef = convert_rbac_RoleRef_To_authorization_RoleRef(&in.RoleRef, in.Namespace)
184+
if out.RoleRef, err = convert_rbac_RoleRef_To_authorization_RoleRef(&in.RoleRef, in.Namespace); err != nil {
185+
return err
186+
}
180187
out.ObjectMeta = in.ObjectMeta
181188
return nil
182189
}
@@ -205,13 +212,18 @@ func convert_rbac_Subjects_To_authorization_Subjects(in []rbac.Subject) ([]api.O
205212
return subjects, nil
206213
}
207214

208-
// rbac.RoleRef has no namespace field since that can be inferred.
209-
// The Origin role ref (api.ObjectReference) requires its namespace value to match the binding's namespace.
210-
// Thus we have to explicitly provide that value as a parameter.
211-
func convert_rbac_RoleRef_To_authorization_RoleRef(in *rbac.RoleRef, namespace string) api.ObjectReference {
212-
return api.ObjectReference{
213-
Name: in.Name,
214-
Namespace: namespace,
215+
// rbac.RoleRef has no namespace field since that can be inferred from the kind of referenced role.
216+
// The Origin role ref (api.ObjectReference) requires its namespace value to match the binding's namespace
217+
// for a binding to a role. For a binding to a cluster role, the namespace value must be the empty string.
218+
// Thus we have to explicitly provide the namespace value as a parameter and use it based on the role's kind.
219+
func convert_rbac_RoleRef_To_authorization_RoleRef(in *rbac.RoleRef, namespace string) (api.ObjectReference, error) {
220+
switch in.Kind {
221+
case "ClusterRole":
222+
return api.ObjectReference{Name: in.Name}, nil
223+
case "Role":
224+
return api.ObjectReference{Name: in.Name, Namespace: namespace}, nil
225+
default:
226+
return api.ObjectReference{}, fmt.Errorf("invalid kind %q for rbac role ref %q", in.Kind, in.Name)
215227
}
216228
}
217229

pkg/authorization/apis/authorization/conversion_test.go

+34-2
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,18 @@ func TestConversionErrors(t *testing.T) {
193193
}, &rbac.ClusterRoleBinding{}, nil)
194194
},
195195
},
196+
{
197+
name: "invalid origin rol ref namespace",
198+
expected: `invalid origin cluster role binding clusterrolebindingname: attempts to reference role in namespace "fancyns" instead of cluster scope`,
199+
f: func() error {
200+
return authorizationapi.Convert_authorization_ClusterRoleBinding_To_rbac_ClusterRoleBinding(&authorizationapi.ClusterRoleBinding{
201+
ObjectMeta: metav1.ObjectMeta{Name: "clusterrolebindingname"},
202+
RoleRef: api.ObjectReference{
203+
Namespace: "fancyns",
204+
},
205+
}, &rbac.ClusterRoleBinding{}, nil)
206+
},
207+
},
196208
{
197209
name: "invalid RBAC subject kind",
198210
expected: `invalid kind for rbac subject: "evenfancieruser"`,
@@ -204,6 +216,18 @@ func TestConversionErrors(t *testing.T) {
204216
}, &authorizationapi.ClusterRoleBinding{}, nil)
205217
},
206218
},
219+
{
220+
name: "invalid RBAC rol ref kind",
221+
expected: `invalid kind "anewfancykind" for rbac role ref "fancyrolref"`,
222+
f: func() error {
223+
return authorizationapi.Convert_rbac_ClusterRoleBinding_To_authorization_ClusterRoleBinding(&rbac.ClusterRoleBinding{
224+
RoleRef: rbac.RoleRef{
225+
Name: "fancyrolref",
226+
Kind: "anewfancykind",
227+
},
228+
}, &authorizationapi.ClusterRoleBinding{}, nil)
229+
},
230+
},
207231
} {
208232
if err := test.f(); err == nil || test.expected != err.Error() {
209233
t.Errorf("%s failed: expected %q got %v", test.name, test.expected, err)
@@ -349,7 +373,7 @@ func setRandomRBACRoleBindingData(subjects []rbac.Subject, roleRef *rbac.RoleRef
349373
setValidRBACKindAndNamespace(subject, i, c)
350374
}
351375
roleRef.APIGroup = rbac.GroupName
352-
roleRef.Kind = getRBACRoleRefKind(namespace)
376+
roleRef.Kind = getRBACRoleRefKind(getRandomScope(namespace, c))
353377
}
354378

355379
func setValidRBACKindAndNamespace(subject *rbac.Subject, i int, c fuzz.Continue) {
@@ -375,7 +399,15 @@ func setRandomOriginRoleBindingData(subjects []api.ObjectReference, roleRef *api
375399
}
376400
unsetUnusedOriginFields(roleRef)
377401
roleRef.Kind = ""
378-
roleRef.Namespace = namespace
402+
roleRef.Namespace = getRandomScope(namespace, c)
403+
}
404+
405+
// we want bindings to both cluster and local roles
406+
func getRandomScope(namespace string, c fuzz.Continue) string {
407+
if c.RandBool() {
408+
return ""
409+
}
410+
return namespace
379411
}
380412

381413
func setValidOriginKindAndNamespace(subject *api.ObjectReference, i int, c fuzz.Continue) {

0 commit comments

Comments
 (0)