Skip to content

S3 Storage

Store deployment artifacts in Amazon S3 or S3-compatible storage.

S3 storage downloads artifacts from S3 buckets:

Use CaseRecommendation
Large artifactsBinary packages, container images
Multi-regionReplicate across regions
Immutable storageVersioned artifacts
Cloud-nativeAWS infrastructure
High availabilityBuilt-in redundancy
PropertyRequiredDescription
NameYesUnique identifier for the storage
BucketYesS3 bucket name
RegionYesAWS region (e.g., us-west-2)
Path PrefixNoFolder prefix within bucket
Endpoint URLNoCustom endpoint for S3-compatible storage
Auth TypeYesAuthentication method
┌─────────────────────────────────────────────────────────────┐
│ Create S3 Storage │
├─────────────────────────────────────────────────────────────┤
│ │
│ Name * │
│ [artifacts ] │
│ │
│ Bucket * │
│ [my-deployment-artifacts ] │
│ │
│ Region * │
│ [us-west-2 ▼] │
│ │
│ Path Prefix │
│ [deployments/ ] │
│ Optional folder prefix within bucket │
│ │
│ Endpoint URL │
│ [ ] │
│ Leave empty for AWS S3, or enter custom endpoint │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ Authentication Type * │
│ ● Access Keys │
│ ○ IAM Role │
│ │
│ Access Key ID * │
│ [AKIA... ] │
│ │
│ Secret Access Key * │
│ [•••••••••••••••••• ] │
│ │
│ [Test] [Cancel] [Create] │
│ │
└─────────────────────────────────────────────────────────────┘
  1. Navigate to Storage in the sidebar (under Infrastructure)
  2. Click New Storage
  3. Click the S3 Storage tab
  4. Enter bucket and region
  5. Configure authentication
  6. Optionally test connection
  7. Click Create

S3 storage is created through POST /api/v1/storage/s3. auth_type is either static (access key ID + secret) or iam_role (STS AssumeRole via role_arn).

Terminal window
# Create S3 storage with static credentials
curl -X POST "$MANTIS_URL/api/v1/storage/s3" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"name": "artifacts",
"bucket": "my-deployment-artifacts",
"region": "us-west-2",
"path_prefix": "deployments/",
"auth_type": "static",
"access_key_id": "AKIA...",
"secret_access_key": "..."
}'
# Create with an IAM role (STS AssumeRole)
curl -X POST "$MANTIS_URL/api/v1/storage/s3" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"name": "artifacts-prod",
"bucket": "prod-artifacts",
"region": "us-east-1",
"auth_type": "iam_role",
"role_arn": "arn:aws:iam::123456789012:role/MantisS3Role"
}'

Organize artifacts within the bucket:

my-deployment-artifacts/
├── deployments/
│ └── customer-portal/
│ ├── v1.0.0/
│ │ └── app.tar.gz
│ ├── v1.1.0/
│ │ └── app.tar.gz
│ └── v1.2.0/
│ └── app.tar.gz
├── configs/
│ ├── nginx.conf
│ └── app.json
└── scripts/
└── setup.sh

Path prefix simplifies file references:

BucketPrefixFilenameFull Path
artifactsdeployments/portal/v1.0.0/app.tar.gzs3://artifacts/deployments/portal/v1.0.0/app.tar.gz
artifacts(none)deployments/portal/v1.0.0/app.tar.gzs3://artifacts/deployments/portal/v1.0.0/app.tar.gz
┌─────────────────────────────────────────────────────────────┐
│ S3 Storage: artifacts │
├─────────────────────────────────────────────────────────────┤
│ │
│ Type: S3 │
│ Bucket: my-deployment-artifacts │
│ Region: us-west-2 │
│ Prefix: deployments/ │
│ Auth Type: Access Keys │
│ Created: January 15, 2024 │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ Connection Status: ● Connected │
│ Last Tested: 2 minutes ago │
│ │
│ [Test Connection] │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ Used By (2 actions): │
│ ┌──────────────────┬──────────────────────────────────┐ │
│ │ Action │ Filename │ │
│ ├──────────────────┼──────────────────────────────────┤ │
│ │ deploy-portal │ portal/v1.2.0/app.tar.gz │ │
│ │ deploy-config │ configs/app.json │ │
│ └──────────────────┴──────────────────────────────────┘ │
│ │
│ [Edit] [Delete] │
│ │
└─────────────────────────────────────────────────────────────┘

Mantis S3 storage supports two auth_type values: static and iam_role.

Access key ID and secret access key, encrypted at rest:

Terminal window
curl -X POST "$MANTIS_URL/api/v1/storage/s3" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"name": "artifacts",
"bucket": "my-bucket",
"region": "us-west-2",
"auth_type": "static",
"access_key_id": "AKIA...",
"secret_access_key": "..."
}'

Cross-account access using an IAM role, with an optional external_id:

Terminal window
curl -X POST "$MANTIS_URL/api/v1/storage/s3" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"name": "cross-account",
"bucket": "other-account-bucket",
"region": "us-east-1",
"auth_type": "iam_role",
"role_arn": "arn:aws:iam::987654321012:role/MantisAccess",
"external_id": "mantis-external-id"
}'

