Skip to content

Commit

Permalink
Feature/plugin/iam user admins (aquasecurity#223)
Browse files Browse the repository at this point in the history
* add min and max admins

* added spec file for testing

* add extra expect

* add additional tests

* fix missing default

* allow 0 for min/max values in settings

Co-authored-by: robertramsey117 <[email protected]>
Co-authored-by: Joel Haubold <[email protected]>
  • Loading branch information
3 people authored and matthewdfuller committed Jan 25, 2020
1 parent d6e37a2 commit e215595
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 15 deletions.
41 changes: 26 additions & 15 deletions plugins/aws/iam/iamUserAdmins.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,35 @@ module.exports = {
'reduces the scope of users with potential access to this data.'
},
settings: {
iam_admin_count: {
name: 'IAM Admin Count',
description: 'The number of IAM user admins to require in the account',
regex: '^[1-9]{1}[0-9]{0,3}$',
iam_admin_count_minimum: {
name: 'IAM Admin Count Minimum',
description: 'The minimum number of IAM user admins to require in the account',
regex: '^[0-9]{0,4}$',
default: 2
},
iam_admin_count_maximum: {
name: 'IAM Admin Count Maximum',
description: 'The maximum number of IAM user admins to require in the account',
regex: '^[0-9]{0,4}$',
default: 2
}
},

run: function(cache, settings, callback) {
var config = {
iam_admin_count: settings.iam_admin_count || this.settings.iam_admin_count.default
// using the `in` operator because 0 is a valid setting
iam_admin_count_minimum: 'iam_admin_count_minimum' in settings
? parseInt(settings.iam_admin_count_minimum)
: this.settings.iam_admin_count_minimum.default,
iam_admin_count_maximum: 'iam_admin_count_maximum' in settings
? parseInt(settings.iam_admin_count_maximum)
: this.settings.iam_admin_count_maximum.default,
};

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

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

var region = helpers.defaultRegion(settings);

var listUsers = helpers.addSource(cache, source,
Expand Down Expand Up @@ -117,7 +128,7 @@ module.exports = {
var policy = listUserPolicies.data.PolicyNames[p];

if (getUserPolicy &&
getUserPolicy[policy] &&
getUserPolicy[policy] &&
getUserPolicy[policy].data &&
getUserPolicy[policy].data.PolicyDocument) {

Expand Down Expand Up @@ -156,7 +167,7 @@ module.exports = {
// Get inline policies attached to group
var listGroupPolicies = helpers.addSource(cache, source,
['iam', 'listGroupPolicies', region, group.GroupName]);

var getGroupPolicy = helpers.addSource(cache, source,
['iam', 'getGroupPolicy', region, group.GroupName]);

Expand Down Expand Up @@ -184,7 +195,7 @@ module.exports = {
var policy = listGroupPolicies.data.PolicyNames[p];

if (getGroupPolicy &&
getGroupPolicy[policy] &&
getGroupPolicy[policy] &&
getGroupPolicy[policy].data &&
getGroupPolicy[policy].data.PolicyDocument) {

Expand Down Expand Up @@ -212,18 +223,18 @@ module.exports = {
cb();
}, function(){
// Use admins array
if (userAdmins.length < config.iam_admin_count) {
if (userAdmins.length < config.iam_admin_count_minimum) {
helpers.addResult(results, 1,
'There are fewer than ' + config.iam_admin_count + ' IAM user administrators',
'There are fewer than the minimum ' + config.iam_admin_count_minimum + ' IAM user administrators',
'global', null, custom);
} else if (userAdmins.length == config.iam_admin_count) {
} else if (userAdmins.length >= config.iam_admin_count_minimum && userAdmins.length <= config.iam_admin_count_maximum) {
helpers.addResult(results, 0,
'There are ' + config.iam_admin_count + ' IAM user administrators',
'There are ' + userAdmins.length + ' IAM user administrators',
'global', null, custom);
} else {
for (u in userAdmins) {
helpers.addResult(results, 2,
'User: ' + userAdmins[u].name + ' is one of ' + userAdmins.length + ' IAM user administrators, which exceeds the expected value of: ' + config.iam_admin_count,
'User: ' + userAdmins[u].name + ' is one of ' + userAdmins.length + ' IAM user administrators, which exceeds the expected value of: ' + config.iam_admin_count_maximum,
'global', userAdmins[u].arn, custom);
}
}
Expand Down
126 changes: 126 additions & 0 deletions plugins/aws/iam/iamUserAdmins.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
var assert = require('assert');
var expect = require('chai').expect;
var iamUserAdmins = require('./iamUserAdmins');

const cache = {
"iam": {
"listUsers": {
"us-east-1": {
"data": [
{
"UserName": "[email protected]",
},
{
"UserName": "[email protected]",
},
]
}
},
"listAttachedUserPolicies": {
"us-east-1": {
"[email protected]": {
"data": {
"AttachedPolicies": [{"PolicyArn":"arn:aws:iam::aws:policy/AdministratorAccess"}],
}
},
"[email protected]": {
"data": {
"AttachedPolicies": [{"PolicyArn":"arn:aws:iam::aws:policy/AdministratorAccess"}],
}
},
}
},
"listUserPolicies": {
"us-east-1": {
"[email protected]": {
"data": {
"PolicyNames": [],
}
},
"[email protected]": {
"data": {
"PolicyNames": [],
}
},
}
},
"listGroupsForUser": {
"us-east-1": {
"[email protected]": {
"data": {
"Groups": [],
}
},
"[email protected]": {
"data": {
"Groups": [],
}
},
}
}
}
}


describe('iamUserAdmins', function () {
describe('run', function () {
it('should FAIL when no users are found', function (done) {
const settings = {
iam_admin_count_minimum: 2,
iam_admin_count_maximum: 2
}

const cache = [{}];


const callback = (err, results) => {
expect(results.length).to.equal(0)
done()
}

iamUserAdmins.run(cache, settings, callback)
})

it('should FAIL when there are not enough users', function (done) {
const settings = {
iam_admin_count_minimum: 3,
iam_admin_count_maximum: 3
}

const callback = (err, results) => {
expect(results[0].status).to.equal(1)
done()
}

iamUserAdmins.run(cache, settings, callback)
})

it('should FAIL when there are too many users', function (done) {
const settings = {
iam_admin_count_minimum: 0,
iam_admin_count_maximum: 0
}

const callback = (err, results) => {
expect(results[0].status).to.equal(2)
done()
}

iamUserAdmins.run(cache, settings, callback)
})

it('should PASS when users are found and fit within range', function (done) {
const settings = {
iam_admin_count_minimum: 1,
iam_admin_count_maximum: 8
}

const callback = (err, results) => {
expect(results[0].status).to.equal(0)
done()
}

iamUserAdmins.run(cache, settings, callback)
})
})
})

0 comments on commit e215595

Please sign in to comment.