Files
seaweedFS/test/s3/iam
Chris Lu f5c666052e feat: add S3 bucket size and object count metrics (#7776)
* feat: add S3 bucket size and object count metrics

Adds periodic collection of bucket size metrics:
- SeaweedFS_s3_bucket_size_bytes: logical size (deduplicated across replicas)
- SeaweedFS_s3_bucket_physical_size_bytes: physical size (including replicas)
- SeaweedFS_s3_bucket_object_count: object count (deduplicated)

Collection runs every 1 minute via background goroutine that queries
filer Statistics RPC for each bucket's collection.

Also adds Grafana dashboard panels for:
- S3 Bucket Size (logical vs physical)
- S3 Bucket Object Count

* address PR comments: fix bucket size metrics collection

1. Fix collectCollectionInfoFromMaster to use master VolumeList API
   - Now properly queries master for topology info
   - Uses WithMasterClient to get volume list from master
   - Correctly calculates logical vs physical size based on replication

2. Return error when filerClient is nil to trigger fallback
   - Changed from 'return nil, nil' to 'return nil, error'
   - Ensures fallback to filer stats is properly triggered

3. Implement pagination in listBucketNames
   - Added listBucketPageSize constant (1000)
   - Uses StartFromFileName for pagination
   - Continues fetching until fewer entries than limit returned

4. Handle NewReplicaPlacementFromByte error and prevent division by zero
   - Check error return from NewReplicaPlacementFromByte
   - Default to 1 copy if error occurs
   - Add explicit check for copyCount == 0

* simplify bucket size metrics: remove filer fallback, align with quota enforcement

- Remove fallback to filer Statistics RPC
- Use only master topology for collection info (same as s3.bucket.quota.enforce)
- Updated comments to clarify this runs the same collection logic as quota enforcement
- Simplified code by removing collectBucketSizeFromFilerStats

* use s3a.option.Masters directly instead of querying filer

* address PR comments: fix dashboard overlaps and improve metrics collection

Grafana dashboard fixes:
- Fix overlapping panels 55 and 59 in grafana_seaweedfs.json (moved 59 to y=30)
- Fix grid collision in k8s dashboard (moved panel 72 to y=48)
- Aggregate bucket metrics with max() by (bucket) for multi-instance S3 gateways

Go code improvements:
- Add graceful shutdown support via context cancellation
- Use ticker instead of time.Sleep for better shutdown responsiveness
- Distinguish EOF from actual errors in stream handling

* improve bucket size metrics: multi-master failover and proper error handling

- Initial delay now respects context cancellation using select with time.After
- Use WithOneOfGrpcMasterClients for multi-master failover instead of hardcoding Masters[0]
- Properly propagate stream errors instead of just logging them (EOF vs real errors)

* improve bucket size metrics: distributed lock and volume ID deduplication

- Add distributed lock (LiveLock) so only one S3 instance collects metrics at a time
- Add IsLocked() method to LiveLock for checking lock status
- Fix deduplication: use volume ID tracking instead of dividing by copyCount
  - Previous approach gave wrong results if replicas were missing
  - Now tracks seen volume IDs and counts each volume only once
- Physical size still includes all replicas for accurate disk usage reporting

* rename lock to s3.leader

* simplify: remove StartBucketSizeMetricsCollection wrapper function

* fix data race: use atomic operations for LiveLock.isLocked field

- Change isLocked from bool to int32
- Use atomic.LoadInt32/StoreInt32 for all reads/writes
- Sync shared isLocked field in StartLongLivedLock goroutine

* add nil check for topology info to prevent panic

* fix bucket metrics: use Ticker for consistent intervals, fix pagination logic

- Use time.Ticker instead of time.After for consistent interval execution
- Fix pagination: count all entries (not just directories) for proper termination
- Update lastFileName for all entries to prevent pagination issues

* address PR comments: remove redundant atomic store, propagate context

- Remove redundant atomic.StoreInt32 in StartLongLivedLock (AttemptToLock already sets it)
- Propagate context through metrics collection for proper cancellation on shutdown
  - collectAndUpdateBucketSizeMetrics now accepts ctx
  - collectCollectionInfoFromMaster uses ctx for VolumeList RPC
  - listBucketNames uses ctx for ListEntries RPC
2025-12-15 19:23:25 -08:00
..
2025-08-30 11:15:48 -07:00
2025-08-30 11:15:48 -07:00
2025-11-12 22:14:50 -08:00
2025-10-13 18:05:17 -07:00
2025-10-13 18:05:17 -07:00
2025-10-13 18:05:17 -07:00
2025-10-13 18:05:17 -07:00

SeaweedFS S3 IAM Integration Tests

This directory contains comprehensive integration tests for the SeaweedFS S3 API with Advanced IAM (Identity and Access Management) system integration.

Overview

Important: The STS service uses a stateless JWT design where all session information is embedded directly in the JWT token. No external session storage is required.

The S3 IAM integration tests validate the complete end-to-end functionality of:

  • JWT Authentication: OIDC token-based authentication with S3 API
  • Policy Enforcement: Fine-grained access control for S3 operations
  • Stateless Session Management: JWT-based session token validation and expiration (no external storage)
  • Role-Based Access Control (RBAC): IAM roles with different permission levels
  • Bucket Policies: Resource-based access control integration
  • Multipart Upload IAM: Policy enforcement for multipart operations
  • Contextual Policies: IP-based, time-based, and conditional access control
  • Presigned URLs: IAM-integrated temporary access URL generation

Test Architecture

Components Tested

  1. S3 API Gateway - SeaweedFS S3-compatible API server with IAM integration
  2. IAM Manager - Core IAM orchestration and policy evaluation
  3. STS Service - Security Token Service for temporary credentials
  4. Policy Engine - AWS IAM-compatible policy evaluation
  5. Identity Providers - OIDC and LDAP authentication providers
  6. Policy Store - Persistent policy storage using SeaweedFS filer

Test Framework

  • S3IAMTestFramework: Comprehensive test utilities and setup
  • Mock OIDC Provider: In-memory OIDC server with JWT signing
  • Service Management: Automatic SeaweedFS service lifecycle management
  • Resource Cleanup: Automatic cleanup of buckets and test data

Test Scenarios

1. Authentication Tests (TestS3IAMAuthentication)

  • Valid JWT Token: Successful authentication with proper OIDC tokens
  • Invalid JWT Token: Rejection of malformed or invalid tokens
  • Expired JWT Token: Proper handling of expired authentication tokens

2. Policy Enforcement Tests (TestS3IAMPolicyEnforcement)

  • Read-Only Policy: Users can only read objects and list buckets
  • Write-Only Policy: Users can only create/delete objects but not read
  • Admin Policy: Full access to all S3 operations including bucket management

3. Session Expiration Tests (TestS3IAMSessionExpiration)

  • Short-Lived Sessions: Creation and validation of time-limited sessions
  • Manual Expiration: Testing session expiration enforcement
  • Expired Session Rejection: Proper access denial for expired sessions

4. Multipart Upload Tests (TestS3IAMMultipartUploadPolicyEnforcement)

  • Admin Multipart Access: Full multipart upload capabilities
  • Read-Only Denial: Rejection of multipart operations for read-only users
  • Complete Upload Flow: Initiate → Upload Parts → Complete workflow

5. Bucket Policy Tests (TestS3IAMBucketPolicyIntegration)

  • Public Read Policy: Bucket-level policies allowing public access
  • Explicit Deny Policy: Bucket policies that override IAM permissions
  • Policy CRUD Operations: Get/Put/Delete bucket policy operations

6. Contextual Policy Tests (TestS3IAMContextualPolicyEnforcement)

  • 🔧 IP-Based Restrictions: Source IP validation in policy conditions
  • 🔧 Time-Based Restrictions: Temporal access control policies
  • 🔧 User-Agent Restrictions: Request context-based policy evaluation

7. Presigned URL Tests (TestS3IAMPresignedURLIntegration)

  • URL Generation: IAM-validated presigned URL creation
  • Permission Validation: Ensuring users have required permissions
  • 🔧 HTTP Request Testing: Direct HTTP calls to presigned URLs

Quick Start

Prerequisites

  1. Go 1.19+ with modules enabled
  2. SeaweedFS Binary (weed) built with IAM support
  3. Test Dependencies:
    go get github.com/stretchr/testify
    go get github.com/aws/aws-sdk-go
    go get github.com/golang-jwt/jwt/v5
    

Running Tests

Complete Test Suite

# Run all tests with service management
make test

# Quick test run (assumes services running)
make test-quick

Specific Test Categories

# Test only authentication
make test-auth

# Test only policy enforcement  
make test-policy

# Test only session expiration
make test-expiration

# Test only multipart uploads
make test-multipart

# Test only bucket policies
make test-bucket-policy

Development & Debugging

# Start services and keep running
make debug

# Show service logs
make logs

# Check service status
make status

# Watch for changes and re-run tests
make watch

Manual Service Management

If you prefer to manage services manually:

# Start services
make start-services

# Wait for services to be ready
make wait-for-services

# Run tests
make run-tests

# Stop services
make stop-services

Configuration

Test Configuration (test_config.json)

The test configuration defines:

  • Identity Providers: OIDC and LDAP configurations
  • IAM Roles: Role definitions with trust policies
  • IAM Policies: Permission policies for different access levels
  • Policy Stores: Persistent storage configurations for IAM policies and roles

Service Ports

Service Port Purpose
Master 9333 Cluster coordination
Volume 8080 Object storage
Filer 8888 Metadata & IAM storage
S3 API 8333 S3-compatible API with IAM

Environment Variables

# SeaweedFS binary location
export WEED_BINARY=../../../weed

# Service ports (optional)
export S3_PORT=8333
export FILER_PORT=8888  
export MASTER_PORT=9333
export VOLUME_PORT=8080

# Test timeout
export TEST_TIMEOUT=30m

# Log level (0-4)
export LOG_LEVEL=2

Test Data & Cleanup

Automatic Cleanup

The test framework automatically:

  • 🗑️ Deletes test buckets created during tests
  • 🗑️ Removes test objects and multipart uploads
  • 🗑️ Cleans up IAM sessions and temporary tokens
  • 🗑️ Stops services after test completion

Manual Cleanup

# Clean everything
make clean

# Clean while keeping services running
rm -rf test-volume-data/

Extending Tests

Adding New Test Scenarios

  1. Create Test Function:

    func TestS3IAMNewFeature(t *testing.T) {
        framework := NewS3IAMTestFramework(t)
        defer framework.Cleanup()
    
        // Test implementation
    }
    
  2. Use Test Framework:

    // Create authenticated S3 client
    s3Client, err := framework.CreateS3ClientWithJWT("user", "TestRole")
    require.NoError(t, err)
    
    // Test S3 operations
    err = framework.CreateBucket(s3Client, "test-bucket")
    require.NoError(t, err)
    
  3. Add to Makefile:

    test-new-feature: ## Test new feature
    	go test -v -run TestS3IAMNewFeature ./...
    

Creating Custom Policies

Add policies to test_config.json:

{
  "policies": {
    "CustomPolicy": {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": ["s3:GetObject"],
          "Resource": ["arn:aws:s3:::specific-bucket/*"],
          "Condition": {
            "StringEquals": {
              "s3:prefix": ["allowed-prefix/"]
            }
          }
        }
      ]
    }
  }
}

