forked from aquasecurity/cloudsploit
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request aquasecurity#1278 from mehakseedat63/SAAS-5567
SAAS-5567: OCI Boot Volume Encryption Plugin
- Loading branch information
Showing
3 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
var async = require('async'); | ||
var helpers = require('../../../helpers/oracle/'); | ||
|
||
module.exports = { | ||
title: 'Boot Volume CMK Encryption', | ||
category: 'Block Storage', | ||
domain: 'Storage', | ||
description: 'Ensures that boot volumes have encryption enabled using desired protection level.', | ||
more_info: 'By default, boot volumes are encrypted using an Oracle-managed master encryption key. To have better control over the encryption process, you can use Customer-Managed Keys (CMKs).', | ||
recommended_action: 'Ensure all boot volumes have desired encryption level.', | ||
link: 'https://docs.oracle.com/en-us/iaas/Content/Security/Reference/blockstorage_security.htm#data-encryption', | ||
apis: ['vault:list', 'keys:list', 'bootVolume:list'], | ||
settings: { | ||
volume_encryption_level: { | ||
name: 'Boot Volume Encryption Level', | ||
description: 'Desired protection level for boot volumes. default: oracle-managed, cloudcmek: customer managed encryption keys, ' + | ||
'cloudhsm: customer managed HSM encryption key', | ||
regex: '^(default|cloudcmek|cloudhsm)$', | ||
default: 'cloudcmek' | ||
} | ||
}, | ||
|
||
run: function(cache, settings, callback) { | ||
var results = []; | ||
var source = {}; | ||
var regions = helpers.regions(settings.govcloud); | ||
var keysObj = {}; | ||
|
||
let desiredEncryptionLevelStr = settings.volume_encryption_level || this.settings.volume_encryption_level.default; | ||
var desiredEncryptionLevel = helpers.PROTECTION_LEVELS.indexOf(desiredEncryptionLevelStr); | ||
|
||
async.series([ | ||
function(cb) { | ||
async.each(regions.keys, function(region, rcb) { | ||
let keys = helpers.addSource( | ||
cache, source, ['keys', 'list', region]); | ||
if (keys && keys.data && keys.data.length) helpers.listToObj(keysObj, keys.data, 'id'); | ||
rcb(); | ||
}, function() { | ||
cb(); | ||
}); | ||
}, | ||
function(cb) { | ||
async.each(regions.bootVolume, function(region, rcb) { | ||
|
||
if (helpers.checkRegionSubscription(cache, source, results, region)) { | ||
|
||
var bootVolumes = helpers.addSource(cache, source, | ||
['bootVolume', 'list', region]); | ||
|
||
if (!bootVolumes) return rcb(); | ||
|
||
if (bootVolumes.err || !bootVolumes.data) { | ||
helpers.addResult(results, 3, | ||
'Unable to query for boot volumes: ' + helpers.addError(bootVolumes), region); | ||
return rcb(); | ||
} | ||
|
||
if (!bootVolumes.data.length) { | ||
helpers.addResult(results, 0, 'No boot volumes found', region); | ||
return rcb(); | ||
} | ||
|
||
bootVolumes.data.forEach(bootVolume => { | ||
if (bootVolume.lifecycleState && bootVolume.lifecycleState === 'TERMINATED') return; | ||
|
||
let currentEncryptionLevel = 1; //default | ||
|
||
if (bootVolume.kmsKeyId) { | ||
currentEncryptionLevel = helpers.getProtectionLevel(keysObj[bootVolume.kmsKeyId], helpers.PROTECTION_LEVELS); | ||
} | ||
|
||
let currentEncryptionLevelStr = helpers.PROTECTION_LEVELS[currentEncryptionLevel]; | ||
|
||
if (currentEncryptionLevel >= desiredEncryptionLevel) { | ||
helpers.addResult(results, 0, | ||
`Boot volume (${bootVolume.displayName}) has encryption level ${currentEncryptionLevelStr} which is greater than or equal to ${desiredEncryptionLevelStr}`, region, bootVolume.id); | ||
} else { | ||
helpers.addResult(results, 2, | ||
`Boot volume (${bootVolume.displayName}) has encryption level ${currentEncryptionLevelStr} which is less than ${desiredEncryptionLevelStr}`, region, bootVolume.id); | ||
} | ||
}); | ||
} | ||
|
||
rcb(); | ||
}, function() { | ||
cb(); | ||
}); | ||
} | ||
], function() { | ||
// Global checking goes here | ||
callback(null, results, source); | ||
}); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
var expect = require('chai').expect; | ||
var plugin = require('./bootVolumeCMKEncryption'); | ||
|
||
const bootVolumes = [ | ||
{ | ||
"compartmentId": "ocid1.tenancy.oc1.aaaaaa.111111", | ||
"definedTags": {}, | ||
"displayName": "vol-2", | ||
"freeformTags": {}, | ||
"systemTags": {}, | ||
"id": "ocid1.volume.oc1.aaaaaa.1111111", | ||
"isHydrated": true, | ||
"kmsKeyId": null, | ||
"lifecycleState": "AVAILABLE", | ||
"performanceTier": null, | ||
"vpusPerGB": null, | ||
"sizeInGBs": 1024, | ||
"sizeInMBs": 1048576, | ||
"sourceDetails": null, | ||
"timeCreated": "2019-08-29T21:46:01.836Z", | ||
"volumeGroupId": null | ||
}, | ||
{ | ||
"compartmentId": "ocid1.tenancy.oc1.aaaaaa.111111", | ||
"definedTags": {}, | ||
"displayName": "vol-2", | ||
"freeformTags": {}, | ||
"systemTags": {}, | ||
"id": "ocid1.volume.oc1.aaaaaa.1111111", | ||
"isHydrated": true, | ||
"lifecycleState": "AVAILABLE", | ||
"performanceTier": null, | ||
"vpusPerGB": null, | ||
"sizeInGBs": 1024, | ||
"sizeInMBs": 1048576, | ||
"sourceDetails": null, | ||
"timeCreated": "2019-08-29T21:46:01.836Z", | ||
"volumeGroupId": null, | ||
"kmsKeyId": 'key-1' | ||
} | ||
]; | ||
|
||
const createCache = (err, data) => { | ||
return { | ||
regionSubscription: { | ||
"list": { | ||
"us-ashburn-1": { | ||
"data": [ | ||
{ | ||
"regionKey": "IAD", | ||
"regionName": "us-ashburn-1", | ||
"status": "READY", | ||
"isHomeRegion": true | ||
}, | ||
{ | ||
"regionKey": "LHR", | ||
"regionName": "uk-london-1", | ||
"status": "READY", | ||
"isHomeRegion": false | ||
}, | ||
{ | ||
"regionKey": "PHX", | ||
"regionName": "us-phoenix-1", | ||
"status": "READY", | ||
"isHomeRegion": false | ||
} | ||
] | ||
} | ||
} | ||
}, | ||
bootVolume: { | ||
list: { | ||
'us-ashburn-1': { | ||
err: err, | ||
data: data | ||
} | ||
} | ||
}, | ||
vault: { | ||
list: { | ||
'us-ashburn-1': { | ||
data: [ | ||
{ | ||
"compartmentId": "compartment-1", | ||
"displayName": "vault-1", | ||
"freeformTags": {}, | ||
"id": "vault-1", | ||
"lifecycleState": "ACTIVE", | ||
}, | ||
] | ||
} | ||
} | ||
}, | ||
keys: { | ||
list: { | ||
'us-ashburn-1': { | ||
data: [ | ||
{ | ||
"compartmentId": "compartment-1", | ||
"definedTags": {}, | ||
"displayName": "key-1", | ||
"freeformTags": {}, | ||
"id": "key-1", | ||
"lifecycleState": "ENABLED", | ||
"timeCreated": "2022-04-30T19:49:12.841Z", | ||
"vaultId": "vault-1", | ||
"protectionMode": "SOFTWARE", | ||
"algorithm": "AES" | ||
} | ||
], | ||
|
||
} | ||
} | ||
} | ||
} | ||
}; | ||
|
||
describe('bootVolumeCMKEncryption', function () { | ||
describe('run', function () { | ||
it('should give unknown result if a boot volume error occurs', function (done) { | ||
const callback = (err, results) => { | ||
expect(results.length).to.be.above(0) | ||
expect(results[0].status).to.equal(3) | ||
expect(results[0].message).to.include('Unable to query for boot volumes') | ||
expect(results[0].region).to.equal('us-ashburn-1') | ||
done() | ||
}; | ||
|
||
const cache = createCache( | ||
['error'], | ||
null | ||
); | ||
|
||
plugin.run(cache, {}, callback); | ||
}) | ||
|
||
it('should give passing result if no boot volumes are found', function (done) { | ||
const callback = (err, results) => { | ||
expect(results.length).to.be.above(0) | ||
expect(results[0].status).to.equal(0) | ||
expect(results[0].message).to.include('No boot volumes found') | ||
expect(results[0].region).to.equal('us-ashburn-1') | ||
done() | ||
}; | ||
|
||
const cache = createCache( | ||
null, | ||
[] | ||
); | ||
|
||
plugin.run(cache, {}, callback); | ||
}) | ||
|
||
|
||
it('should give failing result if boot volume does not have desired encryption level', function (done) { | ||
const callback = (err, results) => { | ||
expect(results.length).to.be.above(0) | ||
expect(results[0].status).to.equal(2) | ||
expect(results[0].message).to.include('which is less') | ||
expect(results[0].region).to.equal('us-ashburn-1') | ||
done() | ||
}; | ||
|
||
const cache = createCache( | ||
null, | ||
[bootVolumes[0]] | ||
); | ||
|
||
plugin.run(cache, {}, callback); | ||
}) | ||
|
||
it('should give passing result if boot volume has desired encryption level', function (done) { | ||
const callback = (err, results) => { | ||
expect(results.length).to.be.above(0) | ||
expect(results[0].status).to.equal(0) | ||
expect(results[0].message).to.include('which is greater than or equal to') | ||
expect(results[0].region).to.equal('us-ashburn-1') | ||
done() | ||
}; | ||
|
||
const cache = createCache( | ||
null, | ||
[bootVolumes[1]] | ||
); | ||
|
||
plugin.run(cache, {}, callback); | ||
}); | ||
}); | ||
}); |