The Complete Guide to Cloud-Native Ransomware Protection in Amazon S3 and KMS

February 3, 2025
Jason Kao

Preventing Ransomware in Amazon S3 and KMS

We've previously covered preventative controls such as Resource Control Policies and Bucket policies for preventing ransomware and creating an effective data perimeter using AWS-native controls such as encryption with KMS and IAM policies. In this post, we'll cover how to prevent ransomware and provide resources & code for 11 different ransomware prevention use cases to ensure preventative controls are in place to prevent against types of ransomware attacks targeting AWS S3.  

These are also available in our GitHub repository: https://github.com/FogSecurity/aws-data-perimeter-iam/blob/main/ransomware_protection.md

For help with preventing ransomware and to stay updated on what we're building, reach out to us at info@fogsecurity.io.

Previous research with reference policies and controls:

We'll look at controls to prevent:

Types of Controls:

S3: Prevent Customer-Provided Encryption (SSE-C)

Recommended Controls: Resource Control Policies and Bucket Policies

There's been recent coverage more reports of ransomware in cloud targeting AWS S3 by utilizing SSE-C, a customer-provided server-side encryption mechanism available in Amazon S3. We cover analysis of these attacks and mitigation techniques in our blog here. One of the methods of preventing usage of SSE-C is to block usage of SSE-C as an encryption method for S3. To do so, we recommend using both Resource Control Policies and Bucket Policies to deny usage of SSE-C. Note: SCPs can also be used, but will not prevent situations where principals outside of your Organization write to resources within your Organization. For more information on when to use RCPs or SCPs, see our technical research here.

Keep in mind, the following policies will not deny other types of encryption such as transparent S3 Managed keys, AWS Managed keys, or Customer Managed (CMKs) keys.

Resource Control Policies (RCPs)

Permissions Needed: organizations:CreatePolicy and organizations:AttachPolicy

Note: To use RCPs for the first time, there may be additional setup to enable the Organization and to enable RCPs. RCPs must also be configured from a management (or a delegated administrator) account within the Organization..

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenySSECEncryption",
      "Effect": "Deny",
      "Principal": "*",
      "Action": [
        "s3:PutObject"
      ],
      "Resource": "*",
      "Condition": {
        "Null": {
          "s3:x-amz-server-side-encryption-customer-algorithm": "false"
        }
      }
    }
  ]
}

We recommend leveraging Resource Control Policies to set standards across all buckets in your Organization, Organizational Unit (OU), or Account. However, if that is not feasible, a bucket policy can be used to protect the bucket itself.  These policies will not change already encrypted objects that exist in the bucket.

Bucket Policies

Permissions Needed: s3:PutBucketPolicy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenySSEC",
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
            	"s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::<your-protected-bucket>/*",
            "Condition": {
        		"Null": {
          			"s3:x-amz-server-side-encryption-customer-algorithm": "false"
        		}
      		}
        }
    ]
}

Note: This was previously covered in our research and overview of ransomware in AWS S3: SSE-C.

S3: Prevent Public Access to S3 Data (General)

Recommended Controls: Account Settings and Resource Control Policies

S3 comes with account and bucket-level settings for Block Public Access. Additionally, Resource Control Policies can be used as an additional layer of security to prevent external (outside your AWS Organization) access to your S3 resources.

We recommend using both account level settings and resource control policies to prevent public access to S3 data.

Account Settings: S3 Block Public Access

Permissions Needed: s3:GetAccountPublicAccessBlock and s3:PutAccountPublicAccessBlock

S3 Block Public Access settings can also be configured for individual buckets and individual access points.  When necessary, we recommend ensuring S3 Block Public Access at the account level first, then if account settings need to be changed to ensure S3 Block Public Access is applied appropriately at the individual bucket and access point level. AWS evaluates all block public access settings across the access point, bucket, and account and will apply the most restrictive combination of those settings.

S3 Block Public Access has 4 settings:

We recommend setting all 4 to true.  For more information about those settings, see AWS's documentation.

