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:
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*X8_mo_l-WktcNIwSQ6w5kA.png)
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.
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*sTOwfwTWLRK8GBVd_7vByQ.png)
- We will include the condition from the policy in the documentation to resolve the findings in the ControlTower version.
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*19XBdxISnosxhEQhJ_i77A.png)
- 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:
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*aq6lRwspfCQRAIxY3H1JYA.png)
Let’s add our parameters and conditional logic to create a working template. Here’s my first cut:
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*yon6DTgfLnAhbUC2Ca6LHA.png)
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
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*H9Ew1KCl-29nZiPR.jpeg)