@c6fc/spellcraft-aws-s3
v2.0.0
Published
Secure-by-default S3 bucket factory. Encryption, ownership and public-access blocks are on unless you opt out.
Readme
@c6fc/spellcraft-aws-s3
Secure-by-default S3 buckets for SpellCraft, in one line of Jsonnet.
Pure Jsonnet — no native functions of its own. It composes the fourteen-odd Terraform resources a properly configured bucket actually needs, and asks you only for what differs from a sensible default.
npm install --save @c6fc/spellcraft-aws-s3 @c6fc/spellcraft-aws-terraformA complete spell
Buckets are bound to a regional provider alias, so a spell declares its
providers once and every resource-producing plugin uses them. providerAliases()
builds the whole set from your live account:
local aws = import "@c6fc/spellcraft-aws-terraform/module.libsonnet";
local s3 = import "@c6fc/spellcraft-aws-s3/module.libsonnet";
{
"providers.tf.json": {
provider: aws.providerAliases("us-east-1"),
},
// Defaults only: KMS-encrypted, public access blocked, TLS 1.2 enforced.
"buckets.tf.json": s3.bucket("artifacts", "us-west-2")
// A public static site.
+ s3.bucket("site", "us-west-2", { type: "static-site" })
// Versioning on, and a couple of defaults relaxed.
+ s3.bucket("scratch", "eu-west-1", {
versioning: "Enabled",
server_side_encryption: false,
}),
}providerAliases("us-east-1") emits an aliased aws provider for every region
your credentials can see, plus an unaliased default for the region you name. The
second argument to bucket() picks which alias its resources bind to.
The same shape applies on GCP with @c6fc/spellcraft-gcp-terraform.
Bucket names
The first argument is the Terraform resource key, and the bucket is created
with bucket_prefix rather than a literal name — so s3.bucket("artifacts", ...)
deploys a bucket called artifacts-<suffix>, with the suffix generated by AWS.
S3 bucket names are globally unique across every AWS account, and this keeps that from being something you negotiate by hand. Reference the real name from Terraform the usual way:
{ value: "${aws_s3_bucket.artifacts.id}" }Defaults
With no options at all, a bucket gets:
- server-side encryption with its own customer-managed KMS key, rotation enabled
- all four public access blocks on
- a bucket policy denying any request below TLS 1.2
BucketOwnerEnforcedobject ownership- bucket owner as request payer
- versioning disabled
Resources beyond the bucket are only emitted when the corresponding option is set, so a default bucket produces eight resources rather than every one the module knows how to build.
Types
type selects a preset. Options you pass alongside it win over the preset.
static-site
Public-readable website hosting: public_access_block: false,
server_side_encryption: false, website: true, and a policy statement allowing
s3:GetObject to any principal.
log-storage
A destination for S3 access logs: acl: "log-delivery-write" with
object_ownership: "ObjectWriter". Both are needed — a canned ACL is ignored
entirely under BucketOwnerEnforced, so the ownership change is what makes the
ACL take effect.
API Reference
bucket(name, region, options = {})
Builds a secure-by-default S3 bucket and its supporting resources.
Returns a { resource: { ... } } object, so it can be a whole .tf.json
file on its own or merged with + alongside other resources.
With no options you get a KMS-encrypted bucket with its own customer-managed
key and rotation enabled, all four public access blocks on, a policy that
denies any request below TLS 1.2, BucketOwnerEnforced ownership, and
versioning disabled. Pass a type for a common preset, or any option below
to override one default. Anything not recognised as an option is passed
straight through as an attribute of aws_s3_bucket.
name is the Terraform resource key, not the bucket name: the bucket is
created with bucket_prefix, so its deployed name is <name>-<suffix> with
a suffix AWS generates. That keeps the globally-unique S3 namespace from
being something you have to negotiate by hand.
Every resource is bound to provider: "aws.<region>", so the spell needs
matching provider aliases — see providerAliases() in
@c6fc/spellcraft-aws-terraform.
- param {string} name - the Terraform resource key, and the bucket's name prefix
- param {string} region - the region alias to bind every resource to
- param {object} [options={}] - overrides; see the option reference in the README
- returns {object} a Terraform
resourceblock
Examples:
local s3 = import "@c6fc/spellcraft-aws-s3/module.libsonnet";
{ "buckets.tf.json": s3.bucket("artifacts", "us-west-2") }local s3 = import "@c6fc/spellcraft-aws-s3/module.libsonnet";
// A public static site, and a log bucket that can receive delivery writes.
{
"site.tf.json": s3.bucket("site", "us-west-2", { type: "static-site" })
+ s3.bucket("logs", "us-west-2", { type: "log-storage" }),
}Options
Anything not listed here is passed straight through as an attribute of
aws_s3_bucket.
acceleration_status (default: false)
Transfer acceleration. Allowed: Enabled, Suspended.
acl (default: false)
A canned ACL. Only takes effect when object_ownership is not
BucketOwnerEnforced.
allow_insecure_access (default: false)
Set true to omit the policy statement that denies requests below TLS 1.2 — in
other words, to permit plain HTTP.
cors_rule (default: [])
An array of CORS rules. See aws_s3_bucket_cors_configuration.
lifecycle_rule (default: [])
An array of lifecycle rules. See aws_s3_bucket_lifecycle_configuration.
logging (default: "")
The name (not ARN) of a bucket to deliver access logs to. Objects are
prefixed <account-id>/<name>-.
object_lock_configuration (default: [])
An array of object lock rules. See aws_s3_bucket_object_lock_configuration.
object_ownership (default: "BucketOwnerEnforced")
Allowed: BucketOwnerEnforced, BucketOwnerPreferred, ObjectWriter.
policy_statements (default: [])
An array of IAM policy statements for the bucket policy, written as IAM accepts
them — not Terraform's policy objects. Merged with the TLS deny statement unless
allow_insecure_access is set.
public_access_block (default: true)
Sets all four public access block settings together.
replication_configuration (default: {})
A complete replication configuration — an object carrying role (the ARN of the
IAM role S3 assumes) and rule. Passed through whole, because the resource needs
both. See
aws_s3_bucket_replication_configuration.
Replication requires versioning enabled on both the source and destination
buckets.
s3.bucket("replicated", "us-west-2", {
versioning: "Enabled",
replication_configuration: {
role: "${aws_iam_role.replication.arn}",
rule: [{
id: "everything",
status: "Enabled",
destination: { bucket: "${aws_s3_bucket.backup.arn}" },
}],
},
})request_payer (default: "BucketOwner")
Allowed: BucketOwner, Requester.
server_side_encryption (default: true)
When true, provisions a dedicated KMS customer-managed key and encrypts with it.
Set false for no SSE configuration.
versioning (default: "Disabled")
Allowed: Enabled, Suspended, Disabled.
website (default: {})
true for a default configuration of index.html and error.html, or an
aws_s3_bucket_website_configuration
object for anything else.
Development
npm test # renders test.jsonnet through a real SpellFrame
npm run doc # regenerates the API section above from module.libsonnetnpm test needs AWS credentials — the module resolves your account ID at
evaluation time for the KMS key policy — but it is read-only and creates nothing.
License
MIT © Brad Woodward