To retrieve Block Public Access Settings for an AWS account via CLI:

aws s3control get-public-access-block \
--account-id <your_account_here>

To set Block Public Access Settings for an AWS account via CLI:

aws s3control put-public-access-block \
--account-id <your_account_here> \
--public-access-block-configuration '{"BlockPublicAcls": true, "IgnorePublicAcls": true, "BlockPublicPolicy": true, "RestrictPublicBuckets": true}'

For AWS's "definition of public" and how they evaluate public, see their documentation here. In February 2024, we found a configuration leveraging S3 and KMS together that would permit open access to a S3 bucket. AWS has since accounted for that configuration and updated their evaluation of public for S3.

Resource Control Policies (RCPs)

Permissions Needed: organizations:CreatePolicy and organizations:AttachPolicy

An additional control to prevent public access to S3.  In this case, we will define public as access by an IAM principal outside of your AWS Organization.  

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "BlockPublicAccessToS3",
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "s3:*"
            ],
            "Resource": "*",
            "Condition": {
                "StringNotEqualsIfExists": {
                    "aws:PrincipalOrgID": "ORG_ID_HERE"
                },
                "BoolIfExists": {
                    "aws:PrincipalIsAWSService": "false"
                }
            }
        }
    ]
}

This control can be modified to fit your organization's needs.  Further ideas could be to specify exact permissions, reduce access to specific OUs (Organizational Units) and accounts (such as production vs development environments).  An example of how to use OUs as a multi-layered data perimeter and to prevent against cross-environment access can be found on our blog here.

The following addition to the RCP can also help prevent against confused deputy attacks:

{
            "Sid": "EnforceConfusedDeputyProtection",
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "s3:*"
            ],
            "Resource": "*",
            "Condition": {
                "StringNotEqualsIfExists": {
                    "aws:SourceOrgID": "ORG_ID_HERE"
                },
                "Null": {
          			"aws:SourceAccount": "false"
        		},
                "Bool": {
                    "aws:PrincipalIsAWSService": "true"
                }
            }
}

S3: Prevent Public Access to S3 (ACLs)

Recommended Controls: Account Settings and S3 Bucket-Level Settings

Account settings for S3 access control lists (ACLs) were set with S3 Block Public Access settings in an earlier section - specifically the BlockPublicAcls and IgnorePublicAcls settings for Block Public Access.

An additional layer of security is to disable ACLs for S3 buckets.

Bucket Settings: Object Ownership

Permissions Needed: s3:GetBucketOwnershipControls and s3:PutBucketOwnershipControls

S3 Object Ownership is a bucket-level setting that can also be used to disable ACLs (S3 access control lists). By disabling ACLs, ACLs will no longer affect access and permissions to data in the S3 bucket.  Thus with ACLs disabled, policies must be used for access to S3.

S3 Object Ownership has 3 settings, each which has different implications for bucket and object ACLs.

We prefer the BucketOwnerEnforced setting that disables ACLs (and is also now AWS's default setting for new buckets)

To check S3 Object Ownership settings via CLI for an existing bucket:

aws s3api get-bucket-ownership-controls \
--bucket <your_bucket_here>

To disable ACLs via S3 Object Ownership for an existing bucket:

aws s3api put-bucket-ownership-controls \
--bucket <your_bucket_here> \
--ownership-controls="Rules=[{ObjectOwnership=BucketOwnerEnforced}]"

For more information on S3 Object Ownership, see AWS's documentation here.

S3: Prevent Deletion of Data in S3

Recommended Controls: Bucket Policies and Bucket-Level Settings

To prevent data deletion in S3, resource control policies can also be used. However, we do see data deletion being necessary for certain teams and use cases.  Thus, we prefer bucket-specific controls.

If resource control policies are preferred at the account, ou, or organization level, we recommend ensuring proper exceptions via resource conditions (which can get complex) to ensure valid use cases are not denied.

Bucket Policies

Permissions Needed: s3:PutBucketPolicy

To prevent deletion, we recommend denying the following 3 permissions: 

A lifecycle configuration can be used to set automated expiration or deletion of data in s3.

This is the standard s3 delete.  The behavior may be different if versioning is enabled.

This is the versioning delete that will delete an object version.

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "DenyDelete",
			"Principal": "*",
			"Effect": "Deny",
			"Action": [
				"s3:PutLifecycleConfiguration",
				"s3:DeleteObject",
				"s3:DeleteObjectVersion"
			],
			"Resource": [
				"arn:aws:s3:::<your_bucket_name>",
				"arn:aws:s3:::<your_bucket_name>/*"
			]
		}
	]
}