Adding Identity Providers

  1. Mock Provider Setup:

    // In test framework
    func (f *S3IAMTestFramework) setupCustomProvider() {
        provider := custom.NewCustomProvider("test-custom")
        // Configure and register
    }
    
  2. Configuration:

    {
      "providers": {
        "custom": {
          "test-custom": {
            "endpoint": "http://localhost:8080",
            "clientId": "custom-client"
          }
        }
      }
    }
    

Troubleshooting

Common Issues

1. Services Not Starting

# Check if ports are available
netstat -an | grep -E "(8333|8888|9333|8080)"

# Check service logs
make logs

# Try different ports
export S3_PORT=18333
make start-services

2. JWT Token Issues

# Verify OIDC mock server
curl http://localhost:8080/.well-known/openid_configuration

# Check JWT token format in logs
make logs | grep -i jwt

3. Permission Denied Errors

# Verify IAM configuration
cat test_config.json | jq '.policies'

# Check policy evaluation in logs  
export LOG_LEVEL=4
make start-services

4. Test Timeouts

# Increase timeout
export TEST_TIMEOUT=60m
make test

# Run individual tests
make test-auth

Debug Mode

Start services in debug mode to inspect manually:

# Start and keep running
make debug

# In another terminal, run specific operations
aws s3 ls --endpoint-url http://localhost:8333

