Files
seaweedFS/test/s3/iam
Chris Lu ae9a943ef6 IAM: Add Service Account Support (#7744) (#7901)
* iam: add ServiceAccount protobuf schema

Add ServiceAccount message type to iam.proto with support for:
- Unique ID and parent user linkage
- Optional expiration timestamp
- Separate credentials (access key/secret)
- Action restrictions (subset of parent)
- Enable/disable status

This is the first step toward implementing issue #7744
(IAM Service Account Support).

* iam: add service account response types

Add IAM API response types for service account operations:
- ServiceAccountInfo struct for marshaling account details
- CreateServiceAccountResponse
- DeleteServiceAccountResponse
- ListServiceAccountsResponse
- GetServiceAccountResponse
- UpdateServiceAccountResponse

Also add type aliases in iamapi package for backwards compatibility.

Part of issue #7744 (IAM Service Account Support).

* iam: implement service account API handlers

Add CRUD operations for service accounts:
- CreateServiceAccount: Creates service account with ABIA key prefix
- DeleteServiceAccount: Removes service account and parent linkage
- ListServiceAccounts: Lists all or filtered by parent user
- GetServiceAccount: Retrieves service account details
- UpdateServiceAccount: Modifies status, description, expiration

Service accounts inherit parent user's actions by default and
support optional expiration timestamps.

Part of issue #7744 (IAM Service Account Support).

* sts: add AssumeRoleWithWebIdentity HTTP endpoint

Add STS API HTTP endpoint for AWS SDK compatibility:
- Create s3api_sts.go with HTTP handlers matching AWS STS spec
- Support AssumeRoleWithWebIdentity action with JWT token
- Return XML response with temporary credentials (AccessKeyId,
  SecretAccessKey, SessionToken) matching AWS format
- Register STS route at POST /?Action=AssumeRoleWithWebIdentity

This enables AWS SDKs (boto3, AWS CLI, etc.) to obtain temporary
S3 credentials using OIDC/JWT tokens.

Part of issue #7744 (IAM Service Account Support).

* test: add service account and STS integration tests

Add integration tests for new IAM features:

s3_service_account_test.go:
- TestServiceAccountLifecycle: Create, Get, List, Update, Delete
- TestServiceAccountValidation: Error handling for missing params

s3_sts_test.go:
- TestAssumeRoleWithWebIdentityValidation: Parameter validation
- TestAssumeRoleWithWebIdentityWithMockJWT: JWT token handling

Tests skip gracefully when SeaweedFS is not running or when IAM
features are not configured.

Part of issue #7744 (IAM Service Account Support).

* iam: address code review comments

- Add constants for service account ID and key lengths
- Use strconv.ParseInt instead of fmt.Sscanf for better error handling
- Allow clearing descriptions by checking key existence in url.Values
- Replace magic numbers (12, 20, 40) with named constants

Addresses review comments from gemini-code-assist[bot]

* test: add proper error handling in service account tests

Use require.NoError(t, err) for io.ReadAll and xml.Unmarshal
to prevent silent failures and ensure test reliability.

Addresses review comment from gemini-code-assist[bot]

* test: add proper error handling in STS tests

Use require.NoError(t, err) for io.ReadAll and xml.Unmarshal
to prevent silent failures and ensure test reliability.
Repeated this fix throughout the file.

Addresses review comment from gemini-code-assist[bot] in PR #7901.

* iam: address additional code review comments

- Specific error code mapping for STS service errors
- Distinguish between Sender and Receiver error types in STS responses
- Add nil checks for credentials in List/GetServiceAccount
- Validate expiration date is in the future
- Improve integration test error messages (include response body)
- Add credential verification step in service account tests

Addresses remaining review comments from gemini-code-assist[bot] across multiple files.

* iam: fix shared slice reference in service account creation

Copy parent's actions to create an independent slice for the service
account instead of sharing the underlying array. This prevents
unexpected mutations when the parent's actions are modified later.

Addresses review comment from coderabbitai[bot] in PR #7901.

* iam: remove duplicate unused constant

Removed redundant iamServiceAccountKeyPrefix as ServiceAccountKeyPrefix
is already defined and used.

Addresses remaining cleanup task.

* sts: document limitation of string-based error mapping

Added TODO comment explaining that the current string-based error
mapping approach is fragile and should be replaced with typed errors
from the STS service in a future refactoring.

This addresses the architectural concern raised in code review while
deferring the actual implementation to a separate PR to avoid scope
creep in the current service account feature addition.

* iam: fix remaining review issues

- Add future-date validation for expiration in UpdateServiceAccount
- Reorder tests so credential verification happens before deletion
- Fix compilation error by using correct JWT generation methods

Addresses final review comments from coderabbitai[bot].

* iam: fix service account access key length

The access key IDs were incorrectly generated with 24 characters
instead of the AWS-standard 20 characters. This was caused by
generating 20 random characters and then prepending the 4-character
ABIA prefix.

Fixed by subtracting the prefix length from AccessKeyLength, so the
final key is: ABIA (4 chars) + random (16 chars) = 20 chars total.

This ensures compatibility with S3 clients that validate key length.

* test: add comprehensive service account security tests

Added comprehensive integration tests for service account functionality:

- TestServiceAccountS3Access: Verify SA credentials work for S3 operations
- TestServiceAccountExpiration: Test expiration date validation and enforcement
- TestServiceAccountInheritedPermissions: Verify parent-child relationship
- TestServiceAccountAccessKeyFormat: Validate AWS-compatible key format (ABIA prefix, 20 char length)

These tests ensure SeaweedFS service accounts are compatible with AWS
conventions and provide robust security coverage.

* iam: remove unused UserAccessKeyPrefix constant

Code cleanup to remove unused constants.

* iam: remove unused iamCommonResponse type alias

Code cleanup to remove unused type aliases.

* iam: restore and use UserAccessKeyPrefix constant

Restored UserAccessKeyPrefix constant and updated s3api tests to use it
instead of hardcoded strings for better maintainability and consistency.

* test: improve error handling in service account security tests

Added explicit error checking for io.ReadAll and xml.Unmarshal in
TestServiceAccountExpiration to ensure failures are reported correctly and
cleanup is performed only when appropriate. Also added logging for failed
responses.

* test: use t.Cleanup for reliable resource cleanup

Replaced defer with t.Cleanup to ensure service account cleanup runs even
when require.NoError fails. Also switched from manual error checking to
require.NoError for more idiomatic testify usage.

* iam: add CreatedBy field and optimize identity lookups

- Added createdBy parameter to CreateServiceAccount to track who created each service account
- Extract creator identity from request context using GetIdentityNameFromContext
- Populate created_by field in ServiceAccount protobuf
- Added findIdentityByName helper function to optimize identity lookups
- Replaced nested loops with O(n) helper function calls in CreateServiceAccount and DeleteServiceAccount

This addresses code review feedback for better auditing and performance.

* iam: prevent user deletion when service accounts exist

Following AWS IAM behavior, prevent deletion of users that have active
service accounts. This ensures explicit cleanup and prevents orphaned
service account resources with invalid ParentUser references.

Users must delete all associated service accounts before deleting the
parent user, providing safer resource management.

* sts: enhance TODO with typed error implementation guidance

Updated TODO comment with detailed implementation approach for replacing
string-based error matching with typed errors using errors.Is(). This
provides a clear roadmap for a follow-up PR to improve error handling
robustness and maintainability.

* iam: add operational limits for service account creation

Added AWS IAM-compatible safeguards to prevent resource exhaustion:
- Maximum 100 service accounts per user (LimitExceededException)
- Maximum 1000 character description length (InvalidInputException)

These limits prevent accidental or malicious resource exhaustion while
not impacting legitimate use cases.

* iam: add missing operational limit constants

Added MaxServiceAccountsPerUser and MaxDescriptionLength constants that
were referenced in the previous commit but not defined.

* iam: enforce service account expiration during authentication

CRITICAL SECURITY FIX: Expired service account credentials were not being
rejected during authentication, allowing continued access after expiration.

Changes:
- Added Expiration field to Credential struct
- Populate expiration when loading service accounts from configuration
- Check expiration in all authentication paths (V2 and V4 signatures)
- Return ErrExpiredToken for expired credentials

This ensures expired service accounts are properly rejected at authentication
time, matching AWS IAM behavior and preventing unauthorized access.

* iam: fix error code for expired service account credentials

Use ErrAccessDenied instead of non-existent ErrExpiredToken for expired
service account credentials. This provides appropriate access denial for
expired credentials while maintaining AWS-compatible error responses.

* iam: fix remaining ErrExpiredToken references

Replace all remaining instances of non-existent ErrExpiredToken with
ErrAccessDenied for expired service account credentials.

* iam: apply AWS-standard key format to user access keys

Updated CreateAccessKey to generate AWS-standard 20-character access keys
with AKIA prefix for regular users, matching the format used for service
accounts. This ensures consistency across all access key types and full
AWS compatibility.

- Access keys: AKIA + 16 random chars = 20 total (was 21 chars, no prefix)
- Secret keys: 40 random chars (was 42, now matches AWS standard)
- Uses AccessKeyLength and UserAccessKeyPrefix constants

* sts: replace fragile string-based error matching with typed errors

Implemented robust error handling using typed errors and errors.Is() instead
of fragile strings.Contains() matching. This decouples the HTTP layer from
service implementation details and prevents errors from being miscategorized
if error messages change.

Changes:
- Added typed error variables to weed/iam/sts/constants.go:
  * ErrTypedTokenExpired
  * ErrTypedInvalidToken
  * ErrTypedInvalidIssuer
  * ErrTypedInvalidAudience
  * ErrTypedMissingClaims

- Updated STS service to wrap provider authentication errors with typed errors
- Replaced strings.Contains() with errors.Is() in HTTP layer for error checking
- Removed TODO comment as the improvement is now implemented

This makes error handling more maintainable and reliable.

* sts: eliminate all string-based error matching with provider-level typed errors

Completed the typed error implementation by adding provider-level typed errors
and updating provider implementations to return them. This eliminates ALL
fragile string matching throughout the entire error handling stack.

Changes:
- Added typed error definitions to weed/iam/providers/errors.go:
  * ErrProviderTokenExpired
  * ErrProviderInvalidToken
  * ErrProviderInvalidIssuer
  * ErrProviderInvalidAudience
  * ErrProviderMissingClaims

- Updated OIDC provider to wrap JWT validation errors with typed provider errors
- Replaced strings.Contains() with errors.Is() in STS service for error mapping
- Complete error chain: Provider -> STS -> HTTP layer, all using errors.Is()

This provides:
- Reliable error classification independent of error message content
- Type-safe error checking throughout the stack
- No order-dependent string matching
- Maintainable error handling that won't break with message changes

* oidc: use jwt.ErrTokenExpired instead of string matching

Replaced the last remaining string-based error check with the JWT library's
exported typed error. This makes the error detection independent of error
message content and more robust against library updates.

Changed from:
  strings.Contains(errMsg, "expired")
To:
  errors.Is(err, jwt.ErrTokenExpired)

This completes the elimination of ALL string-based error matching throughout
the entire authentication stack.

* iam: add description length validation to UpdateServiceAccount

Fixed inconsistency where UpdateServiceAccount didn't validate description
length against MaxDescriptionLength, allowing operational limits to be
bypassed during updates.

Now validates that updated descriptions don't exceed 1000 characters,
matching the validation in CreateServiceAccount.

* iam: refactor expiration check into helper method

Extracted duplicated credential expiration check logic into a helper method
to reduce code duplication and improve maintainability.

Added Credential.isCredentialExpired() method and replaced 5 instances of
inline expiration checks across auth_signature_v2.go and auth_signature_v4.go.

* iam: address critical Copilot security and consistency feedback

Fixed three critical issues identified by Copilot code review:

1. SECURITY: Prevent loading disabled service account credentials
   - Added check to skip disabled service accounts during credential loading
   - Disabled accounts can no longer authenticate

2. Add DurationSeconds validation for STS AssumeRoleWithWebIdentity
   - Enforce AWS-compatible range: 900-43200 seconds (15 min - 12 hours)
   - Returns proper error for out-of-range values

3. Fix expiration update consistency in UpdateServiceAccount
   - Added key existence check like Description field
   - Allows explicit clearing of expiration by setting to empty string
   - Distinguishes between "not updating" and "clearing expiration"

* sts: remove unused durationSecondsStr variable

Fixed build error from unused variable after refactoring duration parsing.

* iam: address remaining Copilot feedback and remove dead code

Completed remaining Copilot code review items:

1. Remove unused getPermission() method (dead code)
   - Method was defined but never called anywhere

2. Improve slice modification safety in DeleteServiceAccount
   - Replaced append-with-slice-operations with filter pattern
   - Avoids potential issues from mutating slice during iteration

3. Fix route registration order
   - Moved STS route registration BEFORE IAM route
   - Prevents IAM route from intercepting STS requests
   - More specific route (with query parameter) now registered first

* iam: improve expiration validation and test cleanup robustness

Addressed additional Copilot feedback:

1. Make expiration validation more explicit
   - Added explicit check for negative values
   - Added comment clarifying that 0 is allowed to clear expiration
   - Improves code readability and intent

2. Fix test cleanup order in s3_service_account_test.go
   - Track created service accounts in a slice
   - Delete all service accounts before deleting parent user
   - Prevents DeleteConflictException during cleanup
   - More robust cleanup even if test fails mid-execution

Note: s3_service_account_security_test.go already had correct cleanup
order due to LIFO defer execution.

* test: remove redundant variable assignments

Removed duplicate assignments of createdSAId, createdAccessKeyId, and
createdSecretAccessKey on lines 148-150 that were already assigned on
lines 132-134.
2025-12-29 20:17:23 -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.