* s3: gate IAM-cache gRPC RPCs behind admin Bearer auth The SeaweedS3IamCacheServer registered on the S3 gateway's internal gRPC port (default 0.0.0.0:18333) accepted PutIdentity/RemoveIdentity/PutPolicy/ DeletePolicy/GetPolicy/ListPolicies/PutGroup/RemoveGroup with no per-RPC authentication. An unauthenticated network peer could call PutIdentity with Actions:[Admin] and write straight into the live accessKeyIdent map that the SigV4 path reads, bypassing S3 authentication entirely. Mirror the filer's IamGrpcServer.checkAdminAuth: require a Bearer token signed with jwt.filer_signing.key (read from the existing s3a.filerGuard) at the top of every IAM-cache RPC. With no key configured the check is a no-op, matching the rest of SeaweedFS's gRPC surface. * credential: attach admin Bearer token to S3 IAM-cache propagation The filer's PropagatingCredentialStore fans IAM mutations out to peer S3 servers over the SeaweedS3IamCache gRPC service. Now that the S3 handlers require a Bearer token signed with jwt.filer_signing.key, attach one to the outgoing propagation context (mirroring shell/iamAdminAuthContext). With no key configured it is a no-op, so deployments that run without the signing key keep working. * credential: mint IAM-cache admin token after master discovery propagateChange attached the admin Bearer token before ListClusterNodes, so master-client retries could run down the (default 10s) token lifetime before the peer S3 fan-out began, leaving peers to reject an expired token and IAM caches stale. Move withIamCacheAdminAuth to after discovery succeeds, immediately before the propagation timeout is derived. * credential: cap IAM-cache propagation timeout below JWT lifetime The propagation fan-out used a fixed 10s timeout. If an operator configures jwt.filer_signing.expires_after_seconds below 10, the admin token can expire while slower S3 peers are still being contacted, leaving their IAM caches stale. Derive the propagation deadline as min(10s, tokenTTL) so it never outlives the token. withIamCacheAdminAuth now returns the token's lifetime (0 = no expiry) for this purpose.
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.