turbot/aws_perimeter
Loading controls...

Control: EC2 AMIs should only be shared with trusted OUs

Description

AWS AMIs can be shared with specific AWS organizations units (OUs) without making the AMI public. This control checks if AMIs are shared with untrusted OUs.

Usage

Run the control in your terminal:

powerpipe control run aws_perimeter.control.ec2_ami_shared_with_trusted_organization_units

Snapshot and share results via Turbot Pipes:

powerpipe login
powerpipe control run aws_perimeter.control.ec2_ami_shared_with_trusted_organization_units --share

Steampipe Tables

Params

ArgsNameDefaultDescriptionVariable
$1trusted_organization_units
["ou-abcdek7fks","ou-123def789"]
A list of trusted organization units.

SQL

with all_amis as (
select
title,
public,
launch_permissions,
region,
_ctx,
tags,
account_id
from
aws_ec2_ami
order by
account_id,
_ctx,
region,
tags,
title
),
ami_data as (
select
title,
public,
string_agg(lp ->> 'Group', ',') as public_access,
to_jsonb(
string_to_array(
string_agg(
split_part((lp ->> 'OrganizationalUnitArn'), '/', 3),
','
),
','
)
) as shared_organization_units,
to_jsonb(
string_to_array(
string_agg(
split_part((lp ->> 'OrganizationalUnitArn'), '/', 3),
','
),
','
)
) - ($1) :: text [ ] as untrusted_organization_units,
region,
_ctx,
tags,
account_id
from
all_amis,
jsonb_array_elements(launch_permissions) lp
group by
title,
public,
region,
_ctx,
account_id,
tags
),
evaluated_amis as (
select
all_amis.*,
public_access,
shared_organization_units,
untrusted_organization_units
from
all_amis
left join ami_data on all_amis.account_id = ami_data.account_id
and all_amis.region = ami_data.region
and all_amis.title = ami_data.title
)
select
title as resource,
case
when public then 'info'
when shared_organization_units is null then 'ok'
when untrusted_organization_units is not null then 'info'
else 'ok'
end as status,
case
when public then title || ' is public.'
when shared_organization_units is null then title || ' is not shared.'
when shared_organization_units is not null then title || ' shared with ' || case
when jsonb_array_length(untrusted_organization_units) > 2 then concat(
'untrusted OUs ',
untrusted_organization_units #> > '{0}',
', ',
untrusted_organization_units #> > '{1}',
' and ' || (
jsonb_array_length(untrusted_organization_units) - 2
) :: text || ' more.'
)
when jsonb_array_length(untrusted_organization_units) = 2 then concat(
'untrusted OUs ',
untrusted_organization_units #> > '{0}',
' and ',
untrusted_organization_units #> > '{1}',
'.'
)
else concat(
'untrusted OU ',
untrusted_organization_units #> > '{0}',
'.'
)
end
else title || ' shared with trusted OU(s).'
end as reason,
region,
account_id
from
evaluated_amis;

Tags