avatarTeri Radichel

Summary

The provided content discusses the formulation of an S3 bucket policy for an AWS Organization CloudTrail bucket, detailing the necessary permissions and conditions to ensure secure access and data integrity.

Abstract

The article delves into the creation of a secure S3 bucket policy tailored for an AWS Organization CloudTrail bucket. It emphasizes the importance of enforcing secure transport (TLS) for data in transit, the use of conditions to control access, and the alignment with AWS Control Tower settings for AWS Config rules. The author critically examines sample policies from AWS documentation and AWS Control Tower, proposing a refined policy that addresses security findings and optimizes permissions for CloudTrail logging. The post also outlines the process of integrating the policy into a CloudFormation template, highlighting common challenges such as policy document malformation errors and the steps to troubleshoot them. The author, Teri Radichel, shares insights from their experience, including the need for methodical testing and adjustments to ensure successful deployment and compatibility with AWS services.

Opinions

  • The author values the security enhancements provided by AWS Control Tower, such as enforcing TLS in transit, and recommends retaining these features in custom bucket policies.
  • There is an opinion that AWS Config rules set up by AWS Control Tower, such as preventing the deletion or alteration of CloudTrail logs, are beneficial and should be considered for future inclusion in the bucket policy.
  • The author expresses a preference for using conditions in policies to granularly control access and permissions, which is demonstrated in the proposed bucket policy.
  • The author critiques the lack of clear error messages from CloudFormation, particularly when dealing with malformed policy documents, and emphasizes the importance of a systematic approach to troubleshooting.
  • The author suggests that the bucket owner's full control over the bucket should be leveraged for access management, rather than relying on explicit permissions for every user, which simplifies the policy and management.
  • There is a concern about the absence of MFA for deletion in both the AWS Control Tower policy and the AWS documentation sample, indicating a potential area for improvement in terms of security best practices.
  • The author advocates for the use of YAML over JSON for CloudFormation templates, as it is more readable and easier to work with, especially when converting JSON policies to a more human-friendly format.

S3 Bucket Policy for an Organization CloudTrail Bucket

ACM.198 Formulating the code for our Organization CloudTrail Bucket

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

⚙️ Part of my series on Automating Cybersecurity Metrics. The Code.

🔒 Related Stories: S3 | AWS Security | Cloud Governance | AWS Organizations

💻 Free Content on Jobs in Cybersecurity | ✉️ Sign up for the Email List

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In the last post we looked at using conditions in policies. That’s because I’m going to use some of those conditions in this post.

In this post we want to create an S3 bucket policy for our CloudTrail bucket. The bucket policy specifies who is allowed to access the bucket and the data in the bucket.

AWS provides a sample CloudFormation bucket policy here for an Organization CloudTrail:

I took at look at the S3 bucket policy created by AWS Control Tower. It looks like this where xxxxxxxx is the organization id and xxxxxxxxxxxxx is the management account ID.

{
 "Version": "2012-10-17",
 "Statement": [
  {
   "Sid": "AllowSSLRequestsOnly",
   "Effect": "Deny",
   "Principal": "*",
   "Action": "s3:*",
   "Resource": [
    "arn:aws:s3:::aws-controltower-logs-xxxxxxxxxxxx-us-west-2",
    "arn:aws:s3:::aws-controltower-logs-xxxxxxxxxxxx-us-west-2/*"
   ],
   "Condition": {
    "Bool": {
     "aws:SecureTransport": "false"
    }
   }
  },
  {
   "Sid": "AWSBucketPermissionsCheck",
   "Effect": "Allow",
   "Principal": {
    "Service": [
     "config.amazonaws.com",
     "cloudtrail.amazonaws.com"
    ]
   },
   "Action": "s3:GetBucketAcl",
   "Resource": "arn:aws:s3:::aws-controltower-logs-xxxxxxxxxxxx-us-west-2"
  },
  {
   "Sid": "AWSConfigBucketExistenceCheck",
   "Effect": "Allow",
   "Principal": {
    "Service": [
     "config.amazonaws.com",
     "cloudtrail.amazonaws.com"
    ]
   },
   "Action": "s3:ListBucket",
   "Resource": "arn:aws:s3:::aws-controltower-logs-xxxxxxxxxxxx-us-west-2"
  },
  {
   "Sid": "AWSBucketDeliveryForConfig",
   "Effect": "Allow",
   "Principal": {
    "Service": "config.amazonaws.com"
   },
   "Action": "s3:PutObject",
   "Resource": "arn:aws:s3:::aws-controltower-logs-xxxxxxxxxxxx-us-west-2/o-xxxxxxxx/AWSLogs/*/*"
  },
  {
   "Sid": "AWSBucketDeliveryForOrganizationTrail",
   "Effect": "Allow",
   "Principal": {
    "Service": "cloudtrail.amazonaws.com"
   },
   "Action": "s3:PutObject",
   "Resource": "arn:aws:s3:::aws-controltower-logs-xxxxxxxxxxxx-us-west-2/o-xxxxxxxx/AWSLogs/*/*"
  }
 ]
}

