Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/plugin/iam/less restrictive iam role policies #293

Closed
76 changes: 54 additions & 22 deletions plugins/aws/iam/iamRolePolicies.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,61 @@ var helpers = require('../../../helpers/aws');

var managedAdminPolicy = 'arn:aws:iam::aws:policy/AdministratorAccess';

function hasFederatedUserRole(policyDocument) {
// true iff every statement refers to federated user access
let statement;
for (statement of policyDocument.Statement) {
if (statement.Action !== 'sts:AssumeRoleWithSAML' && statement.Action !== 'sts:AssumeRoleWithWebIdentity'){
return false;
}
}
return true;
}

Comment on lines +6 to +16
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you move this function to our helpers file: https://github.com/cloudsploit/scans/blob/master/helpers/aws/functions.js
and just import the file like this: var helpers = require('../../../helpers/aws');

module.exports = {
title: 'IAM Role Policies',
category: 'IAM',
description: 'Ensures IAM role policies are properly scoped with specific permissions',
more_info: 'Policies attached to IAM roles should be scoped to least-privileged access and avoid the use of wildcards.',
link: 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html',
recommended_action: 'Ensure that all IAM roles are scoped to specific services and API calls.',
apis: ['IAM:listRoles', 'IAM:listRolePolicies', 'IAM:listAttachedRolePolicies',
'IAM:getPolicy', 'IAM:getRolePolicy'],
apis: ['IAM:listRoles', 'IAM:listRolePolicies', 'IAM:listAttachedRolePolicies', 'IAM:getRolePolicy'],
settings: {
iam_role_policies_ignore_path: {
name: 'IAM Role Policies Ignore Path',
description: 'Ignores roles that contain the provided exact-match path',
regex: '^[0-9A-Za-z/._-]{3,512}$',
default: false
}
},
ignore_service_specific_wildcards: {
name: 'Ignore Service Specific Wildcards',
description: 'enable this to consider only those roles which allow all actions',
regex: '^(true|false)$', // string true or boolean true to enable, string false or boolean false to disable
default: false
},
ignore_identity_federation_roles: {
name: 'Ignore Identity Federation Roles',
description: 'enable this to ignore idp/saml trust roles',
regex: '^(true|false)$', // string true or boolean true to enable, string false or boolean false to disable
default: false
},
},

run: function(cache, settings, callback) {
var config = {
iam_role_policies_ignore_path: settings.iam_role_policies_ignore_path || this.settings.iam_role_policies_ignore_path.default
iam_role_policies_ignore_path: settings.iam_role_policies_ignore_path || this.settings.iam_role_policies_ignore_path.default,
ignore_service_specific_wildcards: settings.ignore_service_specific_wildcards || this.settings.ignore_service_specific_wildcards.default,
ignore_identity_federation_roles: settings.ignore_identity_federation_roles || this.settings.ignore_identity_federation_roles
};

if (config.ignore_service_specific_wildcards === 'false') config.ignore_service_specific_wildcards = false;
if (config.ignore_identity_federation_roles === 'false') config.ignore_identity_federation_roles = false;

var custom = helpers.isCustom(settings, this.settings);

var results = [];
var source = {};

var region = helpers.defaultRegion(settings);

var listRoles = helpers.addSource(cache, source,
Expand All @@ -51,7 +78,13 @@ module.exports = {

async.each(listRoles.data, function(role, cb){
if (!role.RoleName) return cb();

if (hasFederatedUserRole(JSON.parse(decodeURIComponent(role.AssumeRolePolicyDocument))) && config.ignore_identity_federation_roles) {
helpers.addResult(results, 0,
'Role is federated user role',
'global', role.Arn, custom
);
return cb();
}
// Skip roles with user-defined paths
if (config.iam_role_policies_ignore_path &&
config.iam_role_policies_ignore_path.length &&
Expand Down Expand Up @@ -83,7 +116,7 @@ module.exports = {
return cb();
}

var roleFailures = [];
let roleFailures = [];

// See if role has admin managed policy
if (listAttachedRolePolicies &&
Expand All @@ -107,12 +140,10 @@ module.exports = {

for (var p in listRolePolicies.data.PolicyNames) {
var policyName = listRolePolicies.data.PolicyNames[p];

if (getRolePolicy &&
getRolePolicy[policyName] &&
getRolePolicy[policyName] &&
getRolePolicy[policyName].data &&
getRolePolicy[policyName].data.PolicyDocument) {

var statements = helpers.normalizePolicyDocument(
getRolePolicy[policyName].data.PolicyDocument);
if (!statements) break;
Expand All @@ -123,25 +154,26 @@ module.exports = {

if (statement.Effect === 'Allow' &&
!statement.Condition) {
var failMsg;
if (statement.Action.indexOf('*') > -1 &&
let failMsg = false;
if (statement.Action.includes('*') || statement.Action.includes('*:*') &&
statement.Resource &&
statement.Resource.indexOf('*') > -1) {
statement.Resource.includes('*')) {
failMsg = 'Role inline policy allows all actions on all resources';
} else if (statement.Action.indexOf('*') > -1) {
} else if (statement.Action.includes('*') || statement.Action.includes('*:*')) {
failMsg = 'Role inline policy allows all actions on selected resources';
} else if (statement.Action && statement.Action.length) {
} else if (statement.Action && statement.Action.length && !config.ignore_service_specific_wildcards) {
// Check each action for wildcards
var wildcards = [];
for (a in statement.Action) {
if (statement.Action[a].endsWith(':*')) {
wildcards.push(statement.Action[a]);
let wildcards = [];
for (var i in statement.Action) {
if (statement.Action[i].endsWith(':*')) {
wildcards.push(statement.Action[i]);
}
}
if (wildcards.length) failMsg = 'Role inline policy allows wildcard actions: ' + wildcards.join(', ');
if (wildcards.length) {
failMsg = 'Role inline policy allows wildcard actions: '.concat(wildcards.join(', '));
}
}

if (failMsg && roleFailures.indexOf(failMsg) === -1) roleFailures.push(failMsg);
if (failMsg) roleFailures.push(failMsg);
}
}
}
Expand Down
Loading