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

Revised keyVaultKeyExpiry #2105

Merged
merged 10 commits into from
Nov 11, 2024
30 changes: 19 additions & 11 deletions plugins/azure/keyvaults/keyVaultKeyExpiry.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ var async = require('async');
var helpers = require('../../../helpers/azure');

module.exports = {
title: 'Key Vault Key Expiry',
title: 'Key Vault Key Expiry RBAC',
category: 'Key Vaults',
domain: 'Application Integration',
severity: 'High',
description: 'Proactively check for Key Vault keys expiry date and rotate them before expiry date is reached.',
more_info: 'After expiry date has reached for Key Vault key, it cannot be used for cryptographic operations anymore.',
recommended_action: 'Ensure that Key Vault keys are rotated before they get expired.',
description: 'Ensures that expiration date is set for all keys in RBAC Key Vaults.',
more_info: 'Setting an expiration date on keys helps in key lifecycle management and ensures that keys are rotated regularly.',
recommended_action: 'Modify keys in RBAC Key Vaults to have an expiration date set.',
link: 'https://learn.microsoft.com/en-us/azure/key-vault/about-keys-secrets-and-certificates',
apis: ['vaults:list', 'vaults:getKeys'],
settings: {
Expand Down Expand Up @@ -45,38 +45,46 @@ module.exports = {
return rcb();
}

vaults.data.forEach(function(vault){
vaults.data.forEach(function(vault) {
if (!vault || !vault.properties) {
helpers.addResult(results, 3, 'Unable to read vault properties', location, vault.id);
return;
}
if (!vault.properties.enableRbacAuthorization) {
return;
}

var keys = helpers.addSource(cache, source,
['vaults', 'getKeys', location, vault.id]);

if (!keys || keys.err || !keys.data) {
helpers.addResult(results, 3, 'Unable to query for Key Vault keys: ' + helpers.addError(keys), location, vault.id);
} else if (!keys.data.length) {
helpers.addResult(results, 0, 'No Key Vault keys found', location, vault.id);
helpers.addResult(results, 0, 'No Key Vault keys found in RBAC vault', location, vault.id);
} else {
keys.data.forEach(function(key) {
var keyName = key.kid.substring(key.kid.lastIndexOf('/') + 1);
var keyId = `${vault.id}/keys/${keyName}`;

if (!key.attributes || !key.attributes.enabled) {
helpers.addResult(results, 0,
'Key is not enabled', location, keyId);
'Key in RBAC vault is not enabled', location, keyId);
} else if (key.attributes && (key.attributes.expires || key.attributes.exp)) {
let keyExpiry = key.attributes.exp ? key.attributes.exp * 1000 : key.attributes.expires;
let difference = Math.round((new Date(keyExpiry).getTime() - (new Date).getTime())/(24*60*60*1000));
if (difference > config.key_vault_key_expiry_fail) {
helpers.addResult(results, 0,
`Key expires in ${difference} days`, location, keyId);
`Key in RBAC vault expires in ${difference} days`, location, keyId);
} else if (difference > 0){
helpers.addResult(results, 2,
`Key expires in ${difference} days`, location, keyId);
`Key in RBAC vault expires in ${difference} days`, location, keyId);
} else {
helpers.addResult(results, 2,
`Key expired ${Math.abs(difference)} days ago`, location, keyId);
`Key in RBAC vault expired ${Math.abs(difference)} days ago`, location, keyId);
}
} else {
helpers.addResult(results, 0,
'Key expiration is not enabled', location, keyId);
'Key expiration is not enabled in RBAC vault', location, keyId);
}
});
}
Expand Down
109 changes: 42 additions & 67 deletions plugins/azure/keyvaults/keyVaultKeyExpiry.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,96 +12,71 @@ keyExpired.setMonth(keyExpired.getMonth() - 1);

const listKeyVaults = [
{
id: '/subscriptions/abcdfget-ebf6-437f-a3b0-28fc0d22111e/resourceGroups/akhtar-rg/providers/Microsoft.KeyVault/vaults/nauman-test',
name: 'nauman-test',
id: '/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.KeyVault/vaults/test-vault',
name: 'test-vault',
type: 'Microsoft.KeyVault/vaults',
location: 'eastus',
tags: { owner: 'kubernetes' },
sku: { family: 'A', name: 'Standard' },
tenantId: '2d4f0836-5935-47f5-954c-14e713119ac2',
accessPolicies: [
{
tenantId: '2d4f0836-5935-47f5-954c-14e713119ac2',
objectId: 'b4062000-c33b-448b-817e-fa0f17bef4b9',
permissions: {
keys: ['Get', 'List'],
secrets: ['Get', 'List'],
certificates: ['Get', 'List']
}
}
],
enableSoftDelete: true,
softDeleteRetentionInDays: 7,
enableRbacAuthorization: false,
vaultUri: 'https://nauman-test.vault.azure.net/',
provisioningState: 'Succeeded'
}
];

const getKeys = [
properties: {
enableRbacAuthorization: true,
vaultUri: 'https://test-vault.vault.azure.net/'
}
},
{
id: '/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.KeyVault/vaults/test-vault-2',
name: 'test-vault-2',
type: 'Microsoft.KeyVault/vaults',
location: 'eastus',
properties: {
enableRbacAuthorization: false,
vaultUri: 'https://test-vault-2.vault.azure.net/'
}
}
];

