Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

Commit

Permalink
Enforce windows password complexity requirements in acs-engine client… (
Browse files Browse the repository at this point in the history
#3854)

* Enforce windows password complexity requirements in acs-engine client. #2407

Added Windows Agent password complexity check as per guidelines in  https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/password-must-meet-complexity-requirements.

This will prevent generation of arm templates if password complexity for windows vm does not meet the complexity requirements.

* Addressing review comments:

1). Adding negative test cases to ensure passwords whose complexity is not met are getting rejected.
2). Error message reworded to convey the password complexity requirements enforced currently by the implemented regex

* Adding two test cases - password with 0 length and password same as username
  • Loading branch information
vpatelsj authored and tariq1890 committed Sep 20, 2018
1 parent 9ed4a3b commit 3b9c5a8
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 1 deletion.
29 changes: 29 additions & 0 deletions pkg/api/vlabs/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -953,9 +953,38 @@ func (w *WindowsProfile) Validate(orchestratorType string) error {
if e := validate.Var(w.AdminPassword, "required"); e != nil {
return errors.New("WindowsProfile.AdminPassword is required, when agent pool specifies windows")
}
if validatePasswordComplexity(w.AdminUsername, w.AdminPassword) == false {
return errors.New("WindowsProfile.AdminPassword complexity not met. Windows password should contain 3 of the following categories - uppercase letters(A-Z), lowercase(a-z) letters, digits(0-9), special characters (~!@#$%^&*_-+=`|\\(){}[]:;<>,.?/')")
}
return validateKeyVaultSecrets(w.Secrets, true)
}

func validatePasswordComplexity(name string, password string) (out bool) {

if strings.EqualFold(name, password) {
return false
}

if len(password) == 0 {
return false
}

hits := 0
if regexp.MustCompile(`[0-9]+`).MatchString(password) {
hits++
}
if regexp.MustCompile(`[A-Z]+`).MatchString(password) {
hits++
}
if regexp.MustCompile(`[a-z]`).MatchString(password) {
hits++
}
if regexp.MustCompile(`[~!@#\$%\^&\*_\-\+=\x60\|\(\){}\[\]:;"'<>,\.\?/]+`).MatchString(password) {
hits++
}
return hits > 2
}

// Validate validates the KubernetesConfig
func (k *KubernetesConfig) Validate(k8sVersion string, hasWindows bool) error {
// number of minimum retries allowed for kubelet to post node status
Expand Down
31 changes: 30 additions & 1 deletion pkg/api/vlabs/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ func getK8sDefaultProperties(hasWindows bool) *Properties {
}
p.WindowsProfile = &WindowsProfile{
AdminUsername: "azureuser",
AdminPassword: "password",
AdminPassword: "replacepassword1234$",
}
}

Expand Down Expand Up @@ -1265,6 +1265,35 @@ func TestWindowsVersions(t *testing.T) {
"should not error on valid Windows version: %v", err,
)
}
p = getK8sDefaultProperties(true)
p.WindowsProfile.AdminPassword = "Password"
if err := p.Validate(false); err == nil {
t.Errorf(
"should error on windows password complexity not match because no digits and special characters found in the password ",
)
}
p = getK8sDefaultProperties(true)
p.WindowsProfile.AdminPassword = "123!@#"
if err := p.Validate(false); err == nil {
t.Errorf(
"should error on windows password complexity not match because uppercase and lowercase letters found in the password",
)
}
p = getK8sDefaultProperties(true)
p.WindowsProfile.AdminPassword = ""
if err := p.Validate(false); err == nil {
t.Errorf(
"should error on windows password length is zero",
)
}
p = getK8sDefaultProperties(true)
p.WindowsProfile.AdminUsername = "User@123"
p.WindowsProfile.AdminPassword = "User@123"
if err := p.Validate(false); err == nil {
t.Errorf(
"should error on windows password complexity not match because username and password are same",
)
}
sv, _ := semver.Make(version)
p = getK8sDefaultProperties(true)
p.OrchestratorProfile.OrchestratorRelease = fmt.Sprintf("%d.%d", sv.Major, sv.Minor)
Expand Down

0 comments on commit 3b9c5a8

Please sign in to comment.