Skip to content

Commit f3cfae5

Browse files
committed
feat: Create S3 bucket and KMS key.
1 parent 7e2200e commit f3cfae5

File tree

8 files changed

+249
-0
lines changed

8 files changed

+249
-0
lines changed

data.tf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
data "aws_caller_identity" "identity" {}
2+
3+
data "aws_partition" "current" {}

locals.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
locals {
2+
bucket_name = join("-", [var.project, var.environment, var.name])
3+
kms_key_arn = var.encryption_key_arn != null ? var.encryption_key_arn : aws_kms_key.bucket["this"].arn
4+
logs_path = "/AWSLogs/${data.aws_caller_identity.identity.account_id}"
5+
}

main.tf

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
resource "aws_kms_key" "bucket" {
2+
for_each = var.encryption_key_arn != null ? toset([]) : toset(["this"])
3+
4+
description = "Encryption key for bucket ${local.bucket_name}"
5+
deletion_window_in_days = var.key_recovery_period
6+
enable_key_rotation = true
7+
policy = templatefile("${path.module}/templates/key-policy.json.tftpl", {
8+
account : data.aws_caller_identity.identity.account_id
9+
bucket : local.bucket_name
10+
partition : data.aws_partition.current.partition
11+
principals : var.allowed_principals
12+
})
13+
14+
tags = var.tags
15+
}
16+
17+
resource "aws_kms_alias" "bucket" {
18+
for_each = var.encryption_key_arn != null ? toset([]) : toset(["this"])
19+
20+
name = "alias/${local.bucket_name}"
21+
target_key_id = each.value.id
22+
}
23+
24+
module "this" {
25+
source = "boldlink/s3/aws"
26+
version = "2.6.0"
27+
28+
bucket = local.bucket_name
29+
force_destroy = var.force_delete
30+
31+
bucket_policy = templatefile("${path.module}/templates/bucket-policy.yaml.tftpl", {
32+
partition : data.aws_partition.current.partition
33+
bucket : local.bucket_name
34+
})
35+
36+
lifecycle_configuration = [{
37+
id = "state"
38+
status = "Enabled"
39+
40+
filter = {
41+
prefix = ""
42+
}
43+
44+
abort_incomplete_multipart_upload_days = var.abort_incomplete_multipart_upload_days
45+
46+
noncurrent_version_expiration = [{
47+
noncurrent_days = var.noncurrent_version_expiration_days
48+
}]
49+
50+
transition = var.storage_class_transitions
51+
}]
52+
53+
sse_bucket_key_enabled = true
54+
sse_kms_master_key_arn = local.kms_key_arn
55+
sse_sse_algorithm = "aws:kms"
56+
57+
versioning_status = "Enabled"
58+
59+
s3_logging = {
60+
target_bucket = var.logging_bucket
61+
target_prefix = "${local.logs_path}/s3accesslogs/${local.bucket_name}"
62+
}
63+
64+
tags = var.tags
65+
}

outputs.tf

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
output "bucket_name" {
2+
description = "Name of the created bucket."
3+
value = module.this.bucket
4+
}
5+
6+
output "bucket_arn" {
7+
description = "ARN of the created bucket."
8+
value = module.this.arn
9+
}
10+
11+
output "bucket_domain_name" {
12+
description = "Domain name of the created bucket."
13+
value = module.this.bucket_domain_name
14+
}
15+
16+
output "kms_key_arn" {
17+
description = "ARN of the KMS key used for bucket encryption."
18+
value = local.kms_key_arn
19+
}

