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

  1. Check the account in AD: userAccountControl 514 (or 66050 etc.) means disabled — re-enable it (512 = enabled) or use another account
  2. If UserEnabledAttribute is customized, make sure it is an integer-valued attribute and the bitmask matches its bit layout
  3. 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

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


AI-assisted analysis of rancher/rancher@932558d4e6 (2026-08-16). Data as JSON: /api/errors/9c26ea1139909286. Report an issue: GitHub.