Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent CRTBs from being created with mismatching Namespace and ClusterName #294

Merged
merged 5 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ Users can only create/update ClusterRoleTemplateBindings which grant permissions

Users cannot create ClusterRoleTemplateBindings which violate the following constraints:
- Either a user subject (through `UserName` or `UserPrincipalName`) or a group subject (through `GroupName` or `GroupPrincipalName`) must be specified; both a user subject and a group subject cannot be specified
- `ClusterName` must be specified
- `ClusterName` must:
- Be provided as a non-empty value
- Match the namespace of the ClusterRoleTemplateBinding
- The roleTemplate indicated in `RoleTemplateName` must be:
- Provided as a non-empty value
- Valid (i.e. is an existing `roleTemplate` object of given name in the `management.cattle.io/v3` API group)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Users can only create/update ClusterRoleTemplateBindings which grant permissions

Users cannot create ClusterRoleTemplateBindings which violate the following constraints:
- Either a user subject (through `UserName` or `UserPrincipalName`) or a group subject (through `GroupName` or `GroupPrincipalName`) must be specified; both a user subject and a group subject cannot be specified
- `ClusterName` must be specified
- `ClusterName` must:
- Be provided as a non-empty value
- Match the namespace of the ClusterRoleTemplateBinding
- The roleTemplate indicated in `RoleTemplateName` must be:
- Provided as a non-empty value
- Valid (i.e. is an existing `roleTemplate` object of given name in the `management.cattle.io/v3` API group)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func (a *admitter) Admit(request *admission.Request) (*admissionv1.AdmissionResp
defer listTrace.LogIfLong(admission.SlowTraceDuration)

fieldPath := field.NewPath("clusterroletemplatebinding")
var warnings []string

if request.Operation == admissionv1.Update {
oldCRTB, newCRTB, err := objectsv3.ClusterRoleTemplateBindingOldAndNewFromRequest(&request.AdmissionRequest)
Expand All @@ -91,6 +92,10 @@ func (a *admitter) Admit(request *admission.Request) (*admissionv1.AdmissionResp
if err := validateUpdateFields(oldCRTB, newCRTB, fieldPath); err != nil {
return admission.ResponseBadRequest(err.Error()), nil
}

if newCRTB.ClusterName != newCRTB.Namespace {
warnings = append(warnings, "Using CRTBs with namespaces and clusterNames that differ is not supported")
JonCrowther marked this conversation as resolved.
Show resolved Hide resolved
}
}

crtb, err := objectsv3.ClusterRoleTemplateBindingFromRequest(&request.AdmissionRequest)
Expand Down Expand Up @@ -123,6 +128,9 @@ func (a *admitter) Admit(request *admission.Request) (*admissionv1.AdmissionResp
response := &admissionv1.AdmissionResponse{}
auth.SetEscalationResponse(response, auth.ConfirmNoEscalation(request, rules, crtb.ClusterName, a.resolver))

if warnings != nil {
response.Warnings = warnings
}
return response, nil
}

Expand Down Expand Up @@ -160,13 +168,17 @@ func (a *admitter) validateCreateFields(newCRTB *apisv3.ClusterRoleTemplateBindi
hasGroupTarget := newCRTB.GroupName != "" || newCRTB.GroupPrincipalName != ""

if (hasUserTarget && hasGroupTarget) || (!hasUserTarget && !hasGroupTarget) {
return field.Forbidden(fieldPath, "binding must target either a user [userId]/[userPrincipalId] OR a group [groupId]/[groupPrincipalId]")
return field.Forbidden(fieldPath, "binding must target either a user [userName]/[userPrincipalName] OR a group [groupName]/[groupPrincipalName]")
}

if newCRTB.ClusterName == "" {
return field.Required(fieldPath.Child("clusterName"), reason)
}

if newCRTB.ClusterName != newCRTB.Namespace {
return field.Forbidden(fieldPath, "clusterName and namespace must be the same value")
}

if newCRTB.RoleTemplateName == "" {
return field.Required(fieldPath.Child("roleTemplateName"), reason)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -668,10 +668,11 @@ func (c *ClusterRoleTemplateBindingSuite) Test_Create() {
username string
}
tests := []struct {
name string
args args
wantErr bool
allowed bool
name string
args args
wantErr bool
allowed bool
warnings []string
}{
{
name: "base test valid CRTB",
Expand Down Expand Up @@ -793,7 +794,6 @@ func (c *ClusterRoleTemplateBindingSuite) Test_Create() {
},
allowed: false,
},

{
name: "locked role template, crtb owned by grb",
args: args{
Expand Down Expand Up @@ -842,7 +842,6 @@ func (c *ClusterRoleTemplateBindingSuite) Test_Create() {
},
allowed: false,
},

{
name: "locked role template, crtb owned by missing grb",
args: args{
Expand Down Expand Up @@ -875,6 +874,39 @@ func (c *ClusterRoleTemplateBindingSuite) Test_Create() {
},
wantErr: true,
},
{
name: "create mismatched clusterName and namespace",
args: args{
username: adminUser,
oldCRTB: func() *apisv3.ClusterRoleTemplateBinding {
return nil
},
newCRTB: func() *apisv3.ClusterRoleTemplateBinding {
baseCRTB := newDefaultCRTB()
baseCRTB.ClusterName = "c-mismatch"
return baseCRTB
},
},
allowed: false,
},
{
name: "update mismatched clusterName and namespace",
args: args{
username: adminUser,
oldCRTB: func() *apisv3.ClusterRoleTemplateBinding {
baseCRTB := newDefaultCRTB()
baseCRTB.ClusterName = "c-mismatch"
return baseCRTB
},
newCRTB: func() *apisv3.ClusterRoleTemplateBinding {
baseCRTB := newDefaultCRTB()
baseCRTB.ClusterName = "c-mismatch"
return baseCRTB
},
},
allowed: true,
warnings: []string{"Using CRTBs with namespaces and clusterNames that differ is not supported"},
},
}

for i := range tests {
Expand All @@ -892,6 +924,15 @@ func (c *ClusterRoleTemplateBindingSuite) Test_Create() {
if resp.Allowed != test.allowed {
c.Failf("Response was incorrectly validated", "Wanted response.Allowed = '%v' got '%v': result=%+v", test.name, test.allowed, resp.Allowed, resp.Result)
}
// check warnings
if test.warnings != nil {
if len(test.warnings) != len(resp.Warnings) {
c.Failf("Number of warnings in response different from expected", "Wanted response.Warnings: '%v' got '%v'", test.warnings, resp.Warnings)
}
for w := range test.warnings {
assert.Equal(c.T(), test.warnings[w], resp.Warnings[w])
}
}
}
})
}
Expand Down