@enterprise-cmcs/macpro-security-hub-sync
Version:
NPM module to create Jira issues for all findings in Security Hub for the current AWS account..
120 lines (119 loc) • 5.04 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SecurityHub = void 0;
const client_iam_1 = require("@aws-sdk/client-iam");
const client_securityhub_1 = require("@aws-sdk/client-securityhub");
class SecurityHub {
region;
severityLabels;
accountAlias = "";
constructor({ region = "us-east-1", severities = ["HIGH", "CRITICAL"], } = {}) {
this.region = region;
this.severityLabels = severities.map((severity) => ({
Comparison: client_securityhub_1.StringFilterComparison.EQUALS,
Value: severity,
}));
this.fetchAccountAlias().catch((error) => console.error(error));
}
async fetchAccountAlias() {
const iamClient = new client_iam_1.IAMClient({ region: this.region });
const response = await iamClient.send(new client_iam_1.ListAccountAliasesCommand({}));
this.accountAlias = response.AccountAliases?.[0] || "";
}
getAccountAlias() {
return this.accountAlias;
}
async getAllActiveFindings() {
try {
const securityHubClient = new client_securityhub_1.SecurityHubClient({ region: this.region });
const currentTime = new Date();
// delay for filtering out ephemeral issues
const delayForNewIssues = typeof process.env.SECURITY_HUB_NEW_ISSUE_DELAY !== "undefined"
? +process.env.SECURITY_HUB_NEW_ISSUE_DELAY
: 24 * 60 * 60 * 1000; // 1 day
const maxDatetime = new Date(currentTime.getTime() - delayForNewIssues);
const filters = {
RecordState: [{ Comparison: "EQUALS", Value: "ACTIVE" }],
WorkflowStatus: [
{ Comparison: "EQUALS", Value: "NEW" },
{ Comparison: "EQUALS", Value: "NOTIFIED" },
],
SeverityLabel: this.severityLabels,
CreatedAt: [
{
Start: "1970-01-01T00:00:00Z",
End: maxDatetime.toISOString(),
},
],
};
if (process.env.INCLUDE_ALL_PRODUCTS !== "true") {
filters.ProductName = [{ Comparison: "EQUALS", Value: "Security Hub" }];
}
if (process.env.SKIP_PRODUCTS) {
const skipList = process.env.SKIP_PRODUCTS.split(",");
skipList.forEach((product) => {
if (!filters.ProductName) {
filters.ProductName = [];
}
filters.ProductName?.push({
Comparison: "NOT_EQUALS",
Value: product,
});
});
}
// use an object to store unique findings by title
const uniqueFindings = {};
// use a variable to track pagination
let nextToken = undefined;
do {
const response = await securityHubClient.send(new client_securityhub_1.GetFindingsCommand({
Filters: filters,
MaxResults: 100, // this is the maximum allowed per page
NextToken: nextToken,
}));
if (response && response.Findings) {
for (const finding of response.Findings) {
const findingForJira = this.awsSecurityFindingToSecurityHubFinding(finding);
if (findingForJira.title)
uniqueFindings[findingForJira.title] = findingForJira;
}
}
if (response && response.NextToken)
nextToken = response.NextToken;
else
nextToken = undefined;
} while (nextToken);
return Object.values(uniqueFindings).map((finding) => {
return {
accountAlias: this.accountAlias,
...finding,
};
});
}
catch (e) {
throw new Error(`Error getting Security Hub findings: ${e.message}`);
}
}
awsSecurityFindingToSecurityHubFinding(finding) {
if (!finding)
return {};
return {
id: finding.Id,
title: finding.Title,
region: finding.Region,
accountAlias: this.accountAlias,
awsAccountId: finding.AwsAccountId,
severity: finding.Severity && finding.Severity.Label
? finding.Severity.Label
: "",
description: finding.Description,
standardsControlArn: finding.ProductFields && finding.ProductFields.StandardsControlArn
? finding.ProductFields.StandardsControlArn
: "",
remediation: finding.Remediation,
ProductName: finding.ProductName,
Resources: finding.Resources,
};
}
}
exports.SecurityHub = SecurityHub;