mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
remove IAM old migration code (#15476)
```
commit 7bdaf9bc50
Author: Aditya Manthramurthy <donatello@users.noreply.github.com>
Date: Wed Jul 24 17:34:23 2019 -0700
Update on-disk storage format for users system (#7949)
```
Bonus: fixes a bug when etcd keys were being re-encrypted.
This commit is contained in:
parent
fcd4b3ba9b
commit
e0b0a351c6
@ -69,6 +69,12 @@ func migrateIAMConfigsEtcdToEncrypted(ctx context.Context, client *etcd.Client)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If backend doesn't have this file means we have already
|
||||||
|
// attempted then migration
|
||||||
|
if !encrypted {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if encrypted && GlobalKMS != nil {
|
if encrypted && GlobalKMS != nil {
|
||||||
stat, err := GlobalKMS.Stat(ctx)
|
stat, err := GlobalKMS.Stat(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -109,6 +115,8 @@ func migrateIAMConfigsEtcdToEncrypted(ctx context.Context, client *etcd.Client)
|
|||||||
return fmt.Errorf("Decrypting IAM config failed %w, possibly credentials are incorrect", err)
|
return fmt.Errorf("Decrypting IAM config failed %w, possibly credentials are incorrect", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("Decrypting IAM config failed %w, possibly credentials are incorrect", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data = pdata
|
data = pdata
|
||||||
@ -131,6 +139,7 @@ func migrateIAMConfigsEtcdToEncrypted(ctx context.Context, client *etcd.Client)
|
|||||||
if encrypted && GlobalKMS != nil {
|
if encrypted && GlobalKMS != nil {
|
||||||
logger.Info("Migration of encrypted IAM config data completed. All data is now encrypted on etcd.")
|
logger.Info("Migration of encrypted IAM config data completed. All data is now encrypted on etcd.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return deleteKeyEtcd(ctx, client, backendEncryptedFile)
|
return deleteKeyEtcd(ctx, client, backendEncryptedFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,44 +155,56 @@ func migrateConfigPrefixToEncrypted(objAPI ObjectLayer, encrypted bool) error {
|
|||||||
logger.Info(fmt.Sprintf("Attempting to re-encrypt config, IAM users and policies on MinIO with %q (%s)", stat.DefaultKey, stat.Name))
|
logger.Info(fmt.Sprintf("Attempting to re-encrypt config, IAM users and policies on MinIO with %q (%s)", stat.DefaultKey, stat.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
var marker string
|
results := make(chan ObjectInfo)
|
||||||
for {
|
if err := objAPI.Walk(GlobalContext, minioMetaBucket, minioConfigPrefix, results, ObjectOptions{}); err != nil {
|
||||||
res, err := objAPI.ListObjects(GlobalContext, minioMetaBucket, minioConfigPrefix, marker, "", maxObjectList)
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for obj := range results {
|
||||||
|
data, err := readConfig(GlobalContext, objAPI, obj.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, obj := range res.Objects {
|
|
||||||
data, err := readConfig(GlobalContext, objAPI, obj.Name)
|
if !utf8.Valid(data) {
|
||||||
|
pdata, err := madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(data))
|
||||||
|
if err != nil {
|
||||||
|
if GlobalKMS != nil {
|
||||||
|
pdata, err = config.DecryptBytes(GlobalKMS, data, kms.Context{
|
||||||
|
minioMetaBucket: path.Join(minioMetaBucket, obj.Name),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
pdata, err = config.DecryptBytes(GlobalKMS, data, kms.Context{
|
||||||
|
minioMetaBucket: obj.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Decrypting IAM config failed %w, possibly credentials are incorrect", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("Decrypting IAM config failed %w, possibly credentials are incorrect", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data = pdata
|
||||||
|
}
|
||||||
|
|
||||||
|
if GlobalKMS != nil {
|
||||||
|
data, err = config.EncryptBytes(GlobalKMS, data, kms.Context{
|
||||||
|
obj.Bucket: path.Join(obj.Bucket, obj.Name),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !utf8.Valid(data) {
|
|
||||||
data, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(data))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Decrypting config failed %w, possibly credentials are incorrect", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if GlobalKMS != nil {
|
|
||||||
data, err = config.EncryptBytes(GlobalKMS, data, kms.Context{
|
|
||||||
obj.Bucket: path.Join(obj.Bucket, obj.Name),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err = saveConfig(GlobalContext, objAPI, obj.Name, data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !res.IsTruncated {
|
if err = saveConfig(GlobalContext, objAPI, obj.Name, data); err != nil {
|
||||||
break
|
return err
|
||||||
}
|
}
|
||||||
marker = res.NextMarker
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if encrypted && GlobalKMS != nil {
|
if encrypted && GlobalKMS != nil {
|
||||||
logger.Info("Migration of encrypted config data completed. All config data is now encrypted.")
|
logger.Info("Migration of encrypted config data completed. All config data is now encrypted.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return deleteConfig(GlobalContext, objAPI, backendEncryptedFile)
|
return deleteConfig(GlobalContext, objAPI, backendEncryptedFile)
|
||||||
}
|
}
|
||||||
|
@ -57,10 +57,6 @@ func (ids *iamDummyStore) getUsersSysType() UsersSysType {
|
|||||||
return ids.usersSysType
|
return ids.usersSysType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ids *iamDummyStore) migrateBackendFormat(context.Context) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ids *iamDummyStore) loadPolicyDoc(ctx context.Context, policy string, m map[string]PolicyDoc) error {
|
func (ids *iamDummyStore) loadPolicyDoc(ctx context.Context, policy string, m map[string]PolicyDoc) error {
|
||||||
v, ok := ids.iamPolicyDocsMap[policy]
|
v, ok := ids.iamPolicyDocsMap[policy]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -28,7 +28,6 @@ import (
|
|||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/minio/minio-go/v7/pkg/set"
|
"github.com/minio/minio-go/v7/pkg/set"
|
||||||
"github.com/minio/minio/internal/auth"
|
|
||||||
"github.com/minio/minio/internal/config"
|
"github.com/minio/minio/internal/config"
|
||||||
"github.com/minio/minio/internal/kms"
|
"github.com/minio/minio/internal/kms"
|
||||||
"github.com/minio/minio/internal/logger"
|
"github.com/minio/minio/internal/logger"
|
||||||
@ -163,121 +162,6 @@ func (ies *IAMEtcdStore) deleteIAMConfig(ctx context.Context, path string) error
|
|||||||
return deleteKeyEtcd(ctx, ies.client, path)
|
return deleteKeyEtcd(ctx, ies.client, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ies *IAMEtcdStore) migrateUsersConfigToV1(ctx context.Context) error {
|
|
||||||
basePrefix := iamConfigUsersPrefix
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, defaultContextTimeout)
|
|
||||||
defer cancel()
|
|
||||||
r, err := ies.client.Get(ctx, basePrefix, etcd.WithPrefix(), etcd.WithKeysOnly())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
users := etcdKvsToSet(basePrefix, r.Kvs)
|
|
||||||
for _, user := range users.ToSlice() {
|
|
||||||
{
|
|
||||||
// 1. check if there is a policy file in the old loc.
|
|
||||||
oldPolicyPath := pathJoin(basePrefix, user, iamPolicyFile)
|
|
||||||
var policyName string
|
|
||||||
err := ies.loadIAMConfig(ctx, &policyName, oldPolicyPath)
|
|
||||||
if err != nil {
|
|
||||||
switch err {
|
|
||||||
case errConfigNotFound:
|
|
||||||
// No mapped policy or already migrated.
|
|
||||||
default:
|
|
||||||
// corrupt data/read error, etc
|
|
||||||
}
|
|
||||||
goto next
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. copy policy to new loc.
|
|
||||||
mp := newMappedPolicy(policyName)
|
|
||||||
userType := regUser
|
|
||||||
path := getMappedPolicyPath(user, userType, false)
|
|
||||||
if err := ies.saveIAMConfig(ctx, mp, path); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. delete policy file in old loc.
|
|
||||||
deleteKeyEtcd(ctx, ies.client, oldPolicyPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
next:
|
|
||||||
// 4. check if user identity has old format.
|
|
||||||
identityPath := pathJoin(basePrefix, user, iamIdentityFile)
|
|
||||||
var cred auth.Credentials
|
|
||||||
if err := ies.loadIAMConfig(ctx, &cred, identityPath); err != nil {
|
|
||||||
switch err {
|
|
||||||
case errConfigNotFound:
|
|
||||||
// This case should not happen.
|
|
||||||
default:
|
|
||||||
// corrupt file or read error
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the file is already in the new format,
|
|
||||||
// then the parsed auth.Credentials will have
|
|
||||||
// the zero value for the struct.
|
|
||||||
var zeroCred auth.Credentials
|
|
||||||
if cred.Equal(zeroCred) {
|
|
||||||
// nothing to do
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Found a id file in old format. Copy value
|
|
||||||
// into new format and save it.
|
|
||||||
cred.AccessKey = user
|
|
||||||
u := newUserIdentity(cred)
|
|
||||||
if err := ies.saveIAMConfig(ctx, u, identityPath); err != nil {
|
|
||||||
logger.LogIf(ctx, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nothing to delete as identity file location
|
|
||||||
// has not changed.
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ies *IAMEtcdStore) migrateToV1(ctx context.Context) error {
|
|
||||||
var iamFmt iamFormat
|
|
||||||
path := getIAMFormatFilePath()
|
|
||||||
if err := ies.loadIAMConfig(ctx, &iamFmt, path); err != nil {
|
|
||||||
switch err {
|
|
||||||
case errConfigNotFound:
|
|
||||||
// Need to migrate to V1.
|
|
||||||
default:
|
|
||||||
// if IAM format
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if iamFmt.Version >= iamFormatVersion1 {
|
|
||||||
// Nothing to do.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ies.migrateUsersConfigToV1(ctx); err != nil {
|
|
||||||
logger.LogIf(ctx, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save iam format to version 1.
|
|
||||||
if err := ies.saveIAMConfig(ctx, newIAMFormatVersion1(), path); err != nil {
|
|
||||||
logger.LogIf(ctx, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should be called under config migration lock
|
|
||||||
func (ies *IAMEtcdStore) migrateBackendFormat(ctx context.Context) error {
|
|
||||||
ies.Lock()
|
|
||||||
defer ies.Unlock()
|
|
||||||
return ies.migrateToV1(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ies *IAMEtcdStore) loadPolicyDoc(ctx context.Context, policy string, m map[string]PolicyDoc) error {
|
func (ies *IAMEtcdStore) loadPolicyDoc(ctx context.Context, policy string, m map[string]PolicyDoc) error {
|
||||||
data, err := ies.loadIAMConfigBytes(ctx, getPolicyDocPath(policy))
|
data, err := ies.loadIAMConfigBytes(ctx, getPolicyDocPath(policy))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -26,7 +26,6 @@ import (
|
|||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/minio/minio/internal/auth"
|
|
||||||
"github.com/minio/minio/internal/config"
|
"github.com/minio/minio/internal/config"
|
||||||
"github.com/minio/minio/internal/kms"
|
"github.com/minio/minio/internal/kms"
|
||||||
"github.com/minio/minio/internal/logger"
|
"github.com/minio/minio/internal/logger"
|
||||||
@ -74,135 +73,6 @@ func (iamOS *IAMObjectStore) getUsersSysType() UsersSysType {
|
|||||||
return iamOS.usersSysType
|
return iamOS.usersSysType
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate users directory in a single scan.
|
|
||||||
//
|
|
||||||
// 1. Migrate user policy from:
|
|
||||||
//
|
|
||||||
// `iamConfigUsersPrefix + "<username>/policy.json"`
|
|
||||||
//
|
|
||||||
// to:
|
|
||||||
//
|
|
||||||
// `iamConfigPolicyDBUsersPrefix + "<username>.json"`.
|
|
||||||
//
|
|
||||||
// 2. Add versioning to the policy json file in the new
|
|
||||||
// location.
|
|
||||||
//
|
|
||||||
// 3. Migrate user identity json file to include version info.
|
|
||||||
func (iamOS *IAMObjectStore) migrateUsersConfigToV1(ctx context.Context) error {
|
|
||||||
basePrefix := iamConfigUsersPrefix
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
|
||||||
defer cancel()
|
|
||||||
for item := range listIAMConfigItems(ctx, iamOS.objAPI, basePrefix) {
|
|
||||||
if item.Err != nil {
|
|
||||||
return item.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
user := path.Dir(item.Item)
|
|
||||||
{
|
|
||||||
// 1. check if there is policy file in old location.
|
|
||||||
oldPolicyPath := pathJoin(basePrefix, user, iamPolicyFile)
|
|
||||||
var policyName string
|
|
||||||
if err := iamOS.loadIAMConfig(ctx, &policyName, oldPolicyPath); err != nil {
|
|
||||||
switch err {
|
|
||||||
case errConfigNotFound:
|
|
||||||
// This case means it is already
|
|
||||||
// migrated or there is no policy on
|
|
||||||
// user.
|
|
||||||
default:
|
|
||||||
// File may be corrupt or network error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nothing to do on the policy file,
|
|
||||||
// so move on to check the id file.
|
|
||||||
goto next
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. copy policy file to new location.
|
|
||||||
mp := newMappedPolicy(policyName)
|
|
||||||
userType := regUser
|
|
||||||
if err := iamOS.saveMappedPolicy(ctx, user, userType, false, mp); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. delete policy file from old
|
|
||||||
// location. Ignore error.
|
|
||||||
iamOS.deleteIAMConfig(ctx, oldPolicyPath)
|
|
||||||
}
|
|
||||||
next:
|
|
||||||
// 4. check if user identity has old format.
|
|
||||||
identityPath := pathJoin(basePrefix, user, iamIdentityFile)
|
|
||||||
cred := auth.Credentials{
|
|
||||||
AccessKey: user,
|
|
||||||
}
|
|
||||||
if err := iamOS.loadIAMConfig(ctx, &cred, identityPath); err != nil {
|
|
||||||
switch err {
|
|
||||||
case errConfigNotFound:
|
|
||||||
// This should not happen.
|
|
||||||
default:
|
|
||||||
// File may be corrupt or network error
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the file is already in the new format,
|
|
||||||
// then the parsed auth.Credentials will have
|
|
||||||
// the zero value for the struct.
|
|
||||||
if !cred.IsValid() {
|
|
||||||
// nothing to do
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
u := newUserIdentity(cred)
|
|
||||||
if err := iamOS.saveIAMConfig(ctx, u, identityPath); err != nil {
|
|
||||||
logger.LogIf(ctx, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nothing to delete as identity file location
|
|
||||||
// has not changed.
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (iamOS *IAMObjectStore) migrateToV1(ctx context.Context) error {
|
|
||||||
var iamFmt iamFormat
|
|
||||||
path := getIAMFormatFilePath()
|
|
||||||
if err := iamOS.loadIAMConfig(ctx, &iamFmt, path); err != nil {
|
|
||||||
switch err {
|
|
||||||
case errConfigNotFound:
|
|
||||||
// Need to migrate to V1.
|
|
||||||
default:
|
|
||||||
// if IAM format
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if iamFmt.Version >= iamFormatVersion1 {
|
|
||||||
// Nothing to do.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := iamOS.migrateUsersConfigToV1(ctx); err != nil {
|
|
||||||
logger.LogIf(ctx, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save iam format to version 1.
|
|
||||||
if err := iamOS.saveIAMConfig(ctx, newIAMFormatVersion1(), path); err != nil {
|
|
||||||
logger.LogIf(ctx, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should be called under config migration lock
|
|
||||||
func (iamOS *IAMObjectStore) migrateBackendFormat(ctx context.Context) error {
|
|
||||||
iamOS.Lock()
|
|
||||||
defer iamOS.Unlock()
|
|
||||||
return iamOS.migrateToV1(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (iamOS *IAMObjectStore) saveIAMConfig(ctx context.Context, item interface{}, objPath string, opts ...options) error {
|
func (iamOS *IAMObjectStore) saveIAMConfig(ctx context.Context, item interface{}, objPath string, opts ...options) error {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
data, err := json.Marshal(item)
|
data, err := json.Marshal(item)
|
||||||
|
@ -102,6 +102,33 @@ func getUserIdentityPath(user string, userType IAMUserType) string {
|
|||||||
return pathJoin(basePath, user, iamIdentityFile)
|
return pathJoin(basePath, user, iamIdentityFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func saveIAMFormat(ctx context.Context, store IAMStorageAPI) error {
|
||||||
|
var iamFmt iamFormat
|
||||||
|
path := getIAMFormatFilePath()
|
||||||
|
if err := store.loadIAMConfig(ctx, &iamFmt, path); err != nil {
|
||||||
|
switch err {
|
||||||
|
case errConfigNotFound:
|
||||||
|
// Need to migrate to V1.
|
||||||
|
default:
|
||||||
|
// if IAM format
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if iamFmt.Version >= iamFormatVersion1 {
|
||||||
|
// Nothing to do.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save iam format to version 1.
|
||||||
|
if err := store.saveIAMConfig(ctx, newIAMFormatVersion1(), path); err != nil {
|
||||||
|
logger.LogIf(ctx, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func getGroupInfoPath(group string) string {
|
func getGroupInfoPath(group string) string {
|
||||||
return pathJoin(iamConfigGroupsPrefix, group, iamGroupMembersFile)
|
return pathJoin(iamConfigGroupsPrefix, group, iamGroupMembersFile)
|
||||||
}
|
}
|
||||||
@ -374,7 +401,6 @@ type IAMStorageAPI interface {
|
|||||||
unlock()
|
unlock()
|
||||||
rlock() *iamCache
|
rlock() *iamCache
|
||||||
runlock()
|
runlock()
|
||||||
migrateBackendFormat(context.Context) error
|
|
||||||
getUsersSysType() UsersSysType
|
getUsersSysType() UsersSysType
|
||||||
loadPolicyDoc(ctx context.Context, policy string, m map[string]PolicyDoc) error
|
loadPolicyDoc(ctx context.Context, policy string, m map[string]PolicyDoc) error
|
||||||
loadPolicyDocs(ctx context.Context, m map[string]PolicyDoc) error
|
loadPolicyDocs(ctx context.Context, m map[string]PolicyDoc) error
|
||||||
|
34
cmd/iam.go
34
cmd/iam.go
@ -161,11 +161,6 @@ func (sys *IAMSys) LoadServiceAccount(ctx context.Context, accessKey string) err
|
|||||||
return sys.store.UserNotificationHandler(ctx, accessKey, svcUser)
|
return sys.store.UserNotificationHandler(ctx, accessKey, svcUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform IAM configuration migration.
|
|
||||||
func (sys *IAMSys) doIAMConfigMigration(ctx context.Context) error {
|
|
||||||
return sys.store.migrateBackendFormat(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// initStore initializes IAM stores
|
// initStore initializes IAM stores
|
||||||
func (sys *IAMSys) initStore(objAPI ObjectLayer, etcdClient *etcd.Client) {
|
func (sys *IAMSys) initStore(objAPI ObjectLayer, etcdClient *etcd.Client) {
|
||||||
if sys.ldapConfig.Enabled {
|
if sys.ldapConfig.Enabled {
|
||||||
@ -238,31 +233,15 @@ func (sys *IAMSys) Init(ctx context.Context, objAPI ObjectLayer, etcdClient *etc
|
|||||||
// Indicate to our routine to exit cleanly upon return.
|
// Indicate to our routine to exit cleanly upon return.
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// allocate dynamic timeout once before the loop
|
|
||||||
iamLockTimeout := newDynamicTimeout(5*time.Second, 3*time.Second)
|
|
||||||
|
|
||||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
|
||||||
// Migrate storage format if needed.
|
// Migrate storage format if needed.
|
||||||
for {
|
for {
|
||||||
// Hold the lock for migration only.
|
|
||||||
txnLk := objAPI.NewNSLock(minioMetaBucket, minioConfigPrefix+"/iam.lock")
|
|
||||||
|
|
||||||
// let one of the server acquire the lock, if not let them timeout.
|
|
||||||
// which shall be retried again by this loop.
|
|
||||||
lkctx, err := txnLk.GetLock(retryCtx, iamLockTimeout)
|
|
||||||
if err != nil {
|
|
||||||
logger.Info("Waiting for all MinIO IAM sub-system to be initialized.. trying to acquire lock")
|
|
||||||
time.Sleep(time.Duration(r.Float64() * float64(5*time.Second)))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if etcdClient != nil {
|
if etcdClient != nil {
|
||||||
// **** WARNING ****
|
// **** WARNING ****
|
||||||
// Migrating to encrypted backend on etcd should happen before initialization of
|
// Migrating to encrypted backend on etcd should happen before initialization of
|
||||||
// IAM sub-system, make sure that we do not move the above codeblock elsewhere.
|
// IAM sub-system, make sure that we do not move the above codeblock elsewhere.
|
||||||
if err := migrateIAMConfigsEtcdToEncrypted(retryCtx, etcdClient); err != nil {
|
if err := migrateIAMConfigsEtcdToEncrypted(retryCtx, etcdClient); err != nil {
|
||||||
txnLk.Unlock(lkctx.Cancel)
|
|
||||||
if errors.Is(err, errEtcdUnreachable) {
|
if errors.Is(err, errEtcdUnreachable) {
|
||||||
logger.Info("Connection to etcd timed out. Retrying..")
|
logger.Info("Connection to etcd timed out. Retrying..")
|
||||||
continue
|
continue
|
||||||
@ -273,25 +252,16 @@ func (sys *IAMSys) Init(ctx context.Context, objAPI ObjectLayer, etcdClient *etc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// These messages only meant primarily for distributed setup, so only log during distributed setup.
|
|
||||||
if globalIsDistErasure {
|
|
||||||
logger.Info("Waiting for all MinIO IAM sub-system to be initialized.. lock acquired")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Migrate IAM configuration, if necessary.
|
// Migrate IAM configuration, if necessary.
|
||||||
if err := sys.doIAMConfigMigration(retryCtx); err != nil {
|
if err := saveIAMFormat(retryCtx, sys.store); err != nil {
|
||||||
txnLk.Unlock(lkctx.Cancel)
|
|
||||||
if configRetriableErrors(err) {
|
if configRetriableErrors(err) {
|
||||||
logger.Info("Waiting for all MinIO IAM sub-system to be initialized.. possible cause (%v)", err)
|
logger.Info("Waiting for all MinIO IAM sub-system to be initialized.. possible cause (%v)", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
logger.LogIf(ctx, fmt.Errorf("Unable to migrate IAM users and policies to new format: %w", err))
|
logger.LogIf(ctx, errors.New("IAM sub-system is partially initialized, unable to write the IAM format"))
|
||||||
logger.LogIf(ctx, errors.New("IAM sub-system is partially initialized, some users may not be available"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Successfully migrated, proceed to load the users.
|
|
||||||
txnLk.Unlock(lkctx.Cancel)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user