# Stop when done (Ctrl+C in debug terminal)

Log Analysis

# Service-specific logs
tail -f weed-s3.log       # S3 API server
tail -f weed-filer.log    # Filer (IAM storage)  
tail -f weed-master.log   # Master server
tail -f weed-volume.log   # Volume server

# Filter for IAM-related logs
make logs | grep -i iam
make logs | grep -i jwt
make logs | grep -i policy

Performance Testing

Benchmarks

# Run performance benchmarks
make benchmark

# Profile memory usage  
go test -bench=. -memprofile=mem.prof
go tool pprof mem.prof

Load Testing

For load testing with IAM:

  1. Create Multiple Clients:

    // Generate multiple JWT tokens
    tokens := framework.GenerateMultipleJWTTokens(100)
    
    // Create concurrent clients
    var wg sync.WaitGroup
    for _, token := range tokens {
        wg.Add(1)
        go func(token string) {
            defer wg.Done()
            // Perform S3 operations
        }(token)
    }
    wg.Wait()
    
  2. Measure Performance:

    # Run with verbose output
    go test -v -bench=BenchmarkS3IAMOperations
    

CI/CD Integration

GitHub Actions

name: S3 IAM Integration Tests
on: [push, pull_request]

jobs:
  s3-iam-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-go@v3
        with:
          go-version: '1.19'
      
      - name: Build SeaweedFS
        run: go build -o weed ./main.go
      
      - name: Run S3 IAM Tests  
        run: |
          cd test/s3/iam
          make ci

