Closed rbracewell closed 1 year ago
@rbracewell Appreciate trying out Steampipe!
Sad to see it's not yielding the expected result for you. Nicely detailed information to replicate the issue at our end; we will look into it and revert.
Hi @rbracewell thanks for sharing your observation. Appreciate it!
We did reproduce the issue in line with your error as one of the example cases, i.e. restricting the getLocation call by specifying the bucket resource policy. The current plugin design is handling this issue in the way mentioned here. Hence, when we ignore the AccessDenied in aws.spc > ignore_error_codes, it, sets the bucket location as nil and this results in making the affected bucket policy as, nil. This is not getting you the expected result; for now, pls refer to the below attached query
, where we are moving the validation to Info , the reason being we may have cases where there may not be any policy set in the bucket and that returns nil. Let us know if this fits your current need. Pls keep us informed of any other edge cases, you are coming across. Meanwhile, we are discussing further how we can handle it better way. We will keep this thread posted.
with wildcard_action_policies as (
select
arn,
count(*) as statements_num
from
aws_s3_bucket,
jsonb_array_elements(policy_std -> 'Statement') as s
where
s ->> 'Effect' = 'Allow'
-- aws:SourceOwner
and s -> 'Condition' -> 'StringEquals' -> 'aws:sourceowner' is null
and s -> 'Condition' -> 'StringEqualsIgnoreCase' -> 'aws:sourceowner' is null
and (
s -> 'Condition' -> 'StringLike' -> 'aws:sourceowner' is null
or s -> 'Condition' -> 'StringLike' -> 'aws:sourceowner' ? '*'
)
-- aws:SourceAccount
and s -> 'Condition' -> 'StringEquals' -> 'aws:sourceaccount' is null
and s -> 'Condition' -> 'StringEqualsIgnoreCase' -> 'aws:sourceaccount' is null
and (
s -> 'Condition' -> 'StringLike' -> 'aws:sourceaccount' is null
or s -> 'Condition' -> 'StringLike' -> 'aws:sourceaccount' ? '*'
)
-- aws:PrincipalOrgID
and s -> 'Condition' -> 'StringEquals' -> 'aws:principalorgid' is null
and s -> 'Condition' -> 'StringEqualsIgnoreCase' -> 'aws:principalorgid' is null
and (
s -> 'Condition' -> 'StringLike' -> 'aws:principalorgid' is null
or s -> 'Condition' -> 'StringLike' -> 'aws:principalorgid' ? '*'
)
-- aws:PrincipalAccount
and s -> 'Condition' -> 'StringEquals' -> 'aws:principalaccount' is null
and s -> 'Condition' -> 'StringEqualsIgnoreCase' -> 'aws:principalaccount' is null
and (
s -> 'Condition' -> 'StringLike' -> 'aws:principalaccount' is null
or s -> 'Condition' -> 'StringLike' -> 'aws:principalaccount' ? '*'
)
-- aws:PrincipalArn
and s -> 'Condition' -> 'StringEquals' -> 'aws:principalarn' is null
and s -> 'Condition' -> 'StringEqualsIgnoreCase' -> 'aws:principalarn' is null
and (
s -> 'Condition' -> 'StringLike' -> 'aws:principalarn' is null
or s -> 'Condition' -> 'StringLike' -> 'aws:principalarn' ? '*'
)
and (
s -> 'Condition' -> 'ArnEquals' -> 'aws:principalarn' is null
or s -> 'Condition' -> 'ArnEquals' -> 'aws:principalarn' ? '*'
)
and (
s -> 'Condition' -> 'ArnLike' -> 'aws:principalarn' is null
or s -> 'Condition' -> 'ArnLike' -> 'aws:principalarn' ? '*'
)
-- aws:SourceArn
and s -> 'Condition' -> 'StringEquals' -> 'aws:sourcearn' is null
and s -> 'Condition' -> 'StringEqualsIgnoreCase' -> 'aws:sourcearn' is null
and (
s -> 'Condition' -> 'StringLike' -> 'aws:sourcearn' is null
or s -> 'Condition' -> 'StringLike' -> 'aws:sourcearn' ? '*'
)
and (
s -> 'Condition' -> 'ArnEquals' -> 'aws:sourcearn' is null
or s -> 'Condition' -> 'ArnEquals' -> 'aws:sourcearn' ? '*'
)
and (
s -> 'Condition' -> 'ArnLike' -> 'aws:sourcearn' is null
or s -> 'Condition' -> 'ArnLike' -> 'aws:sourcearn' ? '*'
)
and (
s -> 'Principal' -> 'AWS' = '["*"]'
or s ->> 'Principal' = '*'
)
group by
arn
)
select
r.arn as resource,
case
when r.policy is null then 'info'
when p.arn is null then 'ok'
else 'alarm'
end as status,
case
when r.policy is null then title || ' does not have defined policy or insufficient access to the policy.'
when p.arn is null then title || ' policy does not allow public access.'
else title || ' policy contains ' || coalesce(p.statements_num, 0) ||
' statement(s) that allow public access.'
end as reason,
r.region,
r.account_id
from
aws_s3_bucket as r
left join wildcard_action_policies as p on p.arn = r.arn
Agreed Info would be better than Error given your description.
Thanks for the response, @rbracewell , we will adjust the query to info
for such edge cases for the time being.
'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 30 days.'
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 30 days.
Running the AWS perimeter mod control aws_perimeter.control.s3_bucket_policy_prohibit_public_access fails with the error
Error: operation error S3: GetBucketLocation, https response error StatusCode: 403, RequestID: <REDACTED>, HostID: <REDACTED>, api error AccessDenied: Access Denied (SQLSTATE HV000)
This looks to be down to several buckets with messed up permission policies. So I modified the steampipe configuration to include
ignore_error_codes = ["AccessDenied", "AccessDeniedException", "NotAuthorized", "UnauthorizedOperation", "UnrecognizedClientException", "AuthorizationError"]
This at least allows the control to run to a conclusion however, the buckets that previously caused the control to fail now report OK
OK : <BUCKET NAME REDACTED> policy does not allow public access. .......................................................... <nil> <ACCOUNT NAME REDACTED>
Steampipe version (
steampipe -v
) v0.17.4Plugin version (
steampipe plugin list
)To reproduce Create a bucket policy which only allows access to a specific role.
Expected behavior Should these particular resources be flagged as ERROR, as the credentials being used are insufficient for these buckets to be evaluated even though certain error codes are being ignored?