Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 @@ -710,14 +710,16 @@ When settings are created or updated, the following common checks take place:
- The `auth-user-session-idle-ttl-minutes` must be a positive integer and can't be greater than `auth-user-session-ttl-minutes`.
- The `auth-user-info-max-age-seconds` must be a valid duration value.
- The `auth-user-info-resync-cron` must be a valid cron expression.
- If set, `crt-default-ttl-minutes` must be a valid integer no less than `30` and greater than `crt-default-grace-period-minutes` if that value is set.
- If set, `crt-default-grace-period-minutes` must be a valid integer no less than `10` and less than `crt-default-ttl-minutes` if that value is set.

#### Update

When settings are updated, the following additional checks take place:

- Settings with a source of `env` may not be updated

- Read only settings like `cacerts` must not be updated.
- Read only settings like `cacerts` must not be updated, unless the request is generated by the Rancher service account.

- The new value for the setting must not be ""

Expand Down
2 changes: 1 addition & 1 deletion pkg/resources/management.cattle.io/v3/setting/Setting.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ When settings are updated, the following additional checks take place:

- Settings with a source of `env` may not be updated

- Read only settings like `cacerts` must not be updated.
- Read only settings like `cacerts` must not be updated, unless the request is generated by the Rancher service account.

- The new value for the setting must not be ""

Expand Down
7 changes: 4 additions & 3 deletions pkg/resources/management.cattle.io/v3/setting/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (a *admitter) Admit(request *admission.Request) (*admissionv1.AdmissionResp
case admissionv1.Create:
return a.admitCreate(newSetting)
case admissionv1.Update:
return a.admitUpdate(oldSetting, newSetting)
return a.admitUpdate(oldSetting, newSetting, request.UserInfo.Username)
default:
return admission.ResponseAllowed(), nil
}
Expand All @@ -127,16 +127,17 @@ func (a *admitter) admitCreate(newSetting *v3.Setting) (*admissionv1.AdmissionRe
return a.admitCommonCreateUpdate(nil, newSetting)
}

var bypassServiceAccount = "system:serviceaccount:cattle-system:rancher"
var ReadOnlySettings = []string{
"cacerts",
}

func (a *admitter) admitUpdate(oldSetting, newSetting *v3.Setting) (*admissionv1.AdmissionResponse, error) {
func (a *admitter) admitUpdate(oldSetting, newSetting *v3.Setting, username string) (*admissionv1.AdmissionResponse, error) {
if oldSetting.Source == "env" && newSetting.Source != "env" {
return admission.ResponseBadRequest(fmt.Sprintf("setting with source \"%s\" cannot update setting with source \"env\"", newSetting.Source)), nil
}

if slices.Contains(ReadOnlySettings, oldSetting.Name) {
if slices.Contains(ReadOnlySettings, oldSetting.Name) && username != bypassServiceAccount {
return admission.ResponseBadRequest("setting is read only"), nil
}

Expand Down
47 changes: 30 additions & 17 deletions pkg/resources/management.cattle.io/v3/setting/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func (s *SettingSuite) TestAdmitUpdateGuards() {
name string
oldSetting *v3.Setting
newSetting *v3.Setting
username string
allowed bool
}{
{
Expand Down Expand Up @@ -78,6 +79,18 @@ func (s *SettingSuite) TestAdmitUpdateGuards() {
Value: "new-certs",
},
},
{
name: "allow read-only setting frombypass service account",
oldSetting: &v3.Setting{
ObjectMeta: metav1.ObjectMeta{Name: "cacerts"},
},
newSetting: &v3.Setting{
ObjectMeta: metav1.ObjectMeta{Name: "cacerts"},
Value: "new-certs",
},
username: "system:serviceaccount:cattle-system:rancher",
allowed: true,
},
{
name: "allow normal valid update",
oldSetting: &v3.Setting{
Expand All @@ -97,7 +110,7 @@ func (s *SettingSuite) TestAdmitUpdateGuards() {
t.Parallel()

validator := setting.NewValidator(nil, nil)
s.testAdmit(t, validator, test.oldSetting, test.newSetting, v1.Update, test.allowed)
s.testAdmit(t, validator, test.oldSetting, test.newSetting, v1.Update, test.username, test.allowed)
})
}
}
Expand Down Expand Up @@ -197,7 +210,7 @@ func (s *SettingSuite) validateDisableInactiveUserAfter(op v1.Operation) {
Name: setting.DisableInactiveUserAfter,
},
Value: test.value,
}, op, test.allowed)
}, op, "foo", test.allowed)
})
}
}
Expand Down Expand Up @@ -301,7 +314,7 @@ func (s *SettingSuite) validateDeleteInactiveUserAfter(op v1.Operation) {
Name: setting.DeleteInactiveUserAfter,
},
Value: test.value,
}, op, test.allowed)
}, op, "foo", test.allowed)
})
}
}
Expand Down Expand Up @@ -355,7 +368,7 @@ func (s *SettingSuite) validateUserRetentionCron(op v1.Operation) {
Name: setting.UserRetentionCron,
},
Value: test.value,
}, op, test.allowed)
}, op, "foo", test.allowed)
})
}
}
Expand Down Expand Up @@ -413,7 +426,7 @@ func (s *SettingSuite) validateAuthUserInfoMaxAgeSeconds(op v1.Operation) {
Name: setting.AuthUserInfoMaxAgeSeconds,
},
Value: test.value,
}, op, test.allowed)
}, op, "foo", test.allowed)
})
}
}
Expand Down Expand Up @@ -462,7 +475,7 @@ func (s *SettingSuite) validateAuthUserInfoResyncCron(op v1.Operation) {
Name: setting.AuthUserInfoResyncCron,
},
Value: test.value,
}, op, test.allowed)
}, op, "foo", test.allowed)
})
}
}
Expand Down Expand Up @@ -542,7 +555,7 @@ func (s *SettingSuite) validateCRTDefaultTTL(op v1.Operation) {
Name: setting.CRTDefaultTTL,
},
Value: test.value,
}, op, test.allowed)
}, op, "foo", test.allowed)
})
}
}
Expand Down Expand Up @@ -622,7 +635,7 @@ func (s *SettingSuite) validateCRTDefaultGracePeriod(op v1.Operation) {
Name: setting.CRTDefaultGracePeriod,
},
Value: test.value,
}, op, test.allowed)
}, op, "foo", test.allowed)
})
}
}
Expand Down Expand Up @@ -668,7 +681,7 @@ func (s *SettingSuite) validateUserLastLoginDefault(op v1.Operation) {
Name: setting.UserLastLoginDefault,
},
Value: test.value,
}, op, test.allowed)
}, op, "foo", test.allowed)
})
}
}
Expand Down Expand Up @@ -766,7 +779,7 @@ func (s *SettingSuite) TestValidateClusterAgentSchedulingPriorityClass() {
Name: settingName,
},
Value: test.newValue,
}, v1.Update, test.allowed)
}, v1.Update, "foo", test.allowed)
})
}
}
Expand Down Expand Up @@ -885,7 +898,7 @@ func (s *SettingSuite) TestValidateAgentSchedulingPodDisruptionBudget() {
Name: settingName,
},
Value: test.newValue,
}, v1.Update, test.allowed)
}, v1.Update, "foo", test.allowed)
})
}
}
Expand Down Expand Up @@ -1061,19 +1074,19 @@ func (s *SettingSuite) validateAuthUserSessionTTLMinutes(op v1.Operation) {
Name: setting.AuthUserSessionTTLMinutes,
},
Value: test.value,
}, op, test.allowed)
}, op, "foo", test.allowed)
})
}
}

