Anonymous Access to Public Buckets
January 20, 2026 · View on GitHub
This document explains the production-ready anonymous access system in manta-buckets-api, which allows secure browser access to explicitly public buckets without authentication.
Overview
The anonymous access system is enabled by default and provides secure access to public content while maintaining strict security controls. It supports:
- Direct browser access to public bucket content
- API access without authentication for public resources
Architecture
The anonymous access system works by:
- Pre-Authentication Check: Before authentication runs, check if the request targets a public bucket
- Anonymous User Context: Create a temporary user context with
public-readerrole - Bypass Authentication: Skip signature verification for anonymous public access
- Role-Based Authorization: Still enforce RBAC using the anonymous user's roles
- Secure Access: Only objects explicitly marked as public are accessible
Implementation Components
1. Anonymous Authentication Module (lib/anonymous-auth.js)
This module provides the core functionality for handling anonymous requests:
// Key functions:
anonymousAccessHandler() // Middleware for pre-auth anonymous handling
isPublicResourceRequest() // Checks if bucket allows public access
createAnonymousUser() // Creates anonymous user context
extractBucketName() // Parses bucket name from various URL formats
Anonymous User Context:
{
account: { uuid: 'anonymous', login: 'anonymous', isAdmin: false },
user: { uuid: 'anonymous', login: 'anonymous' },
roles: ['public-reader'] // Has public-reader role for authorization
}
2. Authentication Handler Modifications (lib/auth.js)
The existing authentication pipeline is modified to handle anonymous users:
// Skip authentication steps for anonymous access
function checkAuthzScheme(req, res, next) {
if (req.isAnonymousAccess) {
next(); // Skip auth scheme validation
return;
}
// ... existing authentication logic
}
function verifySignature(req, res, next) {
if (req.isAnonymousAccess) {
next(); // Skip signature verification
return;
}
// ... existing signature verification
}
3. Server Integration (lib/server.js)
The anonymous access handler is integrated into the middleware chain:
// Anonymous access handler runs BEFORE authentication
server.use(anonymousAuth.anonymousAccessHandler);
server.use(auth.authenticationHandler({
log: log,
mahi: clients.mahi,
keyapi: clients.keyapi
}));
Request Flow
Authenticated Request (Existing)
Browser → Authentication → Authorization → Bucket Access
Anonymous Public Request (New)
Browser → Anonymous Check → Skip Auth → Authorization → Bucket Access
↓
(if object in bucket is public)
Detailed Anonymous Flow
- Request Received: Browser sends
GET /user/buckets/public/objects/readme.txt - Anonymous Handler: Checks for authentication headers
- No auth headers found
- Extracts bucket name:
public
- Public Bucket Check: Queries bucket metadata for roles
- Finds
public-readerrole on bucket - Marks request as
req.isAnonymousAccess = true
- Finds
- Anonymous Context: Creates anonymous user with
public-readerrole - Skip Authentication: Authentication steps detect anonymous flag and skip
- Authorization: RBAC checks if
public-readerrole can access resource - Serve Content: If authorized, content is returned to browser
Security Model
What's Protected
- Authentication Bypass: Only for requests to buckets with
public-readerrole - Method Restrictions: Only GET and HEAD methods allowed for anonymous access
- Role Enforcement: Authorization still uses RBAC to validate access
- Audit Logging: All anonymous access attempts are logged
What's NOT Changed
- Private Buckets: Still require full authentication
- Write Operations: Anonymous users cannot modify content
- Administrative Operations: Bucket creation, deletion still require auth
- User Management: Account operations still require authentication
Security Considerations
- Bucket Role Verification: The system must verify bucket roles before granting anonymous access
- Method Restrictions: Only safe HTTP methods (GET, HEAD) are allowed
- No Privilege Escalation: Anonymous users cannot gain additional permissions
- Audit Trail: All anonymous access is logged for security monitoring
Security Model
Production Security Features
The system includes comprehensive security controls:
1. Strict Bucket Matching
- Only buckets named exactly
"public"are accessible by default
2. Configuration-Based Controls
# Environment variables for production control
MANTA_ANONYMOUS_ACCESS_ENABLED=true # Anonymous access enabled by default
MANTA_ANONYMOUS_BUCKETS=public # Allowed bucket names (comma-separated)
MANTA_ANONYMOUS_AUDIT_ALL=false # Audit all attempts (default: disabled)
3. Method Restrictions
- Allowed: GET, HEAD operations only
- Blocked: POST, PUT, DELETE, and all modification operations
- Read-Only: Anonymous users cannot modify any content
4. Audit and Monitoring
- All anonymous access attempts are logged
- Configurable audit trail with IP addresses and user agents
- Production monitoring integration ready
5. Role-Based Access Control
- Authorization still enforced through RBAC
- Anonymous users have limited
public-readerrole only - No privilege escalation possible
What's Protected
- Private Buckets: All non-public buckets require full authentication
- Write Operations: Anonymous users cannot modify any content
- Administrative Operations: Bucket management still requires authentication
- Account Operations: User management requires authentication
- Metadata Access: Only explicitly public objects accessible
Configuration
System Configuration
Default Configuration
# Anonymous access is enabled by default with secure settings
MANTA_ANONYMOUS_ACCESS_ENABLED=true # Feature enabled
MANTA_ANONYMOUS_BUCKETS=public # Only "public" bucket allowed
MANTA_ANONYMOUS_STRICT_MODE=true # Maximum security
MANTA_ANONYMOUS_AUDIT_ALL=false # Basic audit logging
Public buckets
A Bucket become publicly accessible when it's name public.
# Create a bucket named exactly "public"
s3cmd --no-check-certificate mb s3://public
# Upload content to the public bucket
s3cmd --no-check-certificate put document.pdf s3://public/
# Access directly from browser
curl https://manta.example.com/user/buckets/public/objects/document.pdf
Using Canned ACLs to allow access to objects within buckets.
By default all buckets are private (except a buckets named 'public'), but it is possible to allow anonymous access to specific objects inside a bucket.
# Share an object within a bucket
s3cmd --no-check-certificate --acl=public-read s3://mybucket/shareobject.txt
Removing Public Access
To make a public bucket private again, you need to remove the public-reader role:
Method 1: Using s3cmd (Recommended)
# Set bucket to private
s3cmd --no-check-certificate --acl-private setacl s3://mybucket/myobject.txt
# Alternative: recreate bucket without public access
s3cmd --no-check-certificate del s3://public-bucket
s3cmd --no-check-certificate mb s3://public-bucket # Private by default
Verifying Bucket Access Status
Check if the Bucket object is public
# Method 1: Check bucket headers for role-tag
curl -JOL https://{manta_endpoint}/{your account}\
/buckets/{bucket}/objects/myobject.txt
Test Browser Access
# Public bucket: Should return JSON or content
curl https://manta.example.com/user/buckets/public
# Private bucket: Should return 403 Forbidden
curl https://manta.example.com/user/buckets/private-bucket
Check Debug Logs
Enable debug logging to see bucket status:
# Look for these log messages
grep "Bucket role lookup result" /var/log/buckets-api.log
grep "Anonymous access check result" /var/log/buckets-api.log
# Public bucket logs:
# Bucket role lookup result (bucket=public-bucket, isPublicByNaming=true, roles=["public-reader"])
# Anonymous access check result (isPublic=true)
# Private bucket logs:
# Bucket role lookup result (bucket=private-bucket, isPublicByNaming=false, roles=[])
# Anonymous access check result (isPublic=false)
Environment Variables
Production Environment Variables
# Core Configuration
MANTA_ANONYMOUS_ACCESS_ENABLED=true # Enable/disable anonymous access (default: true)
MANTA_ANONYMOUS_BUCKETS=public # Comma-separated list of allowed bucket names
MANTA_ANONYMOUS_STRICT_MODE=true # Enable strict security mode (default: true)
# Example: Multiple public buckets
MANTA_ANONYMOUS_BUCKETS=public,cdn,assets
# Example: Disable anonymous access entirely
MANTA_ANONYMOUS_ACCESS_ENABLED=false
Configuration Validation
The system logs its configuration on startup:
MANTA ANONYMOUS ACCESS ENABLED - Configuration: {
"enabled": true,
"allowedBuckets": ["public"],
"strictMode": true,
"auditAll": false
}
Browser Access Examples
Browsers can access content directly to buckets that have the name 'public':
<!-- Direct image access -->
<img src="https://manta.example.com/user/buckets/public/objects/logo.png">
<!-- Static website hosting -->
<iframe src="https://manta.example.com/user/buckets/public/objects/index.html"></iframe>
<!-- Direct download links -->
<a href="https://manta.example.com/user/buckets/public/objects/manual.pdf">
Download Manual
</a>
CORS Support
CORS is not supported. CORS headers are read from object metadata, not automatically added. To set the metadata on your objects:
# Set CORS headers as object metadata
s3cmd put --add-header="x-amz-meta-access-control-allow-origin:*" \
--add-header="x-amz-meta-access-control-allow-methods:GET,HEAD" \
myfile.txt s3://public/
CORS headers are applied from object metadata during response if present. Note that we don't support the OPTION method that's required for preflight requests, to fully support CORS, it must be implemented per bucket and the OPTION method should be supported as well.
Troubleshooting
Common Issues
-
Access Denied on Public Bucket
- Verify bucket has
public-readerrole - Check bucket name extraction in logs
- Ensure anonymous user context is created
- Confirm bucket name contains "public"
- Verify bucket has
-
Can't Remove Public Access
- Use
--acl-privateflag with s3cmd:s3cmd --acl-private setacl s3://bucket - Verify the role-tag header is empty after removal
- Test browser access returns 403 Forbidden
- Check debug logs show
roles=[]andisPublic=false
- Use
-
Public Access Not Working After Setup
- Restart buckets-api service after code changes
- Verify anonymous access handler is loaded before authentication
- Check that bucket name contains "public" (current naming-based detection)
- Ensure browser is not sending authentication headers (clear cookies/auth)
-
Bucket is named Public But Browser Access Fails
- Check if bucket name is "public" (required for current implementation)
- Verify the anonymous access middleware chain is complete
- Look for authorization bypass logs:
authorize: allowing public access - bypassing Mahi authorization - Ensure no authentication headers are being sent by the browser
Debug Logging
Enable debug logging to troubleshoot anonymous access issues:
# Enable debug logging
svccfg -s buckets-api setenv LOG_LEVEL debug
svcadm refresh buckets-api
# Check logs for anonymous access
grep "anonymous" /var/log/buckets-api.log
grep "public-reader" /var/log/buckets-api.log
Log Messages to Monitor
anonymousAccessHandler: checking for anonymous access
isPublicResourceRequest: bucket has public-reader role
checkAuthzScheme: skipping for anonymous access
verifySignature: skipping for anonymous access