Skip to content

Commit 855b4c6

Browse files
committed
feat/support directory bucket
1 parent e23dd4f commit 855b4c6

File tree

13 files changed

+519
-0
lines changed

13 files changed

+519
-0
lines changed

examples/directory-bucket/main.tf

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
locals {
2+
region = "eu-west-1"
3+
zone_id = "euw1-az1"
4+
}
5+
6+
provider "aws" {
7+
region = local.region
8+
9+
# Make it faster by skipping something
10+
skip_metadata_api_check = true
11+
skip_region_validation = true
12+
skip_credentials_validation = true
13+
}
14+
15+
data "aws_caller_identity" "current" {}
16+
17+
module "directory_bucket" {
18+
source = "../../modules/directory-bucket"
19+
20+
bucket_name_prefix = random_pet.this.id
21+
availability_zone_id = local.zone_id
22+
23+
server_side_encryption_configuration = {
24+
sse_algorithm = "aws:kms"
25+
kms_master_key_id = aws_kms_key.objects.id
26+
}
27+
28+
lifecycle_rules = {
29+
all = {
30+
id = "test"
31+
status = "Enabled"
32+
abort_incomplete_multipart_upload = {
33+
days_after_initiation = 7
34+
}
35+
expiration = {
36+
days = 7
37+
}
38+
},
39+
logs = {
40+
status = "Enabled"
41+
expiration = {
42+
days = 5
43+
}
44+
filter = {
45+
prefix = "logs/"
46+
object_size_less_than = 10
47+
}
48+
},
49+
other = {
50+
id = "other"
51+
status = "Enabled"
52+
expiration = {
53+
days = 2
54+
}
55+
filter = {
56+
prefix = "other/"
57+
}
58+
}
59+
}
60+
61+
create_bucket_policy = true
62+
policy_statements = {
63+
write = {
64+
sid = "ReadWriteAccess"
65+
effect = "Allow"
66+
67+
actions = [
68+
"s3express:CreateSession",
69+
]
70+
71+
principals = [
72+
{
73+
type = "AWS"
74+
identifiers = [data.aws_caller_identity.current.account_id]
75+
}
76+
]
77+
}
78+
readonly = {
79+
sid = "ReadOnlyAccess"
80+
effect = "Allow"
81+
82+
actions = [
83+
"s3express:CreateSession",
84+
]
85+
86+
principals = [
87+
{
88+
type = "AWS"
89+
identifiers = [data.aws_caller_identity.current.account_id]
90+
}
91+
]
92+
93+
conditions = [
94+
{
95+
test = "StringEquals"
96+
values = ["ReadOnly"]
97+
variable = "s3express:SessionMode"
98+
}
99+
]
100+
}
101+
}
102+
}
103+
104+
resource "random_pet" "this" {
105+
length = 2
106+
}
107+
108+
resource "aws_kms_key" "objects" {
109+
description = "KMS key is used to encrypt bucket objects"
110+
deletion_window_in_days = 7
111+
}

examples/directory-bucket/outputs.tf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
output "directory_bucket_name" {
2+
description = "Name of the directory bucket."
3+
value = module.directory_bucket.directory_bucket_name
4+
}
5+
6+
output "directory_bucket_arn" {
7+
description = "ARN of the directory bucket."
8+
value = module.directory_bucket.directory_bucket_arn
9+
}

examples/directory-bucket/variables.tf

Whitespace-only changes.

examples/directory-bucket/versions.tf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
terraform {
2+
required_version = ">= 1.0"
3+
4+
required_providers {
5+
aws = {
6+
source = "hashicorp/aws"
7+
version = ">= 5.83"
8+
}
9+
random = {
10+
source = "hashicorp/random"
11+
version = ">= 2.0"
12+
}
13+
}
14+
}

