Object Storage Security
Comprehensive security features to protect your data in DanubeData Object Storage.
Overview
DanubeData Object Storage provides multiple layers of security to ensure your data is protected at rest and in transit. This guide covers encryption, access control, and security best practices.
Encryption
Encryption at Rest
All data stored in DanubeData Object Storage is automatically encrypted using AES-256 encryption.
- Server-Side Encryption (SSE-S3): Enabled by default
- No configuration required: Automatic for all objects
- Zero performance impact: Hardware-accelerated encryption
Encryption in Transit
All connections use TLS 1.3 for maximum security:
- HTTPS only: HTTP connections are not accepted
- Strong cipher suites: Modern TLS configuration
- Certificate validation: Automatic certificate management
Access Control
Access Keys
Access keys are the primary method for authenticating to your buckets via the S3 API.
Creating Access Keys
Via Dashboard:
- Navigate to your bucket
- Click Access Keys tab
- Click Create Access Key
- Configure name and permissions
- Copy the secret key immediately (shown only once)
Via API:
curl -X POST https://api.danubedata.ro/v1/storage/buckets/{bucket_id}/access-keys \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "my-app-key",
"permissions": ["read", "write"]
}'
Permission Levels
| Permission | Description | Operations |
|---|---|---|
| read | Read-only access | GetObject, ListObjects, HeadObject |
| write | Create and update objects | PutObject, CopyObject |
| delete | Remove objects | DeleteObject, DeleteObjects |
| admin | Full bucket control | All operations including policy changes |
Best Practices for Access Keys
- Use least privilege: Only grant permissions that are needed
- Rotate regularly: Create new keys and retire old ones periodically
- Set expiration dates: Use expiring keys for temporary access
- Monitor usage: Check last-used timestamps to identify unused keys
- Never commit to code: Use environment variables or secrets management
Public Access Control
By default, all buckets are private. You can enable public read access for specific use cases.
Enabling Public Access
Via Dashboard:
- Navigate to your bucket
- Click Settings
- Toggle Public Access to enabled
- Confirm the security warning
Via API:
curl -X PATCH https://api.danubedata.ro/v1/storage/buckets/{bucket_id} \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"public_access": true
}'
Public Access Warning
When public access is enabled:
- Anyone can read objects in your bucket
- Objects are accessible via direct URL
- Egress traffic will count against your quota
- Use for static websites, public assets only
Bucket Policies
For fine-grained access control, you can apply JSON bucket policies.
Example: Allow Read from Specific IP
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::my-bucket/*"],
"Condition": {
"IpAddress": {
"aws:SourceIp": "192.168.1.0/24"
}
}
}
]
}
Example: Deny Delete Operations
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": ["s3:DeleteObject", "s3:DeleteBucket"],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
]
}
]
}
CORS Configuration
Configure Cross-Origin Resource Sharing (CORS) to allow web applications to access your bucket.
Why CORS?
Browsers block cross-origin requests by default. If your web application needs to upload or download files directly from Object Storage, you must configure CORS.
Configuring CORS
Via Dashboard:
- Navigate to your bucket
- Click Settings → CORS
- Add CORS rules
- Save changes
Via API:
curl -X PUT https://api.danubedata.ro/v1/storage/buckets/{bucket_id}/cors \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"cors_rules": [
{
"allowed_origins": ["https://myapp.com", "https://*.myapp.com"],
"allowed_methods": ["GET", "PUT", "POST", "DELETE"],
"allowed_headers": ["*"],
"expose_headers": ["ETag", "x-amz-meta-*"],
"max_age_seconds": 3600
}
]
}'
CORS Rule Options
| Field | Description | Example |
|---|---|---|
allowed_origins | Domains allowed to make requests | ["https://myapp.com"] |
allowed_methods | HTTP methods allowed | ["GET", "PUT"] |
allowed_headers | Request headers allowed | ["Content-Type", "Authorization"] |
expose_headers | Response headers exposed to browser | ["ETag"] |
max_age_seconds | How long browser caches preflight | 3600 |
CORS Best Practices
- Be specific with origins: Avoid using
*in production - Limit methods: Only allow methods your app needs
- Set appropriate max_age: Balance security and performance
- Test thoroughly: Use browser dev tools to verify CORS
Presigned URLs
Generate temporary, secure URLs for sharing objects without exposing credentials.
Download URL
import boto3
s3 = boto3.client(
's3',
endpoint_url='https://s3.danubedata.ro',
aws_access_key_id='YOUR_ACCESS_KEY',
aws_secret_access_key='YOUR_SECRET_KEY'
)
# Valid for 1 hour
url = s3.generate_presigned_url(
'get_object',
Params={'Bucket': 'my-bucket', 'Key': 'secret-file.pdf'},
ExpiresIn=3600
)
Upload URL
# Generate upload URL
upload_url = s3.generate_presigned_url(
'put_object',
Params={
'Bucket': 'my-bucket',
'Key': 'uploads/user-file.txt',
'ContentType': 'text/plain'
},
ExpiresIn=3600
)
# Client can upload using:
# curl -X PUT -H "Content-Type: text/plain" --data-binary @file.txt "$upload_url"
Presigned URL Security
- Time-limited: URLs expire after the specified duration
- Operation-specific: Each URL is valid for one operation
- Cannot be revoked: Once generated, valid until expiry
- Audit trail: Track which key generated the URL
Security Best Practices
1. Principle of Least Privilege
Create separate access keys for different applications with only the permissions they need:
# Read-only key for analytics
curl -X POST .../access-keys -d '{"name": "analytics", "permissions": ["read"]}'
# Write-only key for uploads
curl -X POST .../access-keys -d '{"name": "uploader", "permissions": ["write"]}'
# Full access for backups
curl -X POST .../access-keys -d '{"name": "backup", "permissions": ["read", "write", "delete"]}'
2. Enable Versioning for Critical Data
Protect against accidental deletion or overwrites:
curl -X PATCH https://api.danubedata.ro/v1/storage/buckets/{bucket_id} \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{"versioning_enabled": true}'
3. Implement Lifecycle Rules
Automatically delete temporary files and old versions:
{
"rules": [
{
"id": "delete-temp-files",
"prefix": "temp/",
"expiration_days": 7
},
{
"id": "delete-old-versions",
"noncurrent_version_expiration_days": 30
}
]
}
4. Monitor Access Key Usage
Regularly review access keys:
- Check last-used timestamps
- Delete unused keys
- Rotate keys periodically
- Set expiration dates for temporary access
5. Use Separate Buckets for Sensitivity
Organize data by sensitivity level:
production-public- Public assets, CDN contentproduction-private- Application data, user uploadsproduction-sensitive- PII, financial data (most restricted)
6. Audit and Logging
Enable access logging to track all bucket operations:
- Who accessed what objects
- When operations occurred
- Success/failure status
- Source IP addresses
Compliance
GDPR Compliance
DanubeData Object Storage is fully GDPR compliant:
- Data residency: All data stored in Germany (EU)
- Encryption: AES-256 at rest, TLS 1.3 in transit
- Access control: Fine-grained permission management
- Data deletion: Objects can be permanently deleted
- Audit trail: Complete access logging available
Data Retention
Use lifecycle rules to implement data retention policies:
{
"rules": [
{
"id": "gdpr-retention",
"prefix": "user-data/",
"expiration_days": 365,
"noncurrent_version_expiration_days": 90
}
]
}
Troubleshooting
"Access Denied" Errors
- Verify credentials: Check access key and secret
- Check permissions: Ensure key has required permissions
- Bucket ownership: Verify key belongs to bucket's team
- Bucket policy: Check for deny rules blocking access
CORS Errors in Browser
- Check origin: Ensure your domain is in allowed_origins
- Check method: Verify HTTP method is allowed
- Check headers: Ensure required headers are allowed
- Browser cache: Clear preflight cache and retry
Presigned URL Not Working
- Check expiry: URL may have expired
- Clock sync: Ensure server clock is accurate
- URL encoding: Don't manually modify the URL
- Key revocation: Original key may have been deleted
Next Steps
- Object Storage Product Overview - Full feature documentation
- Object Storage Quick Start - Get started guide
- Lifecycle Rules Guide - Automate data management
Questions? Contact support at support@danubedata.ro