/** * Gets the port range for the TCP and UDP protocols defined in the given network * ACL entry. If the range contains {@code -1}, it indicates all ports. * * @param aclEntry the given network ACL entry * @return the port range that this network ACL entry applies to */ @VisibleForTesting static Range<Integer> getPortRangeFromAclEntry(NetworkAclEntry aclEntry) { PortRange portRange = aclEntry.getPortRange(); Range<Integer> ports = null; if (portRange != null) { if (portRange.getFrom() != null && portRange.getTo() != null) { ports = Range.closed(portRange.getFrom(), portRange.getTo()); } else { if (portRange.getFrom() != null) { ports = Range.singleton(portRange.getFrom()); } else if (portRange.getTo() != null) { ports = Range.singleton(portRange.getTo()); } } } return ports; }
private void visitNetworkAcl(VPCDiagramBuilder vpcDiagramBuilder, NetworkAcl acl) throws CfnAssistException { vpcDiagramBuilder.addAcl(acl); String networkAclId = acl.getNetworkAclId(); logger.debug("visit acl " + networkAclId); for(NetworkAclAssociation assoc : acl.getAssociations()) { String subnetId = assoc.getSubnetId(); vpcDiagramBuilder.associateAclWithSubnet(acl, subnetId); for(NetworkAclEntry entry : acl.getEntries()) { if (entry.getEgress()) { vpcDiagramBuilder.addACLOutbound(networkAclId, entry, subnetId); } else { vpcDiagramBuilder.addACLInbound(networkAclId, entry, subnetId); } } } }
/** * Checks network ACL entries against pre-defined network rules. * * Because network ACLs define both allow rules and deny rules, we need check * the enforcements and violations for both allow and deny rules. * * @param networkAclId the network ACL ID * @param sortedEntries the sorted list of network ACL entries * @param direction the network traffic direction * @param accumulator the exception condition accumulator * @param localizationContext the localization context */ private void checkRulesForNetworkAclEntries(String networkAclId, Iterable<NetworkAclEntry> sortedEntries, Direction direction, PluginExceptionConditionAccumulator accumulator, LocalizationContext localizationContext) { Iterable<NetworkRule> rules = networkRules.getRules(direction); if (Iterables.isEmpty(rules)) { return; } List<NetworkRule> pendingRules = Lists.newArrayList(rules); Multimap<String, NetworkRule> violatedRules = HashMultimap.create(); for (NetworkAclEntry aclEntry : sortedEntries) { String cidr = getCidrFromAclEntry(aclEntry); if (cidr != null) { final List<String> ipRanges = ImmutableList.of(cidr); final String protocol = aclEntry.getProtocol(); final Range<Integer> ports = getPortRangeFromAclEntry(aclEntry); final AccessType accessType = AccessType.valueOf(aclEntry.getRuleAction().toUpperCase(localizationContext.getLocale())); Iterator<NetworkRule> ruleIt = pendingRules.iterator(); while (ruleIt.hasNext()) { NetworkRule rule = ruleIt.next(); if (rule.isEnforced(protocol, ports, ipRanges, accessType)) { ruleIt.remove(); } else if (rule.isViolated(protocol, ports, ipRanges, accessType)) { violatedRules.put(networkAclId, rule); ruleIt.remove(); } } } } recordNotEnforcedRules(pendingRules, direction, accumulator, localizationContext, INVALID_ENFORCEMENT_NETWORK_ACL, SUBNET_ID); recordViolatedRules(violatedRules, direction, accumulator, localizationContext, INVALID_VIOLATION_NETWORK_ACL, SUBNET_ID); }
/** * Gets the IP ranges defined in the given network ACL entry. * * @param aclEntry the given network ACL entry * @return the IP range that the network ACL entry applies to */ @VisibleForTesting static String getCidrFromAclEntry(NetworkAclEntry aclEntry) { String ipv4Cidr = aclEntry.getCidrBlock(); if (!Strings.isNullOrEmpty(ipv4Cidr)) { return ipv4Cidr; } else { String ipv6Cidr = aclEntry.getIpv6CidrBlock(); if (!Strings.isNullOrEmpty(ipv6Cidr)) { return ipv6Cidr; } } return null; }
public void addACLOutbound(String aclId, NetworkAclEntry entry, String subnetId) throws CfnAssistException { String cidrUniqueId = createCidrUniqueId("out", aclId, entry); String labelForEdge = labelFromEntry(entry); securityDiagram.addCidr(cidrUniqueId, getLabelFromCidr(entry)); if (entry.getRuleAction().equals(RuleAction.Allow.toString())) { securityDiagram.addConnectionFromSubDiagram(cidrUniqueId, subnetId, subnetDiagramBuilders.get(subnetId), labelForEdge); } else { securityDiagram.addBlockedConnectionFromSubDiagram(cidrUniqueId, subnetId, subnetDiagramBuilders.get(subnetId), labelForEdge); } }
public void addACLInbound(String aclId, NetworkAclEntry entry, String subnetId) throws CfnAssistException { String cidrUniqueId = createCidrUniqueId("in", aclId, entry); String labelForEdge = labelFromEntry(entry); securityDiagram.addCidr(cidrUniqueId, getLabelFromCidr(entry)); // associate subnet with port range and port range with cidr if (entry.getRuleAction().equals(RuleAction.Allow.toString())) { securityDiagram.addConnectionToSubDiagram(cidrUniqueId, subnetId, subnetDiagramBuilders.get(subnetId), labelForEdge); } else { securityDiagram.addBlockedConnectionToSubDiagram(cidrUniqueId, subnetId, subnetDiagramBuilders.get(subnetId), labelForEdge); } }
private String getRuleName(NetworkAclEntry entry) { Integer number = entry.getRuleNumber(); if (number==32767) { return "default"; } return number.toString(); }
private String getRangeFrom(NetworkAclEntry entry) { PortRange portRange = entry.getPortRange(); if (portRange==null) { return("all"); } if (portRange.getFrom().toString().equals(portRange.getTo().toString())) { return String.format("%s", portRange.getFrom()); } return String.format("%s-%s", portRange.getFrom(), portRange.getTo()); }
private String getProtoFrom(NetworkAclEntry entry) { Integer protoNum = Integer.parseInt(entry.getProtocol()); switch(protoNum) { case -1: return "all"; case 1: return "icmp"; case 6: return "tcp"; case 17: return "udp"; } return protoNum.toString(); }
private String getLabelFromCidr(NetworkAclEntry entry) { String cidrBlock = entry.getCidrBlock(); if (cidrBlock.equals("0.0.0.0/0")) { return CIDR_ANY; } return cidrBlock; }
@Override public int compare(NetworkAclEntry entry1, NetworkAclEntry entry2) { return entry1.getRuleNumber().compareTo(entry2.getRuleNumber()); }
/** * Validates the network ACL against the pre-defined network rules. * * <p> * For more information about network ACLs, see <a * href="http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_ACLs.html">Network ACLs</a> in the <i>Amazon * Virtual Private Cloud User Guide</i>. * </p> * * @param client the EC2 client * @param configuration the configuration to be validated * @param accumulator the exception condition accumulator * @param localizationContext the localization context */ private void checkNetworkACL(AmazonEC2Client client, Configured configuration, PluginExceptionConditionAccumulator accumulator, LocalizationContext localizationContext) { String subnetId = configuration.getConfigurationValue(SUBNET_ID, localizationContext); DescribeNetworkAclsResult aclResult; LOG.info(">> Describing network ACL associated with subnet '{}'", subnetId); try { aclResult = client.describeNetworkAcls( new DescribeNetworkAclsRequest().withFilters( new Filter().withName("association.subnet-id").withValues(subnetId) ) ); } catch (AmazonServiceException e) { // Due to backward compatibility, we cannot mandate the IAM permssion: // ec2:DescribeNetworkAcls in customers' accounts and have to fail the // above AWS call gracefully, which means the NetworkACL validation is // optional now. // We have logged a ticket, https://jira.cloudera.com/browse/CLOUD-5345, // to track it, and will make this validation mandatory later. LOG.warn("Failed to retrieve the network ACL for subnet: " + subnetId, e); LOG.warn("Skipping network ACL validation"); return; } List<NetworkAcl> aclList = aclResult.getNetworkAcls(); // Each subnet must be associated with one and only one network ACL. if (aclList.isEmpty()) { LOG.error(String.format(EMPTY_NETWORK_ACL, subnetId)); addError(accumulator, SUBNET_ID, localizationContext, null, EMPTY_NETWORK_ACL, subnetId); return; } if (aclList.size() > 1) { List<String> aclIds = FluentIterable.from(aclList) .transform(new Function<NetworkAcl, String>() { @Override public String apply(NetworkAcl input) { return input.getNetworkAclId(); } }) .toList(); LOG.error(String.format(MORE_THAN_ONE_NETWORK_ACL, aclIds, subnetId)); addError(accumulator, SUBNET_ID, localizationContext, null, MORE_THAN_ONE_NETWORK_ACL, aclIds, subnetId); return; } NetworkAcl networkAcl = aclList.get(0); for (final Direction direction : Direction.values()) { Iterable<NetworkAclEntry> aclEntries = FluentIterable.from(networkAcl.getEntries()) .filter(new Predicate<NetworkAclEntry>() { @Override public boolean apply(NetworkAclEntry aclEntry) { return direction == Direction.INBOUND ? !aclEntry.isEgress() : aclEntry.isEgress(); } }) .toSortedList(new NetworkAclEntryComparator()); checkRulesForNetworkAclEntries(networkAcl.getNetworkAclId(), aclEntries, direction, accumulator, localizationContext); } }
@Override public List<NetworkAclEntry> getEntries() { return (List<NetworkAclEntry>) resource.getAttribute("Entries"); }
private String labelFromEntry(NetworkAclEntry entry) { String proto = getProtoFrom(entry); String range = getRangeFrom(entry); return String.format("%s:[%s]\n(rule:%s)",proto, range, getRuleName(entry)); }
private String createCidrUniqueId(String direction, String aclId, NetworkAclEntry entry) { String uniqueId = String.format("%s_%s_%s", direction, entry.getCidrBlock(), aclId); return uniqueId; }
@Test public void shouldWalkVPCAndAddItemsForDiagram() throws CfnAssistException { Vpc vpc = vpcBuilder.setFacadeVisitExpections(awsFacade); String instanceSubnetId = vpcBuilder.getSubnetId(); Subnet instanceSubnet = vpcBuilder.getSubnet(); String dbSubnetId = vpcBuilder.getDbSubnetId(); Subnet dbSubnet = vpcBuilder.getDbSubnet(); Address eip = vpcBuilder.getEip(); LoadBalancerDescription elb = vpcBuilder.getElb(); DBInstance dbInstance = vpcBuilder.getDbInstance(); Instance instance = vpcBuilder.getInstance(); String instanceId = instance.getInstanceId(); RouteTable routeTable = vpcBuilder.getRouteTable(); NetworkAcl acl = vpcBuilder.getAcl(); NetworkAclEntry outboundEntry = vpcBuilder.getOutboundEntry(); NetworkAclEntry inboundEntry = vpcBuilder.getInboundEntry(); SecurityGroup instanceSecurityGroup = vpcBuilder.getInstanceSecurityGroup(); IpPermission instanceIpPermsInbound = vpcBuilder.getInstanceIpPermsInbound(); IpPermission instanceIpPermsOutbound = vpcBuilder.getInstanceIpPermsOutbound(); SecurityGroup dbSecurityGroup = vpcBuilder.getDBSecurityGroup(); IpPermission dbIpPermsInbound = vpcBuilder.getDbIpPermsInbound(); IpPermission dbIpPermsOutbound = vpcBuilder.getDbIpPermsOutbound(); SecurityGroup elbSecurityGroup = vpcBuilder.getElbSecurityGroup(); EasyMock.expect(diagramFactory.createVPCDiagramBuilder(vpc)).andReturn(vpcDiagramBuilder); EasyMock.expect(diagramFactory.createSubnetDiagramBuilder(vpcDiagramBuilder, instanceSubnet)).andReturn(subnetDiagramBuilder); EasyMock.expect(diagramFactory.createSubnetDiagramBuilder(vpcDiagramBuilder, dbSubnet)).andReturn(dbSubnetDiagramBuilder); subnetDiagramBuilder.add(instance); vpcDiagramBuilder.add(instanceSubnetId, subnetDiagramBuilder); vpcDiagramBuilder.add(dbSubnetId, dbSubnetDiagramBuilder); // route table & routes vpcDiagramBuilder.addAsssociatedRouteTable(routeTable, instanceSubnetId); vpcDiagramBuilder.addRoute(routeTable.getRouteTableId(), instanceSubnetId, vpcBuilder.getRouteA()); vpcDiagramBuilder.addRoute(routeTable.getRouteTableId(), instanceSubnetId, vpcBuilder.getRouteB()); vpcDiagramBuilder.addRoute(routeTable.getRouteTableId(), instanceSubnetId, vpcBuilder.getRouteC()); vpcDiagramBuilder.addAsssociatedRouteTable(routeTable, dbSubnetId); vpcDiagramBuilder.addRoute(routeTable.getRouteTableId(), dbSubnetId, vpcBuilder.getRouteA()); vpcDiagramBuilder.addRoute(routeTable.getRouteTableId(), dbSubnetId, vpcBuilder.getRouteB()); vpcDiagramBuilder.addRoute(routeTable.getRouteTableId(), dbSubnetId, vpcBuilder.getRouteC()); // eip vpcDiagramBuilder.addEIP(eip); vpcDiagramBuilder.linkEIPToInstance(eip.getPublicIp(), instanceId); // elb vpcDiagramBuilder.addELB(elb); vpcDiagramBuilder.associateELBToInstance(elb, instanceId); vpcDiagramBuilder.associateELBToSubnet(elb, instanceSubnetId); vpcDiagramBuilder.associateELBToSubnet(elb, dbSubnetId); vpcDiagramBuilder.addSecurityGroup(elbSecurityGroup); vpcDiagramBuilder.associateInstanceWithSecGroup(elb.getDNSName(), elbSecurityGroup); vpcDiagramBuilder.addSecGroupInboundPerms("secElbGroupId", vpcBuilder.getElbIpPermsInbound()); vpcDiagramBuilder.addSecGroupOutboundPerms("secElbGroupId", vpcBuilder.getElbIpPermsOutbound()); // db vpcDiagramBuilder.addDBInstance(dbInstance); vpcDiagramBuilder.associateDBWithSubnet(dbInstance, dbSubnetId); vpcDiagramBuilder.addSecurityGroup(dbSecurityGroup); vpcDiagramBuilder.associateInstanceWithSecGroup(dbInstance.getDBInstanceIdentifier(), dbSecurityGroup); vpcDiagramBuilder.addSecGroupInboundPerms("secDbGroupId",dbIpPermsInbound); vpcDiagramBuilder.addSecGroupOutboundPerms("secDbGroupId",dbIpPermsOutbound); // acl vpcDiagramBuilder.addAcl(acl); vpcDiagramBuilder.associateAclWithSubnet(acl, instanceSubnetId); vpcDiagramBuilder.addACLOutbound("aclId",outboundEntry, instanceSubnetId); vpcDiagramBuilder.addACLInbound("aclId", inboundEntry, instanceSubnetId); // sec group vpcDiagramBuilder.addSecurityGroup(instanceSecurityGroup, instanceSubnetId); vpcDiagramBuilder.associateInstanceWithSecGroup(instanceId, instanceSecurityGroup); vpcDiagramBuilder.addSecGroupInboundPerms("secGroupId",instanceIpPermsInbound, instanceSubnetId); vpcDiagramBuilder.addSecGroupOutboundPerms("secGroupId",instanceIpPermsOutbound, instanceSubnetId); diagramBuilder.add(vpcDiagramBuilder); replayAll(); VPCVisitor visitor = new VPCVisitor(diagramBuilder, awsFacade, diagramFactory); visitor.visit(vpc); verifyAll(); }
/** * Gets the value of the Entries attribute. If this resource is not yet * loaded, a call to {@code load()} is made to retrieve the value of the * attribute. */ List<NetworkAclEntry> getEntries();