Nothing New Under the Sun
“An ounce of prevention is worth a pound of cure” comes from an anonymous letter printed in the Pennsylvania Gazette, February of 1735.
Some may already know who that author was, but the subject and context of Benjamin Franklin’s words are less well known. “On Protection of Towns from Fire” began by offering citizens advice in safe fire handling. It went on to suggest business regulations, chimney sweep licensing, and the formation of “a club or society… whose business is to attend all fires…” which led to the first Union Fire Company just one year later in 1736 (co-founded by Franklin).
Cut to the Chase - TL;DR
Policies applied through AWS Service Control Policies (SCP) are the fastest and easiest way to secure an AWS environment. So let’s get answers up front and explanations after, because that’s what I like to see when I’m the reader.
- Create an IAM policy with the Action/Effect set to Deny.
- In Action, add any permission you want to evaluate for security.
- Add a Condition, make it Bool, and check for false on secure condition keys. (e.g. “aws:SecureTransport”: “false” to check for TLS)
How’s that for simple? You can apply this enforcement policy organization-wide using SCP or attach it to roles, groups, or even single users. Now let’s dig in and find why this IAM policy style can secure S3 buckets, enforce TLS, encrypt databases, and more. We’ll see how it works, and how you can easily build your own policies to enforce secure actions wherever you want.
The First Rule of IAM Club
The first rule of IAM policy evaluation is: “an explicit deny in any policy overrides any allows.” Another way of explaining would be to say if just one policy uses the deny action on a permission, it will override all the other policies that allow. That’s an extremely powerful rule, because it means a user can write a single policy that will always take precedence over the others. We’re going to use this to enforce only secure actions as seen in step one with Action/Effect set to Deny.
A Best Course of Action
In the second step, I mentioned adding permissions to an action list. At the heart of it, the idea is to list a simple action that you’d like to see being done securely. Think about a common use case: someone wants to prevent unencrypted objects in an S3 bucket. The objects are just sitting in the bucket, so that’s not an action we can work off of with our policy, but what about the action that originally got those objects put in the bucket? That probably rings a bell.
Let’s target using the s3:PutObject action, which causes the security policy to evaluate every time an object is put in a bucket. Remember to think of the actions in step two as something you want to evaluate. Think broadly in terms of “get, put, read” and so forth. The actual security test is separate, which leads us to step three.
Secure is a Condition
Now we need to determine if that action is being carried out in a secure way. Let’s keep to the example of preventing unencrypted objects in an S3 bucket. Evaluate the put action by adding a Condition clause. A condition will determine if the policy will be applied. It’s the deciding factor of when to allow or deny that PutObject from before.
The condition is the “test” or “check” that the action must pass, or else it will be denied. Bool defines the type of test (as in Boolean Logic). Just think of it as asking a simple Yes/No question, which the computer will read as True/False.
Lastly we use the condition to check if the action should be allowed (e.g. only allow secure uploads). Really it’s the key question to our decision, so it’s no wonder these rules or tests are called condition keys. We wanted server side encryption so the key is s3:x-amz-server-side-encryption. To bring it all together, we’ve now created a condition test that is bool and evaluates if “s3:x-amz-server-side-encryption”: “false”.
Looking Back
Let’s think through our logic backwards now from each of the 3 previous steps and see how it sounds if we translated it back into plain English.
- “s3:x-amz-server-side-encryption”: “false”
- “When there is no server side encryption on an S3 bucket…”
- “Action”: [ “s3:PutObject” ]
- “… and there’s a request to put an object in that bucket?”
- “Effect”: “Deny”
- “We deny that.”
It’s clear what the policy is saying when we break each piece out. For the whole picture, here’s the policy in JSON:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3ObjectEncryptCheckSCP",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "*",
"Condition": {
"Bool": {
"s3:x-amz-server-side-encryption": "false"
}
}
}
]
}
You could also read it top down as “We deny any requests to put objects to S3 buckets that do not have server side encryption.”
Conclusion
Your next steps are simple. Start by picking a service you want to secure. Decide which action you want to evaluate. Then pick the condition key to evaluate for. You can do all of this very easily through the Visual Editor in the console, or through IaC such as Terraform or CloudFormation.
If you need a helping hand with securing your cloud environment, contact us! We’re working with everyone right now, from literal startups to global conglomerates. We’re also putting together guides for step-by-step instructions on how to secure common services. Let us know if you’re interested and we can send you an alert when they’re published.
Cheers,
- John Porter