aws-cloudformation / aws-cloudformation/cloudformation-coverage-roadmap

[AWS::Logs::ResourcePolicy] - [BUG] - False-positive drift when PolicyDocument Principal.AWS is a bare account ID

Open
#2,557 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
No language data
Stars
1.1k
Forks
62
PR merge metrics
No merged PRs in 30d

Description

### 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:
1. Template sends `"Principal": {"AWS": "123456789012"}`.
2. CloudWatch Logs stores it as `"arn:aws:iam::123456789012:root"`.
3. Drift detection diffs `"123456789012"` against `"arn:aws:iam::123456789012:root"` and reports drift.
4. 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):

```yaml
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):

```bash
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):

```bash
# 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

Contributor guide

Open the contributing guide

Research direction

Start with repro.yaml and run the listed aws cloudformation deploy and drift-detection commands in us-east-1. Compare the CloudFormation drift output with the direct aws logs put-resource-policy and describe-resource-policies results. Done means the accepted bare account ID no longer produces a false MODIFIED drift report immediately after deployment.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, shell
Domain
cloud, infrastructure
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.