s3: keep dynamic IAM live when -iam.config is set (#9817)

* s3: keep dynamic IAM live when -iam.config is set

-iam.config was treated like a static -config identity file: it set
useStaticConfig, which makes the filer metadata subscription skip
reloads. Identities and policies created at runtime (the IAM gRPC API)
then never took effect, so advanced IAM (OIDC/STS) and dynamic IAM were
mutually exclusive.

Gate useStaticConfig on whether inline identities were actually loaded.
An OIDC/STS-only config carries none, so it keeps the dynamic credential
store live; a -config identity file still freezes its identities as
before.

* s3: mark static identities on config reload too

A -config reload (grace.OnReload) re-reads the file, but only the startup
path marked its identities static, so identities added to the file and
reloaded were left unprotected from dynamic filer updates. Move the
marking into loadS3ApiConfigurationFromFile and make it additive and
scoped to the file's identities, so a reload protects newly added ones
without freezing dynamic filer-managed identities.

* s3: sync reloaded static identities into the credential manager

After marking a (re)loaded config file's identities static, push the
updated set into the credential manager so reloaded identities still
appear in listings and survive later dynamic merges. Centralize the sync
in loadS3ApiConfigurationFromFile and drop the now-redundant call in the
reload hook.
This commit is contained in:
Chris Lu authored and GitHub committed 2026-06-03 23:28:25 -07:00
1 parent ce6a51468a
commit 3e8ec879c4
3 files changed
+170 -17

No files matched your search

+45 -16
View File
@@ -267,17 +267,6 @@ func NewIdentityAccessManagementWithStore(option *S3ApiServerOption, filerClient
if err := iam.loadS3ApiConfigurationFromFile(startConfigFile); err != nil {
glog.Fatalf("fail to load config file %s: %v", startConfigFile, err)
}
// Track identity names from static config to protect them from dynamic updates
// Must be done under lock to avoid race conditions
iam.m.Lock()
iam.useStaticConfig = true
iam.staticIdentityNames = make(map[string]bool)
for _, identity := range iam.identities {
iam.staticIdentityNames[identity.Name] = true
identity.IsStatic = true
}
iam.m.Unlock()
}
// Always try to load/merge config from credential manager (filer/db)
@@ -332,6 +321,30 @@ func NewIdentityAccessManagementWithStore(option *S3ApiServerOption, filerClient
return iam
}
// markStaticIdentities marks the identities declared in a static config file
// (-config, or -iam.config when it carries inline identities) as immutable, so
// dynamic filer reloads can't overwrite them. It is additive and scoped to the
// file's identities: a reload protects newly added ones without un-protecting
// the existing set or freezing dynamic filer-managed identities. useStaticConfig
// stays gated on whether any static identity exists, so an advanced-IAM file
// with no inline identities (OIDC/STS only) keeps the dynamic store live.
func (iam *IdentityAccessManagement) markStaticIdentities(config *iam_pb.S3ApiConfiguration) {
iam.m.Lock()
defer iam.m.Unlock()
if iam.staticIdentityNames == nil {
iam.staticIdentityNames = make(map[string]bool)
}
for _, ident := range config.Identities {
iam.staticIdentityNames[ident.Name] = true
}
for _, identity := range iam.identities {
if iam.staticIdentityNames[identity.Name] {
identity.IsStatic = true
}
}
iam.useStaticConfig = len(iam.staticIdentityNames) > 0
}
func (iam *IdentityAccessManagement) pollIamConfigChanges(interval time.Duration) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
@@ -477,24 +490,40 @@ func (iam *IdentityAccessManagement) loadS3ApiConfigurationFromFile(fileName str
glog.Warningf("KMS initialization failed: %v", err)
}
return iam.LoadS3ApiConfigurationFromBytes(content)
config, err := iam.loadS3ApiConfigurationFromBytes(content)
if err != nil {
return err
}
// Identities listed in a config file are static (immutable). Mark them on
// every load so a reload protects newly added identities too, not just the
// set present at startup, and push the updated set into the credential
// manager so reloaded identities still show up in listings and survive
// later dynamic merges.
iam.markStaticIdentities(config)
iam.updateCredentialManagerStaticIdentities()
return nil
}
func (iam *IdentityAccessManagement) LoadS3ApiConfigurationFromBytes(content []byte) error {
_, err := iam.loadS3ApiConfigurationFromBytes(content)
return err
}
func (iam *IdentityAccessManagement) loadS3ApiConfigurationFromBytes(content []byte) (*iam_pb.S3ApiConfiguration, error) {
s3ApiConfiguration := &iam_pb.S3ApiConfiguration{}
if err := filer.ParseS3ConfigurationFromBytes(content, s3ApiConfiguration); err != nil {
glog.Warningf("unmarshal error: %v", err)
return fmt.Errorf("unmarshal error: %w", err)
return nil, fmt.Errorf("unmarshal error: %w", err)
}
if err := filer.CheckDuplicateAccessKey(s3ApiConfiguration); err != nil {
return err
return nil, err
}
if err := iam.loadS3ApiConfiguration(s3ApiConfiguration); err != nil {
return err
return nil, err
}
return nil
return s3ApiConfiguration, nil
}
func (iam *IdentityAccessManagement) loadS3ApiConfiguration(config *iam_pb.S3ApiConfiguration) error {