Here are some of the changes we can make by pulling out bits of code from each policy:

  • One of the benefits of AWS Control Tower is that it sets up AWS Config rules for you such as don’t allow someone to delete the CloudTrail logs or change them. We aren’t going to use Config just yet. We are not going to add the statements for AWS Config permissions in the AWS Control Tower version for now.
  • The AWS Control Tower version enforces TLS in transit (SecureTransport) which the policy from the documentation doesn’t. Let’s keep that. Essentially that means your bucket must be accessed using HTTPS not HTTP and the requests you send and data you receive back will be encrypted in transit so someone can’t sniff the data on the wire. I wrote about sniffing here:
  • I noticed the following Security findings in the AWS Console for the bucket policy created by AWS Control Tower. I’m going to try to fix those.
  • We will include the condition from the policy in the documentation to resolve the findings in the ControlTower version.
  • The only problem with the above is we can’t add the trail until we create it, but we want to add the bucket to the trail, so we’ll need a condition for that.
  • I see that there is a GetBucketAcl action in both policies. We’ll include that and add the above condition. But why do we need an ACL if those are supposed to be disabled via our bucket ownership setting? Keep reading future posts for more on ACLs.
  • The policy in the documentation has no ListBucket permissions for AWS CloudFormation and it has two PutObject statements. So is ListBucket required? Let’s try without it initially since it is not in the documentation and see what happens.
  • The policy from the documentation allows writing a trail for the account only and the entire organization while the ControlTower policy only writes a trail or the entire organization. I’m going to start with only one trail for the organizations so I only need one PutObject statement, matching the Control Tower bucket policy. I’m not wanting to duplicate trails and costs.
  • There are no permissions in either case for a user to view the logs. How is anyone going to access the log files? Well, here’s where my post on bucket ownership applies. The bucket owner has full control of the bucket. The bucket owner is the account. Anyone in the account with IAM S3 permissions to access the bucket that is not explicitly denied in the S3 bucket policy has access to view the files. Therefore, since our OrgRoot user has full access in this account, that use should be able to view the files. We’ll test this after we create our trail and make any adjustments as needed. More on how that works in the next post.
  • Now if the bucket owner has full control, the bucket owner can delete everything in the account as well right? There’s no enforcement of MFA for deletion in either policy. We’ll look more at deletion after we create the CloudTrail log and can test log deletion after we change the policy.

S3 Bucket Policy (Pseudocode)

Here’s the reformulated policy (for now — we may add Config later). We’ll need to turn some of this into parameters. For one thing, we don’t yet have the CloudTrail ARN.

