rancher/rancher · error
permission denied
Error message
permission denied
What it means
Before accepting a login, Rancher runs permissionCheck → ldap.HasPermission: for entries matching UserObjectClass it parses the UserEnabledAttribute (default userAccountControl) as an integer and treats the account as disabled when (value & UserDisabledBitMask) == UserDisabledBitMask (default 2 = AD ACCOUNTDISABLE). A non-integer attribute value also fails the check. So 'permission denied' here means the AD account is disabled, or the enabled-attribute configuration is wrong.
Source
Thrown at pkg/auth/providers/activedirectory/activedirectory_client.go:170
return groupPrincipals, err
}
func (p *adProvider) UsesUserSecrets() bool { return false }
func (p *adProvider) CanRefreshPrincipals() bool { return true }
func (p *adProvider) getPrincipalsFromSearchResult(lConn ldapv3.Client, config *v3.ActiveDirectoryConfig, result *ldapv3.SearchResult) (v3.Principal, []v3.Principal, error) {
var (
groupPrincipals []v3.Principal
userPrincipal v3.Principal
nonDupGroupPrincipals []v3.Principal
nestedGroupPrincipals []v3.Principal
)
groupMap := make(map[string]bool)
entry := result.Entries[0]
if !p.permissionCheck(entry.Attributes, config) {
return v3.Principal{}, nil, fmt.Errorf("permission denied")
}
memberOf := entry.GetAttributeValues(MemberOfAttribute)
logrus.Debugf("ADConstants userMemberAttribute() {%v}", MemberOfAttribute)
logrus.Debugf("SearchResult memberOf attribute {%s}", memberOf)
isType := false
objectClass := entry.GetAttributeValues(ObjectClass)
for _, obj := range objectClass {
if strings.EqualFold(string(obj), config.UserObjectClass) {
isType = true
}
}
if !isType {
return v3.Principal{}, nil, nil
}
View on GitHub (pinned to 932558d4e6)
Solutions
- Check the account in AD: userAccountControl 514 (or 66050 etc.) means disabled — re-enable it (512 = enabled) or use another account
- If UserEnabledAttribute is customized, make sure it is an integer-valued attribute and the bitmask matches its bit layout
- Clearing the attribute name makes HasPermission return true (check skipped) — use only if you have another enforcement point
Example fix
# before: disabled account userAccountControl: 514 # after: enabled userAccountControl: 512
Defensive patterns
Strategy: try-catch
Validate before calling
// Before wiring automation to an AD account, check its enabled flag // ldapsearch ... '<userDN>' userAccountControl // disabled if value & 0x2
Try / catch
_, _, err := adProvider.Login(ctx, creds)
if err != nil && strings.Contains(err.Error(), "permission denied") {
// account disabled (or enabled-attribute misconfigured):
// surface 'account is disabled' and verify userAccountControl / UserEnabledAttribute config
} Prevention
- Exclude disabled accounts from automated login flows
- If customizing UserEnabledAttribute, pick an integer-valued attribute and matching bitmask
- Remember: non-integer attribute values also fail the check
When it happens
Trigger: Login or principal fetch for a disabled AD account (userAccountControl has bit 0x2, e.g. 514); or UserEnabledAttribute pointing at a non-numeric attribute; or a wrong UserDisabledBitMask marking healthy accounts disabled.
Common situations: Departed/disabled employees or disabled service accounts still attempting login; admins remapping UserEnabledAttribute to a custom attribute (e.g. msDS-UserDontExpirePassword) that is not an integer bitmask.
Related errors
- can't find authprovider
- Unauthorized
- cannot locate user information for %s
- ldap user search found more than one result
- invalid scope %s
AI-assisted analysis of rancher/rancher@932558d4e6 (2026-08-16).
Data as JSON: /api/errors/9c26ea1139909286.
Report an issue: GitHub.