Jenkins Pipeline

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'go build -o weed ./main.go'
            }
        }
        stage('S3 IAM Tests') {
            steps {
                dir('test/s3/iam') {
                    sh 'make ci'
                }
            }
            post {
                always {
                    dir('test/s3/iam') {
                        sh 'make clean'
                    }
                }
            }
        }
    }
}

Contributing

Adding New Tests

  1. Follow Test Patterns:

    • Use S3IAMTestFramework for setup
    • Include cleanup with defer framework.Cleanup()
    • Use descriptive test names and subtests
    • Assert both success and failure cases
  2. Update Documentation:

    • Add test descriptions to this README
    • Include Makefile targets for new test categories
    • Document any new configuration options
  3. Ensure Test Reliability:

    • Tests should be deterministic and repeatable
    • Include proper error handling and assertions
    • Use appropriate timeouts for async operations

Code Style

  • Follow standard Go testing conventions
  • Use require.NoError() for critical assertions
  • Use assert.Equal() for value comparisons
  • Include descriptive error messages in assertions

Support

For issues with S3 IAM integration tests:

  1. Check Logs: Use make logs to inspect service logs
  2. Verify Configuration: Ensure test_config.json is correct
  3. Test Services: Run make status to check service health
  4. Clean Environment: Try make clean && make test

License

This test suite is part of the SeaweedFS project and follows the same licensing terms.