AWS – Adding a Service Control Policy (SCP)

How to Use the Date Command in Ubuntu

Before we begin, we should talk about what SCPs are and how they apply to your organization.

An SCP consists of a policy document that defines (by way of filtering) the services and actions that can be used and performed within an OU or in an AWS account.

If you’ve previously configured an IAM policy, then you will have more than enough background knowledge to get started with SCPs. Apart from a couple of minor exceptions, they look exactly the same.

SCPs can be applied at different levels throughout an organization. The following are the levels, starting from the bottom and going up:

  • AWS account level: An SCP that’s applied to an AWS account takes effect on only that account. It’s important to note that the SCP is very separate from the IAM policies that live inside the account. For example, an SCP might allow full access to S3 for an AWS account but the IAM policies inside the account may deny it (for certain roles and/or users).
  • OU level: An SCP that’s applied at the OU level will apply to all the AWS accounts that live inside the OU, as well as any child OUs (remember that an OU can be a member of an OU).
  • Root level: If an SCP is applied at this level, it will apply to all the AWS accounts inside the organization.

Things can start to get really interesting when you have an SCP applied at multiple levels. The intersection of the policies at the root, OU, account, and IAM levels is evaluated and will determine whether or not an API call is allowed to be made. For example, someone belonging to an IAM role that has full administrator access to an account still won’t be able to call any EC2 APIs if any of the SCPs above it (account, OU, or root) deny EC2 access.

In the following example, we have a top-level OU, Austero Bluth, with an SCP that allows access to all AWS resources for all OUs and accounts underneath it:

Organization hierarchy and policies

Austero Bluth has two child OUs; let’s focus on Sudden Valley. It has an SCP that allows only EC2 and S3. By using a whitelisting approach, anything except these two services will be denied. Remembering that SCPs act like a filter, any OU or AWS accounts living underneath the Sudden Valley OU will, at most, have access to EC2 and S3.

The Sitwell Enterprises Account also has an SCP attached to it. This particular SCP allows S3 and SQS. Note that the SQS statement will have no effect here because the Sitwell account is inside an OU that does not allow SQS. Also, note that this account has no access to EC2, despite the Sudden Valley OU allowing it; this is because EC2 wasn’t explicitly allowed in the SCP attached to the account.

At the IAM level, we have a role in the Sitwell AWS account that allows full administrator privileges. However, because the intersection of the SCPs governing this account will only allow S3, anyone using this role will be denied access if they attempt to use EC2 or SQS, for example.

Let’s also take a look at the Bluth Company Account. The SCP that is attached to it allows full AWS access; however, it lives inside an OU (Balboa Bay) that only allows EC2, RDS, and S3. There is an IAM role inside this account that also allows full admin access but, again, administrators in this account will be limited to EC2, RDS, and S3.

Getting ready

We’re going to proceed step by step through creating an SCP and adding it to an OU.

You’re going to need the ID of the OU in question; you can fetch it from the organization’s web console or use the CLI. It will look something like this:


We’ll be preparing a policy document as well. In this example, we’re going to add an SCP to the Sudden Valley OU to allow access to EC2 and S3. Here’s what our SCP looks like:


How to do it…

Perform the following to create an SCP:

  1. Open a new file in your text editor, add your JSON policy document, and save it.
  2. Run the create-policy CLI command as follows. We’re getting a little tricky with the tr command: here, we’re using it to remove the carriage returns from the policy document, so pay close attention to the syntax in the example provided. Unfortunately, the organization’s CLI doesn’t allow us to provide the path to the policy document directly:
        aws organizations create-policy \
          --content "$(tr -d '\n' < my-policy-file.json)" \ 
          --description "A policy description goes here" \
          --name "My policy" \
  1. If the preceding CLI command works successfully, some JSON will be returned to you containing the ID of the policy we just added. It will look something like the following: 
  1. You can now go ahead and attach this policy to the OU. Use the following CLI command to do this:
        aws organizations attach-policy \
          --target-id <ou-or-aws-account-id> \
          --policy-id <policy-id>
  1. Unfortunately, the preceding command does not output anything if it ran successfully. You can double-check your handiwork in the AWS web console or use the following CLI command to verify that it worked:
        aws organizations list-targets-for-policy \
          --policy-id <policy-id>

How it works…

Again, the policies you add will act as filters at each level of your organizational structure. With this in mind, it might be a good time to point out that testing your policies on a single account before applying them organization-wide will save you a lot of heartache. Making sweeping changes to an SCP living at the top of your organization may create an unforeseen situation at the AWS account level at the bottom of the chain. A local admin in an AWS account is unable to override SCPs.

There’s more…

There are a few more things to keep in mind about SCPs:

  • At the time of writing, you can only have a single root inside an organization (it’s created automatically for you when you create an organization).
  • For obvious reasons, the master account is not affected by any SCPs that are attached to it. You may also notice that it’s technically possible to place the master account in an OU; again, it will be unaffected by any SCPs that have been attached to that OU.
  • Since the master account is unaffected by SCPs, it’s a good idea to leave it as empty as possible and to not create any resources in it. Use child AWS accounts instead so that you can apply fine-grained controls to them.
  • SCPs are required on each OU and account but shouldn’t be considered the only form of access control for your AWS accounts. Apply IAM where appropriate.
  • When we’re creating our policy, we have to specify a --type parameter. At the time of publishing, AWS only supports one variant of OCP: SERVICE_CONTROL_POLICY.
  • As much as possible, follow the principle of least privilege. You want to give your AWS accounts access to only the services they need. This helps you mitigate damage caused by misclicks, programming errors, or compromised accounts.
  • In the long run, you may find it advantageous to not assign controls at the root level. Instead, you may be better off adding all accounts to an OU and applying your controls to the OU instead.
  • Your policies can take a whitelisting or blacklisting approach. In this recipe, we’ve used a whitelist approach, but you may prefer to allow your OUs and accounts to use all services except those you explicitly disallow. You should choose one of these approaches and stick with it, as mixing the two will cause you lots of confusion down the road.
  • Unlike IAM policies, you can’t specify conditions in SCP documents and Resource must be *.

See also

  • The Federating with your AWS account recipe in  Chapter 8, AWS Account Security and Identityfor some discussion around IAM roles

Comments are closed.