diff --git a/helpers/aws/functions.js b/helpers/aws/functions.js index 4791e488da..3c18d5deb7 100644 --- a/helpers/aws/functions.js +++ b/helpers/aws/functions.js @@ -1148,7 +1148,8 @@ var checkTags = function(cache, resourceName, resourceList, region, results, set }); }; -function checkSecurityGroup(securityGroup, cache, region, checkENIs = true) { + +function checkSecurityGroup(securityGroup, cache, region) { let allowsAllTraffic; for (var p in securityGroup.IpPermissions) { var permission = securityGroup.IpPermissions[p]; @@ -1170,84 +1171,15 @@ function checkSecurityGroup(securityGroup, cache, region, checkENIs = true) { } } - if (allowsAllTraffic && checkENIs) { + if (allowsAllTraffic) { return checkNetworkInterface(securityGroup.GroupId, securityGroup.GroupName, '', region, null, securityGroup, cache, true); } - return allowsAllTraffic; + return false; } -var getAttachedELBs = function(cache, source, region, resourceId, lbField, lbAttribute) { - let elbs = []; - - // check classice ELBs - var describeLoadBalancers = helpers.addSource(cache, source, - ['elb', 'describeLoadBalancers', region]); - - if (describeLoadBalancers && !describeLoadBalancers.err && describeLoadBalancers.data && describeLoadBalancers.data.length) { - elbs = describeLoadBalancers.data.filter(lb => lb[lbField] && lb[lbField].some(instance => instance[lbAttribute] === resourceId)); - } - - // check ALBs/NLBs - - var describeLoadBalancersv2 = helpers.addSource(cache, source, - ['elbv2', 'describeLoadBalancers', region]); - - if (describeLoadBalancersv2 && !describeLoadBalancersv2.err && describeLoadBalancersv2.data && describeLoadBalancersv2.data.length) { - describeLoadBalancersv2.data.forEach(function(lb) { - lb.targetGroups = []; - var describeTargetGroups = helpers.addSource(cache, source, - ['elbv2', 'describeTargetGroups', region, lb.DNSName]); - - if (describeTargetGroups && !describeTargetGroups.err && describeTargetGroups.data && describeTargetGroups.data.TargetGroups && describeTargetGroups.data.TargetGroups.length) { - describeTargetGroups.data.TargetGroups.forEach(function(tg) { - var describeTargetHealth = helpers.addSource(cache, source, - ['elbv2', 'describeTargetHealth', region, tg.TargetGroupArn]); - - if (describeTargetHealth && !describeTargetHealth.err && describeTargetHealth.data - && describeTargetHealth.data.TargetHealthDescriptions && describeTargetHealth.data.TargetHealthDescriptions.length) { - describeTargetHealth.data.TargetHealthDescriptions.forEach(healthDescription => { - if (healthDescription.Target && healthDescription.Target.Id && - healthDescription.Target.Id === resourceId) { - lb.targetGroups.push({targetgroupName: tg.TargetGroupName, targetGroupArn: tg.TargetGroupArn}); - } - }); - } - }); - } - - if (lb.targetGroups && lb.targetGroups.length) { - let hasListener = false; - var describeListeners = helpers.addSource(cache, source, - ['elbv2', 'describeListeners', region, lb.DNSName]); - if (describeListeners && describeListeners.data && describeListeners.data.Listeners && describeListeners.data.Listeners.length) { - describeListeners.data.Listeners.forEach(listener => { - if (!hasListener) { - hasListener = listener.DefaultActions.some(action => - action.TargetGroupArn && lb.targetGroups.some(tg => tg.targetGroupArn === action.TargetGroupArn) - ); - } - - }); - } - if (hasListener) { - elbs.push(lb); - } - } - }); - } - - return elbs; -}; - -var checkNetworkExposure = function(cache, source, subnets, securityGroups, elbs, region, results, resource) { +var checkNetworkExposure = function(cache, source, subnetId, securityGroups, region, results) { var internetExposed = ''; - var isSubnetPrivate = false; - - // Check public endpoint access for specific resources like EKS - if (resource && resource.resourcesVpcConfig && resource.resourcesVpcConfig.endpointPublicAccess) { - return 'public endpoint access'; - } // Scenario 1: check if resource is in a private subnet let subnetRouteTableMap, privateSubnets; var describeSubnets = helpers.addSource(cache, source, @@ -1261,139 +1193,80 @@ var checkNetworkExposure = function(cache, source, subnets, securityGroups, elbs } else if (!describeSubnets || describeSubnets.err || !describeSubnets.data) { helpers.addResult(results, 3, 'Unable to query for subnets: ' + helpers.addError(describeSubnets), region); - } else if (describeSubnets.data.length && subnets.length) { + } else if (describeSubnets.data.length && subnetId) { subnetRouteTableMap = getSubnetRTMap(describeSubnets.data, describeRouteTables.data); privateSubnets = getPrivateSubnets(subnetRouteTableMap, describeSubnets.data, describeRouteTables.data); - if (privateSubnets && privateSubnets.length) { - isSubnetPrivate = !subnets.some(subnet => !privateSubnets.includes(subnet.id)); - } - - // if it's in a private subnet and has no ELBs attached then its not exposed - if (isSubnetPrivate && (!elbs || !elbs.length)) { + if (privateSubnets && privateSubnets.length && privateSubnets.find(subnet => subnet === subnetId)) { return ''; } + // If the subnet is not private we will check if security groups and Network ACLs allow internal traffic } - - // If the subnet is not private we will check if security groups and Network ACLs allow internal traffic - // Scenario 2: check if security group allows all traffic var describeSecurityGroups = helpers.addSource(cache, source, ['ec2', 'describeSecurityGroups', region]); - if (!isSubnetPrivate) { - if (!describeSecurityGroups || describeSecurityGroups.err || !describeSecurityGroups.data) { - helpers.addResult(results, 3, - 'Unable to query for security groups: ' + helpers.addError(describeSecurityGroups), region); - } else if (describeSecurityGroups.data.length && securityGroups && securityGroups.length) { - let instanceSGs = describeSecurityGroups.data.filter(sg => securityGroups.find(isg => isg.GroupId === sg.GroupId)); - for (var group of instanceSGs) { - let exposedSG = checkSecurityGroup(group, cache, region); - if (exposedSG) { - internetExposed += internetExposed ? `, ${exposedSG}` : exposedSG; - } - } - } - - - // if security group allows all traffic we need to check NACLs - if (internetExposed.length) { - let subnetIds = subnets.map(s => s.id); - // Scenario 3: check if Network ACLs associated with the resource allow all traffic - var describeNetworkAcls = helpers.addSource(cache, source, - ['ec2', 'describeNetworkAcls', region]); - - if (!describeNetworkAcls || describeNetworkAcls.err || !describeNetworkAcls.data) { - helpers.addResult(results, 3, - `Unable to query for Network ACLs: ${helpers.addError(describeNetworkAcls)}`, region); - } else if (describeNetworkAcls.data.length && subnetIds) { - let naclDeny = true; - for (let subnetId of subnetIds) { - let instanceACL = describeNetworkAcls.data.find(acl => acl.Associations.find(assoc => assoc.SubnetId === subnetId)); - if (instanceACL && instanceACL.Entries && instanceACL.Entries.length) { - const allowRules = instanceACL.Entries.filter(entry => - entry.Egress === false && - entry.RuleAction === 'allow' && - (entry.CidrBlock === '0.0.0.0/0' || entry.Ipv6CidrBlock === '::/0') - ); - - const denyIPv4 = instanceACL.Entries.find(entry => - entry.Egress === false && - entry.RuleAction === 'deny' && - entry.CidrBlock === '0.0.0.0/0' - ); - - const denyIPv6 = instanceACL.Entries.find(entry => - entry.Egress === false && - entry.RuleAction === 'deny' && - entry.Ipv6CidrBlock === '::/0' - ); - - let exposed = allowRules.some(allowRule => { - return !instanceACL.Entries.some(denyRule => { - return ( - denyRule.Egress === false && - denyRule.RuleAction === 'deny' && - ( - (allowRule.CidrBlock && denyRule.CidrBlock === allowRule.CidrBlock) || - (allowRule.Ipv6CidrBlock && denyRule.Ipv6CidrBlock === allowRule.Ipv6CidrBlock) - ) && - denyRule.Protocol === allowRule.Protocol && - ( - denyRule.PortRange ? - (allowRule.PortRange && - denyRule.PortRange.From === allowRule.PortRange.From && - denyRule.PortRange.To === allowRule.PortRange.To) : true - ) && - denyRule.RuleNumber < allowRule.RuleNumber - ); - }); - }); - - // exposed - if NACL has an allow all rule - if (exposed) { - internetExposed += `, nacl ${instanceACL.NetworkAclId}`; - } - - // not exposed - if NACL has a deny rule - if (exposed || !denyIPv4 || !denyIPv6) { - naclDeny = false; - } - } else { - naclDeny = false; - } - } - // not exposed - if all NACLs have deny rules - if (naclDeny) { - return ''; - } + if (!describeSecurityGroups || describeSecurityGroups.err || !describeSecurityGroups.data) { + helpers.addResult(results, 3, + 'Unable to query for security groups: ' + helpers.addError(describeSecurityGroups), region); + } else if (describeSecurityGroups.data.length && securityGroups && securityGroups.length) { + let instanceSGs = describeSecurityGroups.data.filter(sg => securityGroups.find(isg => isg.GroupId === sg.GroupId)); + for (var group of instanceSGs) { + let exposedSG = checkSecurityGroup(group, cache, region); + if (!exposedSG) { + return ''; + } else { + internetExposed += exposedSG; } - } } - // if there are no explicit allow or deny rules, we look at ELBs - if (elbs && elbs.length) { - for (const lb of elbs) { + // Scenario 3: check if Network ACLs associated with the resource allow all traffic + var describeNetworkAcls = helpers.addSource(cache, source, + ['ec2', 'describeNetworkAcls', region]); - let isLBPublic = false; - if (lb.Scheme && lb.Scheme.toLowerCase() === 'internet-facing') { - if (lb.SecurityGroups && lb.SecurityGroups.length && describeSecurityGroups && - !describeSecurityGroups.err && describeSecurityGroups.data && describeSecurityGroups.data.length) { - let elbSGs = describeSecurityGroups.data.filter(sg => lb.SecurityGroups.includes(sg.GroupId)); - for (var elbSG of elbSGs) { - let exposedSG = checkSecurityGroup(elbSG, cache, region, false); - if (exposedSG) { - isLBPublic = true; - } - } - } - } - - if (isLBPublic) { - internetExposed += internetExposed.length ? `, elb ${lb.LoadBalancerName}`: `elb ${lb.LoadBalancerName}`; + if (!describeNetworkAcls || describeNetworkAcls.err || !describeNetworkAcls.data) { + helpers.addResult(results, 3, + `Unable to query for Network ACLs: ${helpers.addError(describeNetworkAcls)}`, region); + } else if (describeNetworkAcls.data.length && subnetId) { + let instanceACL = describeNetworkAcls.data.find(acl => acl.Associations.find(assoc => assoc.SubnetId === subnetId)); + if (instanceACL && instanceACL.Entries && instanceACL.Entries.length) { + + const allowRules = instanceACL.Entries.filter(entry => + entry.Egress === false && + entry.RuleAction === 'allow' && + (entry.CidrBlock === '0.0.0.0/0' || entry.Ipv6CidrBlock === '::/0') + ); + + + // Checking if there's a deny rule with lower rule number + let exposed = allowRules.some(allowRule => { + // Check if there's a deny with a lower rule number + return !instanceACL.Entries.some(denyRule => { + return ( + denyRule.Egress === false && + denyRule.RuleAction === 'deny' && + ( + (allowRule.CidrBlock && denyRule.CidrBlock === allowRule.CidrBlock) || + (allowRule.Ipv6CidrBlock && denyRule.Ipv6CidrBlock === allowRule.Ipv6CidrBlock) + ) && + denyRule.Protocol === allowRule.Protocol && + ( + denyRule.PortRange ? + (allowRule.PortRange && + denyRule.PortRange.From === allowRule.PortRange.From && + denyRule.PortRange.To === allowRule.PortRange.To) : true + ) && + denyRule.RuleNumber < allowRule.RuleNumber + ); + }); + }); + if (exposed) { + internetExposed += `> nacl ${instanceACL.NetworkAclId}`; + } else { + internetExposed = ''; } } } @@ -1439,6 +1312,6 @@ module.exports = { processFieldSelectors: processFieldSelectors, checkNetworkInterface: checkNetworkInterface, checkNetworkExposure: checkNetworkExposure, - getAttachedELBs: getAttachedELBs + }; diff --git a/helpers/azure/functions.js b/helpers/azure/functions.js index 4906bc5143..3fdc0a5652 100644 --- a/helpers/azure/functions.js +++ b/helpers/azure/functions.js @@ -775,7 +775,7 @@ function checkSecurityGroup(securityGroups) { return {exposed: true}; } -function checkNetworkExposure(cache, source, networkInterfaces, securityGroups, location, results, lbNames) { +function checkNetworkExposure(cache, source, networkInterfaces, securityGroups, region, results) { let exposedPath = ''; if (securityGroups && securityGroups.length) { @@ -783,35 +783,12 @@ function checkNetworkExposure(cache, source, networkInterfaces, securityGroups, let exposedSG = checkSecurityGroup(securityGroups); if (exposedSG && exposedSG.exposed) { if (exposedSG.nsg) { - return `nsg ${exposedSG.nsg}` - } else { - return ''; + exposedPath += `nsg ${exposedSG.nsg}` } } - } - if (lbNames && lbNames.length) { - const loadBalancers = shared.addSource(cache, source, - ['loadBalancers', 'listAll', location]); - - if (loadBalancers && !loadBalancers.err && loadBalancers.data && loadBalancers.data.length) { - let resourceLBs = loadBalancers.data.filter(lb => lbNames.includes(lb.id)); - if (resourceLBs && resourceLBs.length) { - for (let lb of resourceLBs) { - let isPublic = false; - if (lb.frontendIPConfigurations && lb.frontendIPConfigurations.length) { - isPublic = lb.frontendIPConfigurations.some(ipConfig => ipConfig.properties - && ipConfig.properties.publicIPAddress && ipConfig.properties.publicIPAddress.id); - if (isPublic && ((lb.nboundNatRules && nboundNatRules.length) || (lb.loadBalancingRules && lb.loadBalancingRules.length))) { - exposedPath += `lb ${lb.name}`; - break; - } - } - } - } - } + return exposedPath } - return exposedPath; } module.exports = { @@ -826,7 +803,7 @@ module.exports = { remediateOpenPorts: remediateOpenPorts, remediateOpenPortsHelper: remediateOpenPortsHelper, checkMicrosoftDefender: checkMicrosoftDefender, - checkFlexibleServerConfigs:checkFlexibleServerConfigs, - checkNetworkExposure: checkNetworkExposure + checkFlexibleServerConfigs: checkFlexibleServerConfigs, + checkNetworkExposure: checkNetworkExposure, }; diff --git a/helpers/google/functions.js b/helpers/google/functions.js index 8a451b411a..babff8dd28 100644 --- a/helpers/google/functions.js +++ b/helpers/google/functions.js @@ -411,8 +411,7 @@ function checkFirewallRules(firewallRules) { } const networkName = firewallRule.network ? firewallRule.network.split('/').pop() : ''; - - let allSources = firewallRule.sourceRanges?.some(sourceAddressPrefix => + let allSources = firewallRule.sourceRanges && firewallRule.sourceRanges.some(sourceAddressPrefix => sourceAddressPrefix === '*' || sourceAddressPrefix === '0.0.0.0/0' || sourceAddressPrefix === '::/0' || @@ -421,13 +420,14 @@ function checkFirewallRules(firewallRules) { sourceAddressPrefix.includes('/0') ); - if (allSources && firewallRule.allowed?.some(allow => !!allow.IPProtocol)) { - return {exposed: true, networkName: `vpc ${networkName}`}; + if (allSources && firewallRule.allowed && firewallRule.allowed.some(allow => !!allow.IPProtocol)) { + return { exposed: true, networkName: `vpc ${networkName}` }; } - - if (allSources && firewallRule.denied?.some(deny => deny.IPProtocol === 'all')) { - return {exposed: false}; + + if (allSources && firewallRule.denied && firewallRule.denied.some(deny => deny.IPProtocol === 'all')) { + return { exposed: false }; } + } return {exposed: true}; @@ -435,122 +435,7 @@ function checkFirewallRules(firewallRules) { } -function getForwardingRules(cache, source, region, resource) { - let rules = []; - - let forwardingRules = getAllDataForService(cache, source, 'forwardingRules', 'list', region); - let backendServices = getAllDataForService(cache, source, 'backendServices', 'list', region); - let targetHttpProxies = getAllDataForService(cache, source, 'targetHttpProxies', 'list', region); - let targetHttpsProxies = getAllDataForService(cache, source, 'targetHttpsProxies', 'list', region); - let urlMaps = getAllDataForService(cache, source, 'urlMaps', 'list', region); - - if (!forwardingRules || !forwardingRules.length || !backendServices || !backendServices.length) { - return []; - } - - backendServices = backendServices.filter(service => { - if (service.backends && service.backends.length) { - return service.backends.some(backend => { - let group = backend.group.replace(/^.*?(\/projects\/.*)$/, '$1'); - return resource.selfLink.includes(group); - }); - } - }); - - if (backendServices && backendServices.length) { - forwardingRules.forEach(rule => { - let rulePath = `FR ${rule.name}`; - let targetProxyLink = ''; - let urlMapLink = ''; - let backendServiceLink = ''; - - if (rule.target && (rule.target.includes('targetHttpProxies') || rule.target.includes('targetHttpsProxies'))) { - let target = rule.target.replace(/^.*?(\/projects\/.*)$/, '$1'); - let targetProxy = rule.target.includes('targetHttpProxies') - ? targetHttpProxies.find(proxy => proxy.selfLink.includes(target)) - : targetHttpsProxies.find(proxy => proxy.selfLink.includes(target)); - - if (targetProxy) { - rulePath += ` > TP ${targetProxy.name}`; - targetProxyLink = targetProxy.selfLink; - - if (targetProxy.urlMap) { - let urlMap = urlMaps.find(map => map.selfLink.includes(targetProxy.urlMap.replace(/^.*?(\/projects\/.*)$/, '$1'))); - if (urlMap && urlMap.defaultService) { - rulePath += ` > UM ${urlMap.name}`; - urlMapLink = urlMap.selfLink; - - let serviceName = urlMap.defaultService.replace(/^.*?(\/projects\/.*)$/, '$1'); - let matchedBackendService = backendServices.find(service => service.selfLink.includes(serviceName)); - - if (matchedBackendService) { - rulePath += ` > BS ${matchedBackendService.name}`; - backendServiceLink = matchedBackendService.selfLink; - } - } - } else { - let matchedBackendService = backendServices.find(service => targetProxy.selfLink.includes(service.selfLink.replace(/^.*?(\/projects\/.*)$/, '$1'))); - - if (matchedBackendService) { - rulePath += ` > BS ${matchedBackendService.name}`; - backendServiceLink = matchedBackendService.selfLink; - } - } - } - } else if (rule.backendService) { - let serviceName = rule.backendService.replace(/^.*?(\/projects\/.*)$/, '$1'); - let matchedBackendService = backendServices.find(service => service.selfLink.includes(serviceName)); - - if (matchedBackendService) { - rulePath += ` > BS ${matchedBackendService.name}`; - backendServiceLink = matchedBackendService.selfLink; - } - } - - if (backendServiceLink) { - rules.push({ ...rule, rulePath }); - } - }); - } - return rules; -} - - -function getAllDataForService(cache, source, service, call, region) { - let allData = []; - - let globalData = shared.addSource(cache, source, [service, call, 'global']); - let regionalData = shared.addSource(cache, source, [service, call, region]); - - - if (globalData && !globalData.err && globalData.data && globalData.data.length) { - allData = allData.concat(globalData.data); - } - - if (regionalData && !regionalData.err && regionalData.data && regionalData.data.length) { - allData = allData.concat(regionalData.data); - } - return allData; -} - -function checkClusterExposure(cluster) { - const privateClusterConfig = cluster.privateClusterConfig || {}; - const masterAuthorizedNetworksConfig = cluster.masterAuthorizedNetworksConfig || {}; - - const cidrBlocks = masterAuthorizedNetworksConfig.cidrBlocks || []; - - const publicCidrPatterns = ['0.0.0.0/0', '::/0', '*', '::0']; - - const hasPublicCIDR = cidrBlocks.some(block => publicCidrPatterns.includes(block)); - - return ( - (!privateClusterConfig.enablePrivateEndpoint && privateClusterConfig.publicEndpoint) || // Public endpoint with no private endpoint - masterAuthorizedNetworksConfig.gcpPublicCidrsAccessEnabled || // Google Cloud public IPs are allowed - hasPublicCIDR // If there is a public CIDR like 0.0.0.0/0, ::/0, or * - ); -} - -function checkNetworkExposure(cache, source, networks, firewallRules, region, results, forwardingRules) { +function checkNetworkExposure(cache, source, networks, firewallRules, region, results) { let exposedPath = ''; if (firewallRules && firewallRules.length) { @@ -560,21 +445,6 @@ function checkNetworkExposure(cache, source, networks, firewallRules, region, re if (isExposed.networkName) { return isExposed.networkName; } - } else { - return ''; - } - } - - // load balancing flow - if (forwardingRules && forwardingRules.length) { - for (let rule of forwardingRules) { - let ipAddress = rule.IPAddress; - if ((rule.loadBalancingScheme === 'EXTERNAL' || rule.loadBalancingScheme === 'EXTERNAL_MANAGED') && - (ipAddress && !ipAddress.startsWith('10.') && !ipAddress.startsWith('192.168.') && !ipAddress.startsWith('172.'))) { - exposedPath = rule.rulePath || rule.name; - break; - - } } } return exposedPath @@ -591,8 +461,5 @@ module.exports = { checkOrgPolicy: checkOrgPolicy, checkIAMRole: checkIAMRole, findOpenAllPortsEgress: findOpenAllPortsEgress, - checkNetworkExposure: checkNetworkExposure, - getForwardingRules: getForwardingRules, - checkClusterExposure: checkClusterExposure, - checkFirewallRules: checkFirewallRules + checkNetworkExposure: checkNetworkExposure }; diff --git a/plugins/aws/ec2/ec2NetworkExposure.js b/plugins/aws/ec2/ec2NetworkExposure.js index 47b969f9d8..371fc90093 100644 --- a/plugins/aws/ec2/ec2NetworkExposure.js +++ b/plugins/aws/ec2/ec2NetworkExposure.js @@ -10,12 +10,10 @@ module.exports = { more_info: 'EC2 instances exposed to the internet are at a higher risk of unauthorized access, data breaches, and cyberattacks. It’s crucial to limit exposure by securing access through proper configuration of security groups, NACLs, and route tables.', link: 'https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Security.html', recommended_action: 'Secure EC2 instances by restricting access with properly configured security groups and NACLs.', - apis: ['EC2:describeInstances', 'EC2:describeNetworkAcls', 'EC2:describeSecurityGroups', 'EC2:describeNetworkInterfaces', 'EC2:describeSubnets', - 'EC2:describeRouteTables', 'ELB:describeLoadBalancers','ELBv2:describeLoadBalancers', 'ELBv2:describeTargetGroups', 'ELBv2:describeTargetHealth', 'ELBv2:describeListeners'], + apis: ['EC2:describeInstances', 'EC2:describeNetworkAcls', 'EC2:describeSecurityGroups', 'EC2:describeNetworkInterfaces', 'EC2:describeSubnets', 'EC2:describeRouteTables'], realtime_triggers: ['ec2:RunInstances','ec2:TerminateInstances', 'ec2:CreateNetworkAcl', 'ec2:ReplaceNetworkAclEntry', 'ec2:ReplaceNetworkAclAssociation', 'ec2:DeleteNetworkAcl', 'ec2:CreateSecurityGroup', 'ec2:AuthorizeSecurityGroupIngress','ec2:ModifySecurityGroupRules','ec2:RevokeSecurityGroupIngress', - 'ec2:DeleteSecurityGroup', 'ec2:ModifyInstanceAttribute', 'ec2:ModifySubnetAttribute', 'elasticloadbalancing:CreateLoadBalancer', 'elasticloadbalancing:ModifyTargetGroups', 'elasticloadbalancing:RegisterTarget', 'elasticloadbalancing:DeregisterTargets', 'elasticloadbalancing:DeleteLoadBalancer', - 'elasticloadbalancing:DeleteTargetGroup', 'elasticloadbalancing:RegisterInstancesWithLoadBalancer', 'elasticloadbalancing:DeregisterInstancesWithLoadBalancer','elasticloadbalancing:CreateListener', 'elasticloadbalancing:DeleteListener'], + 'ec2:DeleteSecurityGroup', 'ec2:ModifyInstanceAttribute', 'ec2:ModifySubnetAttribute'], run: function(cache, settings, callback) { var results = []; @@ -45,11 +43,7 @@ module.exports = { for (var instance of instances.Instances) { const { InstanceId } = instance; const arn = `arn:${awsOrGov}:ec2:${region}:${OwnerId}:instance/${InstanceId}`; - - // List all ELB's attached to the instance - let elbs = helpers.getAttachedELBs(cache, source, region, InstanceId, 'Instances', 'InstanceId'); - - let internetExposed = helpers.checkNetworkExposure(cache, source, [{id: instance.SubnetId}], instance.SecurityGroups, elbs, region, results, instance); + let internetExposed = helpers.checkNetworkExposure(cache, source, instance.SubnetId, instance.SecurityGroups, region, results); if (internetExposed && internetExposed.length) { helpers.addResult(results, 2, `EC2 instance is exposed to the internet through ${internetExposed}`, region, arn); } else { diff --git a/plugins/aws/guardduty/eksProtectionEnabled.js b/plugins/aws/guardduty/eksProtectionEnabled.js index befb261da5..d39f143a18 100644 --- a/plugins/aws/guardduty/eksProtectionEnabled.js +++ b/plugins/aws/guardduty/eksProtectionEnabled.js @@ -39,7 +39,6 @@ module.exports = { } listDetectors.data.forEach(function(detectorId) { - var resource = 'arn:' + awsOrGov + ':guardduty:' + region + ':' + accountId + ':detector/' + detectorId; var getDetector = helpers.addSource(cache, source, ['guardduty', 'getDetector', region, detectorId]); if (!getDetector) return; @@ -50,19 +49,20 @@ module.exports = { } var detector = getDetector.data; + var resource = 'arn:' + awsOrGov + ':guardduty:' + region + ':' + accountId + ':detector/' + detector.detectorId; - if (detector.DataSources && - detector.DataSources.Kubernetes && - detector.DataSources.Kubernetes.AuditLogs && + if (detector.DataSources && + detector.DataSources.Kubernetes && + detector.DataSources.Kubernetes.AuditLogs && detector.DataSources.Kubernetes.AuditLogs.Status && detector.DataSources.Kubernetes.AuditLogs.Status.toLowerCase() === 'disabled'){ helpers.addResult(results, 2, 'GuardDuty EKS protection is disabled', region, resource); } else { helpers.addResult(results, 0, 'GuardDuty EKS protection is enabled', region, resource); - } - + } + }); - + rcb(); }, function(){ callback(null, results, source); diff --git a/plugins/azure/virtualmachines/vmNetworkExposure.js b/plugins/azure/virtualmachines/vmNetworkExposure.js index ccb42e09e1..4258c9954f 100644 --- a/plugins/azure/virtualmachines/vmNetworkExposure.js +++ b/plugins/azure/virtualmachines/vmNetworkExposure.js @@ -10,8 +10,8 @@ module.exports = { more_info: 'Virtual machines exposed to the internet are at a higher risk of unauthorized access, data breaches, and cyberattacks. It’s crucial to limit exposure by securing access through proper configuration of security group and firewall rules.', link: 'https://learn.microsoft.com/en-us/azure/security/fundamentals/virtual-machines-overview', recommended_action: 'Secure VM instances by restricting access with properly configured security group and firewall rules.', - apis: ['virtualMachines:listAll', 'networkInterfaces:listAll', 'networkSecurityGroups:listAll', 'virtualNetworks:listAll', 'loadBalancers:listAll'], - realtime_triggers: ['microsoftcompute:virtualmachines:write', 'microsoftnetwork:networkinterfaces:write', 'microsoftcompute:virtualmachines:delete', 'microsoftnetwork:networkinterfaces:delete', 'microsoftnetwork:networksecuritygroups:write','microsoftnetwork:networksecuritygroups:delete', 'microsoftnetwork:virtualnetworks:write','microsoftnetwork:virtualnetworks:delete','microsoftnetwork:loadbalancers:write', 'microsoftnetwork:loadbalancers:delete'], + apis: ['virtualMachines:listAll', 'networkInterfaces:listAll', 'networkSecurityGroups:listAll', 'virtualNetworks:listAll'], + realtime_triggers: ['microsoftcompute:virtualmachines:write', 'microsoftnetwork:networkinterfaces:write', 'microsoftcompute:virtualmachines:delete', 'microsoftnetwork:networkinterfaces:delete', 'microsoftnetwork:networksecuritygroups:write','microsoftnetwork:networksecuritygroups:delete', 'microsoftnetwork:virtualnetworks:write','microsoftnetwork:virtualnetworks:delete'], run: function(cache, settings, callback) { var results = []; @@ -58,7 +58,6 @@ module.exports = { virtualMachines.data.forEach(virtualMachine => { let vm_interfaces = []; let securityGroups = []; - let loadBalancers = []; if (virtualMachine.networkProfile && virtualMachine.networkProfile.networkInterfaces && virtualMachine.networkProfile.networkInterfaces.length > 0) { let interfaceIDs = virtualMachine.networkProfile.networkInterfaces.map(nic => nic.id); @@ -84,41 +83,8 @@ module.exports = { } securityGroups = networkSecurityGroups.data.filter(nsg => securityGroupIDs.includes(nsg.id)); } - - // get load balancers - for (let nic of vm_interfaces) { - if (nic.ipConfigurations && nic.ipConfigurations.length) { - nic.ipConfigurations.map(ipConfig => { - if (ipConfig.properties) { - if (ipConfig.properties.loadBalancerInboundNatRules && ipConfig.properties.loadBalancerInboundNatRules.length) { - ipConfig.properties.loadBalancerInboundNatRules.forEach(rule => { - let id = rule.id; - let match = id.match(/\/subscriptions\/.+?(?=\/inboundNatRules)/); - - if (match && match[0]) { - if (!loadBalancers.includes(match[0])) { - loadBalancers.push(match[0]); - } - } - }); - } - if (ipConfig.properties.loadBalancerBackendAddressPools && ipConfig.properties.loadBalancerBackendAddressPools.length) { - ipConfig.properties.loadBalancerBackendAddressPools.forEach(pool => { - let id = pool.id; - let match = id.match(/\/subscriptions\/.+?(?=\/backendAddressPools)/); - if (match && match[0]) { - if (!loadBalancers.includes(match[0])) { - loadBalancers.push(match[0]); - } - } - }); - } - } - }); - } - } } - let internetExposed = helpers.checkNetworkExposure(cache, source, vm_interfaces, securityGroups, location, results, loadBalancers); + let internetExposed = helpers.checkNetworkExposure(cache, source, vm_interfaces, securityGroups, location, results); if (internetExposed && internetExposed.length) { helpers.addResult(results, 2, `VM is exposed to the internet through ${internetExposed}`, location, virtualMachine.id); } else { diff --git a/plugins/google/compute/instanceNetworkExposure.js b/plugins/google/compute/instanceNetworkExposure.js index 99c8278c52..2c4e350e5c 100644 --- a/plugins/google/compute/instanceNetworkExposure.js +++ b/plugins/google/compute/instanceNetworkExposure.js @@ -2,6 +2,7 @@ var async = require('async'); var helpers = require('../../../helpers/google'); const { instanceGroups, forwardingRules } = require('../../../helpers/google/regions'); + module.exports = { title: 'Network Exposure', category: 'Compute', @@ -11,15 +12,8 @@ module.exports = { more_info: 'Virtual machines exposed to the internet are at a higher risk of unauthorized access, data breaches, and cyberattacks. It’s crucial to limit exposure by securing access through proper configuration of network and firewall rules.', link: 'https://cloud.google.com/firewall/docs/firewalls', recommended_action: 'Secure VM instances by restricting access with properly configured security group and firewall rules.', - apis: ['instanceGroups:aggregatedList', 'compute:list', 'firewalls:list', 'instanceGroups:listInstances', 'urlMaps:list', 'targetHttpProxies:list', 'targetHttpsProxies:list', - 'forwardingRules:list', 'backendServices:list' - ], - realtime_triggers: ['compute.instances.insert', 'compute.instances.delete', 'compute.instances.update', 'compute.firewalls.insert', 'compute.firewalls.delete', 'compute.firewalls.patch', - 'compute.backendServices.insert', 'compute.backendServices.delete', 'compute.backendServices.patch', 'compute.instanceGroups.insert', 'compute.instanceGroups.delete', 'compute.instanceGroups.update', - 'compute.instanceGroups.addInstances', 'compute.instanceGroups.removeInstances', 'compute.urlMaps.insert', 'compute.urlMaps.delete', 'compute.urlMaps.update', 'compute.urlMaps.patch', - 'compute.targetHttpProxies.insert', 'compute.targetHttpProxies.delete', 'compute.targetHttpProxies.patch', 'compute.targetHttpsProxies.insert', 'compute.targetHttpsProxies.delete', 'compute.targetHttpsProxies.patch', - 'compute.forwardingRules.insert', 'compute.forwardingRules.delete', 'compute.forwardingRules.patch' - ], + apis: ['compute:list', 'firewalls:list'], + realtime_triggers: ['compute.instances.insert', 'compute.instances.delete','compute.firewalls.insert', 'compute.firewalls.delete', 'compute.firewalls.patch'], run: function(cache, settings, callback) { var results = []; @@ -89,33 +83,8 @@ module.exports = { return isNetworkMatch && isTagMatch && isServiceAccountMatch; }); - - networks = networks.map(network => network.split('/').pop()); - - // get all instance groups for instance - let instanceGroups = []; - - var instanceList = helpers.addSource(cache, source, - ['instanceGroups','listInstances', 'global']); - - if (instanceList && !instanceList.err && instanceList.data && instanceList.data.length) { - let groups = instanceList.data.filter(list => list.instance === instance.selfLink); - if (groups && groups.length) { - instanceGroups = groups.map(group => group.parent); - } - } - - - let forwardingRules = []; - if (instanceGroups && instanceGroups.length) { - instanceGroups.forEach(instanceGroup => { - let igForwardingRules = helpers.getForwardingRules(cache, source, region, instanceGroup); - forwardingRules = forwardingRules.concat(igForwardingRules); - }) - - } - let internetExposed = helpers.checkNetworkExposure(cache, source, networks, firewallRules, region, results, forwardingRules); + let internetExposed = helpers.checkNetworkExposure(cache, source, networks, firewallRules, region, results); let resource = helpers.createResourceName('instances', instance.name, project, 'zone', zone); @@ -137,5 +106,4 @@ module.exports = { callback(null, results, source); }); } -}; - +}; \ No newline at end of file