Added inbound rule to security group based on the port mappings of a member in the cluster.
Project: http://git-wip-us.apache.org/repos/asf/stratos/repo Commit: http://git-wip-us.apache.org/repos/asf/stratos/commit/cae92c5e Tree: http://git-wip-us.apache.org/repos/asf/stratos/tree/cae92c5e Diff: http://git-wip-us.apache.org/repos/asf/stratos/diff/cae92c5e Branch: refs/heads/gsoc-projects-2015 Commit: cae92c5e53386566dfd933557b6ca7068be2c61f Parents: 1a2097e Author: swapnilpatilRajaram <[email protected]> Authored: Mon Aug 3 14:27:28 2015 +0000 Committer: swapnilpatilRajaram <[email protected]> Committed: Mon Aug 3 14:27:28 2015 +0000 ---------------------------------------------------------------------- .../aws-extension/src/main/conf/aws.properties | 8 +- .../apache/stratos/aws/extension/AWSHelper.java | 159 ++++++++++++++----- .../stratos/aws/extension/AWSLoadBalancer.java | 145 ++++++++++------- .../apache/stratos/aws/extension/Constants.java | 2 + 4 files changed, 219 insertions(+), 95 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/stratos/blob/cae92c5e/extensions/load-balancer/aws-extension/src/main/conf/aws.properties ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/conf/aws.properties b/extensions/load-balancer/aws-extension/src/main/conf/aws.properties index 05ebded..d4cc18a 100644 --- a/extensions/load-balancer/aws-extension/src/main/conf/aws.properties +++ b/extensions/load-balancer/aws-extension/src/main/conf/aws.properties @@ -3,4 +3,10 @@ secret-key= # load-balancer-prefix should contain only alphabets and dashes and should not exceed 25 characters. load-balancer-prefix=LB- # security group will be created if does not exist. Should contain only ASCII characters and should not exceed 255 characters. -load-balancer-security-group-name=lb-security-group \ No newline at end of file +load-balancer-security-group-name=lb-security-group +# CIDR IP which can be set as allowed source IP of incoming requests for security group mentioned in 'load-balancer-security-group-name' +# 0.0.0.0/0 allows all IPs +allowed-cidr-ip=0.0.0.0/0 +# Internet Protocol allowed for incoming requests for security group mentioned in 'load-balancer-security-group-name'. +# Comma separated e.g. tcp,udp +allowed-protocols=tcp http://git-wip-us.apache.org/repos/asf/stratos/blob/cae92c5e/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java index 164625f..b822939 100644 --- a/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java +++ b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java @@ -55,10 +55,13 @@ public class AWSHelper { private String awsAccessKey; private String awsSecretKey; private String lbPrefix; - private AtomicInteger lbSequence; - private String lbSecurityGroupName; private String lbSecurityGroupDescription; + private String allowedCidrIpForLBSecurityGroup; + + private AtomicInteger lbSequence; + + private List<String> allowedProtocolsForLBSecurityGroup; private ConcurrentHashMap<String, String> regionToSecurityGroupIdMap; @@ -114,6 +117,30 @@ public class AWSHelper { "Invalid load balancer security group name."); } + this.allowedCidrIpForLBSecurityGroup = properties + .getProperty(Constants.ALLOWED_CIDR_IP_KEY); + + if (this.allowedCidrIpForLBSecurityGroup.isEmpty()) { + throw new LoadBalancerExtensionException( + "Invalid allowed CIDR IP."); + } + + String allowedProtocols = properties + .getProperty(Constants.ALLOWED_PROTOCOLS); + + if (allowedProtocols.isEmpty()) { + throw new LoadBalancerExtensionException( + "Please specify at least one Internet protocol."); + } + + String[] protocols = allowedProtocols.split(","); + + this.allowedProtocolsForLBSecurityGroup = new ArrayList<String>(); + + for (String protocol : protocols) { + this.allowedProtocolsForLBSecurityGroup.add(protocol); + } + this.lbSecurityGroupDescription = Constants.LOAD_BALANCER_SECURITY_GROUP_DESCRIPTION; regionToSecurityGroupIdMap = new ConcurrentHashMap<String, String>(); @@ -143,6 +170,14 @@ public class AWSHelper { return lbSequence.getAndIncrement(); } + public String getLbSecurityGroupName() { + return lbSecurityGroupName; + } + + public List<String> getAllowedProtocolsForLBSecurityGroup() { + return allowedProtocolsForLBSecurityGroup; + } + /** * Creates a load balancer and returns its DNS name. Useful when a new * cluster is added. @@ -151,7 +186,7 @@ public class AWSHelper { * @param listeners * @param region * @return DNS name of newly created load balancer - * @throws LoadBalancerExtensionException + * @throws LoadBalancerExtensionException */ public String createLoadBalancer(String name, List<Listener> listeners, String region) throws LoadBalancerExtensionException { @@ -185,7 +220,8 @@ public class AWSHelper { return clbResult.getDNSName(); } catch (AmazonClientException e) { - throw new LoadBalancerExtensionException("Could not create load balancer " + name, e); + throw new LoadBalancerExtensionException( + "Could not create load balancer " + name, e); } } @@ -380,10 +416,8 @@ public class AWSHelper { } - public String getSecurityGroupId(String groupName, String region) - { - if(groupName == null || groupName.isEmpty()) - { + public String getSecurityGroupId(String groupName, String region) { + if (groupName == null || groupName.isEmpty()) { return null; } @@ -395,15 +429,16 @@ public class AWSHelper { describeSecurityGroupsRequest.setGroupNames(groupNames); try { - ec2Client.setEndpoint(String.format(Constants.EC2_ENDPOINT_URL_FORMAT, region)); + ec2Client.setEndpoint(String.format( + Constants.EC2_ENDPOINT_URL_FORMAT, region)); DescribeSecurityGroupsResult describeSecurityGroupsResult = ec2Client .describeSecurityGroups(describeSecurityGroupsRequest); - List<SecurityGroup> securityGroups = describeSecurityGroupsResult.getSecurityGroups(); + List<SecurityGroup> securityGroups = describeSecurityGroupsResult + .getSecurityGroups(); - if( securityGroups != null && securityGroups.size() > 0) - { + if (securityGroups != null && securityGroups.size() > 0) { return securityGroups.get(0).getGroupId(); } } catch (AmazonClientException e) { @@ -425,7 +460,8 @@ public class AWSHelper { createSecurityGroupRequest.setDescription(description); try { - ec2Client.setEndpoint(String.format(Constants.EC2_ENDPOINT_URL_FORMAT, region)); + ec2Client.setEndpoint(String.format( + Constants.EC2_ENDPOINT_URL_FORMAT, region)); CreateSecurityGroupResult createSecurityGroupResult = ec2Client .createSecurityGroup(createSecurityGroupRequest); @@ -440,30 +476,85 @@ public class AWSHelper { } - public void addInboundRuleToSecurityGroup(String groupId, String region) - throws LoadBalancerExtensionException { + public void addInboundRuleToSecurityGroup(String groupId, String region, + String protocol, int port) throws LoadBalancerExtensionException { if (groupId == null || groupId.isEmpty()) { throw new LoadBalancerExtensionException( "Invalid security group Id for addInboundRuleToSecurityGroup."); } - AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest = new AuthorizeSecurityGroupIngressRequest(); - authorizeSecurityGroupIngressRequest.setGroupId(groupId); - authorizeSecurityGroupIngressRequest.setCidrIp("0.0.0.0/0"); - authorizeSecurityGroupIngressRequest.setFromPort(0); - authorizeSecurityGroupIngressRequest.setToPort(65535); - authorizeSecurityGroupIngressRequest.setIpProtocol("tcp"); + boolean ruleAlreadyPresent = false; + + DescribeSecurityGroupsRequest describeSecurityGroupsRequest = new DescribeSecurityGroupsRequest(); + + List<String> groupIds = new ArrayList<String>(); + groupIds.add(groupId); + + describeSecurityGroupsRequest.setGroupIds(groupIds); + + SecurityGroup secirutyGroup = null; try { - ec2Client.setEndpoint(String.format(Constants.EC2_ENDPOINT_URL_FORMAT, region)); + ec2Client.setEndpoint(String.format( + Constants.EC2_ENDPOINT_URL_FORMAT, region)); - ec2Client - .authorizeSecurityGroupIngress(authorizeSecurityGroupIngressRequest); + DescribeSecurityGroupsResult describeSecurityGroupsResult = ec2Client + .describeSecurityGroups(describeSecurityGroupsRequest); + + List<SecurityGroup> securityGroups = describeSecurityGroupsResult + .getSecurityGroups(); + if (securityGroups != null && securityGroups.size() > 0) { + secirutyGroup = securityGroups.get(0); + } } catch (AmazonClientException e) { - throw new LoadBalancerExtensionException( - "Could not add inbound rule to security group " + groupId - + "."); + log.debug("Could not describe security groups.", e); + } + + if (secirutyGroup != null) { + List<IpPermission> existingPermissions = secirutyGroup + .getIpPermissions(); + + IpPermission neededPermission = new IpPermission(); + neededPermission.setFromPort(port); + neededPermission.setToPort(port); + neededPermission.setIpProtocol(protocol); + + Collection<String> ipRanges = new HashSet<String>(); + ipRanges.add(this.allowedCidrIpForLBSecurityGroup); + + neededPermission.setIpRanges(ipRanges); + + if (existingPermissions.contains(neededPermission)) { + ruleAlreadyPresent = true; + } + } + + if (!ruleAlreadyPresent) { + AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest = new AuthorizeSecurityGroupIngressRequest(); + authorizeSecurityGroupIngressRequest.setGroupId(groupId); + authorizeSecurityGroupIngressRequest + .setCidrIp(this.allowedCidrIpForLBSecurityGroup); + authorizeSecurityGroupIngressRequest.setFromPort(port); + authorizeSecurityGroupIngressRequest.setToPort(port); + authorizeSecurityGroupIngressRequest.setIpProtocol(protocol); + + try { + ec2Client.setEndpoint(String.format( + Constants.EC2_ENDPOINT_URL_FORMAT, region)); + + ec2Client + .authorizeSecurityGroupIngress(authorizeSecurityGroupIngressRequest); + + } catch (AmazonClientException e) { + + // if(!e.getMessage().contains("already exist")) + // { + throw new LoadBalancerExtensionException( + "Could not add inbound rule to security group " + + groupId + "."); + // } + } } } @@ -476,20 +567,16 @@ public class AWSHelper { return this.regionToSecurityGroupIdMap.get(region); } else { // Get the the security group id if it is already present. - String securityGroupId = getSecurityGroupId(this.lbSecurityGroupName, region); + String securityGroupId = getSecurityGroupId( + this.lbSecurityGroupName, region); - if(securityGroupId == null) - { - securityGroupId = createSecurityGroup( - this.lbSecurityGroupName, this.lbSecurityGroupDescription, - region); + if (securityGroupId == null) { + securityGroupId = createSecurityGroup(this.lbSecurityGroupName, + this.lbSecurityGroupDescription, region); } this.regionToSecurityGroupIdMap.put(region, securityGroupId); - // Also add the inbound rule - addInboundRuleToSecurityGroup(securityGroupId, region); - return securityGroupId; } } http://git-wip-us.apache.org/repos/asf/stratos/blob/cae92c5e/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java index f9e2e32..c3b80c7 100644 --- a/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java +++ b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java @@ -51,10 +51,11 @@ public class AWSLoadBalancer implements LoadBalancer { awsHelper = new AWSHelper(); } - /* - * configure method iterates over topology and configures the AWS load balancers needed. - * Configuration may involve creating a new load balancer for a cluster, updating existing load balancers - * or deleting unwanted load balancers. + /* + * configure method iterates over topology and configures the AWS load + * balancers needed. Configuration may involve creating a new load balancer + * for a cluster, updating existing load balancers or deleting unwanted load + * balancers. */ public boolean configure(Topology topology) throws LoadBalancerExtensionException { @@ -81,7 +82,8 @@ public class AWSLoadBalancer implements LoadBalancer { // 1. Get all the instances attached // Add/remove instances as necessary - // attachedInstances list is useful in finding out what all new instances + // attachedInstances list is useful in finding out what + // all new instances // should be attached to this load balancer. List<Instance> attachedInstances = awsHelper .getAttachedInstances(loadBalancerName, region); @@ -109,7 +111,8 @@ public class AWSLoadBalancer implements LoadBalancer { .getInstanceId())); if (attachedInstances == null - || !attachedInstances.contains(instance)) { + || !attachedInstances + .contains(instance)) { instancesToAddToLoadBalancer.add(instance); } } @@ -129,62 +132,87 @@ public class AWSLoadBalancer implements LoadBalancer { if (clusterMembers.size() > 0) { -// try -// { - // a unique load balancer name with user-defined prefix and a sequence number. - String loadBalancerName = awsHelper - .generateLoadBalancerName(); - - String region = awsHelper.getAWSRegion(clusterMembers - .iterator().next().getInstanceId()); - - // list of AWS listeners obtained using port mappings of one of the members of the cluster. - List<Listener> listenersForThisCluster = awsHelper - .getRequiredListeners(clusterMembers.iterator() - .next()); - - // DNS name of load balancer which was created. - // This is used in the domain mapping of this cluster. - String loadBalancerDNSName = awsHelper - .createLoadBalancer(loadBalancerName, - listenersForThisCluster, region); + // try + // { + // a unique load balancer name with user-defined + // prefix and a sequence number. + String loadBalancerName = awsHelper + .generateLoadBalancerName(); + + String region = awsHelper + .getAWSRegion(clusterMembers.iterator() + .next().getInstanceId()); + + // list of AWS listeners obtained using port + // mappings of one of the members of the cluster. + List<Listener> listenersForThisCluster = awsHelper + .getRequiredListeners(clusterMembers + .iterator().next()); + + // DNS name of load balancer which was created. + // This is used in the domain mapping of this + // cluster. + String loadBalancerDNSName = awsHelper + .createLoadBalancer(loadBalancerName, + listenersForThisCluster, region); + + // Also add the inbound rule + // For each listener, add a new rule with load + // balancer port as allowed protocol. + + for (Listener listener : listenersForThisCluster) { + int port = listener.getLoadBalancerPort(); + + for (String protocol : awsHelper + .getAllowedProtocolsForLBSecurityGroup()) { + awsHelper + .addInboundRuleToSecurityGroup( + awsHelper + .getSecurityGroupId( + awsHelper + .getLbSecurityGroupName(), + region), + region, protocol, port); + } + } - log.info("Load balancer '" + loadBalancerDNSName - + "' created for cluster '" - + cluster.getClusterId()); + log.info("Load balancer '" + loadBalancerDNSName + + "' created for cluster '" + + cluster.getClusterId()); - // register instances to LB - List<Instance> instances = new ArrayList<Instance>(); + // register instances to LB + List<Instance> instances = new ArrayList<Instance>(); - for (Member member : clusterMembers) { - String instanceId = member.getInstanceId(); + for (Member member : clusterMembers) { + String instanceId = member.getInstanceId(); - log.debug("Instance id : " - + awsHelper.getAWSInstanceName(instanceId)); + log.debug("Instance id : " + + awsHelper + .getAWSInstanceName(instanceId)); - Instance instance = new Instance(); - instance.setInstanceId(awsHelper - .getAWSInstanceName(instanceId)); + Instance instance = new Instance(); + instance.setInstanceId(awsHelper + .getAWSInstanceName(instanceId)); - instances.add(instance); - } + instances.add(instance); + } - awsHelper.registerInstancesToLoadBalancer( - loadBalancerName, instances, region); + awsHelper.registerInstancesToLoadBalancer( + loadBalancerName, instances, region); - // Create domain mappings + // Create domain mappings - LoadBalancerInfo loadBalancerInfo = new LoadBalancerInfo( - loadBalancerName, region); + LoadBalancerInfo loadBalancerInfo = new LoadBalancerInfo( + loadBalancerName, region); - clusterIdToLoadBalancerMap.put(cluster.getClusterId(), - loadBalancerInfo); - activeClusters.add(cluster.getClusterId()); -// } -// catch(LoadBalancerExtensionException e) -// { -// log.debug(e); -// } + clusterIdToLoadBalancerMap.put( + cluster.getClusterId(), loadBalancerInfo); + activeClusters.add(cluster.getClusterId()); + // } + // catch(LoadBalancerExtensionException e) + // { + // log.debug(e); + // } } } } @@ -213,8 +241,8 @@ public class AWSLoadBalancer implements LoadBalancer { } /* - * start method is called after extension if configured first time. - * Does nothing but logs the message. + * start method is called after extension if configured first time. Does + * nothing but logs the message. */ public void start() throws LoadBalancerExtensionException { @@ -222,8 +250,8 @@ public class AWSLoadBalancer implements LoadBalancer { } /* - * reload method is called every time after extension if configured. - * Does nothing but logs the message. + * reload method is called every time after extension if configured. Does + * nothing but logs the message. */ public void reload() throws LoadBalancerExtensionException { // Check what is appropriate to do here. @@ -247,8 +275,9 @@ public class AWSLoadBalancer implements LoadBalancer { } /** - * Used to store load balancer name and the region in which it is created. - * This helps in finding region while calling API methods to modify/delete a load balancer. + * Used to store load balancer name and the region in which it is created. This + * helps in finding region while calling API methods to modify/delete a load + * balancer. */ class LoadBalancerInfo { private String name; http://git-wip-us.apache.org/repos/asf/stratos/blob/cae92c5e/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java ---------------------------------------------------------------------- diff --git a/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java index ea6a359..0792e00 100644 --- a/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java +++ b/extensions/load-balancer/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java @@ -37,6 +37,8 @@ public class Constants { public static final String LOAD_BALANCER_SECURITY_GROUP_DESCRIPTION = "Security group for load balancers created for Apache Stratos."; public static final String ELB_ENDPOINT_URL_FORMAT = "elasticloadbalancing.%s.amazonaws.com"; public static final String EC2_ENDPOINT_URL_FORMAT = "ec2.%s.amazonaws.com"; + public static final String ALLOWED_CIDR_IP_KEY = "allowed-cidr-ip"; + public static final String ALLOWED_PROTOCOLS = "allowed-protocols"; public static final int LOAD_BALANCER_NAME_MAX_LENGTH = 32; public static final int LOAD_BALANCER_PREFIX_MAX_LENGTH = 25; public static final int SECURITY_GROUP_NAME_MAX_LENGTH = 255;
