Securing Amazon Simple Storage Service (Amazon S3) - Part 2

In the previous article, we discussed three topics which are what Amazon S3 is, what are the Amazon S3 security best practices, and we configured the AWS Terraform Provider and variables necessary to build the AWS resources.

In part two, we will review the Terraform code used to deploy the AWS resources and deploy the Terraform code to AWS.

You can access all of the code used in my GitHub repository.

s3-image

AWS Resources

We will be using Terraform to build the following:

  • Amazon S3 Buckets
  • AWS CloudTrail
  • AWS Key Management Service (KMS)
  • Amazon Macie
  • AWS Config
  • Amazon Simple Notification Service (SNS)
  • Amazon Eventbridge
  • IAM Policies and Roles
  • Review Terraform Code

Amazon S3

Below is the Terraform code for creating the Amazon S3 bucket used to store sensitive data. As discussed in the previous article, several Amazon S3 security best practices are enabled in the code.

s3_lab.tf

module "lab_s3_bucket" {
  source = "terraform-aws-modules/s3-bucket/aws"

  bucket        = local.aws_s3_bucket_name
  force_destroy = true

  server_side_encryption_configuration = {
    rule = {
      apply_server_side_encryption_by_default = {
        sse_algorithm = "AES256"
      }
    }
  }

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true

  versioning = {
    enabled = true
  }
 
  logging = {
    target_bucket = module.logs_s3_bucket.s3_bucket_id
    target_prefix = "logs/"
  }

  #Bucket policies
  attach_deny_insecure_transport_policy = true
 
  lifecycle_rule = [
    {
      id      = "archive"
      enabled = true
      abort_incomplete_multipart_upload_days = 7

      transition = [
        {
          days          = 30
          storage_class = "STANDARD_IA"
        },
        {
          days          = 90
          storage_class = "GLACIER_IR"
        }
      ]

      expiration = {
        days = 365
      }
    },
  ]

  tags = {
    Classification = "Sensitive"
  }
}

Terraform code to upload two sensitive files to the S3 Lab bucket.

resource "aws_s3_object" "sensitive_files" 
  bucket   = module.lab_s3_bucket.s3_bucket_id
  for_each = fileset("./files/", "**/*")
  key      = each.value
  source   = "./files/${each.value}"
  etag     = filemd5("./files/${each.value}")

  tags = {
    Classification = "Sensitive"
  }

Two additional Amazon S3 buckets are also created but are not reviewed here, which are an Amazon S3 Bucket for storing the logs for each Amazon S3 bucket and an Amazon S3 Bucket to store the AWS Cloudtrail Logs, AWS Macie findings, and AWS Config rule results.

This is the snippet of code in the Terraform code to enable logging for an Amazon S3 bucket.

logging = {
  target_bucket = module.logs_s3_bucket.s3_bucket_id
  target_prefix = "logs/"
}

AWS CloudTrail

The following is Terraform code for creating AWS CloudTrail used to audit Amazon S3.

cloudtrail.tf

#Configure CloudTrail with the S3 bucket and IAM role
resource "aws_cloudtrail" "cloudtrail" {
  name                          = "${local.aws_s3_bucket_name}-cloudtrail"
  s3_bucket_name                = module.audit_s3_bucket.s3_bucket_id
  s3_key_prefix                 = "cloudtrail"
  is_multi_region_trail         = false
  include_global_service_events = true
  enable_log_file_validation    = true
  enable_logging                = true

  event_selector {
    read_write_type           = "All"
    include_management_events = true

    data_resource {
      type = "AWS::S3::Object"
      values = [
        "${module.audit_s3_bucket.s3_bucket_arn}/",
        "${module.logs_s3_bucket.s3_bucket_arn}/",
        "${module.poc_s3_bucket.s3_bucket_arn}/",
      ]
    }
  }

  depends_on = [module.audit_s3_bucket]
}

Amazon Macie

The following is an excerpt of Terraform code for creating Amazon Macie used to monitor and detect sensitive data in Amazon S3 objects. As you can see, this code enables Amazon Macie and creates an Amazon Macie classification job that runs one-time.

macie.tf

#Enable Amazon Macie
resource "aws_macie2_account" "macie" {
  finding_publishing_frequency = "FIFTEEN_MINUTES"
  status                       = "ENABLED"
}

#Create Classification Job for Amazon Macie
resource "aws_macie2_classification_job" "macie_one_time" {
  job_type = "ONE_TIME"
  name     = "${local.aws_s3_bucket_name}-macie-job"

  s3_job_definition {
    bucket_definitions {
      account_id = data.aws_caller_identity.current.account_id
      buckets    = [local.aws_s3_bucket_name]
    }
  }

  sampling_percentage = 100

  depends_on = [
    aws_macie2_account.macie,
    module.audit_s3_bucket
  ]
}