const getKeys = [
{
"attributes": {
"created": "2022-04-10T17:57:43+00:00",
"enabled": true,
"expires": null,
"notBefore": null,
"recoveryLevel": "CustomizedRecoverable+Purgeable",
"updated": "2022-04-10T17:57:43+00:00"
},
"kid": "https://nauman-test.vault.azure.net/keys/nauman-test",
"managed": null,
"name": "nauman-test",
"tags": {
"hello": "world"
}
"kid": "https://test-vault.vault.azure.net/keys/test-key",
"name": "test-key"
},
{
"attributes": {
"created": "2022-04-10T17:57:43+00:00",
"enabled": true,
"expires": keyExpiryPass,
"notBefore": null,
"recoveryLevel": "CustomizedRecoverable+Purgeable",
"updated": "2022-04-10T17:57:43+00:00"
},
"kid": "https://nauman-test.vault.azure.net/keys/nauman-test",
"managed": null,
"name": "nauman-test",
"tags": {
"hello": "world"
}
"kid": "https://test-vault.vault.azure.net/keys/test-key-2",
"name": "test-key-2"
},
{
"attributes": {
"created": "2022-04-10T17:57:43+00:00",
"enabled": true,
"expires": keyExpiryFail,
"notBefore": null,
"recoveryLevel": "CustomizedRecoverable+Purgeable",
"updated": "2022-04-10T17:57:43+00:00"
},
"kid": "https://nauman-test.vault.azure.net/keys/nauman-test",
"managed": null,
"name": "nauman-test",
"tags": {
"hello": "world"
}
"kid": "https://test-vault.vault.azure.net/keys/test-key-3",
"name": "test-key-3"
},
{
"attributes": {
"created": "2022-04-10T17:57:43+00:00",
"enabled": true,
"expires": keyExpired,
"notBefore": null,
"recoveryLevel": "CustomizedRecoverable+Purgeable",
"updated": "2022-04-10T17:57:43+00:00"
},
"kid": "https://nauman-test.vault.azure.net/keys/nauman-test",
"managed": null,
"name": "nauman-test",
"tags": {
"hello": "world"
}
"kid": "https://test-vault.vault.azure.net/keys/test-key-4",
"name": "test-key-4"
}
];

Expand All @@ -116,7 +91,7 @@ const createCache = (err, list, keys) => {
},
getKeys: {
'eastus': {
'/subscriptions/abcdfget-ebf6-437f-a3b0-28fc0d22111e/resourceGroups/akhtar-rg/providers/Microsoft.KeyVault/vaults/nauman-test': {
'/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.KeyVault/vaults/test-vault': {
err: err,
data: keys
}
Expand All @@ -126,13 +101,13 @@ const createCache = (err, list, keys) => {
}
};

describe('keyVaultKeyExpiry', function() {
describe('keyVaultKeyExpiryRbac', function() {
describe('run', function() {
it('should give passing result if no keys found', function(done) {
it('should give passing result if no key vaults found', function(done) {
const callback = (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('No Key Vaults found');
expect(results[0].message).to.include('No Key Vaults found ');
alphadev4 marked this conversation as resolved.
Show resolved Hide resolved
expect(results[0].region).to.equal('eastus');
done()
};
Expand All @@ -144,7 +119,7 @@ describe('keyVaultKeyExpiry', function() {
const callback = (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('Key expiration is not enabled');
expect(results[0].message).to.include('Key expiration is not enabled in RBAC vault');
expect(results[0].region).to.equal('eastus');
done()
};
Expand All @@ -156,36 +131,36 @@ describe('keyVaultKeyExpiry', function() {
const callback = (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('Key expires in');
expect(results[0].message).to.include('Key in RBAC vault expires in');
expect(results[0].region).to.equal('eastus');
done()
};

auth.run(createCache(null, listKeyVaults, [getKeys[1]]), { key_vault_key_expiry_fail: '30' }, callback);
auth.run(createCache(null, [listKeyVaults[0]], [getKeys[1]]), { key_vault_key_expiry_fail: '30' }, callback);
});

it('should give failing results if the key has reached', function(done) {
it('should give failing results if the key has expired', function(done) {
const callback = (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(2);
expect(results[0].message).to.include('Key expired');
expect(results[0].message).to.include('Key in RBAC vault expired');
expect(results[0].region).to.equal('eastus');
done()
};

auth.run(createCache(null, listKeyVaults, [getKeys[3]]), { key_vault_key_expiry_fail: '40' }, callback);
auth.run(createCache(null, [listKeyVaults[0]], [getKeys[3]]), { key_vault_key_expiry_fail: '40' }, callback);
});

it('should give failing results if the key expired within failure expiry date', function(done) {
it('should give failing result if the key expires within failure expiry date', function(done) {
const callback = (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(2);
expect(results[0].message).to.include('Key expires');
expect(results[0].message).to.include('Key in RBAC vault expires');
expect(results[0].region).to.equal('eastus');
done()
};

auth.run(createCache(null, listKeyVaults, [getKeys[2]]), { key_vault_key_expiry_fail: '40' }, callback);
auth.run(createCache(null, [listKeyVaults[0]], [getKeys[2]]), { key_vault_key_expiry_fail: '40' }, callback);
});
});
});
});
Loading