Skip to content

Commit

Permalink
Added Google BigQuery Dataset All Users Policy plugin and test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
AkhtarAmir committed Apr 29, 2021
1 parent c652d8d commit ccff1c9
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 5 deletions.
22 changes: 20 additions & 2 deletions collectors/google/collector.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,14 @@ var calls = {
parent: true
}
},
datasets: {
list: {
api: 'bigquery',
version: 'v2',
location: null,
project: true
}
}
};

var postcalls = {
Expand Down Expand Up @@ -244,9 +252,19 @@ var postcalls = {
filterKey: ['instance'],
filterValue: ['name'],
}
},
datasets: {
get: {
api: 'bigquery',
version: 'v2',
location: null,
reliesOnService: ['datasets'],
reliesOnCall: ['list'],
filterKey: ['datasetId'],
filterValue: ['id'],
project: true
}
}


};

var collect = function(GoogleConfig, settings, callback) {
Expand Down
2 changes: 2 additions & 0 deletions exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -725,5 +725,7 @@ module.exports = {
'vpcNetworkRouteLogging' : require(__dirname + '/plugins/google/logging/vpcNetworkRouteLogging.js'),
'vpcNetworkLogging' : require(__dirname + '/plugins/google/logging/vpcNetworkLogging.js'),
'logSinksEnabled' : require(__dirname + '/plugins/google/logging/logSinksEnabled.js'),

'datasetAllUsersPolicy' : require(__dirname + '/plugins/google/bigquery/datasetAllUsersPolicy.js')
}
};
7 changes: 5 additions & 2 deletions helpers/google/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,9 @@ var run = function(GoogleConfig, collection, settings, service, callObj, callKey
records = collection[callObj.reliesOnService[reliedService]][callObj.reliesOnCall[reliedService]][region].data;
async.eachLimit(records, 10, function(record, recordCb) {
for (var filter in callObj.filterKey) {
callObj.params[callObj.filterKey[filter]] = record[callObj.filterValue[filter]];
callObj.params[callObj.filterKey[filter]] = (record[callObj.filterValue[filter]].includes(':')) ?
record[callObj.filterValue[filter]].split(':')[1] :
record[callObj.filterValue[filter]];
options.version = callObj.version;
}
if (callObj.parent) {
Expand Down Expand Up @@ -348,14 +350,15 @@ var execute = function(LocalGoogleConfig, collection, service, callObj, callKey,
}
};
var parentParams;
if (callObj.project) callObj.params.projectId = LocalGoogleConfig.project;
if (callObj.nested && callObj.parent) {
parentParams = {auth: callObj.params.auth, parent: callObj.params.parent};
executor['projects']['locations'][service][callKey](parentParams, LocalGoogleConfig, executorCb);
} else if (callObj.nested) {
parentParams = {auth: callObj.params.auth, parent: callObj.params.parent};
executor['projects']['locations']['keyRings'][service][callKey](parentParams, LocalGoogleConfig, executorCb);
} else if (callObj.resource) {
parentParams = {auth: callObj.auth, resource_: LocalGoogleConfig.project};
parentParams = {auth: callObj.auth};
executor[service][callKey](parentParams, LocalGoogleConfig, executorCb);
} else if (callObj.serviceAccount) {
parentParams = {auth: callObj.params.auth, name: callObj.params.parent};
Expand Down
3 changes: 2 additions & 1 deletion helpers/google/regions.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,6 @@ module.exports = {
serviceAccounts: ['global'],
keys: ['global'],
sinks: ['global'],
users: ['global']
users: ['global'],
datasets: ['global']
};
68 changes: 68 additions & 0 deletions plugins/google/bigquery/datasetAllUsersPolicy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
var async = require('async');
var helpers = require('../../../helpers/google');

module.exports = {
title: 'Dataset All Users Policy',
category: 'BigQuery',
description: 'Ensure that BigQuery datasets do not allow public read, write or delete access.',
more_info: 'Granting permissions to allUsers or allAuthenticatedUsers allows anyone to access the dataset. Such access might not be desirable if sensitive data is being stored in the dataset.',
link: 'https://cloud.google.com/bigquery/docs/dataset-access-controls',
recommended_action: 'Ensure that each dataset is configured so that no member is set to allUsers or allAuthenticatedUsers.',
apis: ['datasets:list', 'datasets:get'],

run: function(cache, settings, callback) {
var results = [];
var source = {};
var regions = helpers.regions();

async.each(regions.datasets, function(region, rcb){
let datasetsGet = helpers.addSource(cache, source,
['datasets', 'get', region]);

if (!datasetsGet) return rcb();

if (datasetsGet.err || !datasetsGet.data) {
helpers.addResult(results, 3, 'Unable to query BigQuery datasets: ' + helpers.addError(datasetsGet), region);
return rcb();
}

if (!datasetsGet.data.length) {
helpers.addResult(results, 0, 'No BigQuery datasets found', region);
return rcb();
}

async.each(datasetsGet.data, (dataset, dcb) => {
if (!dataset.id) return dcb();

var permissionStr = [];
if (dataset.access) {
for (let rolePermission of dataset.access) {
for (let property in rolePermission) {
if (!rolePermission['role']) continue;

if (rolePermission[property].toLowerCase() == 'allusers' || rolePermission[property].toLowerCase() == 'allauthenticatedusers') {
permissionStr.push(`${rolePermission['role']} access to ${rolePermission[property]}`);
}
}
}

if (permissionStr.length) {
helpers.addResult(results, 2,
`BigQuery dataset provides ${permissionStr.join(',')}`, region, dataset.id);
} else {
helpers.addResult(results, 0,
'BigQuery dataset does not provide public access', region, dataset.id);
}
} else {
helpers.addResult(results, 0,
'BigQuery dataset does not provide public access', region, dataset.id);
}
});

rcb();
}, function(){
// Global checking goes here
callback(null, results, source);
});
}
}
120 changes: 120 additions & 0 deletions plugins/google/bigquery/datasetAllUsersPolicy.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
var assert = require('assert');
var expect = require('chai').expect;
var plugin = require('./datasetAllUsersPolicy');

const datasetGet = [
{
"kind": "bigquery#dataset",
"id": "aqua-dev-cloudsploit:aqua_ds",
"selfLink": "https://www.googleapis.com/bigquery/v2/projects/aqua-dev-cloudsploit/datasets/aqua_ds",
"datasetReference": { "datasetId": "aqua_ds", "projectId": "aqua-dev-cloudploit" },
"access": [
{ "role": "WRITER", "specialGroup": "projectWriters" },
{ "role": "OWNER", "specialGroup": "projectOwners" },
{ "role": "READER", "specialGroup": "projectReaders" }
],
"creationTime": "1619622395743",
"lastModifiedTime": "1619699668544",
"location": "US",
"type": "DEFAULT"
},
{
"kind": "bigquery#dataset",
"id": "aqua-dev-cloudsploit:aqua_ds",
"selfLink": "https://www.googleapis.com/bigquery/v2/projects/aqua-dev-cloudsploit/datasets/aqua_ds",
"datasetReference": { "datasetId": "aqua_ds", "projectId": "aqua-dev-cloudploit" },
"access": [
{ "role": "WRITER", "iamMember": "allUsers" },
{ "role": "WRITER", "specialGroup": "projectWriters" },
{ "role": "OWNER", "specialGroup": "projectOwners" },
{ "role": "READER", "specialGroup": "allAuthenticatedUsers" },
{ "role": "READER", "specialGroup": "projectReaders" }
],
"creationTime": "1619622395743",
"lastModifiedTime": "1619699668544",
"location": "US",
"type": "DEFAULT"
}
];

const createCache = (err, data) => {
return {
datasets: {
get: {
'global': {
err: err,
data: data
}
}
}
}
};

describe('datasetAllUsersPolicy', function () {
describe('run', function () {
it('should give unknown result if unable to query BigQuery datasets', 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 BigQuery datasets');
expect(results[0].region).to.equal('global');
done()
};

const cache = createCache(
['error'],
null,
);

plugin.run(cache, {}, callback);
});
it('should give passing result if no datasets 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 BigQuery datasets found');
expect(results[0].region).to.equal('global');
done()
};

const cache = createCache(
null,
[],
);

plugin.run(cache, {}, callback);
});
it('should give passing result if BigQuery dataset does not provide public access', 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('BigQuery dataset does not provide public access');
expect(results[0].region).to.equal('global');
done()
};

const cache = createCache(
null,
[datasetGet[0]]
);

plugin.run(cache, {}, callback);
});
it('should give failing result if BigQuery dataset provides public access', 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('BigQuery dataset provides');
expect(results[0].region).to.equal('global');
done()
};

const cache = createCache(
null,
[datasetGet[1]]
);

plugin.run(cache, {}, callback);
})
})
});

0 comments on commit ccff1c9

Please sign in to comment.