Resource Name
AWS::Logs::ResourcePolicy
Issue Description
Deploying an AWS::Logs::ResourcePolicy whose PolicyDocument uses a bare account ID as the principal (for example "Principal": {"AWS": "123456789012"}) causes CloudFormation drift detection to always report the resource as MODIFIED, with no template changes and no manual edits to the policy.
The obvious fix (write the principal as the root ARN so it matches what is stored) does not work: CloudWatch Logs rejects that form at deploy time with HTTP 400 Principal section of policy contains ARN instead of account ID. One form deploys but always drifts; the other form does not deploy at all.
What happens step by step:
- Template sends
"Principal": {"AWS": "123456789012"}.
- CloudWatch Logs stores it as
"arn:aws:iam::123456789012:root".
- Drift detection diffs
"123456789012" against "arn:aws:iam::123456789012:root" and reports drift.
- Re-deploying the same template is a no-op ("No changes to deploy"); drift is still reported. Forcing an update on an unrelated property (for example
RetentionInDays) does not clear it, because CloudFormation only re-calls PutResourcePolicy when the policy body itself changes.
Impact: any stack that grants an account-root principal on a CloudWatch log group is permanently reported as drifted. This includes every CDK-managed log group whose resource policy takes an account principal, since CDK converts principals to the bare account ID form on purpose in LogGroup.addToResourcePolicy() (aws/aws-cdk#37797) precisely because CloudWatch Logs rejects the ARN form. Drift-based compliance checks and CI gates that require IN_SYNC produce constant false alarms.
Expected Behavior
StackDriftStatus: IN_SYNC immediately after deploy, since the template has not been modified and no one edited the policy out of band.
Observed Behavior
StackDriftStatus: DRIFTED
ResourceType: AWS::Logs::ResourcePolicy
StackResourceDriftStatus: MODIFIED
PropertyDifferences[0]:
PropertyPath: /PolicyDocument
ExpectedValue: ... "Principal":{"AWS":"123456789012"} ...
ActualValue: ... "Principal":{"AWS":"arn:aws:iam::123456789012:root"} ...
DifferenceType: NOT_EQUAL
Test Cases
Save as repro.yaml (replace 123456789012 with your account ID):
AWSTemplateFormatVersion: '2010-09-09'
Resources:
LG:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /cwl-drift-repro
RetentionInDays: 1
RP:
Type: AWS::Logs::ResourcePolicy
Properties:
PolicyName: cwl-drift-repro-policy
PolicyDocument: !Sub |
{
"Version":"2012-10-17",
"Statement":[{
"Sid":"AllowAccount",
"Effect":"Allow",
"Principal":{"AWS":"123456789012"},
"Action":"logs:PutLogEvents",
"Resource":"${LG.Arn}"
}]
}
Deploy, then run drift detection immediately (no changes in between):
STACK=cwl-drift-repro; REGION=us-east-1
aws cloudformation deploy --stack-name $STACK --template-file repro.yaml --region $REGION
TOKEN=$(aws cloudformation detect-stack-drift --stack-name $STACK --region $REGION \
--query StackDriftDetectionId --output text)
while :; do
S=$(aws cloudformation describe-stack-drift-detection-status \
--stack-drift-detection-id $TOKEN --region $REGION --query DetectionStatus --output text)
[ "$S" != "DETECTION_IN_PROGRESS" ] && break; sleep 5
done
aws cloudformation describe-stack-resource-drifts --stack-name $STACK --region $REGION
Direct CloudWatch Logs repro (confirms the rewrite happens in CloudWatch Logs, not CloudFormation):
# Rejected on write
aws logs put-resource-policy --policy-name test-arn \
--policy-document '{"Version":"2012-10-17","Statement":[{"Sid":"X","Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:root"},"Action":"logs:PutLogEvents","Resource":"*"}]}'
# InvalidParameterException: Principal section of policy contains ARN instead of account ID
# Accepted, but read-back shows it was rewritten
aws logs put-resource-policy --policy-name test-bare \
--policy-document '{"Version":"2012-10-17","Statement":[{"Sid":"X","Effect":"Allow","Principal":{"AWS":"123456789012"},"Action":"logs:PutLogEvents","Resource":"*"}]}'
aws logs describe-resource-policies --query 'resourcePolicies[?policyName==`test-bare`].policyDocument' --output text
# "Principal":{"AWS":"arn:aws:iam::123456789012:root"}
Other Details
Reproduced in region: us-east-1
Resource Name
AWS::Logs::ResourcePolicy
Issue Description
Deploying an
AWS::Logs::ResourcePolicywhosePolicyDocumentuses a bare account ID as the principal (for example"Principal": {"AWS": "123456789012"}) causes CloudFormation drift detection to always report the resource asMODIFIED, with no template changes and no manual edits to the policy.The obvious fix (write the principal as the root ARN so it matches what is stored) does not work: CloudWatch Logs rejects that form at deploy time with HTTP 400
Principal section of policy contains ARN instead of account ID. One form deploys but always drifts; the other form does not deploy at all.What happens step by step:
"Principal": {"AWS": "123456789012"}."arn:aws:iam::123456789012:root"."123456789012"against"arn:aws:iam::123456789012:root"and reports drift.RetentionInDays) does not clear it, because CloudFormation only re-callsPutResourcePolicywhen the policy body itself changes.Impact: any stack that grants an account-root principal on a CloudWatch log group is permanently reported as drifted. This includes every CDK-managed log group whose resource policy takes an account principal, since CDK converts principals to the bare account ID form on purpose in
LogGroup.addToResourcePolicy()(aws/aws-cdk#37797) precisely because CloudWatch Logs rejects the ARN form. Drift-based compliance checks and CI gates that requireIN_SYNCproduce constant false alarms.Expected Behavior
StackDriftStatus: IN_SYNCimmediately after deploy, since the template has not been modified and no one edited the policy out of band.Observed Behavior
Test Cases
Save as
repro.yaml(replace123456789012with your account ID):Deploy, then run drift detection immediately (no changes in between):
Direct CloudWatch Logs repro (confirms the rewrite happens in CloudWatch Logs, not CloudFormation):
Other Details
Reproduced in region: us-east-1