site healing: Skip stale iam asset updates from peer. (#15203)

Allow healing to apply IAM change only when peer
gave the most recent update.
This commit is contained in:
Poorna
2022-07-01 13:19:13 -07:00
committed by GitHub
parent 63ac260bd5
commit 0ea5c9d8e8
12 changed files with 489 additions and 349 deletions

View File

@@ -599,14 +599,14 @@ func (sys *IAMSys) ListPolicyDocs(ctx context.Context, bucketName string) (map[s
}
// SetPolicy - sets a new named policy.
func (sys *IAMSys) SetPolicy(ctx context.Context, policyName string, p iampolicy.Policy) error {
func (sys *IAMSys) SetPolicy(ctx context.Context, policyName string, p iampolicy.Policy) (time.Time, error) {
if !sys.Initialized() {
return errServerNotInitialized
return time.Time{}, errServerNotInitialized
}
err := sys.store.SetPolicy(ctx, policyName, p)
updatedAt, err := sys.store.SetPolicy(ctx, policyName, p)
if err != nil {
return err
return updatedAt, err
}
if !sys.HasWatcher() {
@@ -618,7 +618,7 @@ func (sys *IAMSys) SetPolicy(ctx context.Context, policyName string, p iampolicy
}
}
}
return nil
return updatedAt, nil
}
// DeleteUser - delete user (only for long-term users not STS users).
@@ -707,9 +707,9 @@ func (sys *IAMSys) notifyForUser(ctx context.Context, accessKey string, isTemp b
// elsewhere), the AssumeRole case (because the parent user is real and their
// policy is associated via policy-set API) and the AssumeRoleWithLDAP case
// (because the policy association is made via policy-set API).
func (sys *IAMSys) SetTempUser(ctx context.Context, accessKey string, cred auth.Credentials, policyName string) error {
func (sys *IAMSys) SetTempUser(ctx context.Context, accessKey string, cred auth.Credentials, policyName string) (time.Time, error) {
if !sys.Initialized() {
return errServerNotInitialized
return time.Time{}, errServerNotInitialized
}
if newGlobalAuthZPluginFn() != nil {
@@ -717,14 +717,14 @@ func (sys *IAMSys) SetTempUser(ctx context.Context, accessKey string, cred auth.
policyName = ""
}
err := sys.store.SetTempUser(ctx, accessKey, cred, policyName)
updatedAt, err := sys.store.SetTempUser(ctx, accessKey, cred, policyName)
if err != nil {
return err
return time.Time{}, err
}
sys.notifyForUser(ctx, cred.AccessKey, true)
return nil
return updatedAt, nil
}
// ListBucketUsers - list all users who can access this 'bucket'
@@ -782,11 +782,11 @@ func (sys *IAMSys) IsTempUser(name string) (bool, string, error) {
return false, "", errServerNotInitialized
}
cred, found := sys.store.GetUser(name)
u, found := sys.store.GetUser(name)
if !found {
return false, "", errNoSuchUser
}
cred := u.Credentials
if cred.IsTemp() {
return true, cred.ParentUser, nil
}
@@ -800,11 +800,11 @@ func (sys *IAMSys) IsServiceAccount(name string) (bool, string, error) {
return false, "", errServerNotInitialized
}
cred, found := sys.store.GetUser(name)
u, found := sys.store.GetUser(name)
if !found {
return false, "", errNoSuchUser
}
cred := u.Credentials
if cred.IsServiceAccount() {
return true, cred.ParentUser, nil
}
@@ -828,22 +828,22 @@ func (sys *IAMSys) GetUserInfo(ctx context.Context, name string) (u madmin.UserI
}
// SetUserStatus - sets current user status, supports disabled or enabled.
func (sys *IAMSys) SetUserStatus(ctx context.Context, accessKey string, status madmin.AccountStatus) error {
func (sys *IAMSys) SetUserStatus(ctx context.Context, accessKey string, status madmin.AccountStatus) (updatedAt time.Time, err error) {
if !sys.Initialized() {
return errServerNotInitialized
return updatedAt, errServerNotInitialized
}
if sys.usersSysType != MinIOUsersSysType {
return errIAMActionNotAllowed
return updatedAt, errIAMActionNotAllowed
}
err := sys.store.SetUserStatus(ctx, accessKey, status)
updatedAt, err = sys.store.SetUserStatus(ctx, accessKey, status)
if err != nil {
return err
return
}
sys.notifyForUser(ctx, accessKey, false)
return nil
return updatedAt, nil
}
func (sys *IAMSys) notifyForServiceAccount(ctx context.Context, accessKey string) {
@@ -867,34 +867,34 @@ type newServiceAccountOpts struct {
}
// NewServiceAccount - create a new service account
func (sys *IAMSys) NewServiceAccount(ctx context.Context, parentUser string, groups []string, opts newServiceAccountOpts) (auth.Credentials, error) {
func (sys *IAMSys) NewServiceAccount(ctx context.Context, parentUser string, groups []string, opts newServiceAccountOpts) (auth.Credentials, time.Time, error) {
if !sys.Initialized() {
return auth.Credentials{}, errServerNotInitialized
return auth.Credentials{}, time.Time{}, errServerNotInitialized
}
if parentUser == "" {
return auth.Credentials{}, errInvalidArgument
return auth.Credentials{}, time.Time{}, errInvalidArgument
}
var policyBuf []byte
if opts.sessionPolicy != nil {
err := opts.sessionPolicy.Validate()
if err != nil {
return auth.Credentials{}, err
return auth.Credentials{}, time.Time{}, err
}
policyBuf, err = json.Marshal(opts.sessionPolicy)
if err != nil {
return auth.Credentials{}, err
return auth.Credentials{}, time.Time{}, err
}
if len(policyBuf) > 16*humanize.KiByte {
return auth.Credentials{}, fmt.Errorf("Session policy should not exceed 16 KiB characters")
return auth.Credentials{}, time.Time{}, fmt.Errorf("Session policy should not exceed 16 KiB characters")
}
}
// found newly requested service account, to be same as
// parentUser, reject such operations.
if parentUser == opts.accessKey {
return auth.Credentials{}, errIAMActionNotAllowed
return auth.Credentials{}, time.Time{}, errIAMActionNotAllowed
}
m := make(map[string]interface{})
@@ -922,24 +922,24 @@ func (sys *IAMSys) NewServiceAccount(ctx context.Context, parentUser string, gro
} else {
accessKey, secretKey, err = auth.GenerateCredentials()
if err != nil {
return auth.Credentials{}, err
return auth.Credentials{}, time.Time{}, err
}
}
cred, err := auth.CreateNewCredentialsWithMetadata(accessKey, secretKey, m, secretKey)
if err != nil {
return auth.Credentials{}, err
return auth.Credentials{}, time.Time{}, err
}
cred.ParentUser = parentUser
cred.Groups = groups
cred.Status = string(auth.AccountOn)
err = sys.store.AddServiceAccount(ctx, cred)
updatedAt, err := sys.store.AddServiceAccount(ctx, cred)
if err != nil {
return auth.Credentials{}, err
return auth.Credentials{}, time.Time{}, err
}
sys.notifyForServiceAccount(ctx, cred.AccessKey)
return cred, nil
return cred, updatedAt, nil
}
type updateServiceAccountOpts struct {
@@ -949,18 +949,18 @@ type updateServiceAccountOpts struct {
}
// UpdateServiceAccount - edit a service account
func (sys *IAMSys) UpdateServiceAccount(ctx context.Context, accessKey string, opts updateServiceAccountOpts) error {
func (sys *IAMSys) UpdateServiceAccount(ctx context.Context, accessKey string, opts updateServiceAccountOpts) (updatedAt time.Time, err error) {
if !sys.Initialized() {
return errServerNotInitialized
return updatedAt, errServerNotInitialized
}
err := sys.store.UpdateServiceAccount(ctx, accessKey, opts)
updatedAt, err = sys.store.UpdateServiceAccount(ctx, accessKey, opts)
if err != nil {
return err
return updatedAt, err
}
sys.notifyForServiceAccount(ctx, accessKey)
return nil
return updatedAt, nil
}
// ListServiceAccounts - lists all services accounts associated to a specific user
@@ -978,7 +978,7 @@ func (sys *IAMSys) ListServiceAccounts(ctx context.Context, accessKey string) ([
}
// ListTempAccounts - lists all services accounts associated to a specific user
func (sys *IAMSys) ListTempAccounts(ctx context.Context, accessKey string) ([]auth.Credentials, error) {
func (sys *IAMSys) ListTempAccounts(ctx context.Context, accessKey string) ([]UserIdentity, error) {
if !sys.Initialized() {
return nil, errServerNotInitialized
}
@@ -995,32 +995,32 @@ func (sys *IAMSys) ListTempAccounts(ctx context.Context, accessKey string) ([]au
func (sys *IAMSys) GetServiceAccount(ctx context.Context, accessKey string) (auth.Credentials, *iampolicy.Policy, error) {
sa, embeddedPolicy, err := sys.getServiceAccount(ctx, accessKey)
if err != nil {
return sa, embeddedPolicy, err
return auth.Credentials{}, embeddedPolicy, err
}
// Hide secret & session keys
sa.SecretKey = ""
sa.SessionToken = ""
return sa, embeddedPolicy, nil
sa.Credentials.SecretKey = ""
sa.Credentials.SessionToken = ""
return sa.Credentials, embeddedPolicy, nil
}
// getServiceAccount - gets information about a service account
func (sys *IAMSys) getServiceAccount(ctx context.Context, accessKey string) (auth.Credentials, *iampolicy.Policy, error) {
func (sys *IAMSys) getServiceAccount(ctx context.Context, accessKey string) (u UserIdentity, p *iampolicy.Policy, err error) {
if !sys.Initialized() {
return auth.Credentials{}, nil, errServerNotInitialized
return u, nil, errServerNotInitialized
}
sa, ok := sys.store.GetUser(accessKey)
if !ok || !sa.IsServiceAccount() {
return auth.Credentials{}, nil, errNoSuchServiceAccount
if !ok || !sa.Credentials.IsServiceAccount() {
return u, nil, errNoSuchServiceAccount
}
var embeddedPolicy *iampolicy.Policy
jwtClaims, err := auth.ExtractClaims(sa.SessionToken, sa.SecretKey)
jwtClaims, err := auth.ExtractClaims(sa.Credentials.SessionToken, sa.Credentials.SecretKey)
if err != nil {
jwtClaims, err = auth.ExtractClaims(sa.SessionToken, globalActiveCred.SecretKey)
jwtClaims, err = auth.ExtractClaims(sa.Credentials.SessionToken, globalActiveCred.SecretKey)
if err != nil {
return auth.Credentials{}, nil, err
return u, nil, err
}
}
pt, ptok := jwtClaims.Lookup(iamPolicyClaimNameSA())
@@ -1028,11 +1028,11 @@ func (sys *IAMSys) getServiceAccount(ctx context.Context, accessKey string) (aut
if ptok && spok && pt == embeddedPolicyType {
policyBytes, err := base64.StdEncoding.DecodeString(sp)
if err != nil {
return auth.Credentials{}, nil, err
return u, nil, err
}
embeddedPolicy, err = iampolicy.ParseConfig(bytes.NewReader(policyBytes))
if err != nil {
return auth.Credentials{}, nil, err
return u, nil, err
}
}
@@ -1050,13 +1050,13 @@ func (sys *IAMSys) GetClaimsForSvcAcc(ctx context.Context, accessKey string) (ma
}
sa, ok := sys.store.GetUser(accessKey)
if !ok || !sa.IsServiceAccount() {
if !ok || !sa.Credentials.IsServiceAccount() {
return nil, errNoSuchServiceAccount
}
jwtClaims, err := auth.ExtractClaims(sa.SessionToken, sa.SecretKey)
jwtClaims, err := auth.ExtractClaims(sa.Credentials.SessionToken, sa.Credentials.SecretKey)
if err != nil {
jwtClaims, err = auth.ExtractClaims(sa.SessionToken, globalActiveCred.SecretKey)
jwtClaims, err = auth.ExtractClaims(sa.Credentials.SessionToken, globalActiveCred.SecretKey)
if err != nil {
return nil, err
}
@@ -1071,7 +1071,7 @@ func (sys *IAMSys) DeleteServiceAccount(ctx context.Context, accessKey string, n
}
sa, ok := sys.store.GetUser(accessKey)
if !ok || !sa.IsServiceAccount() {
if !ok || !sa.Credentials.IsServiceAccount() {
return nil
}
@@ -1093,30 +1093,30 @@ func (sys *IAMSys) DeleteServiceAccount(ctx context.Context, accessKey string, n
// CreateUser - create new user credentials and policy, if user already exists
// they shall be rewritten with new inputs.
func (sys *IAMSys) CreateUser(ctx context.Context, accessKey string, ureq madmin.AddOrUpdateUserReq) error {
func (sys *IAMSys) CreateUser(ctx context.Context, accessKey string, ureq madmin.AddOrUpdateUserReq) (updatedAt time.Time, err error) {
if !sys.Initialized() {
return errServerNotInitialized
return updatedAt, errServerNotInitialized
}
if sys.usersSysType != MinIOUsersSysType {
return errIAMActionNotAllowed
return updatedAt, errIAMActionNotAllowed
}
if !auth.IsAccessKeyValid(accessKey) {
return auth.ErrInvalidAccessKeyLength
return updatedAt, auth.ErrInvalidAccessKeyLength
}
if !auth.IsSecretKeyValid(ureq.SecretKey) {
return auth.ErrInvalidSecretKeyLength
return updatedAt, auth.ErrInvalidSecretKeyLength
}
err := sys.store.AddUser(ctx, accessKey, ureq)
updatedAt, err = sys.store.AddUser(ctx, accessKey, ureq)
if err != nil {
return err
return updatedAt, err
}
sys.notifyForUser(ctx, accessKey, false)
return nil
return updatedAt, nil
}
// SetUserSecretKey - sets user secret key
@@ -1291,9 +1291,9 @@ func (sys *IAMSys) updateGroupMembershipsForLDAP(ctx context.Context) {
}
// GetUser - get user credentials
func (sys *IAMSys) GetUser(ctx context.Context, accessKey string) (cred auth.Credentials, ok bool) {
func (sys *IAMSys) GetUser(ctx context.Context, accessKey string) (u UserIdentity, ok bool) {
if !sys.Initialized() {
return cred, false
return u, false
}
fallback := false
@@ -1304,7 +1304,7 @@ func (sys *IAMSys) GetUser(ctx context.Context, accessKey string) (cred auth.Cre
fallback = true
}
cred, ok = sys.store.GetUser(accessKey)
u, ok = sys.store.GetUser(accessKey)
if !ok && !fallback {
// accessKey not found, also
// IAM store is not in fallback mode
@@ -1313,10 +1313,10 @@ func (sys *IAMSys) GetUser(ctx context.Context, accessKey string) (cred auth.Cre
// exists now. If it doesn't proceed to
// fail.
sys.store.LoadUser(ctx, accessKey)
cred, ok = sys.store.GetUser(accessKey)
u, ok = sys.store.GetUser(accessKey)
}
return cred, ok && cred.IsValid()
return u, ok && u.Credentials.IsValid()
}
// Notify all other MinIO peers to load group.
@@ -1333,61 +1333,61 @@ func (sys *IAMSys) notifyForGroup(ctx context.Context, group string) {
// AddUsersToGroup - adds users to a group, creating the group if
// needed. No error if user(s) already are in the group.
func (sys *IAMSys) AddUsersToGroup(ctx context.Context, group string, members []string) error {
func (sys *IAMSys) AddUsersToGroup(ctx context.Context, group string, members []string) (updatedAt time.Time, err error) {
if !sys.Initialized() {
return errServerNotInitialized
return updatedAt, errServerNotInitialized
}
if sys.usersSysType != MinIOUsersSysType {
return errIAMActionNotAllowed
return updatedAt, errIAMActionNotAllowed
}
err := sys.store.AddUsersToGroup(ctx, group, members)
updatedAt, err = sys.store.AddUsersToGroup(ctx, group, members)
if err != nil {
return err
return updatedAt, err
}
sys.notifyForGroup(ctx, group)
return nil
return updatedAt, nil
}
// RemoveUsersFromGroup - remove users from group. If no users are
// given, and the group is empty, deletes the group as well.
func (sys *IAMSys) RemoveUsersFromGroup(ctx context.Context, group string, members []string) error {
func (sys *IAMSys) RemoveUsersFromGroup(ctx context.Context, group string, members []string) (updatedAt time.Time, err error) {
if !sys.Initialized() {
return errServerNotInitialized
return updatedAt, errServerNotInitialized
}
if sys.usersSysType != MinIOUsersSysType {
return errIAMActionNotAllowed
return updatedAt, errIAMActionNotAllowed
}
err := sys.store.RemoveUsersFromGroup(ctx, group, members)
updatedAt, err = sys.store.RemoveUsersFromGroup(ctx, group, members)
if err != nil {
return err
return updatedAt, err
}
sys.notifyForGroup(ctx, group)
return nil
return updatedAt, nil
}
// SetGroupStatus - enable/disabled a group
func (sys *IAMSys) SetGroupStatus(ctx context.Context, group string, enabled bool) error {
func (sys *IAMSys) SetGroupStatus(ctx context.Context, group string, enabled bool) (updatedAt time.Time, err error) {
if !sys.Initialized() {
return errServerNotInitialized
return updatedAt, errServerNotInitialized
}
if sys.usersSysType != MinIOUsersSysType {
return errIAMActionNotAllowed
return updatedAt, errIAMActionNotAllowed
}
err := sys.store.SetGroupStatus(ctx, group, enabled)
updatedAt, err = sys.store.SetGroupStatus(ctx, group, enabled)
if err != nil {
return err
return updatedAt, err
}
sys.notifyForGroup(ctx, group)
return nil
return updatedAt, nil
}
// GetGroupDescription - builds up group description
@@ -1414,9 +1414,9 @@ func (sys *IAMSys) ListGroups(ctx context.Context) (r []string, err error) {
}
// PolicyDBSet - sets a policy for a user or group in the PolicyDB.
func (sys *IAMSys) PolicyDBSet(ctx context.Context, name, policy string, isGroup bool) error {
func (sys *IAMSys) PolicyDBSet(ctx context.Context, name, policy string, isGroup bool) (updatedAt time.Time, err error) {
if !sys.Initialized() {
return errServerNotInitialized
return updatedAt, errServerNotInitialized
}
// Determine user-type based on IDP mode.
@@ -1425,9 +1425,9 @@ func (sys *IAMSys) PolicyDBSet(ctx context.Context, name, policy string, isGroup
userType = stsUser
}
err := sys.store.PolicyDBSet(ctx, name, policy, userType, isGroup)
updatedAt, err = sys.store.PolicyDBSet(ctx, name, policy, userType, isGroup)
if err != nil {
return err
return
}
// Notify all other MinIO peers to reload policy
@@ -1440,7 +1440,7 @@ func (sys *IAMSys) PolicyDBSet(ctx context.Context, name, policy string, isGroup
}
}
return nil
return updatedAt, nil
}
// PolicyDBGet - gets policy set on a user or group. If a list of groups is