func (s *SettingSuite) testAdmit(t *testing.T, validator *setting.Validator, oldSetting, newSetting *v3.Setting, op v1.Operation, allowed bool) {
func (s *SettingSuite) testAdmit(t *testing.T, validator *setting.Validator, oldSetting, newSetting *v3.Setting, op v1.Operation, username string, allowed bool) {
oldObjRaw, err := json.Marshal(oldSetting)
require.NoError(t, err, "failed to marshal old Setting")

objRaw, err := json.Marshal(newSetting)
require.NoError(t, err, "failed to marshal Setting")

resp, err := validator.Admitters()[0].Admit(newRequest(op, objRaw, oldObjRaw))
resp, err := validator.Admitters()[0].Admit(newRequest(op, objRaw, oldObjRaw, username))
require.NoError(t, err)
assert.Equal(t, allowed, resp.Allowed)
}
Expand All @@ -1088,7 +1101,7 @@ func (s *SettingSuite) TestValidatingWebhookFailurePolicy() {
require.Equal(t, &ignorePolicy, webhook[0].FailurePolicy)
}

func newRequest(op v1.Operation, obj, oldObj []byte) *admission.Request {
func newRequest(op v1.Operation, obj, oldObj []byte, username string) *admission.Request {
return &admission.Request{
AdmissionRequest: v1.AdmissionRequest{
UID: "1",
Expand All @@ -1097,7 +1110,7 @@ func newRequest(op v1.Operation, obj, oldObj []byte) *admission.Request {
RequestKind: &gvk,
RequestResource: &gvr,
Operation: op,
UserInfo: authenticationv1.UserInfo{Username: "foo", UID: ""},
UserInfo: authenticationv1.UserInfo{Username: username, UID: ""},
Object: runtime.RawExtension{Raw: obj},
OldObject: runtime.RawExtension{Raw: oldObj},
},
Expand Down Expand Up @@ -1666,7 +1679,7 @@ func (s *SettingSuite) validateAuthUserSessionTTLIdleMinutes(op v1.Operation, t
Name: setting.AuthUserSessionIdleTTLMinutes,
},
Value: tt.value,
}, op, tt.allowed)
}, op, "foo", tt.allowed)
})
}
}
Loading