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 TDE Protectors Encrypted Plugin Update #2101

Merged
merged 2 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions helpers/azure/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,11 @@ var calls = {
url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.ContainerService/managedClusters?api-version=2020-03-01'
}
},
managedInstances: {
list: {
url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Sql/managedInstances?api-version=2021-11-01'
}
},
networkWatchers: {
listAll: {
url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Network/networkWatchers?api-version=2022-01-01'
Expand Down Expand Up @@ -845,6 +850,13 @@ var postcalls = {
url: 'https://management.azure.com/{id}/encryptionProtector?api-version=2015-05-01-preview'
},
},
managedInstanceEncryptionProtectors: {
listByInstance: {
reliesOnPath: 'managedInstances.list',
properties: ['id'],
url: 'https://management.azure.com/{id}/encryptionProtector?api-version=2024-05-01-preview'
},
},
webApps: {
getAuthSettings: {
reliesOnPath: 'webApps.list',
Expand Down
3 changes: 2 additions & 1 deletion helpers/azure/locations.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,5 +136,6 @@ module.exports = {
batchAccounts: locations,
machineLearning: locations,
apiManagementService: locations,
synapse: locations
synapse: locations,
managedInstances: locations
};
155 changes: 100 additions & 55 deletions plugins/azure/sqlserver/tdeProtectorEncrypted.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,82 +8,127 @@ module.exports = {
severity: 'Medium',
description: 'Ensures SQL Server TDE protector is encrypted with BYOK (Bring Your Own Key)',
more_info: 'Enabling BYOK in the TDE protector allows for greater control and transparency, as well as increasing security by having full control of the encryption keys.',
recommended_action: 'Ensure that a BYOK key is set for the Transparent Data Encryption of each SQL Server.',
recommended_action: 'Ensure that a BYOK key is set for the Transparent Data Encryption of each SQL Server or Managed Instance.',
link: 'https://learn.microsoft.com/en-us/azure/sql-database/transparent-data-encryption-byok-azure-sql',
apis: ['servers:listSql', 'encryptionProtectors:listByServer'],
apis: ['servers:listSql', 'encryptionProtectors:listByServer', 'managedInstances:list', 'managedInstanceEncryptionProtectors:listByInstance'],
settings: {
sql_tde_protector_encryption_key: {
name: 'SQL Server TDE Protector Encryption Key Type',
description: 'Desired encryption key for SQL Server transparent data encryption; default=service-managed key, cmk=customer-managed key',
description: 'Desired encryption key for SQL Server and Managed Instance transparent data encryption; default=service-managed key, cmk=customer-managed key',
regex: '(default|byok)',
default: 'byok'
}
},
realtime_triggers: ['microsoftsql:servers:write', 'microsoftsql:servers:delete', 'microsodtsql:servers:encryptionprotector:write'],
realtime_triggers: ['microsoftsql:servers:write', 'microsoftsql:servers:delete', 'microsoftsql:servers:encryptionprotector:write'],

run: function(cache, settings, callback) {
const results = [];
const source = {};
const locations = helpers.locations(settings.govcloud);

var config = {
sql_tde_protector_encryption_key: settings.sql_tde_protector_encryption_key || this.settings.sql_tde_protector_encryption_key.default
};

async.each(locations.servers, function(location, rcb) {

var servers = helpers.addSource(cache, source,
['servers', 'listSql', location]);

if (!servers) return rcb();

if (servers.err || !servers.data) {
helpers.addResult(results, 3,
'Unable to query for SQL servers: ' + helpers.addError(servers), location);
return rcb();
}

if (!servers.data.length) {
helpers.addResult(results, 0, 'No SQL servers found', location);
return rcb();
}

servers.data.forEach(function(server) {
const encryptionProtectors = helpers.addSource(cache, source,
['encryptionProtectors', 'listByServer', location, server.id]);

if (!encryptionProtectors || encryptionProtectors.err || !encryptionProtectors.data) {
helpers.addResult(results, 3,
'Unable to query for SQL Server Encryption Protectors: ' + helpers.addError(encryptionProtectors), location, server.id);

function checkEncryptionProtection(encryptionProtector, location, config, serviceType) {
if (config.sql_tde_protector_encryption_key == 'byok') {
if ((encryptionProtector.kind &&
encryptionProtector.kind.toLowerCase() != 'azurekeyvault') ||
(encryptionProtector.serverKeyType &&
encryptionProtector.serverKeyType.toLowerCase() != 'azurekeyvault') ||
!encryptionProtector.uri) {
helpers.addResult(results, 2,
`${serviceType} TDE protector is not encrypted with BYOK`, location, encryptionProtector.id);
} else {
if (!encryptionProtectors.data.length) {
helpers.addResult(results, 0, 'No SQL Server Encryption Protectors found for server', location, server.id);
} else {
encryptionProtectors.data.forEach(encryptionProtector => {
if (config.sql_tde_protector_encryption_key == 'byok') {
if ((encryptionProtector.kind &&
encryptionProtector.kind.toLowerCase() != 'azurekeyvault') ||
(encryptionProtector.serverKeyType &&
encryptionProtector.serverKeyType.toLowerCase() != 'azurekeyvault') ||
!encryptionProtector.uri) {
helpers.addResult(results, 2,
'SQL Server TDE protector is not encrypted with BYOK', location, encryptionProtector.id);
} else {
helpers.addResult(results, 0,
'SQL Server TDE protector is encrypted with BYOK', location, encryptionProtector.id);
}
} else {
helpers.addResult(results, 0,
'SQL Server TDE protector is encrypted with service-managed key', location, encryptionProtector.id);
}
});
helpers.addResult(results, 0,
`${serviceType} TDE protector is encrypted with BYOK`, location, encryptionProtector.id);
}
} else {
if (encryptionProtector.kind || encryptionProtector.serverKeyType) {
helpers.addResult(results, 0,
`${serviceType} TDE protector is encrypted with service-managed key`, location, encryptionProtector.id);
}
}
}

async.each(locations.servers, function(location, rcb) {
async.parallel([
// Check SQL Servers
function(cb) {
const servers = helpers.addSource(cache, source,
['servers', 'listSql', location]);

if (!servers) return cb();

if (servers.err || !servers.data) {
helpers.addResult(results, 3,
'Unable to query for SQL servers: ' + helpers.addError(servers), location);
return cb();
}

if (!servers.data.length) {
helpers.addResult(results, 0, 'No SQL servers found', location);
return cb();
}

servers.data.forEach(server => {
const encryptionProtectors = helpers.addSource(cache, source,
['encryptionProtectors', 'listByServer', location, server.id]);

if (!encryptionProtectors || encryptionProtectors.err || !encryptionProtectors.data) {
helpers.addResult(results, 3,
'Unable to query for SQL Server Encryption Protectors: ' + helpers.addError(encryptionProtectors), location, server.id);
} else if (!encryptionProtectors.data.length) {
helpers.addResult(results, 0, 'No SQL Server Encryption Protectors found', location, server.id);
} else {
encryptionProtectors.data.forEach(protector => {
checkEncryptionProtection(protector, location, config, 'SQL Server');
});
}
});

cb();
},
// Check Managed Instances
function(cb) {
const managedInstances = helpers.addSource(cache, source,
['managedInstances', 'list', location]);

if (!managedInstances) return cb();

if (managedInstances.err || !managedInstances.data) {
helpers.addResult(results, 3,
'Unable to query for managed instances: ' + helpers.addError(managedInstances), location);
return cb();
}

if (!managedInstances.data.length) {
helpers.addResult(results, 0, 'No managed instances found', location);
return cb();
}

managedInstances.data.forEach(instance => {
const managedInstanceEncryptionProtectors = helpers.addSource(cache, source,
['managedInstanceEncryptionProtectors', 'listByInstance', location, instance.id]);

if (!managedInstanceEncryptionProtectors || managedInstanceEncryptionProtectors.err || !managedInstanceEncryptionProtectors.data) {
helpers.addResult(results, 3,
'Unable to query for Managed Instance Encryption Protectors: ' + helpers.addError(managedInstanceEncryptionProtectors), location, instance.id);
} else if (!managedInstanceEncryptionProtectors.data.length) {
helpers.addResult(results, 0, 'No Managed Instance Encryption Protectors found', location, instance.id);
} else {
managedInstanceEncryptionProtectors.data.forEach(protector => {
checkEncryptionProtection(protector, location, config, 'Managed Instance');
});
}
});

cb();
}
], function() {
rcb();
});

rcb();
}, function() {
// Global checking goes here
callback(null, results, source);
});
}
Expand Down
Loading
Loading