S3 Storage with ACLs
S3 storage with ACLs
This pattern composes Object Storage.
What this template does#
Provisions an S3-compatible object storage bucket with credentials and access policies:
- Object storage container with configurable access policy
- S3 credentials (access key + secret key) for programmatic access
- Bucket policy for read/write or read-only access patterns
- CORS configuration for web application access
Parameters#
| Parameter | Description | Default |
|---|---|---|
bucket_name | Storage container name | No default |
access_policy | Bucket access policy | private |
cors_origins | Allowed CORS origins | [] |
versioning | Enable object versioning | false |
s3_endpoint | Quake AI S3-compatible endpoint URL | https://object.us-east-1.rumble.cloud |
s3_region | S3 region identifier | us-east-1 |
When to use this pattern#
Create an S3-compatible bucket with a canned ACL through the AWS provider. Choose compute-backed patterns when the workload needs VMs; this pattern covers object storage only.
Estimated cost#
Template source#
Show source (6 files)Hide source
resource "aws_s3_bucket" "this" {
bucket = var.bucket_name
}
resource "aws_s3_bucket_acl" "this" {
bucket = aws_s3_bucket.this.id
acl = var.access_policy
}
resource "aws_s3_bucket_versioning" "this" {
bucket = aws_s3_bucket.this.id
versioning_configuration {
status = var.versioning ? "Enabled" : "Suspended"
}
}
resource "aws_s3_bucket_cors_configuration" "this" {
count = length(var.cors_origins) > 0 ? 1 : 0
bucket = aws_s3_bucket.this.id
cors_rule {
allowed_headers = ["*"]
allowed_methods = ["GET", "PUT", "POST"]
allowed_origins = var.cors_origins
max_age_seconds = 3600
}
}
resource "aws_s3_bucket_policy" "read_only" {
count = var.access_policy == "public-read" ? 1 : 0
bucket = aws_s3_bucket.this.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "PublicReadGetObject"
Effect = "Allow"
Principal = "*"
Action = "s3:GetObject"
Resource = "${aws_s3_bucket.this.arn}/*"
}
]
})
}
variable "bucket_name" {
description = "Storage container name"
type = string
}
variable "access_policy" {
description = "Bucket access policy (private, public-read, public-read-write)"
type = string
default = "private"
}
variable "cors_origins" {
description = "Allowed CORS origins"
type = list(string)
default = []
}
variable "versioning" {
description = "Enable object versioning"
type = bool
default = false
}
variable "s3_endpoint" {
description = "Quake AI S3-compatible endpoint URL"
type = string
default = "https://object.us-east-1.rumble.cloud"
}
variable "s3_region" {
description = "S3 region identifier"
type = string
default = "us-east-1"
}
output "bucket_name" {
description = "Name of the created bucket"
value = aws_s3_bucket.this.id
}
output "bucket_arn" {
description = "ARN of the created bucket"
value = aws_s3_bucket.this.arn
}
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.s3_region
skip_credentials_validation = true
skip_metadata_api_check = true
skip_requesting_account_id = true
endpoints {
s3 = var.s3_endpoint
}
}
# Required
bucket_name = "YOUR_BUCKET_NAME"
# access_policy = "private"
# cors_origins = []
# versioning = false
# s3_endpoint = "https://object.us-east-1.rumble.cloud"
# s3_region = "us-east-1"
# S3 Storage ACL
S3-compatible object storage bucket with access policies, optional versioning, and optional CORS configuration for Quake AI object storage.
## Prerequisites
- OpenTofu >= 1.6.0 or Terraform >= 1.6.0
- Quake AI EC2-compatible credentials for the HashiCorp AWS provider. See [Credential bootstrap](#credential-bootstrap) for how to mint and export them; the template will not run without them.
## Credential bootstrap
The AWS provider needs EC2-compat credentials issued by Keystone. The Quake AI OpenStack application credential is a separate credential type and will not satisfy the AWS provider. Create an EC2-compat pair and export the standard AWS variables before running `tofu plan`:
```bash
openstack ec2 credentials create
# Capture the `access` and `secret` values from the output table.
export AWS_ACCESS_KEY_ID=<access>
export AWS_SECRET_ACCESS_KEY=<secret>
export AWS_ENDPOINT_URL_S3=https://object.us-east-1.rumble.cloud
```
The EC2 credential is project-scoped. Rotate it like any AWS access key; revoke with `openstack ec2 credentials delete <access>`.
## Usage
1. Clone or copy this template directory
2. Copy `terraform.tfvars.example` to `terraform.tfvars` and fill in your values
3. Complete the [Credential bootstrap](#credential-bootstrap) so `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_ENDPOINT_URL_S3` are exported in your shell
4. Initialize: `tofu init`
5. Preview: `tofu plan`
6. Apply: `tofu apply`
## Variables
| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `bucket_name` | string | yes | n/a | Storage container (bucket) name |
| `access_policy` | string | no | `private` | Bucket ACL (`private`, `public-read`, `public-read-write`) |
| `cors_origins` | list(string) | no | `[]` | Allowed CORS origins (empty disables CORS resource) |
| `versioning` | bool | no | `false` | Enable object versioning |
| `s3_endpoint` | string | no | `https://object.us-east-1.rumble.cloud` | S3-compatible endpoint URL |
| `s3_region` | string | no | `us-east-1` | Region identifier passed to the provider |
## Documentation
Full documentation: [S3 storage ACL template](/docs/automation/templates/s3-storage-acl)
<!-- last_validated: 2026-05-19 -->
Resources, parameters, and variables
bucket_namerequiredaccess_policy="private"cors_origins=[]versioning=falses3_endpoint="https://object.us-east-1.rumble.cloud"s3_region="us-east-1"
Tearing down#
Customize this pattern#
See also#
- Deploy the S3 Storage with ACLs template with OpenTofu: end-to-end tutorial for this template
- Object Storage overview
- S3 credentials
Usage Guidelines
The sample code, software libraries, command line tools, proofs of concept, templates, and other related technology on this page (including any of the foregoing that is provided by Quake AI personnel) is provided to you as Quake AI Content under the Quake AI Customer Agreement, or the relevant written agreement between you and Quake AI (whichever applies). Do not use this Quake AI Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the Quake AI Content (such as sample code) as appropriate for production grade use based on your specific quality control practices and standards. Deploying Quake AI Content may incur Quake AI charges for creating or using Quake AI chargeable resources, such as running Compute instances or storing data in Object Storage. Your use is also subject to the Acceptable Use Policy.
For the full policy, see Usage Guidelines.
Last validated: 07.07.2026