* test(s3api): cover IAM inline policy aws:SourceIp + group inline gap Unit tests under weed/s3api/ drive PutUserPolicy / PutGroupPolicy → reload → VerifyActionPermission with a synthetic 127.0.0.1 request and assert that the policy's IpAddress condition flips the outcome. The user-policy cases pass on master (hydrateRuntimePolicies already routes inline docs through the policy engine, so Condition blocks are honored end- to-end). The group-policy case fails: PutGroupPolicy still returns NotImplemented, so a group inline doc never lands in the engine. Integration counterparts live under test/s3/iam/ and exercise the same paths against a live SeaweedFS S3+IAM endpoint. * s3api: support group inline policies + Condition enforcement PutGroupPolicy/GetGroupPolicy/DeleteGroupPolicy/ListGroupPolicies used to return NotImplemented in embedded IAM mode, so anything attached to a group as an inline doc — including aws:SourceIp or any other Condition — was simply unreachable. Wire the four endpoints to the credential-store methods that were already in place (memory, postgres, filer_etc all implement GroupInlinePolicyStore). On every config reload, hydrateRuntimePolicies now also walks LoadGroupInlinePolicies, registers each doc in the IAM policy engine under __inline_group_policy__/<group>/<policy>, and appends that key to Group.PolicyNames so evaluateIAMPolicies picks it up through its existing group walk. PutGroupPolicy/DeleteGroupPolicy are added to the ReloadConfiguration trigger list in DoActions. Side fix: MemoryStore.LoadConfiguration now surfaces store.groups too. Without it iam.groups never repopulated on a memory-store reload, so group policy evaluation silently no-op'd whether the policy was inline or attached. The existing tests didn't notice because no test reloaded through cm after creating a group. The NotImplemented unit test is inverted to drive the new round-trip. * s3api: drop redundant refreshIAMConfiguration from Put/DeleteGroupPolicy DoActions already triggers ReloadConfiguration for both actions via the explicit reload list, so calling refreshIAMConfiguration inline runs the load twice per request. Per PR review. * s3api: scope group-policy resource names per test; tighten deny polling - Integration test resource names get a per-test suffix so retried or parallel CI jobs don't trip EntityAlreadyExists / BucketAlreadyExists. - Deny-path Eventually loops gate on AccessDenied via a typed helper rather than any non-nil error; transient setup errors no longer end the wait prematurely. - ListGroupPolicies returns ServiceFailure when the credential manager is nil, matching Put/Get/DeleteGroupPolicy. * test(s3 iam): cover both IPv4 and IPv6 loopback in allow CIDRs CI runners with happy-eyeballs resolve `localhost` to ::1 first, in which case a 127.0.0.0/8-only allow would silently never match and the deny-driven enforcement test would hang for the allow case. Add ::1/128 to every loopback-matching policy so the allow path works regardless of which loopback family the SDK lands on.
Credential Store Integration
This document shows how the credential store has been integrated into SeaweedFS's S3 API and IAM API components.
Quick Start
-
Generate credential configuration:
weed scaffold -config=credential -output=. -
Edit credential.toml to enable your preferred store (filer_etc is enabled by default)
-
Start S3 API server - it will automatically load credential.toml:
weed s3 -filer=localhost:8888
Integration Overview
The credential store provides a pluggable backend for storing S3 identities and credentials, supporting:
- Filer-based storage (filer_etc) - Uses existing filer storage (default)
- PostgreSQL - Shared database for multiple servers
- Memory - In-memory storage for testing
Configuration
Using credential.toml
Generate the configuration template:
weed scaffold -config=credential
This creates a credential.toml file with all available options. The filer_etc store is enabled by default:
# Filer-based credential store (default, uses existing filer storage)
[credential.filer_etc]
enabled = true
# PostgreSQL credential store (recommended for multi-node deployments)
[credential.postgres]
enabled = false
hostname = "localhost"
port = 5432
username = "seaweedfs"
password = "your_password"
database = "seaweedfs"
# Memory credential store (for testing only, data is lost on restart)
[credential.memory]
enabled = false
The credential.toml file is automatically loaded from these locations (in priority order):
./credential.toml$HOME/.seaweedfs/credential.toml/etc/seaweedfs/credential.toml
Server Configuration
Both S3 API and IAM API servers automatically load credential.toml during startup. No additional configuration is required.
Usage Examples
Filer-based Store (Default)
[credential.filer_etc]
enabled = true
This uses the existing filer storage and is compatible with current deployments.
PostgreSQL Store
[credential.postgres]
enabled = true
hostname = "localhost"
port = 5432
username = "seaweedfs"
password = "your_password"
database = "seaweedfs"
schema = "public"
sslmode = "disable"
table_prefix = "sw_"
connection_max_idle = 10
connection_max_open = 100
connection_max_lifetime_seconds = 3600
Memory Store (Testing)
[credential.memory]
enabled = true
Environment Variables
All credential configuration can be overridden with environment variables:
# Override PostgreSQL password
export WEED_CREDENTIAL_POSTGRES_PASSWORD=secret
# Override PostgreSQL hostname
export WEED_CREDENTIAL_POSTGRES_HOSTNAME=db.example.com
# Enable/disable stores
export WEED_CREDENTIAL_FILER_ETC_ENABLED=true
Rules:
- Prefix with
WEED_CREDENTIAL_ - Convert to uppercase
- Replace
.with_
Implementation Details
Components automatically load credential configuration during startup:
// Server initialization
if credConfig, err := credential.LoadCredentialConfiguration(); err == nil && credConfig != nil {
credentialManager, err := credential.NewCredentialManager(
credConfig.Store,
credConfig.Config,
credConfig.Prefix,
)
if err != nil {
return nil, fmt.Errorf("failed to initialize credential manager: %v", err)
}
// Use credential manager for operations
}
Benefits
- Easy Configuration - Generate template with
weed scaffold -config=credential - Pluggable Storage - Switch between filer_etc, PostgreSQL without code changes
- Backward Compatibility - Filer-based storage works with existing deployments
- Scalability - Database stores support multiple concurrent servers
- Performance - Database access can be faster than file-based storage
- Testing - Memory store simplifies unit testing
- Environment Override - All settings can be overridden with environment variables
Error Handling
When a credential store is configured, it must initialize successfully or the server will fail to start:
if credConfig != nil {
credentialManager, err = credential.NewCredentialManager(...)
if err != nil {
return nil, fmt.Errorf("failed to initialize credential manager: %v", err)
}
}
This ensures explicit configuration - if you configure a credential store, it must work properly.