Skip to content

Commit bb58925

Browse files
added plugin for vm cmk auto key rotation, updated collector file to handle nested properties for api calls
1 parent cab05b5 commit bb58925

File tree

5 files changed

+186
-2
lines changed

5 files changed

+186
-2
lines changed

collectors/azure/collector.js

+3
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ let collect = function(AzureConfig, settings, callback) {
210210
// Check and replace properties
211211
if (subCallObj.properties && subCallObj.properties.length) {
212212
subCallObj.properties.forEach(function(propToReplace) {
213+
if (propToReplace.includes('.')) {
214+
regionData[propToReplace] = parseCollection(propToReplace, regionData);
215+
}
213216
if (regionData[propToReplace]) {
214217
var re = new RegExp(`{${propToReplace}}`, 'g');
215218
localReq.url = subCallObj.url.replace(re, regionData[propToReplace]);

exports.js

+1
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,7 @@ module.exports = {
753753
'vmSecureBootEnabled' : require(__dirname + '/plugins/azure/virtualmachines/vmSecureBootEnabled.js'),
754754
'vmDiskDeleteConfig' : require(__dirname + '/plugins/azure/virtualmachines/vmDiskDeleteConfig.js'),
755755
'vmEncryptionAtHost' : require(__dirname + '/plugins/azure/virtualmachines/vmEncryptionAtHost.js'),
756+
'vmDiskCMKRotation' : require(__dirname + '/plugins/azure/virtualmachines/vmDiskCMKRotation.js'),
756757

757758
'bastionHostExists' : require(__dirname + '/plugins/azure/bastion/bastionHostExists.js'),
758759

helpers/azure/api.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ var calls = {
228228
},
229229
disks: {
230230
list: {
231-
url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Compute/disks?api-version=2019-07-01'
231+
url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Compute/disks?api-version=2023-04-02'
232232
}
233233
},
234234
networkSecurityGroups: {
@@ -977,7 +977,14 @@ var postcalls = {
977977
url: 'https://management.azure.com/subscriptions/{id}/securityPolicies?api-version=2023-05-01'
978978

979979
}
980-
}
980+
},
981+
diskEncryptionSet: {
982+
get: {
983+
reliesOnPath: 'disks.list',
984+
properties: ['encryption.diskEncryptionSetId'],
985+
url: 'https://management.azure.com/{encryption.diskEncryptionSetId}?api-version=2023-04-02',
986+
}
987+
},
981988

982989
};
983990

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
var async = require('async');
2+
3+
var helpers = require('../../../helpers/azure/');
4+
5+
module.exports = {
6+
title: 'VM Disk Auto key Rotation CMK',
7+
category: 'Virtual Machines',
8+
domain: 'Compute',
9+
description: 'Ensures that auto key rotation for CMK is enabled for disk encryption.',
10+
more_info: 'Automatic key rotation helps ensure your keys are secure. A disk references a key via its disk encryption set. When you enable automatic rotation for a disk encryption set, the system will automatically update all managed disks, snapshots, and images referencing the disk encryption set to use the new version of the key within one hour.',
11+
recommended_action: 'Enable auto key rotation for CMK for all disks encryption.',
12+
link: 'https://learn.microsoft.com/en-us/azure/virtual-machines/disk-encryption#automatic-key-rotation-of-customer-managed-keys',
13+
apis: ['disks:list','diskEncryptionSet:get'],
14+
realtime_triggers: ['microsoftcompute:disks:write','microsoftcompute:disks:delete','microsoftcompute:diskencryptionsets:write'],
15+
16+
run: function(cache, settings, callback) {
17+
var results = [];
18+
var source = {};
19+
var locations = helpers.locations(settings.govcloud);
20+
21+
async.each(locations.disks, function(location, rcb) {
22+
23+
var disks = helpers.addSource(cache, source, ['disks', 'list', location]);
24+
25+
if (!disks) return rcb();
26+
27+
if (disks.err || !disks.data) {
28+
helpers.addResult(results, 3, 'Unable to query for virtual machine disk volumes: ' + helpers.addError(disks), location);
29+
return rcb();
30+
}
31+
if (!disks.data.length) {
32+
helpers.addResult(results, 0, 'No existing disk volumes found', location);
33+
return rcb();
34+
}
35+
36+
37+
disks.data.forEach((disk) => {
38+
if (disk.encryption && disk.encryption.type &&
39+
disk.encryption.type.toLowerCase() === 'encryptionatrestwithplatformkey') {
40+
helpers.addResult(results, 0, 'Disk is using platform managed key for encryption', location, disk.id);
41+
42+
} else {
43+
if (disk.encryption && disk.encryption.diskEncryptionSetId) {
44+
45+
var diskEncryptionSet = helpers.addSource(cache, source, ['diskEncryptionSet', 'get', location, disk.id]);
46+
47+
if (diskEncryptionSet && diskEncryptionSet.data && diskEncryptionSet.data.rotationToLatestKeyVersionEnabled) {
48+
helpers.addResult(results, 0, 'Disk auto key rotation for customer managed key is enabled', location, disk.id);
49+
50+
} else {
51+
helpers.addResult(results, 2, 'Disk auto key rotation for customer managed key is disabled', location, disk.id);
52+
}
53+
}
54+
55+
56+
}
57+
});
58+
rcb();
59+
}, function() {
60+
// Global checking goes here
61+
callback(null, results, source);
62+
});
63+
}
64+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
var expect = require('chai').expect;
2+
var vmDiskAutoKeyRotationCMK = require('./vmDiskCMKRotation');
3+
4+
const disks = [
5+
{
6+
"id": "/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.Compute/disks/test-disk",
7+
"name": "test-disk",
8+
"location": "eastus",
9+
"encryption": {
10+
"type": "EncryptionAtRestWithPlatformKey"
11+
}
12+
},
13+
{
14+
"id": "/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.Compute/disks/test-disk-cmk",
15+
"name": "test-disk-cmk",
16+
"location": "eastus",
17+
"encryption": {
18+
"diskEncryptionSetId": "/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.Compute/diskEncryptionSets/test-disk-es"
19+
}
20+
}
21+
];
22+
23+
const diskEncryptionSet = {
24+
"id": "/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.Compute/diskEncryptionSets/test-disk-es",
25+
"name": "test-disk-es",
26+
"location": "eastus",
27+
"rotationToLatestKeyVersionEnabled": true
28+
};
29+
30+
const createCache = (disks, diskEncryptionSet) => {
31+
const diskId = (disks && disks.length) ? disks[0].id : null;
32+
return {
33+
disks: {
34+
list: {
35+
'eastus': {
36+
data: disks
37+
}
38+
}
39+
},
40+
diskEncryptionSet: {
41+
get: {
42+
'eastus': {
43+
[diskId]: {
44+
data: diskEncryptionSet
45+
}
46+
}
47+
}
48+
}
49+
};
50+
};
51+
52+
describe('vmDiskAutoKeyRotationCMK', function() {
53+
describe('run', function() {
54+
it('should give passing result if no disk volumes found', function(done) {
55+
const cache = createCache([], null);
56+
vmDiskAutoKeyRotationCMK.run(cache, {}, (err, results) => {
57+
expect(results.length).to.equal(1);
58+
expect(results[0].status).to.equal(0);
59+
expect(results[0].message).to.include('No existing disk volumes found');
60+
expect(results[0].region).to.equal('eastus');
61+
done();
62+
});
63+
});
64+
65+
it('should give unknown result if unable to query for disk volumes', function(done) {
66+
const cache = createCache(null, null);
67+
vmDiskAutoKeyRotationCMK.run(cache, {}, (err, results) => {
68+
expect(results.length).to.equal(1);
69+
expect(results[0].status).to.equal(3);
70+
expect(results[0].message).to.include('Unable to query for virtual machine disk volumes:');
71+
expect(results[0].region).to.equal('eastus');
72+
done();
73+
});
74+
});
75+
76+
it('should give passing result if disk is using platform managed key', function(done) {
77+
const cache = createCache([disks[0]], null);
78+
vmDiskAutoKeyRotationCMK.run(cache, {}, (err, results) => {
79+
expect(results.length).to.equal(1);
80+
expect(results[0].status).to.equal(0);
81+
expect(results[0].message).to.include('Disk is using platform managed key for encryption');
82+
expect(results[0].region).to.equal('eastus');
83+
done();
84+
});
85+
});
86+
87+
it('should give passing result if disk auto key rotation for customer managed key is enabled', function(done) {
88+
const cache = createCache([disks[1]], diskEncryptionSet);
89+
vmDiskAutoKeyRotationCMK.run(cache, {}, (err, results) => {
90+
expect(results.length).to.equal(1);
91+
expect(results[0].status).to.equal(0);
92+
expect(results[0].message).to.include('Disk auto key rotation for customer managed key is enabled');
93+
expect(results[0].region).to.equal('eastus');
94+
done();
95+
});
96+
});
97+
98+
it('should give failing result if disk auto key rotation for customer managed key is disabled', function(done) {
99+
const cache = createCache([disks[1]], { rotationToLatestKeyVersionEnabled: false });
100+
vmDiskAutoKeyRotationCMK.run(cache, {}, (err, results) => {
101+
expect(results.length).to.equal(1);
102+
expect(results[0].status).to.equal(2);
103+
expect(results[0].message).to.include('Disk auto key rotation for customer managed key is disabled');
104+
expect(results[0].region).to.equal('eastus');
105+
done();
106+
});
107+
});
108+
});
109+
});

0 commit comments

Comments
 (0)