Bucket Settings: Object Versioning

Permissions Needed: s3:PutBucketVersioning

By default, S3 versioning in disabled on S3 buckets.  However, S3 versioning can be used as an additional layer of security in preventing ransomware via data deletion in S3.

With S3 versioning enabled, a simple delete will apply a delete marker to that object version.  To delete an object with S3 versioning enabled, a specific object version must be specified via s3:DeleteObjectVersion.  Thus, when Object Versioning is enabled, deletion is more complex and thus more difficult for attackers. MFA Delete can also be specified for the bucket.

aws s3api put-bucket-versioning \
--bucket <your_bucket_here> \
--versioning-configuration Status=Enabled
			

Bucket Settings: Object Lock

Permissions Needed: s3:PutBucketObjectLockConfiguration

S3 Object Lock has 2 settings and can be used to help prevent deletion of data in Amazon S3:

We recommend using governance mode unless required.  When in compliance mode, an object version cannot be overwritten or deleted by any user 0 not even the AWS account root user.  The only way to delete the object prior to the retention date expiring is to delete the associated AWS account.

Thus, we recommend using governance mode, where some users may still be able to alter retention settings (as a break glass access).  To do so, these users must have the s3:BypassGovernanceRetention permission.  Keep in mind that the S3 console by default will include the x-amz-bypass-governance-retention:true  header.  We recommend ensuring only proper IAM Principals have the s3:BypassGovernanceRetention permission.

To enable object lock for an existing bucket:

aws s3api put-object-lock-configuration \
--bucket <your_bucket_here> \
--object-lock-configuration='{ "ObjectLockEnabled": "Enabled", "Rule": { "DefaultRetention": { "Mode": "GOVERNANCE", "Days": 30 }}}'

Note: Setting Object Lock on an s3 bucket only applies to new objects placed in the bucket and does not apply to existing objects. To lock existing objects, see AWS's documentation here.

Additional controls can be configured via organizational policies such as RCPs and SCPs to limit s3:BypassGovernanceRetention.

S3: Require AWS KMS Encryption (non SSE-C and non-S3 Managed)

Recommended Controls: Resource Control Policies and Bucket Policies

This control will only permit for AWS Managed or Customer Managed KMS Keys.  SSE-C and S3 Managed (SSE-S3) encryption will be denied. We covered SSE-C above and in our previous research here.  While SSE-S3 is now the default encryption applied by AWS to new S3 objects, it is transparent encryption and may not provide an additional layer of security via the KMS Key policy. We generally recommend using Customer Managed KMS Keys (CMKs) when possible to add an additional layer of security.

Resource Control Policies (RCPs)

Permissions Needed: organizations:CreatePolicy and organizations:AttachPolicy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "EnforceKMSEncryption",
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
            	"s3:PutObject"
                ],
            "Resource": "*",
            "Condition": {
                "Null": {
                    "s3:x-amz-server-side-encryption-aws-kms-key-id": "true"
                }
            }
        }
    ]
}

Bucket Policies

Permissions Needed: s3:PutBucketPolicy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenySSEC",
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
            	"s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::<your_bucket_name>/*",
            "Condition": {
        		"Null": {
          			"s3:x-amz-server-side-encryption-aws-kms-key-id": "true"
        		}
      		}
        }
    ]
}

S3: Prevent Modification of Account Settings

Recommended Controls: Service Control Policies

In this reference, we'll add another layer of security by preventing modification.