AWS Config

Below is an excerpt of Terraform code for creating AWS Config rules for monitoring Amazon S3 configurations. Each of these rules is an AWS Config managed rule that can be enabled. If you would like to see the other AWS Config managed rules can be reviewed here.

config.tf

# Configure AWS Config Rules for monitoring Amazon S
resource "aws_config_config_rule" "s3" {
  for_each = {
    s3-bucket-versioning-enabled             = "S3_BUCKET_VERSIONING_ENABLED"
    s3-bucket-ssl-requests-only              = "S3_BUCKET_SSL_REQUESTS_ONLY"
    s3-bucket-server-side-encryption-enabled = "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED"
    s3-bucket-logging-enabled                = "S3_BUCKET_LOGGING_ENABLED"
    s3-bucket-acl-prohibited                 = "S3_BUCKET_ACL_PROHIBITED"
    s3-event-notifications-enabled           = "S3_EVENT_NOTIFICATIONS_ENABLED"
    s3-bucket-level-public-access-prohibited = "S3_BUCKET_LEVEL_PUBLIC_ACCESS_PROHIBITED"
  }

  name = "${local.aws_s3_bucket_name}-${each.key}-config-rule"

  source {
    owner             = "AWS"
    source_identifier = each.value
  }

  scope {
    tag_key   = "Project"
    tag_value = local.project
  }

  depends_on = [aws_config_configuration_recorder.config]
}

Amazon Eventbridge

With Amazon Eventbridge, you can send notifications on several findings. The code below shows how Amazon Eventbridge will send a notification to an Amazon SNS topic when Amazon Macie produces any findings. Any subscribed users will be emailed once the notification is sent to the Amazon SNS topic.

eventbridge.tf

# Create Amazon Eventbridge Rule for Amazon Macie findings
resource "aws_cloudwatch_event_rule" "macie" {
  name        = "${local.aws_s3_bucket_name}-aws-macie-rule"
  description = "Capture macie"

  event_pattern = jsonencode({
    source = ["aws.macie"]
    detail-type = [
      "Macie Finding"
    ]
  })
}

resource "aws_cloudwatch_event_target" "config-macie" {
  rule      = aws_cloudwatch_event_rule.macie.name
  target_id = "SendToSNS"
  arn       = aws_sns_topic.sns.arn
}

We just finished reviewing Terraform code to create and secure Amazon S3 Buckets. Several of the code blocks from above are just snippets of code. Please see the git repo for the complete code.

Deploy Terraform code

Follow these steps to set up the AWS resources and environment:

terraform init
terraform validate
terraform plan -out=plan.out
terraform apply plan.out

After completing these steps, the Amazon S3 Buckets should be configured and secured.

Below is what you should see after you finish the terraform commands. state-lock

Conclusion

This article reviewed the Terraform code used to deploy the AWS resources and successfully deployed the Terraform Code to AWS. We now have an Amazon S3 Bucket containing sensitive data that is secure and protected with Amazon S3 best practices. Amazon Macie monitors the Amazon S3 bucket to scan for sensitive data. 2 additional Amazon S3 buckets were created to help secure all of the Amazon S3 buckets. A dedicated Amazon S3 Bucket stores all the Amazon S3 Logs from all Amazon S3 buckets. The final Amazon S3 bucket stores the CloudTrail logs, the Amazon Macie findings, and the AWS Config finding.

In part three, we will validate that the Amazon S3 best practices were followed when deploying the code with Terraform, review the findings for Amazon Macie and AWS Config findings, and validate that email notifications are being sent for Amazon Macie and AWS Config findings. Last, we will run some tests to see if we can detect any changes to the Amazon S3 buckets.

AWS Web Talk - AWS Trusted Advisor
Older post

AWS Web Talk - AWS Trusted Advisor

As a CTO at Blue Sentry Cloud with 12 AWS certifications, I know firsthand the importance of optimizing AWS costs for a successful cloud computing strategy. In this video, I share best practices for AWS cost optimization, including monitoring and controlling spending, leveraging automation, using reserved instances and savings plans, and more. Check it out to learn how to reduce your AWS spending and improve efficiency significantly.

Newer post

Securing Amazon Simple Storage Service (Amazon S3) - Part 1

One of the things I hear about is how sensitive data is accessed easily due to insecure Amazon S3 configurations. I am excited to write a 3-part article on Securing Amazon S3. In part one, Follow along as we discuss what Amazon S3 is, what Amazon S3 security best practices are, and we configure the AWS Terraform Provider.

Securing Amazon Simple Storage Service (Amazon S3) - Part 1