templates/bucket-policy.yaml.tftpl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Version: "2012-10-17"
2+
Statement:
3+
- Sid: AllowSSLRequestsOnly
4+
Effect: Deny
5+
Principal: "*"
6+
Action:
7+
- s3:*
8+
Resource:
9+
- arn:${partition}:s3:::${bucket}
10+
- arn:${partition}:s3:::${bucket}/*
11+
Condition:
12+
Bool:
13+
aws:SecureTransport: false

templates/key-policy.yaml.tftpl

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Version: "2012-10-17"
2+
Statement:
3+
- Sid: Enable IAM User Permissions
4+
Effect: Allow
5+
Principal:
6+
AWS: arn:${partition}:iam::${account}:root
7+
Action: kms:*
8+
Resource: "*"
9+
- Sid: Allow S3 to encrypt and decrypt objects
10+
Effect: Allow
11+
Principal:
12+
AWS: "*"
13+
Action:
14+
- kms:Decrypt
15+
- kms:Encrypt
16+
- kms:GenerateDataKey
17+
- kms:ReEncrypt*
18+
Resource: "*"
19+
Condition:
20+
StringLike:
21+
kms:CallerAccount: "${account}"
22+
kms:EncryptionContext:aws:s3:arn:
23+
- "arn:${partition}:s3:::${bucket}"
24+
- "arn:${partition}:s3:::${bucket}/*"
25+
{% if length(principals) > 0 }
26+
- Sid: Allow other resources to use the key
27+
Effect: Allow
28+
Principal:
29+
AWS:
30+
{% for principal in principals }
31+
- "${principal}"
32+
%{ endfor }
33+
Action:
34+
- kms:GenerateDataKey
35+
- kms:Decrypt
36+
{% endif }

variables.tf

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
variable "abort_incomplete_multipart_upload_days" {
2+
type = number
3+
description = "Number of days to abort incomplete multipart uploads."
4+
default = 7
5+
6+
validation {
7+
condition = var.abort_incomplete_multipart_upload_days > 0
8+
error_message = "Abort incomplete multipart upload days must be greater than 0."
9+
}
10+
}
11+
12+
variable "allowed_principals" {
13+
type = list(string)
14+
description = <<-EOT
15+
List of AWS principal ARNs to allow to use the KMS key. This is used to
16+
grant access to other resources that need to use the key, such as ECS task
17+
roles.
18+
EOT
19+
}
20+
21+
variable "encryption_key_arn" {
22+
type = string
23+
description = "ARN of the KMS key to use for S3 bucket encryption. If not provided, a new KMS key will be created."
24+
default = null
25+
}
26+
27+
variable "environment" {
28+
type = string
29+
description = "The environment for the deployment."
30+
default = "development"
31+
}
32+
33+
variable "force_delete" {
34+
type = bool
35+
description = "Whether to force delete the bucket and its contents."
36+
default = false
37+
}
38+
39+
variable "key_recovery_period" {
40+
type = number
41+
description = "Number of days to recover the created KMS key after deletion. Must be between 7 and 30."
42+
default = 30
43+
44+
validation {
45+
condition = var.key_recovery_period > 6 && var.key_recovery_period < 31
46+
error_message = "Key recovery period must be between 7 and 30."
47+
}
48+
}
49+
50+
variable "logging_bucket" {
51+
type = string
52+
description = "S3 bucket to send access logs to."
53+
}
54+
55+
variable "name" {
56+
type = string
57+
description = "Name of the bucket. The project and environment will be prepended to this automatically."
58+
}
59+
60+
variable "noncurrent_version_expiration_days" {
61+
type = number
62+
description = "Number of days to expire noncurrent versions of objects."
63+
default = 30
64+
65+
validation {
66+
condition = var.noncurrent_version_expiration_days > 0
67+
error_message = "Noncurrent version expiration days must be greater than 0."
68+
}
69+
70+
validation {
71+
condition = var.noncurrent_version_expiration_days <= var.abort_incomplete_multipart_upload_days
72+
error_message = "Noncurrent version expiration days must be less than or equal to the abort incomplete multipart upload days."
73+
}
74+
}
75+
76+
variable "storage_class_transitions" {
77+
type = list(object({
78+
days = number
79+
storage_class = string
80+
}))
81+
82+
description = "List of storage class transitions to apply to the bucket."
83+
default = [{
84+
days = 30
85+
storage_class = "STANDARD_IA"
86+
}]
87+
}
88+
89+
variable "project" {
90+
type = string
91+
description = "Project that these resources are supporting."
92+
}
93+
94+
variable "tags" {
95+
type = map(string)
96+
description = "Optional tags to be applied to all resources."
97+
default = {}
98+
}

versions.tf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
terraform {
2+
required_version = ">= 1.10"
3+
4+
required_providers {
5+
aws = {
6+
source = "hashicorp/aws"
7+
version = ">= 6.28"
8+
}
9+
}
10+
}

0 commit comments

Comments
 (0)