AnalysisType: policy
Filename: aws_s3_bucket_object_lock_configured.py
PolicyID: "AWS.S3.BucketObjectLockConfigured"
DisplayName: "AWS S3 Bucket Object Lock Configured"
Enabled: false
ResourceTypes:
- AWS.S3.Bucket
Tags:
- AWS
- S3
- PCI
- Impact:Data Destruction
Reports:
PCI:
- 10.5.3
MITRE ATT&CK:
- TA0040:T1485
Severity: Low
Description: >
This policy validates that S3 buckets have an Object Lock configuration enabled. This should be used with specific suppression lists to ensure it is applied only to appropriate S3 buckets, such as those containing CloudTrail or other auditable records.
Runbook: Create a new S3 bucket with an appropriate Object Lock configuration and point audit records to that bucket.
Reference: https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock.html
Tests:
- Name: Object Lock Configured With Governance
ExpectedResult: false
Resource:
{
"AccountId": "123456789012",
"Arn": "arn:aws:s3:::example-bucket",
"EncryptionRules":
[
{
"ApplyServerSideEncryptionByDefault":
{ "KMSMasterKeyID": null, "SSEAlgorithm": "AES256" },
},
],
"Grants":
[
{
"Grantee":
{
"DisplayName": "example.user",
"EmailAddress": null,
"ID": "1",
"Type": "CanonicalUser",
"URI": null,
},
"Permission": "FULL_CONTROL",
},
],
"LifecycleRules": null,
"LoggingPolicy": null,
"MFADelete": "Disabled",
"Name": "example-bucket",
"ObjectLockConfiguration":
{
"ObjectLockEnabled": "Enabled",
"Rule":
{
"DefaultRetention":
{ "Days": 1, "Mode": "GOVERNANCE", "Years": null },
},
},
"Owner": { "DisplayName": "example.user", "ID": "1" },
"Policy": null,
"PublicAccessBlockConfiguration":
{
"BlockPublicAcls": true,
"BlockPublicPolicy": true,
"IgnorePublicAcls": true,
"RestrictPublicBuckets": true,
},
"Region": "us-west-2",
"ResourceId": "arn:aws:s3:::example-bucket",
"ResourceType": "AWS.S3.Bucket",
"Tags": { "environment": "pci" },
"TimeCreated": "2019-01-01T00:00:00.000Z",
"Versioning": "Enabled",
}
- Name: Object Lock Configured With Compliance
ExpectedResult: true
Resource:
{
"AccountId": "123456789012",
"Arn": "arn:aws:s3:::example-bucket",
"EncryptionRules":
[
{
"ApplyServerSideEncryptionByDefault":
{ "KMSMasterKeyID": null, "SSEAlgorithm": "AES256" },
},
],
"Grants":
[
{
"Grantee":
{
"DisplayName": "example.user",
"EmailAddress": null,
"ID": "1",
"Type": "CanonicalUser",
"URI": null,
},
"Permission": "FULL_CONTROL",
},
],
"LifecycleRules": null,
"LoggingPolicy": null,
"MFADelete": "Disabled",
"Name": "example-bucket",
"ObjectLockConfiguration":
{
"ObjectLockEnabled": "Enabled",
"Rule":
{
"DefaultRetention":
{ "Days": 365, "Mode": "COMPLIANCE", "Years": null },
},
},
"Owner": { "DisplayName": "example.user", "ID": "1" },
"Policy": null,
"PublicAccessBlockConfiguration":
{
"BlockPublicAcls": true,
"BlockPublicPolicy": true,
"IgnorePublicAcls": true,
"RestrictPublicBuckets": true,
},
"Region": "us-west-2",
"ResourceId": "arn:aws:s3:::example-bucket",
"ResourceType": "AWS.S3.Bucket",
"Tags": { "environment": "pci" },
"TimeCreated": "2019-01-01T00:00:00.000Z",
"Versioning": "Enabled",
}
- Name: Object Lock Not Configured
ExpectedResult: false
Resource:
{
"AccountId": "123456789012",
"Arn": "arn:aws:s3:::example-bucket",
"EncryptionRules":
[
{
"ApplyServerSideEncryptionByDefault":
{ "KMSMasterKeyID": null, "SSEAlgorithm": "AES256" },
},
],
"Grants":
[
{
"Grantee":
{
"DisplayName": "example.user",
"EmailAddress": null,
"ID": "1",
"Type": "CanonicalUser",
"URI": null,
},
"Permission": "FULL_CONTROL",
},
],
"LifecycleRules": null,
"LoggingPolicy": null,
"MFADelete": "Disabled",
"Name": "example-bucket",
"ObjectLockConfiguration":
{ "ObjectLockEnabled": "Disabled", "Rule": null },
"Owner": { "DisplayName": "example.user", "ID": "1" },
"Policy": null,
"PublicAccessBlockConfiguration":
{
"BlockPublicAcls": true,
"BlockPublicPolicy": true,
"IgnorePublicAcls": true,
"RestrictPublicBuckets": true,
},
"Region": "us-west-2",
"ResourceId": "arn:aws:s3:::example-bucket",
"ResourceType": "AWS.S3.Bucket",
"Tags": { "environment": "pci" },
"TimeCreated": "2019-01-01T00:00:00.000Z",
"Versioning": "Enabled",
}
# ------ paired body: aws_s3_bucket_object_lock_configured.py ------
from panther_base_helpers import deep_get
RETENTION_PERIOD_DAYS = 365
def policy(resource):
object_lock = resource["ObjectLockConfiguration"]
# Object lock configuration is not enabled, or enabled without a rule
if not object_lock or object_lock["ObjectLockEnabled"] != "Enabled" or not object_lock["Rule"]:
return False
# Ensure ObjectLockConfiguration is in COMPLIANCE mode, not GOVERNANCE mode
if deep_get(object_lock, "Rule", "DefaultRetention", "Mode") != "COMPLIANCE":
return False
return (
deep_get(object_lock, "Rule", "DefaultRetention", "Days", default=0)
>= RETENTION_PERIOD_DAYS
)