Changing the account public access block requires the caller id to match the account id in the endpoints and thus, a SCP will suffice. A RCP can also be used here.

Service Control Policies (SCPs)

Permissions Needed: organizations:CreatePolicy and organizations:AttachPolicy

In the following SCP, we'll leave an exception via condition for an administrator role in the AWS accounts. That condition can be modified to fit your enterprise's needs.

{    
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyS3AccountSettingWithException",
      "Effect": "Deny",
      "Action": [
        "s3:PutAccountPublicAccessBlock"
      ],
      "Resource": "*",
      "Condition": {
        "ArnNotLike": {
          "aws:PrincipalARN":"arn:aws:iam::*:role/<your_admin_role>"
        }
      }
    }
  ]
}

S3: Prevent Modification of Bucket and Object Settings

Recommended Controls: Resource Control Policies

The following permissions for bucket-level settings and object-level settings can be used to set versioning, change public settings, ownership, and other settings that are covered in our ransomware research.  We recommend using a resource control policy to prevent unauthorized modifications to settings.

Your company's requirements may be different, so we recommend working with other stakeholders to determine appropriate controls. An example could be that development teams may need to set bucket policies, and thus other compensating controls may be used to ensure bucket policies are secure.

Bucket Level Settings:

Object Level Settings:

{    
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyS3SettingsWithException",
      "Effect": "Deny",
      "Action": [
		"s3:PutBucketAcl",
		"s3:PutBucketOwnershipControls",
		"s3:PutBucketPolicy",
		"s3:PutBucketPublicAccessBlock",
		"s3:PutBucketObjectLockConfiguration",
		"s3:PutBucketVersioning",
		"s3:PutObjectAcl",
		"s3:PutObjectVersionAcl",
		"s3:PutObjectLegalHold",
		"s3:PutObjectRetention"
      ],
      "Resource": "*",
      "Condition": {
        "ArnNotLikeIfExists": {
          "aws:PrincipalARN":"arn:aws:iam::*:role/<your_admin_role>"
        }
      }
    }
  ]
}

KMS: Prevent External Access (Outside Organization) to KMS

Recommended Controls: Resource Control Policies

This could look like data access or full KMS (kms:*) in our resource control policy.  In the examples here, we'll block decryption to prevent ransomware that needs to decrypt data via KMS. In our resource control policy, we'll block access from outside of our AWS Organization.  This control can be modified to meet your enterprise's needs.

Resource Control Policies (RCPs)

Permissions Needed: organizations:CreatePolicy and organizations:AttachPolicy

{
    "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"
                }
            }
        }
    ]
}

An addition can be made to prevent against confused deputy attacks:

{
            "Sid": "EnforceConfusedDeputyProtection",
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": "*",
            "Condition": {
                "StringNotEqualsIfExists": {
                    "aws:SourceOrgID": "ORG_ID_HERE"
                },
                "Null": {
          			"aws:SourceAccount": "false"
        		},
                "Bool": {
                    "aws:PrincipalIsAWSService": "true"
                }
            }
}

Note: These policies were previously covered in our research on creating a data perimeter with RCPs.

KMS: Prevent External Key Store (XKS)

Recommended Controls: Service Control Policies

A hypothetical but complex attack vector for ransomware is to use KMS External Key Stores (XKS) as detailed by Harsh here. We don't think this attack will be seen due to the complex nature and easier vectors for ransomware.  In order to encrypt data, an attacker would need access to create an external key store, connect the key store, create a KMS key with XKS specified, and then encrypt data with that key.

For this control, we recommend a SCP since external key store actions cannot be done by IAM principals outside of the account. A RCP can also be used if desired.

Service Control Policies (SCPs)

Permissions Needed: organizations:CreatePolicy and organizations:AttachPolicy

{
  "Version": "2012–10–17",
  "Statement": [
    {
      "Sid": "PreventKMSCustomKeyStoreActions",
      "Effect": "Deny",
      "Action": [
        "kms:CreateCustomKeyStore",
        "kms:UpdateCustomKeyStore",
        "kms:ConnectCustomKeyStore",
        "kms:DisconnectCustomKeyStore",
        "kms:DeleteCustomKeyStore"
      ],
      "Resource": "*"
    }
  ]
}

