Skip to content

Commit

Permalink
syncing with saas
Browse files Browse the repository at this point in the history
  • Loading branch information
Meerab-Shafique committed Feb 27, 2025
1 parent 9512e0a commit 7c38f5f
Show file tree
Hide file tree
Showing 29 changed files with 157 additions and 322 deletions.
2 changes: 1 addition & 1 deletion collectors/aws/accessanalyzer/listFindingsV2.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ module.exports = function(AWSConfig, collection, retries, callback) {
}, function(){
callback();
});
};
};
93 changes: 71 additions & 22 deletions collectors/azure/collector.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
- api_calls: (Optional) If provided, will only query these APIs.
- Example:
{
"skip_locations": ["eastus", "westus"],
"api_calls": ["storageAccounts:list", "resourceGroups:list"]
"skip_locations": ["eastus", "westus"],
"api_calls": ["storageAccounts:list", "resourceGroups:list"]
}
- callback: Function to call when the collection is complete
*********************/
Expand Down Expand Up @@ -62,14 +62,59 @@ let collect = function(AzureConfig, settings, callback, fargateFlag) {
var collection = {};

let makeCall = function(localUrl, obj, cb, localData) {
helpers.call({
url: localUrl,
post: obj.post,
token: obj.graph ? loginData.graphToken : (obj.vault ? loginData.vaultToken : loginData.token),
govcloud : AzureConfig.Govcloud
}, function(err, data, response) {
if (err) return cb(err, null, response);
const makeApiCall = async(retryAttempt = 0) => {
try {
const response = await new Promise((resolve, reject) => {
helpers.call({
url: localUrl,
post: obj.post,
token: obj.graph ? loginData.graphToken : (obj.vault ? loginData.vaultToken : loginData.token),
govcloud: AzureConfig.Govcloud
}, (err, data, apiResponse) => {
if (err) {
reject({ error: err, response: apiResponse });
} else {
resolve({ data, response: apiResponse });
}
});
});

handleResponse(response.data);
} catch (error) {
if (error.error && error.error.includes('ECONNRESET') && retryAttempt < 3) {
// Refresh token using callback patterns
helpers.login(AzureConfig, function(refreshErr, refreshedLoginData) {
if (refreshErr) {
return cb(`Failed to refresh token: ${refreshErr}`, null, error.response);
}

// Update loginData with refreshed tokens
loginData = refreshedLoginData;
console.log('Token refreshed successfully. New token data:', JSON.stringify({
environment: loginData.environment,
token: loginData.token ? '***' + loginData.token.slice(-8) : null,
graphToken: loginData.graphToken ? '***' + loginData.graphToken.slice(-8) : null,
vaultToken: loginData.vaultToken ? '***' + loginData.vaultToken.slice(-8) : null
}, null, 2));

// Retry with new token
makeApiCall(retryAttempt + 1)
.then(() => cb(null, null, null))
.catch(err => cb(err, null, null));
});
} else {
return cb(error.error, null, error.response);
}
}
};

// Start the async process
makeApiCall().catch(error => {
console.log(`Unexpected error in makeApiCall: ${error}`);
cb(error, null, null);
});

function handleResponse(data) {
// If a new nextLink is provided, this will be updated. There shouldn't
// be a need to hold on to the previous value
if (data && obj.hasListResponse && data.length) data.value = data;
Expand All @@ -85,17 +130,24 @@ let collect = function(AzureConfig, settings, callback, fargateFlag) {
return cb(null, localData);
}

let resData = localData || data;
const resData = localData || data;
if (data && ((obj.paginate && data[obj.paginate]) || data['nextLink']) && (!obj.limit || (obj.limit && resData && resData.value && resData.value.length < obj.limit))) {
obj.nextUrl = data['nextLink'] || data[obj.paginate];
processCall(obj, cb, localData || data);
} else {
return cb(null, localData || data || []);
}
});
}
};

let processCall = function(obj, cb, localData) {
let callbackCalled = false;
const wrappedCallback = (err, data, response) => {
if (callbackCalled) return;
callbackCalled = true;
cb(err, data, response);
};

if (fargateFlag) {
const maxApiRetryAttempts = 15;
let initialResponse = null;
Expand All @@ -108,38 +160,36 @@ let collect = function(AzureConfig, settings, callback, fargateFlag) {
return retryAfter;
},
errorFilter: function(err) {
return err.includes('TooManyRequests');
const errorMessage = typeof err === 'string' ? err : err.message || err.toString();
return errorMessage.includes('TooManyRequests');
}
}, function(retryCallback) {
let localUrl = obj.nextUrl || obj.url.replace(/\{subscriptionId\}/g, AzureConfig.SubscriptionID);
// Temporary fix to add additional buffer of 6 seconds before each call
var rateLimit = obj.rateLimit && obj.rateLimit == 3000? 6000: obj.rateLimit;
if (rateLimit) {
setTimeout(function() {
console.log(`Fargate collector rate limited: url: ${localUrl}`);
makeCall(localUrl, obj, function(err, data, response) {
initialResponse = response;
return retryCallback(err, data, response);
retryCallback(err, data, response);
}, localData);
}, rateLimit);
} else {
makeCall(localUrl, obj, function(err, data, response) {
initialResponse = response;
return retryCallback(err, data, response);
retryCallback(err, data, response);
}, localData);
}
}, function(err, data, response) {
cb(err, data, response);
});
}, wrappedCallback);
} else {
let localUrl = obj.nextUrl || obj.url.replace(/\{subscriptionId\}/g, AzureConfig.SubscriptionID);
if (obj.rateLimit) {
setTimeout(function() {
console.log(`url: ${localUrl}`);
makeCall(localUrl, obj, cb, localData);
makeCall(localUrl, obj, wrappedCallback, localData);
}, obj.rateLimit);
} else {
makeCall(localUrl, obj, cb, localData);
makeCall(localUrl, obj, wrappedCallback, localData);
}
}
};
Expand Down Expand Up @@ -531,5 +581,4 @@ let collect = function(AzureConfig, settings, callback, fargateFlag) {
});
};