Minimum IAM policy for S3 storage:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::my-deployment-artifacts",
"arn:aws:s3:::my-deployment-artifacts/*"
]
}
]
}
ActionPurpose
s3:GetObjectRead artifact files
s3:ListBucketList available artifacts

For cross-account access, configure trust relationship:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "mantis-external-id"
}
}
}
]
}
Terminal window
curl -X POST "$MANTIS_URL/api/v1/storage/s3" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"name": "minio-storage",
"bucket": "artifacts",
"region": "us-east-1",
"endpoint_url": "https://minio.example.com",
"auth_type": "static",
"access_key_id": "...",
"secret_access_key": "..."
}'
Terminal window
curl -X POST "$MANTIS_URL/api/v1/storage/s3" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"name": "do-spaces",
"bucket": "my-space",
"region": "nyc3",
"endpoint_url": "https://nyc3.digitaloceanspaces.com",
"auth_type": "static",
"access_key_id": "...",
"secret_access_key": "..."
}'
Terminal window
curl -X POST "$MANTIS_URL/api/v1/storage/s3" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"name": "r2-storage",
"bucket": "my-bucket",
"region": "auto",
"endpoint_url": "https://accountid.r2.cloudflarestorage.com",
"auth_type": "static",
"access_key_id": "...",
"secret_access_key": "..."
}'

Enable bucket versioning for artifact history:

Terminal window
# Enable versioning via AWS CLI
aws s3api put-bucket-versioning \
--bucket my-deployment-artifacts \
--versioning-configuration Status=Enabled

Automatically clean up old artifacts:

{
"Rules": [
{
"ID": "Delete old versions",
"Status": "Enabled",
"NoncurrentVersionExpiration": {
"NoncurrentDays": 90
}
}
]
}

Create storage backends per region:

Create one S3 storage source per region (each POST to /api/v1/storage/s3 with its own region and bucket):

{ "name": "artifacts-us-west", "bucket": "artifacts-us-west-2", "region": "us-west-2", "auth_type": "static", "access_key_id": "...", "secret_access_key": "..." }
{ "name": "artifacts-us-east", "bucket": "artifacts-us-east-1", "region": "us-east-1", "auth_type": "static", "access_key_id": "...", "secret_access_key": "..." }
{ "name": "artifacts-eu", "bucket": "artifacts-eu-west-1", "region": "eu-west-1", "auth_type": "static", "access_key_id": "...", "secret_access_key": "..." }

Click Test Connection to verify:

┌─────────────────────────────────────────────────────────────┐
│ Connection Test Results │
├─────────────────────────────────────────────────────────────┤
│ │
│ ● Connected in 142ms │
│ Bucket exists: Yes. Read access: Yes. │
│ │
└─────────────────────────────────────────────────────────────┘
Terminal window
# Test an S3 storage connection (by storage ID)
curl -X POST "$MANTIS_URL/api/v1/storage/s3/<storage-id>/test" \
-H "Authorization: Bearer $TOKEN"
# Output (HTTP 200):
# {
# "success": true,
# "latency_ms": 142,
# "error": null,
# "bucket_exists": true,
# "read_access": true
# }
Auth Method (auth_type)Security LevelWhen to Use
IAM Role (iam_role)HighCross-account access
Static keys (static)MediumExternal hosting

Organize by version in S3:

deployments/
├── customer-portal/
│ ├── v1.0.0/app.tar.gz
│ ├── v1.1.0/app.tar.gz
│ └── latest/app.tar.gz # Symlink or copy

Organize with meaningful prefixes:

my-bucket/
├── production/ # Production artifacts
├── staging/ # Staging artifacts
├── development/ # Development artifacts
└── shared/ # Cross-environment

Encrypt artifacts at rest:

Terminal window
# Enable default encryption on bucket
aws s3api put-bucket-encryption \
--bucket my-deployment-artifacts \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}]
}'

Use bucket policies for security:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-deployment-artifacts",
"arn:aws:s3:::my-deployment-artifacts/*"
],
"Condition": {
"Bool": { "aws:SecureTransport": "false" }
}
}
]
}

Cause: Insufficient IAM permissions

Solution:

  1. Check IAM policy has required actions
  2. Verify bucket policy allows access
  3. Confirm resource ARN is correct

Cause: Wrong bucket name or region

Solution:

  1. Verify bucket name spelling
  2. Check bucket exists in specified region
  3. Confirm account has access

Cause: Wrong or expired access keys

Solution:

  1. Regenerate access keys in AWS Console
  2. Update credentials in Mantis
  3. Check for copy/paste errors

Cause: Network or endpoint issues

Solution:

  1. Verify endpoint URL is correct
  2. Check VPC/security group settings
  3. Confirm internet access from Mantis server

Cause: Large artifacts or network latency

Solution:

  1. Use regional bucket close to Mantis server
  2. Consider artifact compression
  3. Check for bandwidth limits