Since the release of AWS Resource Control Policies (RCPs), we’ve seen multiple posts on how to use RCPs. We believe a holistic security strategy in AWS with Organizational Policies include both Resource Control Policies (RCPs) and Service Control Policies (SCPs).
We previously did research and provided example RCPs on how to create a data perimeters here. In this follow-up post, we'll cover the following:
Since RCPs are a new release from late 2024, we see companies adopting RCPs as the following categories:
RCPs offer the following benefits that SCPs did not cover or completely cover:
There are different challenges with each category above including:
We can simplify this to the following 2 high-level use cases:
We can translate that to AWS terms:
There is overlap with those 2 use cases as follows:
The following is AWS's more complex table on how to use SCPs and RCPs.
SCP and RCP Limits include:
For more information, see AWS's documentation for SCP limitations and RCP limitations.
Since we like Venn diagrams, here's a Venn diagram on how to use RCPs and SCPs from a high-level security perspective.
Keep in mind that there are scenarios where both RCPs and SCPs can apply. If possible, both can be configured as multiple layers of security. An example would be to block access to a certain bucket you own from a specific identity within your Organization. This control can be achieved with either an RCP or SCP.
The below examples will cover considerations to use RCPs or SCPs in addition to the high-level use cases above. For any organizational-level policy, we recommend meticulous testing to ensure no impact on running infrastructure and applications.
Protecting Resources in S3, STS, KMS, SQS, Secrets Manager
Currently, AWS RCPs only support S3, STS (Security Token Service), KMS (Key Management Service), SQS (Simple Queue Service), and Secrets Manager. These services can be extended to protect resources in IAM (via STS, including actions such as sts:AssumeRole
) and other services such as DynamoDB (via KMS).
Enforcing Consistent Security Standards for Resources
IAM Role Trust Policies, S3 Bucket Policies, KMS Key Policies, SQS Queue Policies, and Secrets Manager Secrets Resource-Based Policies are all examples of resource-based policies that may have variability. With RCPs, access standards can be set across an organization, organizational unit, and/or account.
You're running out of attachment room or space in SCPs
If the use case can be achieved by both SCPs and RCPs and you're running out of attachment room or space in SCPs, RCPs can be used.
You want to use NotResource in your policy
SCPs do not support NotResource. If using NotResource
, we recommend using RCPs. With any of the more complex policy elements such as NotResource
, we recommend using care to ensure the policy logic matches intent.
An example of a policy that uses NotResource may include resource exclusions. Resource exclusions could be for limited business use cases that do not conform to typical company security standards and thus may need to be added to an exclusion list.
A common exclusion list could be for IAM roles and role assumption via STS. In certain cases, external vendors may assume roles within your organization. The following RCP can be used to exclude vendor roles from a RCP statement that protects against external role assumption from outside the organization and then uses a 2nd statement to ensure only trusted vendor accounts can access the vendor role within your organization.
Note: the following can be supplemented with confused deputy protection to prevent malicious actors impersonating AWS services by using condition keys such as aws:SourceAccount
or aws:SourceOrgID
. An example of confused deputy protection can be found here in our sample RCP on restricting access to production data.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyExternalRoleAssumption",
"Effect": "Deny",
"Principal": "*",
"Action": "sts:AssumeRole",
"NotResource": "arn:aws:iam::*:role/<trusted_vendor_role>",
"Condition": {
"StringNotEqualsIfExists": {
"aws:PrincipalOrgID": "<your_org_id>"
},
"BoolIfExists": {
"aws:PrincipalIsAWSService": "false"
}
}
},
{
"Sid": "DenyAccessOutsideOfThirdPartyTrustedAccounts",
"Effect": "Deny",
"Principal": "*",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::*:role/<trusted_vendor_role>",
"Condition": {
"StringNotEqualsIfExists": {
"aws:PrincipalAccount": "<trusted_external_vendor_account>"
},
"BoolIfExists": {
"aws:PrincipalIsAWSService": "false"
}
}
}
]
}
If your use case can be achieved by either RCPs or SCPs, here are reasons to use SCPs over RCPs:
Service Support in AWS
You're looking to restrict access to a service that's not S3, STS (Security Token Service), KMS (Key Management Service), SQS (Simple Queue Service), or Secrets Manager. RCPs currently do not support services outside of those 5 services.
Desire or Need to use NotAction
RCPs do not support NotAction
elements. If there are needs for using NotAction
(with Denys), we recommend using SCPs. As with the more complex policy elements such as NotResource
, we recommend using care to ensure the policy logic matches intent with the usage of NotAction
.
One usage for SCPs is to deny access to broader services. Such examples may be purpose-built accounts in an Organization used for platform administration such as delegated administration. The below example policy showcases how that may be done (assuming usage of a default Allow * policy as well such as the default FullAWSAccess policy).
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RestrictServicesOutsideOfLimitedAdministration",
"Effect": "Deny",
"NotAction": [
"organizations:*",
"account:*",
"cloudtrail:*",
"iam:*",
"sts:*"
],
"Resource": "*"
}
]
}
Migrating from SCP to RCP
Below is an example of migrating a control from an SCP to an RCP while gaining additional security for resources within your Organization. An additional layer of data security for AWS S3 can be to require either an AWS Managed KMS Key or a Customer Managed Key (Read more here.)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnforceKMSEncryption",
"Effect": "Deny",
"Action": [
"s3:PutObject",
"s3:ReplicateObject"
],
"Resource": "*",
"Condition": {
"Null": {
"s3:x-amz-server-side-encryption-aws-kms-key-id": "true"
}
}
}
]
}
Now, we can use an RCP to accomplish something similar:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnforceKMSEncryption",
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:PutObject",
"s3:ReplicateObject"
],
"Resource": "*",
"Condition": {
"Null": {
"s3:x-amz-server-side-encryption-aws-kms-key-id": "true"
}
}
}
]
}
Note: To use the same policy as a RCP, we added the "Principal": "*"
block.
If migrating this from an SCP to an RCP, the following will change in terms of security:
The control will still hold that:
If you want to talk more about data perimeters, security controls like the policies above, or have questions about implementing organizational policies such as RCPs and SCPs, we are happy to chat at info@fogsecurity.io.
Fog Security: Creating a Data Perimeter with Resource Control Policies (RCPs) and AWS KMS
Fog Security GitHub: Example Resource Control Policies
AWS: Authorization Policies in AWS Organizations