{
 "Version": "2012-10-17",
 "Statement": [
  {
   "Sid": "AllowSSLRequestsOnly",
   "Effect": "Deny",
   "Principal": "*",
   "Action": "s3:*",
   "Resource": [
    "[bucket-arn]",
    "[bucket-arn]/*"
   ],
   "Condition": {
    "Bool": {
     "aws:SecureTransport": "false"
    }
   }
  },
  {
   "Sid": "GetBucketAcl",
   "Effect": "Allow",
   "Principal": {
    "Service": [
     "cloudtrail.amazonaws.com"
    ]
   },
   "Action": "s3:GetBucketAcl",
   "Resource": "[bucket arn]",
   "Condition": {
        "StringEquals": {
             "aws:SourceArn": "[CloudTrail ARN]"
        }
     }
  },
  {
   "Sid": "WriteToBucket",
   "Effect": "Allow",
   "Principal": {
    "Service": "cloudtrail.amazonaws.com"
   },
   "Action": "s3:PutObject",
   "Resource": "[bucket arn + path to logs]",
   "Condition": {
        "StringEquals": {
             "aws:SourceArn": "[CloudTrail ARN]"
        }
     }
  }
 ]
}

But here’s our template in YAML using the tool I wrote about in the last post.

Version: '2012-10-17'
Statement:
  - Sid: AllowSSLRequestsOnly
    Effect: Deny
    Principal: '*'
    Action: 's3:*'
    Resource:
      - '[bucket-arn]'
      - '[bucket-arn]/*'
    Condition:
      Bool:
        'aws:SecureTransport': 'false'
  - Sid: GetBucketAcl
    Effect: Allow
    Principal:
      Service:
        - cloudtrail.amazonaws.com
    Action: 's3:GetBucketAcl'
    Resource: '[bucket arn]'
    Condition:
      StringEquals:
        'aws:SourceArn': '[CloudTrail ARN]'
  - Sid: WriteToBucket
    Effect: Allow
    Principal:
      Service: cloudtrail.amazonaws.com
    Action: 's3:PutObject'
    Resource: '[bucket arn + path to logs]'
    Condition:
      StringEquals:
        'aws:SourceArn': '[CloudTrail ARN]'

Add the Policy to a CloudFormation Template

Now that we have the bucket policy itself, we need to translate this to CloudFormation and pass in the appropriate parameters. The CloudFormation template to deploy this policy is pretty simple:

Let’s add our parameters and conditional logic to create a working template. Here’s my first cut:

Now let’s attempt to deploy this bucket. Hint: I need to fix a bunch of things which I will do in the next post.

As always, I tried to deploy the bucket which should be based on working code and I got the dreaded “Policy Document Malformed” exception which tells me absolutely nothing. I’ve written about why the errors CloudFormation gives you for policy documents is a problem before. Here’s one of my posts on the topic.

Since the error message doesn’t help, I’m going to show you how I troubleshoot and get bucket policies working the next post. They can get tricky, but if you take a methodical approach, it’s not so bad.

Update: Although I got this bucket policy to deploy…Cloudtrail wouldn’t let me deploy a trail with this bucket. Find out how I fixed that in an upcoming post.

Follow for updates.

Teri Radichel | © 2nd Sight Lab 2023

About Teri Radichel:
~~~~~~~~~~~~~~~~~~~~
⭐️ Author: Cybersecurity Books
⭐️ Presentations: Presentations by Teri Radichel
⭐️ Recognition: SANS Award, AWS Security Hero, IANS Faculty
⭐️ Certifications: SANS ~ GSE 240
⭐️ Education: BA Business, Master of Software Engineering, Master of Infosec
⭐️ Company: Penetration Tests, Assessments, Phone Consulting ~ 2nd Sight Lab
Need Help With Cybersecurity, Cloud, or Application Security?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
🔒 Request a penetration test or security assessment
🔒 Schedule a consulting call
🔒 Cybersecurity Speaker for Presentation
Follow for more stories like this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
❤️ Sign Up my Medium Email List
❤️ Twitter: @teriradichel
❤️ LinkedIn: https://www.linkedin.com/in/teriradichel
❤️ Mastodon: @teriradichel@infosec.exchange
❤️ Facebook: 2nd Sight Lab
❤️ YouTube: @2ndsightlab
Cloudtrail
S3
Bucket Policy
Cloud Security
AWS
Recommended from ReadMedium