module.exports = collect;

module.exports = collect;
3 changes: 3 additions & 0 deletions exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,9 @@ module.exports = {
'buildProjectEnvPriviligedMode' : require(__dirname + '/plugins/aws/codebuild/buildProjectEnvPriviligedMode.js'),
'codebuildProjectLoggingEnabled': require(__dirname + '/plugins/aws/codebuild/codebuildProjectLoggingEnabled.js'),

'codestarValidRepoProviders' : require(__dirname + '/plugins/aws/codestar/codestarValidRepoProviders.js'),
'codestarHasTags' : require(__dirname + '/plugins/aws/codestar/codestarHasTags.js'),

'pipelineArtifactsEncrypted' : require(__dirname + '/plugins/aws/codepipeline/pipelineArtifactsEncrypted.js'),

'dataStoreEncrypted' : require(__dirname + '/plugins/aws/healthlake/dataStoreEncrypted.js'),
Expand Down
1 change: 0 additions & 1 deletion helpers/aws/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1840,7 +1840,6 @@ var postcalls = [
},
sendIntegration: serviceMap['IAM'][0]
},

APIGateway: {
getStages: {
reliesOnService: 'apigateway',
Expand Down
2 changes: 1 addition & 1 deletion helpers/aws/api_multipart.js
Original file line number Diff line number Diff line change
Expand Up @@ -2018,7 +2018,7 @@ var postcalls = [
reliesOnCall: 'listFunctions',
filterKey: 'FunctionName',
filterValue: 'FunctionName',
rateLimit: 500, // it's not documented but experimentally 10/second works.
rateLimit: 500, // it's not documented but experimental 10/second works.
},
getFunction: {
reliesOnService: 'lambda',
Expand Down
7 changes: 5 additions & 2 deletions helpers/azure/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ module.exports = {

console.log(`[ERROR] Unhandled error from Azure API: Body: ${JSON.stringify(body)}`);
}
if (error && error.code === 'ECONNRESET') {
console.log('[ERROR] Unhandled error from Azure API: Error: ECONNRESET');
return callback('Unknown error occurred while calling the Azure API: ECONNRESET');
}

console.log(`[ERROR] Unhandled error from Azure API: Error: ${error}`);
return callback('Unknown error occurred while calling the Azure API');
Expand Down Expand Up @@ -232,5 +236,4 @@ module.exports = {
},

reduceProperties: reduceProperties
};

};
2 changes: 1 addition & 1 deletion helpers/azure/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ function checkNetworkExposure(cache, source, networkInterfaces, securityGroups,
if (lb.frontendIPConfigurations && lb.frontendIPConfigurations.length) {
isPublic = lb.frontendIPConfigurations.some(ipConfig => ipConfig.properties
&& ipConfig.properties.publicIPAddress && ipConfig.properties.publicIPAddress.id);
if (isPublic && ((lb.inboundNatRules && inboundNatRules.length) || (lb.loadBalancingRules && lb.loadBalancingRules.length))) {
if (isPublic && ((lb.inboundNatRules && lb.inboundNatRules.length) || (lb.loadBalancingRules && lb.loadBalancingRules.length))) {
exposedPath += exposedPath.length ? `, lb ${lb.name}` : `lb ${lb.name}`;
}
}
Expand Down
2 changes: 1 addition & 1 deletion helpers/google/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ function getForwardingRules(cache, source, region, resource) {
if (service.backends && service.backends.length) {
return service.backends.some(backend => {
let group = backend.group.replace(/^.*?(\/projects\/.*)$/, '$1');
return resource.selfLink.includes(group);
return (resource.selfLink && resource.selfLink.includes(group));
});
}
});
Expand Down
2 changes: 1 addition & 1 deletion plugins/alibaba/ecs/openSalt.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module.exports = {
title: 'Open Salt',
category: 'ECS',
domain: 'Compute',
severity: 'Critical',
severity: 'Medium',
description: 'Ensure that security groups does not have TCP ports 4505 or 4506 for the Salt master open to the public.',
more_info: 'Active Salt vulnerabilities, CVE-2020-11651 and CVE-2020-11652 are exploiting Salt instances exposed to the internet. These ports should be closed immediately.',
link: 'https://www.alibabacloud.com/help/doc-detail/25471.htm',
Expand Down
8 changes: 4 additions & 4 deletions plugins/aws/accessanalyzer/accessAnalyzerActiveFindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module.exports = {
var source = {};
var regions = helpers.regions(settings);

async.each(regions.accessanalyzer, function(region, rcb){
async.each(regions.accessanalyzer, function(region, rcb){
var listAnalyzers = helpers.addSource(cache, source,
['accessanalyzer', 'listAnalyzers', region]);

Expand Down Expand Up @@ -57,14 +57,14 @@ module.exports = {
let filteredv2 = listFindingsV2.data.findings.filter(finding => finding.status === 'ACTIVE');
totalFiltered = totalFiltered.concat(filteredv2);
}

if ((!listFindings || listFindings.err || !listFindings.data) && (!listFindingsV2 || listFindingsV2.err || !listFindingsV2.data)) {
helpers.addResult(results, 3,
`Unable to IAM Access Analyzer findings: ${helpers.addError(listFindings)} ${helpers.addError(listFindingsV2)}`,
region, resource);
continue;
}
}

if (!totalFiltered.length) {
helpers.addResult(results, 0,
'Amazon IAM Access Analyzer has no active findings',
Expand Down
30 changes: 15 additions & 15 deletions plugins/aws/accessanalyzer/accessAnalyzerActiveFindings.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ const listAnalyzers = [
];

const listFindings = [
{
"findings": [
{
"findings": [
{
"action": [
"kms:RetireGrant"
Expand Down Expand Up @@ -74,9 +74,9 @@ const listFindings = [
"updatedAt": "2022-01-12T13:48:20+00:00"
}
]
},
{
"findings": [
},
{
"findings": [
{
"action": [
"kms:RetireGrant"
Expand Down Expand Up @@ -134,13 +134,13 @@ const listFindings = [
"updatedAt": "2022-01-12T13:48:20+00:00"
}
]
}
}

];

const listFindingsV2 = [
{
"findings": [
{
"findings": [
{
"analyzedAt": "2025-01-23T13:06:24+00:00",
"createdAt": "2025-01-23T13:06:56+00:00",
Expand Down Expand Up @@ -175,9 +175,9 @@ const listFindingsV2 = [
"findingType": "UnusedPermission"
},
]
},
{
"findings": [
},
{
"findings": [
{
"analyzedAt": "2025-01-23T13:06:24+00:00",
"createdAt": "2025-01-23T13:06:56+00:00",
Expand Down Expand Up @@ -212,7 +212,7 @@ const listFindingsV2 = [
"findingType": "UnusedPermission"
},
]
}
}

]

Expand Down Expand Up @@ -269,7 +269,7 @@ describe('accessAnalyzerActiveFindings', function () {
expect(results[0].status).to.equal(0);
expect(results[0].region).to.equal('us-east-1');
expect(results[0].message).to.include('Amazon IAM Access Analyzer has no active findings');

done();
});
});
Expand All @@ -282,7 +282,7 @@ describe('accessAnalyzerActiveFindings', function () {
expect(results[0].status).to.equal(0);
expect(results[0].region).to.equal('us-east-1');
expect(results[0].message).to.include('Amazon IAM Access Analyzer has no active findings');

done();
});
});
Expand Down
2 changes: 1 addition & 1 deletion plugins/aws/codestar/codestarHasTags.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,4 @@ describe('codestarHasTags', function () {
});
});
});
});
});
3 changes: 2 additions & 1 deletion plugins/aws/codestar/codestarValidRepoProviders.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ module.exports = {

let repoProvider = (describeProject.data.projectTemplateId.split('/').length > 1) ?
describeProject.data.projectTemplateId.split('/')[1] : '';

if (config.codestar_disallowed_repo_providers.includes(repoProvider)) {
helpers.addResult(results, 2,
`CodeStar project is using ${repoProvider} as repository provider which should not be used`,
Expand All @@ -77,4 +78,4 @@ module.exports = {
callback(null, results, source);
});
}
};
};
2 changes: 1 addition & 1 deletion plugins/aws/ec2/openSalt.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module.exports = {
title: 'Open Salt',
category: 'EC2',
domain: 'Compute',
severity: 'Critical',
severity: 'High',
description: 'Determine if TCP ports 4505 or 4506 for the Salt master are open to the public',
more_info: 'Active Salt vulnerabilities, CVE-2020-11651 and CVE-2020-11652 are exploiting Salt instances exposed to the internet. These ports should be closed immediately.',
link: 'https://help.saltstack.com/hc/en-us/articles/360043056331-New-SaltStack-Release-Critical-Vulnerability',
Expand Down
2 changes: 1 addition & 1 deletion plugins/aws/ec2/securityGroupRfc1918.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module.exports = {
private_cidrs: {
name: 'EC2 RFC 1918 CIDR Addresses',
description: 'A comma-separated list of CIDRs that indicates reserved private addresses',
regex: '/^(?=.*[^.]$)((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).?){4}$/',
regex: '^(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).?){4}/(?:[0-9]|[1-2][0-9]|3[0-2])(?:,(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).?){4}/(?:[0-9]|[1-2][0-9]|3[0-2]))*)?$',
default: '10.0.0.0/8,172.16.0.0/12,192.168.0.0/16'
}
},
Expand Down
Loading

0 comments on commit 7c38f5f

Please sign in to comment.