KMS: Prevent Key Creation with non AWS_KMS Key Material

Recommended Controls: Service Control Policies

KMS Keys can have key material originating from the following:

With external key material, if the key material is lost, data encrypted with the KMS key is lost. When using key material that AWS KMS generates (AWS_KMS key origin), AWS manages key material and only deletes key material when the KMS key is deleted. Your organization may have different encryption requirements and as such, these controls may be modified to fit your organization's unique needs. See AWS's documentation for more information about the shared responsibility model in cloud.

Your organization may have specific security requirements that may require usage of CloudHSM or other non AWS_KMS Key material. Prior to applying any organizational policy such as SCPs, we recommend ensuring security controls match company requirements.

This control restricts creation of KMS Keys that have non AWS_KMS key material.  Keep in mind, this control does not permit creation of KMS keys with AWS_KMS key material and in order to do so, appropriate IAM policies must be applied.

Service Control Policies (SCPs)

Permissions Needed: organizations:CreatePolicy and organizations:AttachPolicy

For this control, we'll use the kms:KeyOrigin condition key in the SCP.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyKMSKeysCreationWithNonAWSKMSMaterial",
      "Effect": "Deny",
      "Action": "kms:CreateKey",
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "kms:KeyOrigin": "AWS_KMS"
        }
      }
    }
  ]
}

KMS: Prevent Key Usage with non AWS_KMS Key Material

Recommended Controls: Resource Control Policies

Another control to prevent usage of non AWS_KMS key material KMS Keys is as follows:

Resource Control Policies (RCPs)

Permissions Needed: organizations:CreatePolicy and organizations:AttachPolicy

In this resource control policy, we limit encryption actions with non AWS_KMS key material. Decryption is not denied as this control will prevent against data being encrypted with potentially attacker-controlled or managed keys. In certain theorized attacks, the attackers can remove key material and render data inoperable.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "RestrictUsageOfNonAWSKMSKeyMaterial",
      "Effect": "Deny",
      "Principal": "*",
      "Action": [
        "kms:Encrypt",
        "kms:GenerateDataKey",
        "kms:GenerateDataKeyWithoutPlaintext",
        "kms:GenerateDataKeyPair",
        "kms:GenerateDataKeyPairWithoutPlaintext",
        "kms:ReEncrypt*"
      ],
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "kms:KeyOrigin": "AWS_KMS"
        }
      }
    }
  ]
}

Conclusion

The above examples are preventative measures that will help with ransomware prevention. We recommend using these preventative controls alongside other controls such as IAM controls, backing up data, logging and monitoring, and in general good security practice.

As with any security change, we recommend extensive testing of all controls above - specifically in development and test environments first before applying to production resources as to avoid disruption and potential adverse impact on existing resources. We also recommend working with internal stakeholders to see which security controls make sense for your company to ensure proper business function.

Keep in mind that these controls above are meant as guidelines and may need to be edited to fit your specific enterprise needs and goals.  Additionally, we see these preventative measures as part of a holistic security strategy and will not cover preventing all security incidents. For example, these controls above will not cover overprivileged and/or compromised credentials.  We also recommend good IAM controls such as least privilege for permissions and protecting IAM credentials.

For help or comments with ransomware and data perimeters, reach out to us at info@fogsecurity.io.

References

Fog Security: Protecting Data and Preventing Ransomware - The IAM Guide to Managing and Updating Encryption for AWS Resources

Fog Security: Creating a Data Perimeter with Resource Control Policies (RCPs) and AWS KMS

Fog Security: Ransomware in AWS S3, SSE-C

Fog Security: The Complexity of AWS Data Access with KMS Encryption and KMS Key Grants

AWS: Security Best Practices in IAM

AWS S3: Protecting Data with Encryption

Subscribe to stay up to date on cloud data security and our work.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.