Troubleshooting S3 bucket policies
ACM.199 A working Organization CloudTrail Bucket Policy
Part of my series on Automating Cybersecurity Metrics and stories on AWS S3 Buckets. The Code.
Free Content on Jobs in Cybersecurity | Sign up for the Email List
In the last post I pieced together a bucket policy for an organization CloudTrail bucket policy. Then I got a malformed policy document error.
Now I need to troubleshoot the policy. After a few failed attempts, I have to do it the old-fashioned way (and a more sensible way if you are new to S3 bucket policies).
I’m going to piece together my bucket policy one statement at a time. I’m going to hard-code the values to something that works. Then I’m going to turn each value into a parameter one at a time.
S3 policy deploy function
First, here’s my function that I create to deploy the template. As always this function uses the generic code I wrote to deploy a CloudFormation stack.
I look up the organization ID to pass into the CloudFormation template. The trail is optional, if passed in. Right now we don’t have a trail, so that parameter does not get passed to the template. The rest is standard, per how I’ve been deploying things up to now.
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*4_Rkz5hnbENFHuqXLVTHAg.png)
Then I add a line to call to the script at the end of the deployment function.
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*BUopSmIeBVMnPnnimtOp7A.png)
Malformed Policy Document
“Malformed Policy Document” could be anything. The error returns no number, no information, nothing. I wrote about that in the last post and here:
I really, really wish the CloudFormation team or whomever passes them this message could help a dev out and give me a hint.
The other problem is that this particular problem I caused, whatever it is, takes a very long time to fail. So I have to wait forever for the failure to try again. It’s a waste of time to randomly try different things and sit there waiting for a failure.
As a reminder, I pretty much copied this policy from the AWS Documentation and the Control Tower bucket policy. Then I converted it from JSON to YAML using an online tool and swapped values for parameters. I was crossing my fingers that copying the code would keep my policy free of typos and errors but alas, no.
Pinpointing the error in the S3 bucket policy
Here’s the current policy.
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*cARD6O9PhWWv8Rmqr_LNZQ.png)
I copy and paste that policy to a backup file.
cp CloudTrailPolicy.yaml CloudtrailPolicy.yaml.bak
Next I delete everything except the first statement in the first file.
vi CloudTrailPolicy.yaml
[delete, delete, delete]
!wq
I end up with this:
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*SqqCweB0J8QbMHpLQKr4Wg.png)
What I also do is remove the two sub statements and replace them with the correct hard coded values. I can look up the CloudTrail bucket ARN and replace these two lines:
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*jtn9ZE5Dhixpgt5S_GECWQ.png)
Note that the first like is simply the bucket ARN.
The second line is the bucket ARN with /* at the end.
Then I can try to deploy just that simple policy.
And, it works.
So now I’m going to try to add back in my sub statement. I had already tried it a few different ways. Let’s revisit the ImportValue documentation and make sure I have formulated that correctly.
Now, I had tried the Sub first, and then the ImportValue first. Here’s an important note on ImportValue with sub.
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*RuqiDpl6RyEjyPf9getE1A.png)
In the case above, the Sub is used to formulate the value passed to ImportValue. That’s not what we are doing here. I’m trying to use the value returned from ImportValue in a Sub.
But actually, don’t need a Sub at all for the first line. Let’s replace that with a simple ImportValue and see if it works.
I’m going to copy and paste my export name to make sure I don’t have any typos in that.
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*J8TIq2u757-am-C8fNf34A.png)
I replace the first resource with this:
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*j_lNAvH-kmgVSp1XcU47Pg.png)
Run the deployment again. Success.
Now let’s try the second value. The ImportValue documentation didn’t really help us because it only covers the case of using a Sub to create an ImportValue name.
Let’s look at the Sub documentation. As I’m writing this I think I know what I need to do before even looking at it.
There are a couple of ways to use Sub. We want this one:
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*4eFxuyZzbHoAnUFRbGSZdQ.png)
The String is the value you want to end up with, that has tokens that need to be replaced with values. Following that is a list of values with which to replace the token. Here’s the example in the documentation.
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*880rn46v_OPNcWHnalMoMw.png)
We want this:
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*r01tbGCR2oYsjQa_cUA3hw.png)
I was tryin to use a shorthand version of Sub which doesn’t work with ImportValue apparently.
If you get an error “Mapping Values Not Allowed Here” make sure you have the !Sub on one line followed by the dashes indented on the next two lines. the first line contains the string with the tokens to replace. The lines after define the values for each token.
Cool let’s add the next statement. For the next statement I’m going to leave the condition off initially as I do not know if that is part of the problem. I’m trying to set the condition to * since I don’t have a CloudTrail yet.
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*LX7DwiEU4_0QJGexUdUdig.png)
This statement is taking a very long time to deploy, unlike the last. And yes, I get a malformed policy document. In the statement above I retyped some of the lines because CloudShell copy and paste from a Mac is pretty unusable at the moment (hopefully fixed soon). I have no space after the dash before cloudtrail.amazonaws.com. I fixed that and it works.
Now let’s try to add the policy condition. I wrote about Conditions in policies here:
Not to be confused with CloudFormation conditions which provide an if this or that construct to optionally deploy resources:
Here’s our policy condition. I can’t use that Ref because the ARN is an output of another CloudFormation staack so I need to use ImportValue.
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*QYSlL3laKfcq1-iMSxURxg.png)
This is one thing I’m not sure will work. I’m setting the default for this parameter to an asterisk (*).
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*G3hHefALn29e7egVwzOqkQ.png)
Yay it works. One more statement to go. In the last statement I was also using an invalid sub format. I changed it to match the first statement and the template successfully deployed. Here’s what I have for at the moment:
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*N4vxKiwdQ9XIJpOfCtwIkg.png)
However, there’s one more thing I need to fix. The path where the files are written is incorrect. Refer to the bucket policy for CloudFormation documentation.
This is where the files will be written for an organization:
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*OgTHJKtqoTQ1dp7vzhyqvQ.png)
Here’s where we need our organization id. I initially wrote the code like this:
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*jLy40nbJCXR-JTAJ2A1ftg.png)
And got this error:
One or more Fn::Sub intrinsic functions don’t specify expected arguments. Specify a string as first argument, and an optional second argument to specify a mapping of values to replace in the string.
This is kind of nuts. Everythig seems to be a list of things in YAML but in this case we need a mapping where the values to replace the tokens in the sub start with only one dash. Or in other words, remove the dahs before OrgId above.
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*y6rSpXoBendD5HE4_BgrnA.png)
And it works.
Final policy template:
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*FC2Ufx55aPqFxvTzHmKZvw.png)
You can head over to your S3 bucket, click on Permissions and scroll down to see that the policy is successfully deployed.
![](https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*aLF6pdmhT3Qg-15K-LkFdQ.png)
Next I want to take a look at the S3 Access Log bucket policy created by Control Tower. Supposedly that bucket was supposed to automatically get a policy assigned to it per the AWS console, but no policy existed on that bucket. I suspect we’ll need to go ahead and add one.
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)