modules/directory-bucket/main.tf

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
locals {
2+
bucket_name = "${var.bucket_name_prefix}--${var.availability_zone_id}--x-s3"
3+
}
4+
5+
resource "aws_s3_directory_bucket" "this" {
6+
count = var.create ? 1 : 0
7+
8+
bucket = local.bucket_name
9+
data_redundancy = var.data_redundancy
10+
force_destroy = var.force_destroy
11+
type = var.type
12+
13+
location {
14+
name = var.availability_zone_id
15+
type = var.location_type
16+
}
17+
}
18+
19+
resource "aws_s3_bucket_server_side_encryption_configuration" "this" {
20+
count = var.create && length(var.server_side_encryption_configuration) > 0 ? 1 : 0
21+
22+
bucket = aws_s3_directory_bucket.this[0].bucket
23+
24+
rule {
25+
bucket_key_enabled = true
26+
27+
apply_server_side_encryption_by_default {
28+
sse_algorithm = var.server_side_encryption_configuration.sse_algorithm
29+
kms_master_key_id = try(var.server_side_encryption_configuration.kms_master_key_id, null)
30+
}
31+
}
32+
}
33+
34+
resource "aws_s3_bucket_lifecycle_configuration" "this" {
35+
count = var.create && length(var.lifecycle_rules) > 0 ? 1 : 0
36+
37+
bucket = aws_s3_directory_bucket.this[0].bucket
38+
39+
dynamic "rule" {
40+
for_each = var.lifecycle_rules
41+
42+
content {
43+
id = try(rule.value.id, rule.key)
44+
status = try(rule.value.enabled ? "Enabled" : "Disabled", tobool(rule.value.status) ? "Enabled" : "Disabled", title(lower(rule.value.status)))
45+
46+
# Max 1 block - abort_incomplete_multipart_upload
47+
dynamic "abort_incomplete_multipart_upload" {
48+
for_each = try([rule.value.abort_incomplete_multipart_upload_days], [])
49+
50+
content {
51+
days_after_initiation = try(rule.value.abort_incomplete_multipart_upload_days, null)
52+
}
53+
}
54+
55+
# Max 1 block - expiration
56+
dynamic "expiration" {
57+
for_each = try(flatten([rule.value.expiration]), [])
58+
59+
content {
60+
days = try(expiration.value.days, null)
61+
}
62+
}
63+
64+
# Max 1 block - filter - with one key argument or a single tag
65+
dynamic "filter" {
66+
for_each = [for v in try(flatten([rule.value.filter]), []) : v if max(length(keys(v))) == 1]
67+
68+
content {
69+
object_size_greater_than = try(filter.value.object_size_greater_than, null)
70+
object_size_less_than = try(filter.value.object_size_less_than, null)
71+
prefix = try(filter.value.prefix, null)
72+
}
73+
}
74+
75+
# Max 1 block - filter - with more than one key arguments or multiple tags
76+
dynamic "filter" {
77+
for_each = [for v in try(flatten([rule.value.filter]), []) : v if max(length(keys(v))) > 1]
78+
79+
content {
80+
and {
81+
object_size_greater_than = try(filter.value.object_size_greater_than, null)
82+
object_size_less_than = try(filter.value.object_size_less_than, null)
83+
prefix = try(filter.value.prefix, null)
84+
}
85+
}
86+
}
87+
}
88+
}
89+
}
90+
91+
resource "aws_s3_bucket_policy" "this" {
92+
count = var.create && var.create_bucket_policy ? 1 : 0
93+
94+
bucket = aws_s3_directory_bucket.this[0].bucket
95+
policy = data.aws_iam_policy_document.this[0].json
96+
}
97+
98+
data "aws_iam_policy_document" "this" {
99+
count = var.create && var.create_bucket_policy ? 1 : 0
100+
101+
source_policy_documents = var.source_policy_documents
102+
override_policy_documents = var.override_policy_documents
103+
104+
dynamic "statement" {
105+
for_each = var.policy_statements
106+
107+
content {
108+
sid = try(statement.value.sid, null)
109+
actions = try(statement.value.actions, null)
110+
not_actions = try(statement.value.not_actions, null)
111+
effect = try(statement.value.effect, null)
112+
resources = try(statement.value.resources, [aws_s3_directory_bucket.this[0].arn])
113+
not_resources = try(statement.value.not_resources, null)
114+
115+
dynamic "principals" {
116+
for_each = try(statement.value.principals, [])
117+
118+
content {
119+
type = principals.value.type
120+
identifiers = principals.value.identifiers
121+
}
122+
}
123+
124+
dynamic "not_principals" {
125+
for_each = try(statement.value.not_principals, [])
126+
127+
content {
128+
type = not_principals.value.type
129+
identifiers = not_principals.value.identifiers
130+
}
131+
}
132+
133+
dynamic "condition" {
134+
for_each = try(statement.value.conditions, [])
135+
136+
content {
137+
test = condition.value.test
138+
values = condition.value.values
139+
variable = condition.value.variable
140+
}
141+
}
142+
}
143+
}
144+
}

