On November 13th, 2024, AWS released Resource Control Policies (RCPs). These are not Service Control Policies (SCPs), but rather a good complement to SCPs. We see Resource Control Policies as a good way to enforce data perimeters and to protect resources.
In this post, we'll analyze Resource Control Policies, explain the benefits of RCPs vs SCPs, and give 5 examples of how to use RCPs to build a multi-layered data perimeter to protect data. As of the release, AWS Resource Control Policies only support KMS, Secrets Manager, SQS (Simple Queue Service), STS (Security Token Service), and S3. We'll cover how to creatively use RCPs to protect data across multiple AWS services including those not covered by RCPs. These use cases including layered methods to keep secrets non-public, building zones of trust and preventing cross-environment data access, and more.
SCPs control actions that IAM principals under one's management can perform, while RCPs control actions that can be performed on resources under one's management (resources within the Organization). There's an overlap for SCPs and RCPs for actions performed by IAM Principals within the organization on resources within the organization.
When using RCPs, keep in mind the examples below utilize Deny
statements which override any explicit Allows in other policies. We and AWS recommend testing RCPs thoroughly. Additionally, the RCPFullAWSAccess
policy is attached to the organization root, every OU, and every account when RCPs are enabled. This policy does not grant access and cannot be detached.
GitHub Repository: https://github.com/FogSecurity/aws-data-perimeter-iam/tree/main/policies/resource_control_policies
Prerequisites: Use of Customer Managed Keys (and not AWS Owned Keys)
RCPs today only support KMS, Secrets Manager, SQS, STS, and S3. Thus, to protect data across other services (such as DynamoDB), we need to think creatively. If those resources are encrypted with KMS, we can use KMS in a RCP to create a data perimeter as such where we:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnforceEncryptionReadPerimeter",
"Effect": "Deny",
"Principal": "*",
"Action": [
"kms:Decrypt"
],
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"aws:PrincipalOrgID": "ORG_ID_HERE"
},
"BoolIfExists": {
"aws:PrincipalIsAWSService": "false"
}
}
}
]
}
We can also add a statement to prevent against confused deputy issues.
{
"Sid": "EnforceConfusedDeputyProtection",
"Effect": "Deny",
"Principal": "*",
"Action": [
"kms:Decrypt"
],
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"aws:SourceOrgID": "ORG_ID_HERE"
},
"Null": {
"aws:SourceAccount": "false"
},
"Bool": {
"aws:PrincipalIsAWSService": "true"
}
}
}
We can take the data perimeter one step further. This also is predicated on use of encryption via AWS KMS CMKs.
Assuming a similar structure to AWS's recommended structure for Organizations, this RCP can be attached to the Production OUs. This RCP limits decryption and thus data access to production data by limiting access to principals within the Production OUs.
By using these RCPs, we can create a zone of trust around the Production OUs and limit access to data from Non-Production OUs.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnforceEncryptionReadPerimeter",
"Effect": "Deny",
"Principal": "*",
"Action": [
"kms:Decrypt"
],
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"aws:PrincipalOrgPaths": [
"<ProductionOrgPath1>",
"<ProductionOrgPath2>"
]
},
"BoolIfExists": {
"aws:PrincipalIsAWSService": "false"
}
}
},
{
"Sid": "EnforceProductionConfusedDeputyProtection",
"Effect": "Deny",
"Principal": "*",
"Action": [
"kms:Decrypt"
],
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"aws:SourceOrgPaths": [
"<ProductionOrgPath1>",
"<ProductionOrgPath2>"
]
},
"Null": {
"aws:SourceAccount": "false"
},
"Bool": {
"aws:PrincipalIsAWSService": "true"
}
}
}
]
}
Previously, when working with key policies that were too restrictive - unlocking the key policies required using the account root principal, which has security implications. Although now, with the release of AssumeRoot
, using the root principal can be less dangerous.
This RCP prevents putting a key policy on a key that renders the key unmanageable.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnforceKMSEncryption",
"Effect": "Deny",
"Principal": "*",
"Action": [
"kms:PutKeyPolicy",
"kms:CreateKey"
],
"Resource": "*",
"Condition": {
"Bool": {
"kms:BypassPolicyLockoutSafetyCheck": true
}
}
}
]
}
While S3 has features such as bucket encryption settings, the feature does not require all object uploads to use AWS KMS (objects can be uploaded with AWS Owned encryption).
One of AWS's examples includes a statement to enforce KMS encryption for S3. We add more to this example to ensure all new objects in the S3 bucket are encrypted with a KMS Key. This policy adds a condition to 2 actions that can write in S3: s3:ReplicateObject
and s3:PutObject
to ensure all object puts including replication are encrypted with AWS KMS.
This policy does the following:
{
"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"
}
}
}
]
}
This example RCP has 2 parts and thus 2 layers of security:
BlockPublicPolicy
to be set to True
while adding a resource policy to a secret.{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnforceOrgForSecretsManager",
"Effect": "Deny",
"Principal": "*",
"Action": [
"secretsmanager:*"
],
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"aws:PrincipalOrgID": "<ORG_ID_HERE>"
},
"BoolIfExists": {
"aws:PrincipalIsAWSService": "false"
}
}
},
{
"Sid": "DenyPublicPolicyUpdate",
"Effect": "Deny",
"Principal": "*",
"Action": [
"secretsmanager:PutResourcePolicy"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"secretsmanager:BlockPublicPolicy": "false"
}
}
}
]
}
The examples listed above are examples of how to use AWS's new policy feature, resource control policies, to create data perimeters and protect your AWS resources at scale.
Run, don't walk to implement RCPs in your accounts today!
If you're interested in talking more about data perimeters and cloud encryption, reach out to us at info@fogsecurity.io.
AWS Resource Control Policy Announcement
AWS Documentation: Organizing AWS Environment
AWS Documentation: Best Practices for Organization Structure