Linode Object Storage Bucket
S3-compatible bucket with scoped access keys, versioning, lifecycle rules, and optional static-site hosting.
Verification
Plan-validatedPassed: module logic verified on a mocked plan — inputs, validation rules, conditional creation and outputs resolve (no real provider, no cloud).
Conformance
- Static validation (fmt · validate · tflint)
- Security scan: findings disclosed (Checkov)
- Plan tests (mocked: validation rules · outputs)
Provenance
- SHA-256 checksum
- Signature (pending)
Functional
- Live test pending (no cloud run yet)
Last verified 2026-06-28 · how we verify
Documentation
linode-object-storage
S3-compatible Linode Object Storage bucket — private and versioned by
default — with optional lifecycle rules, custom-domain TLS, and a
least-privilege access key scoped to just this bucket. Works with Terraform
and OpenTofu (>= 1.6), Linode provider >= 3.14, < 4.0.
Status: static-validated, live-test pending. This module ships under live-test quarantine: it has passed
tofu fmt,tofu validate, andtflint, but the real apply → verify → destroy gate is pending a Linode Object Storage sandbox (the service is a flat $5/mo while enabled). Treat the secure defaults below as the contract.
Design & secure defaults
- Private by default.
acl = "private"— no anonymous access. Thepublic-read-writecanned ACL (anonymous write to anyone) is rejected by variable validation outright. - Versioning on by default for data protection, paired with an optional
noncurrent_version_expiration_dayslifecycle rule so old versions don't accumulate cost unbounded. - Least-privilege key. The generated
linode_object_storage_keyis scoped with abucket_accessblock to this bucket only — not an account-wide key. Permission defaults toread_write; setread_onlyfor consumers. Thesecret_keyoutput issensitiveand is only returned at create time. - CORS off unless you opt in (
cors_enabled = true), and even then prefer a narrow per-origin policy via the S3 API for production browser apps. - Custom-domain TLS via the optional
certblock (PEM cert + key, keptsensitive) so a public bucket can be served over HTTPS on your domain.
Usage
module "bucket" {
source = "./linode-object-storage"
label = "acme-prod-assets"
region = "us-ord-1"
lifecycle_rules = {
expire-tmp = {
prefix = "tmp/"
expiration_days = 7
}
prune-old-versions = {
noncurrent_version_expiration_days = 30
}
}
}
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
label | string | — | Bucket name, 3-63 chars, S3 naming rules (required) |
region | string | — | Object Storage region slug, e.g. us-ord-1 (required) |
acl | string | "private" | Canned ACL (private/public-read/authenticated-read) |
versioning | bool | true | Enable object versioning |
cors_enabled | bool | false | Enable permissive (all-origin) CORS |
lifecycle_rules | map(object) | {} | Rule id => { enabled, prefix, abort_incomplete_multipart_upload_days, expiration_days, expiration_date, expired_object_delete_marker, noncurrent_version_expiration_days } |
cert | object | null | { certificate, private_key } PEM for custom-domain HTTPS (sensitive) |
create_access_key | bool | true | Create a scoped Object Storage key |
access_key_label | string | null | Key label (defaults to <label>-key) |
access_key_permissions | string | "read_write" | read_only or read_write |
Outputs
| Name | Description |
|---|---|
bucket_label | Bucket label/name |
bucket_id | Resource ID (region:label) |
region | Object Storage region |
hostname | Bucket hostname |
s3_endpoint | S3-compatible endpoint URL |
endpoint_type | S3 endpoint type |
access_key_id | Access key ID (or null) |
secret_key | Secret key (sensitive, or null) |
Requirements
- Terraform or OpenTofu
>= 1.6 linode/linodeprovider>= 3.14, < 4.0- Object Storage must be enabled on the account (a flat $5/mo while active).
- The provider's
acl/versioning/lifecycle_rulefeatures use the S3 API under the hood and require object-storage-scoped credentials (the provider token, oraccess_key/secret_keyon the provider). - Destroy must empty the bucket first — Linode does not force-delete a
non-empty bucket, and the provider has no
force_destroyflag. Empty the bucket (e.g. vias3tooling) beforedestroy. - "Static-site hosting" is the standard S3 convention (upload an
index.html/error.htmland serve from the bucket's public endpoint); it is not a separate Terraform argument on this resource.
License
Commercial — LicenseRef-IaCBazaar-Commercial. © IaC Bazaar. Original work
(not derived from a third-party module).