App-FargateStack
view release on metacpan or search on metacpan
lib/App/FargateStack/Checker.pm view on Meta::CPAN
foreach my $svc (@services) {
my $result = eval { _simulate_passrole_once( $iam, $policy_source_arn, $role_arns, $svc ) };
if ( $EVAL_ERROR || !$result ) {
# If org blocks simulation, warn rather than fail
return row_warn( 'iam:PassRole', 'Simulation not permitted; verify PassRole manually' );
}
# result is an arrayref of EvalDecision strings: allowed | explicitDeny | implicitDeny
my @dec = @{ $result || [] };
$decisions_by_service{$svc} = \@dec;
}
# Aggregate decisions: any explicitDeny -> FAIL
# otherwise any implicitDeny -> WARN
# otherwise all allowed -> PASS
my $detail = q{};
my $status = 'PASS';
foreach my $svc (@services) {
my $dec = $decisions_by_service{$svc} || [];
my $svc_summary = sprintf '%s: %s', $svc, ( join q{,}, @{$dec} );
if ( grep { $_ eq 'explicitDeny' } @{$dec} ) {
$status = 'FAIL';
}
elsif ( $status ne 'FAIL' && grep { $_ eq 'implicitDeny' } @{$dec} ) {
$status = 'WARN';
}
$detail .= $svc_summary . q{ };
}
$detail =~ s/\s+\z//;
if ( $status eq 'FAIL' ) { return row_fail( 'iam:PassRole', $detail ); }
if ( $status eq 'WARN' ) { return row_warn( 'iam:PassRole', $detail ); }
return row_ok( 'iam:PassRole', $detail || 'allowed' );
}
########################################################################
sub _principal_to_policy_source_arn {
########################################################################
my ( $sts_arn, $account_id ) = @_;
# Examples:
# arn:aws:sts::123456789012:assumed-role/DeployerRole/SESSION -> arn:aws:iam::123456789012:role/DeployerRole
# arn:aws:iam::123456789012:user/someuser -> arn:aws:iam::123456789012:user/someuser
return q{} if !$sts_arn || !$account_id;
if ( $sts_arn =~ m{\A arn:aws:sts::\Q$account_id\E:assumed-role/([^/]+)/}xsm ) {
my $role = $1;
return sprintf 'arn:aws:iam::%s:role/%s', $account_id, $role;
}
if ( $sts_arn =~ m{\A arn:aws:iam::\Q$account_id\E:(user|role)/}xsm ) {
return $sts_arn;
}
# Fallback: try to coerce to iam::role if it looks like an sts assumed role
return $sts_arn;
}
########################################################################
sub _role_arns_from_names {
########################################################################
my ( $account_id, $role_names ) = @_;
$role_names ||= [];
my @arns;
foreach my $name ( @{$role_names} ) {
next if !$name;
push @arns, sprintf 'arn:aws:iam::%s:role/%s', $account_id, $name;
}
return \@arns;
}
########################################################################
sub _simulate_passrole_once {
########################################################################
my ( $iam, $policy_source_arn, $resource_arns, $passed_to_service ) = @_;
# Build CLI JSON for --context-entries
my $context_json = sprintf
q|[{"ContextKeyName":"iam:PassedToService","ContextKeyValues":["%s"],"ContextKeyType":"string"}]|,
$passed_to_service;
# Ask for just the decision list
return $iam->command(
'simulate-principal-policy' => [
'--policy-source-arn' => $policy_source_arn,
'--action-names' => 'iam:PassRole',
'--resource-arns' => @{$resource_arns},
'--context-entries' => $context_json,
'--query' => 'EvaluationResults[].EvalDecision',
'--output' => 'json',
]
);
}
########################################################################
sub _gate {
########################################################################
my ( $need, $caps ) = @_;
my $result = 'YES';
foreach ( @{$need} ) {
next if $caps->{$_} =~ /PASS/xsm;
return 'NO' if $caps->{$_} eq 'FAIL';
$result = 'MAYBE';
}
return $result;
}
########################################################################
( run in 0.544 second using v1.01-cache-2.11-cpan-39bf76dae61 )