initial commit
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
# s3_bucket_2023 module
|
||||
This module creates s3 bucket, following new terraform standards.
|
||||
|
||||
If lifecycle policy is enabled, provide the expiration days.
|
||||
Transition days are hard-coded with intelligent-tiering class to simplify administration.
|
||||
|
||||
## Example
|
||||
```hcl
|
||||
module "bucket1" {
|
||||
source = "../../../../whk1-bea-sys-ss-prd-codecommit-sharedmodules/Storage/s3_bucket_2023"
|
||||
|
||||
bucket_name = var.bucket_name1
|
||||
bucket_policy_json = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Id" : "",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "Set permissions for objects",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"AWS" : "851239346925"
|
||||
},
|
||||
"Action" : ["s3:ReplicateObject", "s3:ReplicateDelete"],
|
||||
"Resource" : "arn:aws:s3:::${var.bucket_name1}/*"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
enable_encryption = true
|
||||
encryption_key_arn = var.encryption_key_arn
|
||||
enable_versioning = false
|
||||
enable_bucket_logging = false
|
||||
enable_bucket_lifecycle = true
|
||||
current_version_expiration_days = 731
|
||||
noncurrent_version_expiration_days = 731
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Note on bucket replication
|
||||
To securely replicate a bucket to a bucket in another aws account, kms key is required.
|
||||
|
||||
Steps to setup replication are:
|
||||
1. Create replication iam role on the source account, with an assume role policy trusting s3
|
||||
```json
|
||||
{
|
||||
"Effect":"Allow",
|
||||
"Principal":{
|
||||
"Service":"s3.amazonaws.com"
|
||||
},
|
||||
"Action":"sts:AssumeRole"
|
||||
}
|
||||
```
|
||||
The role needs permissions granted in the role iam policy. For example:
|
||||
```json
|
||||
{
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"s3:ListBucket",
|
||||
"s3:GetReplicationConfiguration"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": "arn:aws:s3:::whk1-bea-icc-mbk-prd-vpc01-flowlog-s3-accept",
|
||||
"Sid": ""
|
||||
},
|
||||
{
|
||||
"Action": [
|
||||
"s3:GetObjectVersionTagging",
|
||||
"s3:GetObjectVersionForReplication",
|
||||
"s3:GetObjectVersionAcl"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": "arn:aws:s3:::whk1-bea-icc-mbk-prd-vpc01-flowlog-s3-accept/*",
|
||||
"Sid": ""
|
||||
},
|
||||
{
|
||||
"Action": [
|
||||
"s3:ReplicateTags",
|
||||
"s3:ReplicateObject",
|
||||
"s3:ReplicateDelete",
|
||||
"s3:ObjectOwnerOverrideToBucketOwner"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": "arn:aws:s3:::whk1-bea-icc-log-mbk-prd-vpc01-flowlog-s3-accept/*",
|
||||
"Sid": ""
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"kms:Decrypt",
|
||||
"kms:GenerateDataKey"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:kms:ap-east-1:851239346925:key/708b6ece-05f5-40ed-a91c-dbcf2af46407"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"kms:GenerateDataKey",
|
||||
"kms:Encrypt"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:kms:ap-east-1:894849410890:key/b555d9d6-d451-4ec8-8ca2-cb6849cadee4"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Version": "2012-10-17"
|
||||
}
|
||||
```
|
||||
If bucket key is used, then additional permission needs to be granted
|
||||
```json
|
||||
{
|
||||
"Action":[
|
||||
"kms:Decrypt"
|
||||
],
|
||||
"Effect":"Allow",
|
||||
"Condition":{
|
||||
"StringLike":{
|
||||
"kms:ViaService":"s3.ap-east-1.amazonaws.com",
|
||||
"kms:EncryptionContext:aws:s3:arn":[
|
||||
"arn:aws:s3:::<source-bucket-name>/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Resource":[
|
||||
"arn:aws:kms:ap-east-1:<source-account-id>:key/<source-account-key-id>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Action":[
|
||||
"kms:Encrypt"
|
||||
],
|
||||
"Effect":"Allow",
|
||||
"Condition":{
|
||||
"StringLike":{
|
||||
"kms:ViaService":"s3.ap-east-1.amazonaws.com",
|
||||
"kms:EncryptionContext:aws:s3:arn":[
|
||||
"arn:aws:s3:::<dest-bucket-name>/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Resource":[
|
||||
"arn:aws:kms:ap-east-1:<dest-account-id>:key/<dest-account-key-id>"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
2. On the destination account, grant access in KMS key policy
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Id": "key-consolepolicy-3",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Enable IAM User Permissions",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::<dest-account-id>:root"
|
||||
},
|
||||
"Action": "kms:*",
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Sid": "Allow use of the key",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": [
|
||||
"arn:aws:iam::<src-account-id>:root",
|
||||
"arn:aws:iam::<dest-account-id>:root"
|
||||
]
|
||||
},
|
||||
"Action": [
|
||||
"kms:Encrypt",
|
||||
"kms:Decrypt",
|
||||
"kms:ReEncrypt*",
|
||||
"kms:GenerateDataKey*",
|
||||
"kms:DescribeKey"
|
||||
],
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Sid": "Allow attachment of persistent resources",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": [
|
||||
"arn:aws:iam::<src-account-id>:root",
|
||||
"arn:aws:iam::<dest-account-id>:root"
|
||||
]
|
||||
},
|
||||
"Action": [
|
||||
"kms:CreateGrant",
|
||||
"kms:ListGrants",
|
||||
"kms:RevokeGrant"
|
||||
],
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"Bool": {
|
||||
"kms:GrantIsForAWSResource": "true"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Sid": "Allow AWS Service to use the key",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": [
|
||||
"s3.amazonaws.com",
|
||||
"delivery.logs.amazonaws.com",
|
||||
"cloudtrail.amazonaws.com"
|
||||
]
|
||||
},
|
||||
"Action": [
|
||||
"kms:Encrypt",
|
||||
"kms:Decrypt",
|
||||
"kms:ReEncrypt*",
|
||||
"kms:GenerateDataKey*",
|
||||
"kms:DescribeKey"
|
||||
],
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
3. Edit destination bucket policy
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Id": "",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Set permissions for objects",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::<src-account-id>:root"
|
||||
},
|
||||
"Action": [
|
||||
"s3:ReplicateDelete",
|
||||
"s3:ReplicateObject",
|
||||
"s3:ReplicateTags",
|
||||
"s3:ObjectOwnerOverrideToBucketOwner"
|
||||
],
|
||||
"Resource": "arn:aws:s3:::<dest-bucket-name>/*"
|
||||
},
|
||||
{
|
||||
"Sid": "Set permissions on bucket",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::<src-account-id>:root"
|
||||
},
|
||||
"Action": [
|
||||
"s3:List*",
|
||||
"s3:GetBucketVersioning",
|
||||
"s3:PutBucketVersioning"
|
||||
],
|
||||
"Resource": "arn:aws:s3:::<dest-bucket-name>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,173 @@
|
||||
resource "aws_s3_bucket" "this" {
|
||||
bucket = var.bucket_name
|
||||
force_destroy = var.bucket_force_destroy
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_public_access_block" "block_public_access" {
|
||||
bucket = aws_s3_bucket.this.id
|
||||
|
||||
block_public_acls = true
|
||||
block_public_policy = true
|
||||
ignore_public_acls = true
|
||||
restrict_public_buckets = true
|
||||
}
|
||||
|
||||
# Add SecureTransport restriction by default
|
||||
data "aws_iam_policy_document" "bucket_policy" {
|
||||
source_policy_documents = [var.bucket_policy_json]
|
||||
|
||||
statement {
|
||||
sid = "AllowSSLRequestsOnly"
|
||||
actions = ["s3:*"]
|
||||
effect = "Deny"
|
||||
principals {
|
||||
type = "*"
|
||||
identifiers = ["*"]
|
||||
}
|
||||
resources = [
|
||||
aws_s3_bucket.this.arn,
|
||||
"${aws_s3_bucket.this.arn}/*"
|
||||
]
|
||||
condition {
|
||||
test = "Bool"
|
||||
values = [false]
|
||||
variable = "aws:SecureTransport"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_policy" "bucket_policy" {
|
||||
bucket = aws_s3_bucket.this.id
|
||||
# policy = var.bucket_policy_json
|
||||
policy = data.aws_iam_policy_document.bucket_policy.json
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_lifecycle_configuration" "lifecycle" {
|
||||
count = var.enable_bucket_lifecycle ? 1 : 0
|
||||
bucket = aws_s3_bucket.this.id
|
||||
rule {
|
||||
id = "CurrentVersion"
|
||||
|
||||
expiration {
|
||||
days = var.current_version_expiration_days
|
||||
}
|
||||
|
||||
status = "Enabled"
|
||||
|
||||
transition {
|
||||
days = 15
|
||||
storage_class = "INTELLIGENT_TIERING"
|
||||
}
|
||||
}
|
||||
|
||||
rule {
|
||||
id = "NonCurrentVersion"
|
||||
|
||||
noncurrent_version_expiration {
|
||||
noncurrent_days = var.noncurrent_version_expiration_days
|
||||
}
|
||||
|
||||
noncurrent_version_transition {
|
||||
noncurrent_days = 15
|
||||
storage_class = "INTELLIGENT_TIERING"
|
||||
}
|
||||
|
||||
status = var.enable_versioning ? "Enabled" : "Disabled"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
resource "aws_s3_bucket_intelligent_tiering_configuration" "intel_tiering_config" {
|
||||
bucket = aws_s3_bucket.this.id
|
||||
name = "IntelligentTieringArchiveConfigurations"
|
||||
|
||||
tiering {
|
||||
access_tier = "DEEP_ARCHIVE_ACCESS"
|
||||
days = 180 # minimum
|
||||
}
|
||||
tiering {
|
||||
access_tier = "ARCHIVE_ACCESS"
|
||||
days = 90
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_logging" "logging" {
|
||||
count = var.enable_bucket_logging ? 1 : 0
|
||||
bucket = aws_s3_bucket.this.id
|
||||
target_bucket = var.logging_bucket_id
|
||||
target_prefix = "s3-log/"
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_server_side_encryption_configuration" "encryption" {
|
||||
count = var.enable_encryption ? 1 : 0
|
||||
bucket = aws_s3_bucket.this.id
|
||||
rule {
|
||||
apply_server_side_encryption_by_default {
|
||||
kms_master_key_id = var.encryption_key_arn
|
||||
sse_algorithm = length(var.encryption_key_arn) > 0 ? "aws:kms" : "AES256"
|
||||
}
|
||||
bucket_key_enabled = length(var.encryption_key_arn) > 0 ? true : false
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_versioning" "versioning" {
|
||||
count = var.enable_versioning ? 1 : 0
|
||||
bucket = aws_s3_bucket.this.id
|
||||
versioning_configuration {
|
||||
status = "Enabled"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_replication_configuration" "replication" {
|
||||
count = var.enable_replication && var.enable_versioning ? 1 : 0
|
||||
role = var.replication_role_arn
|
||||
bucket = aws_s3_bucket.this.id
|
||||
|
||||
|
||||
rule {
|
||||
id = "replrule1"
|
||||
status = "Enabled"
|
||||
delete_marker_replication {
|
||||
status = "Enabled"
|
||||
}
|
||||
|
||||
source_selection_criteria {
|
||||
replica_modifications {
|
||||
status = "Enabled"
|
||||
}
|
||||
sse_kms_encrypted_objects {
|
||||
status = "Enabled"
|
||||
}
|
||||
}
|
||||
|
||||
destination {
|
||||
bucket = var.replication_dest_bucket_name
|
||||
storage_class = "INTELLIGENT_TIERING"
|
||||
|
||||
account = var.replication_destination_aws_account_id
|
||||
|
||||
encryption_configuration {
|
||||
replica_kms_key_id = var.replication_destination_kms_key_arn
|
||||
}
|
||||
|
||||
access_control_translation {
|
||||
owner = "Destination"
|
||||
}
|
||||
|
||||
replication_time {
|
||||
status = "Enabled"
|
||||
time {
|
||||
minutes = 15
|
||||
}
|
||||
}
|
||||
|
||||
metrics {
|
||||
status = "Enabled"
|
||||
event_threshold {
|
||||
minutes = 15
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
output bucket_name {
|
||||
value = aws_s3_bucket.this.id
|
||||
}
|
||||
|
||||
output bucket_arn {
|
||||
value = aws_s3_bucket.this.arn
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
variable "bucket_name" {
|
||||
type = string
|
||||
description = "Name of bucket"
|
||||
}
|
||||
|
||||
variable "bucket_force_destroy" {
|
||||
type = bool
|
||||
default = false
|
||||
description = "Indicates all objects should be deleted from the bucket when the bucket is destroyed."
|
||||
}
|
||||
|
||||
variable "bucket_policy_json" {
|
||||
type = string
|
||||
default = "{}"
|
||||
description = "Json-encoded bucket policy. The AllowSSLRequestsOnly policy is merged with this input."
|
||||
}
|
||||
|
||||
variable "current_version_expiration_days" {
|
||||
type = number
|
||||
default = 2560
|
||||
description = "731 for flowlogs"
|
||||
validation {
|
||||
condition = var.current_version_expiration_days > 15
|
||||
error_message = "Must be greater than 15 days"
|
||||
}
|
||||
}
|
||||
|
||||
variable "noncurrent_version_expiration_days" {
|
||||
type = number
|
||||
default = 2560
|
||||
description = "731 for flowlogs"
|
||||
}
|
||||
|
||||
variable "enable_bucket_logging" {
|
||||
type = bool
|
||||
description = "Enable bucket logging"
|
||||
}
|
||||
variable "logging_bucket_id" {
|
||||
type = string
|
||||
default = null
|
||||
description = "Logging bucket id"
|
||||
}
|
||||
variable "enable_encryption" {
|
||||
type = bool
|
||||
description = "Enable encryption for s3 bucket"
|
||||
}
|
||||
variable "encryption_key_arn" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Leave blank to use AES256"
|
||||
}
|
||||
variable "enable_versioning" {
|
||||
type = bool
|
||||
description = "Enable s3 bucket versioning"
|
||||
}
|
||||
variable "enable_bucket_lifecycle" {
|
||||
type = bool
|
||||
description = "Enable s3 bucket lifecycle"
|
||||
}
|
||||
|
||||
variable "enable_replication" {
|
||||
type = bool
|
||||
default = false
|
||||
description = "Enable s3 bucket replication"
|
||||
}
|
||||
|
||||
variable "replication_role_arn" {
|
||||
type = string
|
||||
default = null
|
||||
description = "IAM role of s3 bucket replication"
|
||||
}
|
||||
|
||||
variable "replication_dest_bucket_name" {
|
||||
type = string
|
||||
default = null
|
||||
description = "Replica bucket name"
|
||||
}
|
||||
|
||||
variable "replication_destination_aws_account_id" {
|
||||
type = number
|
||||
default = null
|
||||
description = "AWS account id of replica bucket"
|
||||
}
|
||||
|
||||
variable "replication_destination_kms_key_arn" {
|
||||
type = string
|
||||
default = null
|
||||
description = "KMS key ARN of destination bucket"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
terraform {
|
||||
required_version = ">= 1.3.0"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 3.72.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user