Skip to content
IaC Templates

S3 Storage with ACLs

Template · Updated Jul 2026
Validated Jul 2026

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#

ParameterDescriptionDefault
bucket_nameStorage container nameNo default
access_policyBucket access policyprivate
cors_originsAllowed CORS origins[]
versioningEnable object versioningfalse
s3_endpointQuake AI S3-compatible endpoint URLhttps://object.us-east-1.rumble.cloud
s3_regionS3 region identifierus-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#

6 files. Download the zip or expand to copy any file.Download s3-storage-acl.zip
Show source (6 files)
main.tfHCL
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}/*"
      }
    ]
  })
}
variables.tfHCL
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"
}
outputs.tfHCL
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
}
versions.tfHCL
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
  }
}
terraform.tfvars.exampleHCL
# 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"
README.mdMarkdown
# 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
Provisions
Parameterized by
Variables
  • bucket_namerequired
  • access_policy="private"
  • cors_origins=[]
  • versioning=false
  • s3_endpoint="https://object.us-east-1.rumble.cloud"
  • s3_region="us-east-1"

Tearing down#

Customize this pattern#

See also#

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

Was this page helpful?