initial commit
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
data "aws_caller_identity" "this" {}
|
||||
|
||||
resource "aws_backup_vault" "AbVault" {
|
||||
for_each = var.vaults
|
||||
name = each.key
|
||||
kms_key_arn = each.value.kms_key_arn
|
||||
}
|
||||
|
||||
resource "aws_backup_vault_policy" "AbPolicy" {
|
||||
for_each = aws_backup_vault.AbVault
|
||||
backup_vault_name = each.value
|
||||
policy = var.policy != null ? var.policy : jsonencode({
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "DefaultAwsBackupPolicy"
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"AWS" : data.aws_caller_identity.this.account_id
|
||||
},
|
||||
"Action" : [
|
||||
"backup:*"
|
||||
],
|
||||
"Resource" : "*"
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_backup_plan" "plan" {
|
||||
for_each = var.plans
|
||||
name = each.key
|
||||
dynamic "rule" {
|
||||
for_each = var.plans
|
||||
content {
|
||||
rule_name = rule.value.rule.rule_name
|
||||
schedule = rule.value.rule.schedule
|
||||
target_vault_name = rule.value.rule.target_vault_name
|
||||
dynamic "lifecycle" {
|
||||
for_each = rule.value.rule.lifecycle
|
||||
content {
|
||||
cold_storage_after = lifecycle.value.cold_storage_after
|
||||
delete_after = lifecycle.value.delete_after
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_backup_selection" "AbSelection" {
|
||||
for_each = var.selections
|
||||
name = each.key
|
||||
iam_role_arn = each.value.iam_role_arn
|
||||
plan_id = each.value.plan_id
|
||||
|
||||
dynamic "selection_tag" {
|
||||
for_each = each.value.selection_tags
|
||||
content {
|
||||
type = selection_tag.value.type
|
||||
key = selection_tag.value.key
|
||||
value = selection_tag.value.value
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
variable "vaults" {
|
||||
type = object({
|
||||
kms_key_arn = string
|
||||
})
|
||||
description = "Map of vaults"
|
||||
}
|
||||
|
||||
variable "policy" {
|
||||
type = string
|
||||
description = "Json encoded policy"
|
||||
}
|
||||
|
||||
variable "plans" {
|
||||
type = object({
|
||||
rule = object({
|
||||
rule_name = string
|
||||
schedule = string
|
||||
target_vault_name = string
|
||||
lifecycle = object({
|
||||
cold_storage_after = number
|
||||
delete_after = number
|
||||
})
|
||||
})
|
||||
})
|
||||
description = "Backup plans"
|
||||
}
|
||||
|
||||
variable "selections" {
|
||||
type = object({
|
||||
iam_role_arn = string
|
||||
plan_id = string
|
||||
selection_tags = object({
|
||||
type = string
|
||||
key = string
|
||||
value = string
|
||||
})
|
||||
})
|
||||
description = "Backup selections"
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<!-- This readme file is generated with terraform-docs -->
|
||||
# S3LbAccessLog
|
||||
Module to create s3 bucket for LB access logging. Bucket policy is automatically set
|
||||
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| terraform | >= 1.3.0 |
|
||||
| aws | ~> 5.0 |
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| aws | ~> 5.0 |
|
||||
|
||||
## Modules
|
||||
|
||||
No modules.
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
|
||||
| [aws_s3_bucket_lifecycle_configuration.lifecycle](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource |
|
||||
| [aws_s3_bucket_policy.bucket_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |
|
||||
| [aws_s3_bucket_public_access_block.block_public_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |
|
||||
| [aws_s3_bucket_server_side_encryption_configuration.encryption](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |
|
||||
| [aws_iam_policy_document.bucket_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
|
||||
| [aws_region.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:--------:|
|
||||
| bucket\_name | Name of bucket | `string` | n/a | yes |
|
||||
| current\_version\_expiration\_days | Delete logs after days - default 30 | `number` | `30` | no |
|
||||
| enable\_bucket\_lifecycle | Enable s3 bucket lifecycle | `bool` | `true` | no |
|
||||
| encryption\_key\_arn | Leave blank to use AES256 | `string` | `""` | no |
|
||||
| region\_account\_map | AWS account id from which LB logs are produced | `map(string)` | <pre>{<br> "af-south-1": "098369216593",<br> "ap-east-1": "754344448648",<br> "ap-northeast-1": "582318560864",<br> "ap-northeast-2": "600734575887",<br> "ap-northeast-3": "383597477331",<br> "ap-south-1": "718504428378",<br> "ap-southeast-1": "114774131450",<br> "ap-southeast-2": "783225319266",<br> "ap-southeast-3": "589379963580",<br> "ca-central-1": "985666609251",<br> "eu-central-1": "054676820928",<br> "eu-north-1": "897822967062",<br> "eu-south-1": "635631232127",<br> "eu-west-1": "156460612806",<br> "eu-west-2": "652711504416",<br> "eu-west-3": "009996457667",<br> "me-south-1": "076674570225",<br> "sa-east-1": "507241528517",<br> "us-east-1": "127311923021",<br> "us-east-2": "033677994240",<br> "us-west-1": "027434742980",<br> "us-west-2": "797873946194"<br>}</pre> | no |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| bucket\_arn | n/a |
|
||||
| bucket\_name | n/a |
|
||||
|
||||
---
|
||||
## Authorship
|
||||
This module was developed by xpk.
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* # S3LbAccessLog
|
||||
* Module to create s3 bucket for LB access logging. Bucket policy is automatically set
|
||||
*/
|
||||
|
||||
resource "aws_s3_bucket" "this" {
|
||||
bucket = var.bucket_name
|
||||
force_destroy = true
|
||||
}
|
||||
|
||||
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_region" "this" {}
|
||||
|
||||
data "aws_iam_policy_document" "bucket_policy" {
|
||||
# Regions created before 2022
|
||||
dynamic "statement" {
|
||||
for_each = can(var.region_account_map[data.aws_region.this.id]) ? [1] : []
|
||||
content {
|
||||
sid = "AllowLbWrite_Pre2022Region"
|
||||
actions = ["s3:PutObject", "s3:GetBucketAcl"]
|
||||
effect = "Allow"
|
||||
principals {
|
||||
identifiers = [
|
||||
var.region_account_map[data.aws_region.this.id]
|
||||
]
|
||||
type = "AWS"
|
||||
}
|
||||
resources = [
|
||||
aws_s3_bucket.this.arn,
|
||||
"${aws_s3_bucket.this.arn}/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# regions created after 2022
|
||||
dynamic "statement" {
|
||||
for_each = can(var.region_account_map[data.aws_region.this.id]) ? [] : [1]
|
||||
content {
|
||||
sid = "AllowLbWrite_Post2022Region"
|
||||
actions = ["s3:PutObject", "s3:GetBucketAcl"]
|
||||
effect = "Allow"
|
||||
principals {
|
||||
identifiers = ["logdelivery.elasticloadbalancing.amazonaws.com"]
|
||||
type = "Service"
|
||||
}
|
||||
resources = [
|
||||
aws_s3_bucket.this.arn,
|
||||
"${aws_s3_bucket.this.arn}/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Sets up bucket policy referencing AWS doc
|
||||
# https://docs.aws.amazon.com/elasticloadbalancing/latest/application/enable-access-logging.html
|
||||
resource "aws_s3_bucket_policy" "bucket_policy" {
|
||||
bucket = aws_s3_bucket.this.id
|
||||
policy = data.aws_iam_policy_document.bucket_policy.json
|
||||
}
|
||||
|
||||
# Sets up bucket retention
|
||||
resource "aws_s3_bucket_lifecycle_configuration" "lifecycle" {
|
||||
count = var.enable_bucket_lifecycle ? 1 : 0
|
||||
bucket = aws_s3_bucket.this.id
|
||||
rule {
|
||||
id = "ExpireAfterRetention"
|
||||
|
||||
filter {}
|
||||
|
||||
expiration {
|
||||
days = var.current_version_expiration_days
|
||||
}
|
||||
|
||||
status = "Enabled"
|
||||
}
|
||||
}
|
||||
|
||||
# Enable encryption by default
|
||||
resource "aws_s3_bucket_server_side_encryption_configuration" "encryption" {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,52 @@
|
||||
variable "bucket_name" {
|
||||
type = string
|
||||
description = "Name of bucket"
|
||||
}
|
||||
|
||||
variable "current_version_expiration_days" {
|
||||
type = number
|
||||
default = 30
|
||||
description = "Delete logs after days - default 30"
|
||||
}
|
||||
|
||||
variable "encryption_key_arn" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Leave blank to use AES256"
|
||||
}
|
||||
|
||||
variable "enable_bucket_lifecycle" {
|
||||
type = bool
|
||||
description = "Enable s3 bucket lifecycle"
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "region_account_map" {
|
||||
type = map(string)
|
||||
description = "AWS account id from which LB logs are produced"
|
||||
default = {
|
||||
us-east-1 = "127311923021"
|
||||
us-east-2 = "033677994240"
|
||||
us-west-1 = "027434742980"
|
||||
us-west-2 = "797873946194"
|
||||
af-south-1 = "098369216593"
|
||||
ap-east-1 = "754344448648"
|
||||
ap-southeast-3 = "589379963580"
|
||||
ap-south-1 = "718504428378"
|
||||
ap-northeast-3 = "383597477331"
|
||||
ap-northeast-2 = "600734575887"
|
||||
ap-southeast-1 = "114774131450"
|
||||
ap-southeast-2 = "783225319266"
|
||||
ap-northeast-1 = "582318560864"
|
||||
ca-central-1 = "985666609251"
|
||||
eu-central-1 = "054676820928"
|
||||
eu-west-1 = "156460612806"
|
||||
eu-west-2 = "652711504416"
|
||||
eu-south-1 = "635631232127"
|
||||
eu-west-3 = "009996457667"
|
||||
eu-north-1 = "897822967062"
|
||||
me-south-1 = "076674570225"
|
||||
sa-east-1 = "507241528517"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = ">= 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<!-- This readme file is generated with terraform-docs -->
|
||||
## Requirements
|
||||
|
||||
No requirements.
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| aws | n/a |
|
||||
|
||||
## Modules
|
||||
|
||||
No modules.
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_backup_plan.ab-plan](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_plan) | resource |
|
||||
| [aws_backup_region_settings.ab-settings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_region_settings) | resource |
|
||||
| [aws_backup_selection.ab-selection-by-service-type](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_selection) | resource |
|
||||
| [aws_backup_vault.ab-vault](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_vault) | resource |
|
||||
| [aws_backup_vault_policy.ab-vault-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_vault_policy) | resource |
|
||||
| [aws_iam_role.ab-iam-role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
|
||||
| [aws_iam_role_policy_attachment.ab-iam-role-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
|
||||
| [aws_kms_alias.ab-kms-key-alias](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |
|
||||
| [aws_kms_key.ab-kms-key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |
|
||||
| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:--------:|
|
||||
| daily-backup-cron | Daily backup rule cron expression | `string` | n/a | yes |
|
||||
| daily-backup-retention | Daily backup retention period | `number` | n/a | yes |
|
||||
| monthly-backup-cron | Monthly backup rule cron expression | `string` | n/a | yes |
|
||||
| monthly-backup-retention | Monthly backup retention period | `number` | n/a | yes |
|
||||
| service-opt-in | n/a | <pre>map(object({<br> enabled = bool<br> }))</pre> | <pre>{<br> "Aurora": {<br> "enabled": false<br> },<br> "DynamoDB": {<br> "enabled": true<br> },<br> "EBS": {<br> "enabled": false<br> },<br> "EC2": {<br> "enabled": true<br> },<br> "EFS": {<br> "enabled": true<br> },<br> "FSx": {<br> "enabled": false<br> },<br> "RDS": {<br> "enabled": true<br> },<br> "Redshift": {<br> "enabled": true<br> },<br> "S3": {<br> "enabled": false<br> },<br> "VirtualMachine": {<br> "enabled": false<br> }<br>}</pre> | no |
|
||||
|
||||
## Outputs
|
||||
|
||||
No outputs.
|
||||
|
||||
---
|
||||
## Authorship
|
||||
This module was developed by xpk.
|
||||
@@ -0,0 +1,43 @@
|
||||
data "aws_caller_identity" "this" {}
|
||||
|
||||
resource "aws_kms_key" "ab-kms-key" {
|
||||
description = "KMS key for aws backup"
|
||||
deletion_window_in_days = 10
|
||||
policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Id" : "awsbackup-service",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "Enable IAM User Permissions",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"AWS" : "arn:aws:iam::${data.aws_caller_identity.this.id}:root"
|
||||
},
|
||||
"Action" : "kms:*",
|
||||
"Resource" : "*"
|
||||
},
|
||||
{
|
||||
"Sid" : "Allow attachment of persistent resources",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : "*",
|
||||
"Action" : [
|
||||
"kms:CreateGrant",
|
||||
"kms:ListGrants",
|
||||
"kms:RevokeGrant"
|
||||
],
|
||||
"Resource" : "*",
|
||||
"Condition" : {
|
||||
"Bool" : {
|
||||
"kms:GrantIsForAWSResource" : "true"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_kms_alias" "ab-kms-key-alias" {
|
||||
name = "alias/awsbackup-kms-key"
|
||||
target_key_id = aws_kms_key.ab-kms-key.id
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
# build local data structure
|
||||
|
||||
locals {
|
||||
backup-config = {
|
||||
"Aurora" : {
|
||||
enabled = var.service-opt-in.Aurora.enabled
|
||||
arn-prefix = "arn:aws:rds:*:*:cluster:*"
|
||||
}
|
||||
"DynamoDB" : {
|
||||
enabled = var.service-opt-in.DynamoDB.enabled
|
||||
arn-prefix = "arn:aws:dynamodb:*:*:table/*"
|
||||
}
|
||||
"EBS" : {
|
||||
enabled = var.service-opt-in.EBS.enabled
|
||||
arn-prefix = "arn:aws:ec2:*:*:volume/*"
|
||||
}
|
||||
"EC2" : {
|
||||
enabled = var.service-opt-in.EC2.enabled
|
||||
arn-prefix = "arn:aws:ec2:*:*:instance/*"
|
||||
}
|
||||
"EFS" : {
|
||||
enabled = var.service-opt-in.EFS.enabled
|
||||
arn-prefix = "arn:aws:elasticfilesystem:*:*:file-system/*"
|
||||
}
|
||||
"FSx" : {
|
||||
enabled = var.service-opt-in.FSx.enabled
|
||||
arn-prefix = "arn:*:fsx:*"
|
||||
}
|
||||
"Redshift" : {
|
||||
enabled = var.service-opt-in.Redshift.enabled
|
||||
arn-prefix = "arn:aws:redshift:*:*:cluster:*"
|
||||
}
|
||||
"RDS" : {
|
||||
enabled = var.service-opt-in.RDS.enabled
|
||||
arn-prefix = "arn:aws:rds:*:*:db:*"
|
||||
}
|
||||
# this version can't handle space
|
||||
# "Storage Gateway" : {
|
||||
# enabled = var.opt-in-storagegateway
|
||||
# arn-prefix = "arn:aws:storagegateway:*:*:gateway/*"
|
||||
# }
|
||||
"VirtualMachine" : {
|
||||
enabled = var.service-opt-in.VirtualMachine.enabled
|
||||
arn-prefix = "arn:aws:backup-gateway:*:*:vm/*"
|
||||
}
|
||||
"S3" : {
|
||||
enabled = var.service-opt-in.S3.enabled
|
||||
arn-prefix = "arn:aws:s3:::*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_backup_region_settings" "ab-settings" {
|
||||
resource_type_opt_in_preference = {
|
||||
for k, v in local.backup-config : k => v.enabled
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_backup_vault" "ab-vault" {
|
||||
for_each = toset([
|
||||
for k, v in local.backup-config : k
|
||||
if v.enabled
|
||||
])
|
||||
name = "BackupVault-${each.value}"
|
||||
kms_key_arn = aws_kms_key.ab-kms-key.arn
|
||||
}
|
||||
|
||||
resource "aws_backup_vault_policy" "ab-vault-policy" {
|
||||
for_each = aws_backup_vault.ab-vault
|
||||
backup_vault_name = each.value.name
|
||||
policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Id" : "default",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "default",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"AWS" : data.aws_caller_identity.this.account_id
|
||||
},
|
||||
"Action" : [
|
||||
"backup:DescribeBackupVault",
|
||||
"backup:DeleteBackupVault",
|
||||
"backup:PutBackupVaultAccessPolicy",
|
||||
"backup:DeleteBackupVaultAccessPolicy",
|
||||
"backup:GetBackupVaultAccessPolicy",
|
||||
"backup:StartBackupJob",
|
||||
"backup:GetBackupVaultNotifications",
|
||||
"backup:PutBackupVaultNotifications"
|
||||
],
|
||||
"Resource" : each.value.arn
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_backup_plan" "ab-plan" {
|
||||
for_each = aws_backup_vault.ab-vault
|
||||
name = "BackupPlan-${replace(each.value.name, "BackupVault-", "")}"
|
||||
|
||||
# daily backup
|
||||
rule {
|
||||
rule_name = "Daily"
|
||||
target_vault_name = each.value.name
|
||||
schedule = var.daily-backup-cron
|
||||
start_window = 60
|
||||
completion_window = 240
|
||||
|
||||
lifecycle {
|
||||
delete_after = var.daily-backup-retention
|
||||
}
|
||||
|
||||
recovery_point_tags = {
|
||||
"CreatedBy" : "AWSBackup"
|
||||
"AWSBackupPlan" : "BackupPlan-${replace(each.value.name, "BackupVault-", "")}-Daily"
|
||||
}
|
||||
}
|
||||
|
||||
# monthly backup (when overlap with daily, only monthly backup will be created.
|
||||
# see https://docs.aws.amazon.com/aws-backup/latest/devguide/creating-a-backup-plan.html)
|
||||
rule {
|
||||
rule_name = "Monthly"
|
||||
target_vault_name = each.value.name
|
||||
schedule = var.monthly-backup-cron
|
||||
start_window = 60
|
||||
completion_window = 240
|
||||
|
||||
lifecycle {
|
||||
delete_after = var.monthly-backup-retention
|
||||
cold_storage_after = var.daily-backup-retention # move to cold storage after daily retention, supported on a few services only
|
||||
}
|
||||
|
||||
recovery_point_tags = {
|
||||
"CreatedBy" : "AWSBackup"
|
||||
"AWSBackupPlan" : "BackupPlan-${replace(each.value.name, "BackupVault-", "")}-Monthly"
|
||||
}
|
||||
}
|
||||
|
||||
# advanced_backup_setting {
|
||||
# backup_options = {
|
||||
# WindowsVSS = "enabled"
|
||||
# }
|
||||
# resource_type = "EC2"
|
||||
# }
|
||||
}
|
||||
#
|
||||
resource "aws_iam_role" "ab-iam-role" {
|
||||
name = "AwsBackupRole"
|
||||
assume_role_policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Action" : ["sts:AssumeRole"],
|
||||
"Effect" : "allow",
|
||||
"Principal" : {
|
||||
"Service" : ["backup.amazonaws.com"]
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy_attachment" "ab-iam-role-policy" {
|
||||
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup"
|
||||
role = aws_iam_role.ab-iam-role.name
|
||||
}
|
||||
|
||||
resource "aws_backup_selection" "ab-selection-by-service-type" {
|
||||
for_each = aws_backup_plan.ab-plan
|
||||
iam_role_arn = aws_iam_role.ab-iam-role.arn
|
||||
name = "SelectionByServiceType"
|
||||
plan_id = each.value.id
|
||||
resources = [lookup(local.backup-config, replace(each.value.name, "BackupPlan-", "")).arn-prefix]
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
variable "daily-backup-cron" {
|
||||
type = string
|
||||
description = "Daily backup rule cron expression"
|
||||
}
|
||||
|
||||
variable "monthly-backup-cron" {
|
||||
type = string
|
||||
description = "Monthly backup rule cron expression"
|
||||
}
|
||||
|
||||
variable "daily-backup-retention" {
|
||||
type = number
|
||||
description = "Daily backup retention period"
|
||||
}
|
||||
|
||||
variable "monthly-backup-retention" {
|
||||
type = number
|
||||
description = "Monthly backup retention period"
|
||||
}
|
||||
|
||||
variable "service-opt-in" {
|
||||
type = map(object({
|
||||
enabled = bool
|
||||
}))
|
||||
default = {
|
||||
"Aurora" : {
|
||||
enabled = false
|
||||
}
|
||||
"DynamoDB" : {
|
||||
enabled = true
|
||||
}
|
||||
"EBS" : {
|
||||
enabled = false
|
||||
}
|
||||
"EC2" : {
|
||||
enabled = true
|
||||
}
|
||||
"EFS" : {
|
||||
enabled = true
|
||||
}
|
||||
"FSx" : {
|
||||
enabled = false
|
||||
}
|
||||
"Redshift" : {
|
||||
enabled = true
|
||||
}
|
||||
"RDS" : {
|
||||
enabled = true
|
||||
}
|
||||
"VirtualMachine" : {
|
||||
enabled = false
|
||||
}
|
||||
"S3" : {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# Overview
|
||||
This module creates s3 bucket using default settings and AWS AES256 encryption
|
||||
The bucket is meant for infrastructure use. Versioning is off and object expires in 90 days
|
||||
|
||||
## Inputs:
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:-----:|
|
||||
| application | name of application | string | none | yes |
|
||||
| environment | capacity of environment (prd/dev/lab) | string | none | yes |
|
||||
| customer-name | owner of aws resources | string | none | yes |
|
||||
| project | name of project | string | none | yes |
|
||||
| default-tags | tags to be added to resources | list | none | yes |
|
||||
| aws-region-short | short name of aws region (e.g. apne1) | string | none | yes |
|
||||
| bucket-name | name or prefix of s3 bucket | string | none | yes |
|
||||
| add-random-suffix | Whether to append a random string to bucket name | bool | false | no |
|
||||
| bucket-policy-json | bucket policy | json | none | yes |
|
||||
| enable-bucket-versioning | Whether to enable bucket versioning | bool | false | no |
|
||||
| bucket-retain-days | Days before s3 objects are expired on s3 | number | 90 | no |
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
module random-suffix {
|
||||
source = "../../util/random"
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket" "s3bucket" {
|
||||
bucket = var.add-random-suffix ? "${var.bucket-name}-${module.random-suffix.number}" : var.bucket-name
|
||||
tags = var.default-tags
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_policy" "bucket-policy" {
|
||||
bucket = aws_s3_bucket.s3bucket.bucket
|
||||
policy = var.bucket-policy-json
|
||||
|
||||
}
|
||||
resource "aws_s3_bucket_lifecycle_configuration" "bucket-lifecycle-config" {
|
||||
count = var.bucket-enable-lifecycle ? 1 : 0
|
||||
|
||||
bucket = aws_s3_bucket.s3bucket.bucket
|
||||
|
||||
rule {
|
||||
id = "default"
|
||||
status = "Enabled"
|
||||
|
||||
dynamic "noncurrent_version_expiration" {
|
||||
for_each = var.enable-bucket-versioning ? [1] : []
|
||||
content {
|
||||
noncurrent_days = 90
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "expiration" {
|
||||
for_each = var.bucket-retain-days > 0 ? [1] : []
|
||||
content {
|
||||
days = var.bucket-retain-days
|
||||
}
|
||||
}
|
||||
|
||||
transition {
|
||||
days = var.transition-ia-days
|
||||
storage_class = "STANDARD_IA"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_acl" "bucket-acl" {
|
||||
bucket = aws_s3_bucket.s3bucket.bucket
|
||||
acl = var.bucket-acl
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_versioning" "bucket-versioning" {
|
||||
count = var.enable-bucket-versioning ? 1 : 0
|
||||
bucket = aws_s3_bucket.s3bucket.id
|
||||
versioning_configuration {
|
||||
status = "Enabled"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_server_side_encryption_configuration" "bucket-encryption" {
|
||||
bucket = aws_s3_bucket.s3bucket.bucket
|
||||
rule {
|
||||
apply_server_side_encryption_by_default {
|
||||
sse_algorithm = "AES256"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_public_access_block" "s3-public-access-settings" {
|
||||
bucket = aws_s3_bucket.s3bucket.id
|
||||
|
||||
block_public_acls = true
|
||||
block_public_policy = true
|
||||
ignore_public_acls = true
|
||||
restrict_public_buckets = true
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_ownership_controls" "ctbucket-ownership-setting" {
|
||||
bucket = aws_s3_bucket.s3bucket.id
|
||||
|
||||
rule {
|
||||
object_ownership = "BucketOwnerPreferred"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
output bucket-name {
|
||||
value = aws_s3_bucket.s3bucket.id
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
variable "default-tags" {}
|
||||
variable "bucket-retain-days" {
|
||||
type = number
|
||||
default = 90
|
||||
}
|
||||
variable "bucket-name" {}
|
||||
variable "bucket-policy-json" {}
|
||||
variable "enable-bucket-versioning" {
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
variable "add-random-suffix" {
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable bucket-acl {
|
||||
type = string
|
||||
default = "private"
|
||||
}
|
||||
|
||||
variable bucket-enable-lifecycle {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable transition-ia-days {
|
||||
type = number
|
||||
default = 30
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<!-- This readme file is generated with terraform-docs -->
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| terraform | >= 1.3.0 |
|
||||
| aws | >= 5.0 |
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| aws | >= 5.0 |
|
||||
| random | n/a |
|
||||
|
||||
## Modules
|
||||
|
||||
No modules.
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_iam_role.replication-role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
|
||||
| [aws_iam_role_policy.role-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
|
||||
| [aws_s3_bucket_replication_configuration.replication-config](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_replication_configuration) | resource |
|
||||
| [random_id.rid](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
|
||||
| [aws_iam_policy_document.assume_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
|
||||
| [aws_iam_policy_document.replication-role-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
|
||||
| [aws_s3_bucket.destination-bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_bucket) | data source |
|
||||
| [aws_s3_bucket.source-bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_bucket) | data source |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|------------------|:--------:|
|
||||
| destination-bucket-account-id | Account id of destination bucket. | `string` | `"111122223333"` | no |
|
||||
| destination-bucket-encryption-key-arn | Encryption key arn for destination bucket | `string` | n/a | yes |
|
||||
| destination-bucket-name | Name of destination bucket | `string` | n/a | yes |
|
||||
| source-bucket-name | Name of source s3 bucket | `string` | n/a | yes |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| replication-role-arn | n/a |
|
||||
|
||||
---
|
||||
## Authorship
|
||||
This module was developed by xpk.
|
||||
@@ -0,0 +1,152 @@
|
||||
# sets up data sources for s3 buckets
|
||||
|
||||
data "aws_s3_bucket" "source-bucket" {
|
||||
bucket = var.source-bucket-name
|
||||
}
|
||||
|
||||
data "aws_s3_bucket" "destination-bucket" {
|
||||
bucket = var.destination-bucket-name
|
||||
}
|
||||
|
||||
# Create replication role in source account
|
||||
data "aws_iam_policy_document" "assume_role_policy" {
|
||||
statement {
|
||||
actions = ["sts:AssumeRole"]
|
||||
|
||||
principals {
|
||||
type = "Service"
|
||||
identifiers = ["s3.amazonaws.com"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data "aws_iam_policy_document" "replication-role-policy" {
|
||||
statement {
|
||||
sid = "AccessToReplicaBucket"
|
||||
actions = [
|
||||
"s3:ReplicateObject",
|
||||
"s3:ReplicateDelete",
|
||||
"s3:ReplicateTags",
|
||||
"s3:ObjectOwnerOverrideToBucketOwner"
|
||||
]
|
||||
effect = "Allow"
|
||||
resources = [
|
||||
data.aws_s3_bucket.source-bucket.arn,
|
||||
data.aws_s3_bucket.destination-bucket.arn,
|
||||
"${data.aws_s3_bucket.source-bucket.arn}/*",
|
||||
"${data.aws_s3_bucket.destination-bucket.arn}/*"
|
||||
]
|
||||
}
|
||||
statement {
|
||||
sid = "ReadAccessOnSourceBuckets"
|
||||
actions = ["s3:Get*", "s3:List*"]
|
||||
effect = "Allow"
|
||||
resources = [
|
||||
data.aws_s3_bucket.source-bucket.arn,
|
||||
]
|
||||
}
|
||||
statement {
|
||||
sid = "ObjectAccessOnSourceBuckets"
|
||||
actions = [
|
||||
"s3:GetObjectVersionForReplication",
|
||||
"s3:GetObjectVersionAcl",
|
||||
"s3:GetObjectVersionTagging"
|
||||
]
|
||||
effect = "Allow"
|
||||
resources = [
|
||||
"${data.aws_s3_bucket.source-bucket.arn}/*"
|
||||
]
|
||||
}
|
||||
statement {
|
||||
sid = "DecryptSourceBucketObjects"
|
||||
actions = [
|
||||
"kms:Decrypt"
|
||||
]
|
||||
effect = "Allow"
|
||||
resources = ["*"]
|
||||
}
|
||||
statement {
|
||||
sid = "EncryptReplicaObjects"
|
||||
actions = [
|
||||
"kms:Encrypt"
|
||||
]
|
||||
effect = "Allow"
|
||||
resources = ["*"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "random_id" "rid" {
|
||||
byte_length = 4
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "replication-role" {
|
||||
name = "BucketReplicationRole${random_id.rid.dec}"
|
||||
assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "role-policy" {
|
||||
name = "bucket-replication"
|
||||
role = aws_iam_role.replication-role.id
|
||||
policy = data.aws_iam_policy_document.replication-role-policy.json
|
||||
}
|
||||
|
||||
# Setup bucket replication
|
||||
resource "aws_s3_bucket_replication_configuration" "replication-config" {
|
||||
role = aws_iam_role.replication-role.arn
|
||||
bucket = var.source-bucket-name
|
||||
|
||||
rule {
|
||||
id = "ReplicateAll"
|
||||
|
||||
status = "Enabled"
|
||||
|
||||
source_selection_criteria {
|
||||
sse_kms_encrypted_objects {
|
||||
status = "Enabled"
|
||||
}
|
||||
}
|
||||
|
||||
# V2 replication configurations
|
||||
delete_marker_replication {
|
||||
status = "Enabled"
|
||||
}
|
||||
|
||||
filter {
|
||||
}
|
||||
|
||||
destination {
|
||||
bucket = data.aws_s3_bucket.destination-bucket.arn
|
||||
storage_class = "INTELLIGENT_TIERING"
|
||||
account = var.destination-bucket-account-id
|
||||
|
||||
access_control_translation {
|
||||
owner = "Destination"
|
||||
}
|
||||
|
||||
encryption_configuration {
|
||||
replica_kms_key_id = var.destination-bucket-encryption-key-arn
|
||||
}
|
||||
|
||||
replication_time {
|
||||
status = "Enabled"
|
||||
time {
|
||||
minutes = 15
|
||||
}
|
||||
}
|
||||
|
||||
metrics {
|
||||
status = "Enabled"
|
||||
event_threshold {
|
||||
minutes = 15
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_object" "test-file" {
|
||||
depends_on = [aws_s3_bucket_replication_configuration.replication-config]
|
||||
bucket = data.aws_s3_bucket.source-bucket.id
|
||||
key = "replication-test-file"
|
||||
content = "If this file shows up in the destination bucket, replication has been successfully configured."
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
output replication-role-arn {
|
||||
value = aws_iam_role.replication-role.arn
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
variable source-bucket-name {
|
||||
type = string
|
||||
description = "Name of source s3 bucket"
|
||||
}
|
||||
|
||||
variable destination-bucket-name {
|
||||
type = string
|
||||
description = "Name of destination bucket"
|
||||
}
|
||||
|
||||
variable destination-bucket-account-id {
|
||||
type = string
|
||||
description = "Account id of destination bucket. Defaults to BEA-SYS-LOG-UAT"
|
||||
default = "894849410890"
|
||||
}
|
||||
|
||||
variable destination-bucket-encryption-key-arn {
|
||||
type = string
|
||||
description = "Encryption key arn for destination bucket"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
terraform {
|
||||
required_version = ">= 1.3.0"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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