- Cloud Security Lab a Week (S.L.A.W)
- Posts
- Enforce Org-Wide Configurations with Declarative Policies
Enforce Org-Wide Configurations with Declarative Policies
We've learned how to use policies to protect resources and control who can do what; now it's time to learn how to centrally enforce configurations with a brand-new (as of this writing) policy type!
Prerequisites
Have an AWS Organization. Ideally with the hierarchy we built in this training.
The Lesson
Okay, it’s time to address the gremlin in the room from our lab on Block Public Access.
I realize some of you out there were like, “Wait, this thing restricts access? And can work retroactively? And even override all my other IAM and resource policies? But I don’t write it in JSON? What kind of strange beast hath AWS wrought?”
(I assume my editor will tell me if that last sentence is grammatically correct for any prior version of English). [It’s not grammatically incorrect, but it’s all over the place chronologically and linguistically. I’m letting it pass. -Ed]
BPA is a bit of a weird one. And it’s even weirder now that AWS has added it as a defense for EBS snapshots and even VPCs (a big one we’ll get to later).
Something you might have picked up on as we’ve gone along is that a lot of the time when we are clicking things in the console, we are defining configuration settings for various services. Way back when we turned on CloudTrail we set it up as an organizations trail, pointed it to an S3 bucket, and set some other things. While we used API calls (via clicky clicky), those API calls set up the configuration.
The way to think about BPA is as another configuration, but for security. If you recall the IAM policy evaluation logic (the latest version is in our RCP lab), that shows how all the IAM and resource-based and SCP policies interact to approve or deny something. BPA isn’t part of that flow — it’s simply “Can this bucket contain anything public?”
It’s a checkbox. It’s a state definition. Call it what you want, but that’s why it can’t be circumvented by some new IAM policy… it’s on (for various states of on) or it’s off. These are security invariants which prevent bad things from happening.
Cool, but how do we manage these things at scale? Especially when there might be other security and operations related configurations we want to enforce consistently?
Well, there’s the old way and the new way. And the old way hurt. We would have to set baseline configurations to be deployed with infrastructure as code, and then restrict any changes by using SCPs or identity-based policies. Heck, for a lot of things that is still the only way to enforce consistent configurations. But a few weeks before I wrote this, we got the new hotness: Declarative Policies.
Declarative Policies
Released in December 2024, they enforce desired configurations for certain AWS services. How? Probably elves. Possibly pixies.
Here’s how to think of them in relation to the other kinds of policies we’ve covered:
IAM (permissions) policies: Define what someone can do.
Permission Boundaries: Define the maximum things someone can possibly do, but don’t actually give them permissions to do any of it.
Service Control Policies: Define the maximum actions allowed to an account.
Resource policies: Define the access and actions allowed on a resource.
Resource Control Policies: Define the maximum actions and access allowed for resources in an account.
If you refer back to that policy evaluation logic, these all work together to define whether an API call or remote access is allowed. Amazon calls these authorization policies because they’re all about authorizing something; enforcement happens only when someone tries to do something. So now we get to add…
Declarative policies: Define and enforce certain configuration settings for certain services. Mostly ones which are interesting for security.
Declarative policies define and enforce a desired state. Full stop. They are not authorization policies; they enforce configuration states for (this is copied from the documentation as of December 2024):
Service | Setting |
---|---|
VPC | VPC Block Public Access |
EC2 | Serial Console Access Image Block Public Access Allowed Images Settings Instance Metadata Defaults |
EBS | Snapshot Block Public Access |
Some of these are very cool. Like, I can’t wait for our VPC Block Public Access lab. EBS allowed images is possibly one of the most important for enterprises, because they can now enforce which AMIs can be used (this was practically impossible to enforce consistently and effectively before). Now you can allow people only to use approved and secure images! Or you can require IMDSv2 (remember that metadata service thing?) in every account. Just these half-dozen settings can be very impactful.
And no, as of this writing S3 BPA isn’t supported. I suspect it’s either fear of the ability to break S3 at scale… or because BPA has both account and bucket level settings.
Declarative policies are written in JSON (natch) in your management account (we could delegate administration, but we won’t today). You apply them to OUs and accounts just like SCPs or RCPs. The service includes a feature to perform a pre-check and see what the impact would be if you rolled out the policy.
Key Lesson Points
Declarative policies enforce desired configuration states for certain AWS settings and services.
They enable baseline configurations which are enforced in your organization.
Today these are largely security-related settings like Block Public Access.
We call these security invariants. Heck, Chris and I even did an AWS re:Invent talk on them!
The Lab
Declarative policies are managed like all our other organization policies, but they come with an extra little safety feature which checks how things are configured and generates a report so you can identify opportunities to break things. Uh, maybe I worded that wrong, but I think my statement is still accurate.
We will:
Create an S3 bucket to store the report.
Set up the bucket policy so the declarative policies service can write the report.
Run the report.
Review the results.
Enable a declarative policy to require IMDSv2 in our Production OU.
Video Walkthrough
Step-by-Step
We’ll be working completely in the management account today, so log in to your sign-in portal > CloudSLAW > AdministratorAccess > S3. THEN CHANGE YOUR REGION TO VIRGINIA!!!! This is a very important step. Remember that all global services, including Organizations, actually run in us-east-1 Virginia. Our S3 bucket for the report needs to be there (I messed this up the first time, and you can see my extra bucket sitting around in the video):
Then Create bucket:
Name it declarative-results-firstinitiallastname-randomcrap then Create bucket:
Then click on the bucket name > Permissions > Bucket policy > Edit:
Copy this policy and paste it in:
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DeclarativePoliciesReportBucket",
"Effect": "Allow",
"Principal": {
"Service": ["report.declarative-policies-ec2.amazonaws.com"]
},
"Action": ["s3:PutObject"],
"Resource": "arn:aws:s3:::amzn-s3-demo-bucket/*",
"Condition": {
"StringEquals": {
"aws:SourceArn": "arn:aws:declarative-policies-ec2:us-east-1:your-12-digit-account-id:*"
}
}
}]
}
Notice those two boxed bits? You need to swap in your bucket ARN and Account ID. By now you should be able to read and understand what’s going on here: we need the bucket ARN to allow access to write new objects to this bucket (which is why the “*” is at the end — without that it would only have permission to change the bucket’s settings, not put things into it). It also restricts access to only the policy engine from your account.
On the downside, the service has EC2 in the name, so maybe we won’t be seeing it for other services like S3?
The bucket ARN is right above the window, and the account ID is easily available in the upper-right corner menu. Make sure when you paste them in you leave the wildcards, which means ignoring the warning on line 13:
Then Save changes.
Now we need to go to Organizations > Policies > Declarative policies for EC2:
I’m feeling cheeky so I’ll just put this next screenshot here for you to figure out the next step:
Now we need to create our account status status report, which is only possible after you try to view it. So Actions > View account status report:
Since we don’t have one, Generate status report:
Browse > Pick the S3 bucket you just created > click Root > Submit (scroll down to the bottom):
My report took about 5 minutes to generate. We don’t have that many accounts in our org, so it goes fast. I could see this taking much longer in a larger environment.
Yours should look identical to mine. You can dig down into every account and region to check the settings.
Notice that we don’t have IMDSv2 set as the default anywhere. Since I spent all that time telling you how bad v1 is, let’s fix that. Click Declarative policies for EC2 in the breadcrumb trail:
Then Create policy and use these settings. We will build it out for IMDSv2:
Another cool feature we are skipping is the Custom error message which users will see if they try to violate policy. I suggest finding the personal cell phone number of your least-favorite coworker and setting it to say “If you see this error please call 555-555-5555.”
Click your new policy > Targets, then select Workloads > Production. This will enforce IMDSv2 on all production workloads. If possible run it everywhere, but for our purposes I want to keep the option to run insecure things in the NonProd OU so we can have fun experiments.
All set!
Now I highly advise you to go into a regional service like EC2 and change your region back to Oregon before you forget!
Lab Key Points
Always run a status report before applying a new declarative policy.
-Rich
Reply