modules/directory-bucket/outputs.tf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
output "directory_bucket_name" {
2+
description = "Name of the directory bucket."
3+
value = try(aws_s3_directory_bucket.this[0].bucket, null)
4+
}
5+
6+
output "directory_bucket_arn" {
7+
description = "ARN of the directory bucket."
8+
value = try(aws_s3_directory_bucket.this[0].arn, null)
9+
}

modules/directory-bucket/variables.tf

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
variable "create" {
2+
description = "Whether to create directory bucket resources"
3+
type = bool
4+
default = true
5+
}
6+
7+
variable "bucket_name_prefix" {
8+
description = "Bucket name prefix"
9+
type = string
10+
default = null
11+
}
12+
13+
variable "data_redundancy" {
14+
description = "Data redundancy. Valid values: `SingleAvailabilityZone`"
15+
type = string
16+
default = null
17+
}
18+
19+
variable "force_destroy" {
20+
description = "Boolean that indicates all objects should be deleted from the bucket when the bucket is destroyed so that the bucket can be destroyed without error. These objects are not recoverable"
21+
type = bool
22+
default = null
23+
}
24+
25+
variable "type" {
26+
description = "Bucket type. Valid values: `Directory`"
27+
type = string
28+
default = "Directory"
29+
}
30+
31+
variable "availability_zone_id" {
32+
description = "Availability Zone ID or Local Zone ID"
33+
type = string
34+
default = null
35+
}
36+
37+
variable "location_type" {
38+
description = "Location type. Valid values: `AvailabilityZone` or `LocalZone`"
39+
type = string
40+
default = null
41+
}
42+
43+
variable "server_side_encryption_configuration" {
44+
description = "Map containing server-side encryption configuration."
45+
type = any
46+
default = {}
47+
}
48+
49+
variable "lifecycle_rules" {
50+
description = "List of maps containing configuration of object lifecycle management."
51+
type = any
52+
default = {}
53+
}
54+
55+
variable "create_bucket_policy" {
56+
description = "Whether to create a directory bucket policy."
57+
type = bool
58+
default = false
59+
}
60+
61+
variable "source_policy_documents" {
62+
description = "List of IAM policy documents that are merged together into the exported document. Statements must have unique `sid`s"
63+
type = list(string)
64+
default = []
65+
}
66+
67+
variable "override_policy_documents" {
68+
description = "List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank `sid`s will override statements with the same `sid`"
69+
type = list(string)
70+
default = []
71+
}
72+
73+
variable "policy_statements" {
74+
description = "A map of IAM policy statements for custom permission usage"
75+
type = any
76+
default = {}
77+
}

modules/directory-bucket/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.0"
3+
4+
required_providers {
5+
aws = {
6+
source = "hashicorp/aws"
7+
version = ">= 5.83"
8+
}
9+
}
10+
}

0 commit comments

Comments
 (0)