Verify AWS credentials and trailtool readiness
$ trailtool status
AWS credentials: OK (account XXXXXXXXXXXX)
Ingestor stack: OK (trailtool-ingestor)
Data access: OKGood, trailtool is ready. Let me check the role for denied events.
Get SandboxPowerUser role details
$ trailtool roles detail SandboxPowerUser --format json{
"name": "AWSReservedSSO_SandboxPowerUser_XXXXXXXXXXXXXXXX",
"account_id": "XXXXXXXXXXXX",
"total_events": 60,
"total_denied_events": 11,
"top_denied_event_names": {
"cloudtrail.amazonaws.com:LookupEvents": 1,
"iam.amazonaws.com:GetRole": 3,
"logs.amazonaws.com:GetLogEvents": 1
},
"denied_event_accesses": [
{
"service": "cloudtrail.amazonaws.com",
"event_name": "LookupEvents",
"count": 1,
"error_message": "User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/AWSReservedSSO_SandboxPowerUser_XXXXXXXXXXXXXXXX/alex@engseclabs.com is not authorized to perform: cloudtrail:LookupEvents because no identity-based policy allows the cloudtrail:LookupEvents action"
},
{
"service": "logs.amazonaws.com",
"event_name": "GetLogEvents",
"count": 1,
"error_message": "User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/AWSReservedSSO_SandboxPowerUser_XXXXXXXXXXXXXXXX/alex@engseclabs.com is not authorized to perform: logs:GetLogEvents on resource: arn:aws:logs:us-east-1:XXXXXXXXXXXX:log-group:/aws/lambda/trailtool-ingestor:log-stream:2026/03/23/[$LATEST]2aefc3cf2b6e4a0da94ca867e23eb598 because no identity-based policy allows the logs:GetLogEvents action"
},
{
"service": "iam.amazonaws.com",
"event_name": "GetRole",
"count": 3,
"error_message": "User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/AWSReservedSSO_SandboxPowerUser_XXXXXXXXXXXXXXXX/alex@engseclabs.com is not authorized to perform: iam:GetRole on resource: role AWSReservedSSO_SandboxPowerUser_XXXXXXXXXXXXXXXX because no identity-based policy allows the iam:GetRole action"
}
]
}3 denied actions, all caused by missing identity-based policy permissions. Let me generate a policy that includes them.
Generate policy including denied actions
$ trailtool roles policy SandboxPowerUser --include-denied --explain --format json{
"total_actions_used": 37,
"policy_json": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudtrail:LookupEvents",
"iam:GetRole",
"logs:GetLogEvents"
],
"Resource": ["*"]
}
]
}
}The generated policy includes the 3 denied actions. Now let me compare against the current Terraform inline policy.
Review current inline policy in main.tf
The current policy has 6 statements. Comparing against the denied actions:
| Denied Action | Status | Fix |
|---|---|---|
cloudtrail:LookupEvents |
Missing from policy | Add to GlobalReadOnly statement (Resource: *) |
iam:GetRole |
Already in HCL but not yet deployed | Will be applied with this change |
logs:GetLogEvents |
Missing from policy | Add to LogsTrailTool statement (scoped to trailtool log group) |
Update inline policy in main.tf — added cloudtrail:LookupEvents to the GlobalReadOnly statement and logs:GetLogEvents to the LogsTrailTool statement, scoped to arn:aws:logs:*:*:log-group:/aws/lambda/trailtool-ingestor:*.
Verify the change with terraform plan
$ terraform plan
...
Terraform will perform the following actions:
# aws_ssoadmin_permission_set_inline_policy.sandbox_power_user_policy will be updated in-place
~ inline_policy = jsonencode(
~ {
~ Statement = [
~ {
~ Action = [
"cloudtrail:GetTrailStatus",
+ "cloudtrail:LookupEvents",
...
"health:DescribeEventAggregates",
+ "iam:GetRole",
"kms:Decrypt",
]
},
~ {
~ Action = [
"logs:DescribeLogStreams",
+ "logs:GetLogEvents",
]
},
]
}
)
Plan: 0 to add, 1 to change, 0 to destroy.Plan shows 1 in-place update — the inline policy gains the 3 missing permissions.
Apply the change
$ terraform apply -auto-approve
...
aws_ssoadmin_permission_set_inline_policy.sandbox_power_user_policy: Modifying...
aws_ssoadmin_permission_set_inline_policy.sandbox_power_user_policy: Modifications complete after 6s
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.Summary:
- 3 AccessDenied actions found for SandboxPowerUser via
trailtool roles detail - 2 permissions added to
main.tf:cloudtrail:LookupEvents→ GlobalReadOnly statement (Resource: *)logs:GetLogEvents→ LogsTrailTool statement (scoped toarn:aws:logs:*:*:log-group:/aws/lambda/trailtool-ingestor:*)
- 1 permission already in HCL (
iam:GetRole) — was pending apply, now deployed terraform planconfirmed a single in-place update;terraform applysucceeded