diff --git a/apps/dashboard/pom.xml b/apps/dashboard/pom.xml index afcbf4894f..e6b3945585 100644 --- a/apps/dashboard/pom.xml +++ b/apps/dashboard/pom.xml @@ -51,6 +51,21 @@ aws-java-sdk-autoscaling 1.12.405 + + com.amazonaws + aws-java-sdk-ec2 + 1.12.405 + + + com.amazonaws + aws-java-sdk-sts + 1.12.405 + + + com.amazonaws + aws-java-sdk-iam + 1.12.405 + org.apache.struts struts2-core diff --git a/apps/dashboard/src/main/java/com/akto/action/quick_start/QuickStartAction.java b/apps/dashboard/src/main/java/com/akto/action/quick_start/QuickStartAction.java index b8ccb88a14..e89283b49b 100644 --- a/apps/dashboard/src/main/java/com/akto/action/quick_start/QuickStartAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/quick_start/QuickStartAction.java @@ -3,6 +3,7 @@ import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.InetAddress; import java.util.*; import java.util.concurrent.*; @@ -11,11 +12,11 @@ import com.akto.utils.platform.DashboardStackDetails; import com.akto.utils.platform.MirroringStackDetails; import com.akto.utils.cloud.stack.dto.StackState; -import com.amazonaws.services.cloudformation.model.Tag; +import com.amazonaws.services.cloudformation.AmazonCloudFormation; +import com.amazonaws.services.cloudformation.AmazonCloudFormationClientBuilder; +import com.amazonaws.services.cloudformation.model.*; import org.apache.commons.lang3.StringUtils; import org.bson.conversions.Bson; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.akto.action.UserAction; import com.akto.dao.ApiTokensDao; @@ -60,6 +61,28 @@ public class QuickStartAction extends UserAction { private String aktoDashboardStackName; + private DeploymentMethod deploymentMethod; + + private String aktoNLBIp; + private String aktoMongoConn; + + public enum DeploymentMethod { + AWS_TRAFFIC_MIRRORING, + KUBERNETES; + + public DeploymentMethod getDeploymentMethod(String deploymentMethod) { + if (StringUtils.isEmpty(deploymentMethod)) { + return AWS_TRAFFIC_MIRRORING; + } + for (DeploymentMethod method : DeploymentMethod.values()) { + if (method.name().equalsIgnoreCase(deploymentMethod)) { + return method; + } + } + return null; + } + } + private static final LoggerMaker loggerMaker = new LoggerMaker(QuickStartAction.class); @@ -87,6 +110,9 @@ public String fetchQuickStartPageState() { } public String fetchLoadBalancers() { + if(deploymentMethod != null && deploymentMethod.equals(DeploymentMethod.KUBERNETES)) { + return handleKubernetes(); + } List availableLBs = new ArrayList<>(); List selectedLBs = new ArrayList<>(); ExecutorService executorService = Executors.newFixedThreadPool(3); @@ -135,6 +161,52 @@ public String fetchLoadBalancers() { return Action.SUCCESS.toUpperCase(); } + private String handleKubernetes(){ + try { + DescribeStackResourcesRequest req = new DescribeStackResourcesRequest(); + req.setStackName(MirroringStackDetails.getStackName()); + req.setLogicalResourceId(MirroringStackDetails.AKTO_NLB); + AmazonCloudFormation cloudFormation = AmazonCloudFormationClientBuilder.standard() + .build(); + cloudFormation.describeStackResources(req); + this.dashboardHasNecessaryRole = true; + } catch (Exception e){ // TODO: Handle specific exception + if(e.getMessage().contains("not authorized")){ + this.dashboardHasNecessaryRole = false; + } else{ + this.dashboardHasNecessaryRole = true; + } + } + this.awsRegion = System.getenv(Constants.AWS_REGION); + this.awsAccountId = System.getenv(Constants.AWS_ACCOUNT_ID); + this.aktoMirroringStackName = MirroringStackDetails.getStackName(); + this.aktoDashboardStackName = DashboardStackDetails.getStackName(); + this.aktoDashboardRoleName = DashboardStackDetails.getAktoDashboardRole(); + + return Action.SUCCESS.toUpperCase(); + } + + public String createKubernetesStack(){ + if (!AwsStack.getInstance().checkIfStackExists(MirroringStackDetails.getStackName())) { + try { + Map parameters = new HashMap<>(); + parameters.put("MongoIp", System.getenv("AKTO_MONGO_CONN")); + parameters.put("KeyPair", System.getenv("EC2_KEY_PAIR")); + parameters.put("SubnetId", System.getenv("EC2_SUBNET_ID")); + String template = convertStreamToString(AwsStack.class + .getResourceAsStream("/cloud_formation_templates/kubernetes_mirroring.template")); + List tags = Utils.fetchTags(DashboardStackDetails.getStackName()); + String stackId = AwsStack.getInstance().createStack(MirroringStackDetails.getStackName(), parameters, template, tags); + loggerMaker.infoAndAddToDb(String.format("Stack %s creation started successfully", stackId), LogDb.DASHBOARD); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + throw new RuntimeException("Akto mirroring setup is complete!!"); + } + return Action.SUCCESS.toUpperCase(); + } + private String filterLBName(String lbArn) { if(StringUtils.isEmpty(lbArn)){ return ""; @@ -215,6 +287,12 @@ public String checkStackCreationProgress() { loggerMaker.infoAndAddToDb("Nothing set in DB, moving on", LogDb.DASHBOARD); } } + if(DeploymentMethod.KUBERNETES.equals(this.deploymentMethod) && Stack.StackStatus.CREATE_COMPLETE.toString().equals(this.stackState.getStatus())){ + loggerMaker.infoAndAddToDb("Stack creation complete, fetching outputs", LogDb.DASHBOARD); + Map outputsMap = Utils.fetchOutputs(MirroringStackDetails.getStackName()); + this.aktoNLBIp = outputsMap.get("AktoNLB"); + this.aktoMongoConn = System.getenv("AKTO_MONGO_CONN"); + } return Action.SUCCESS.toUpperCase(); } @@ -342,4 +420,28 @@ private static String convertStreamToString(InputStream in) throws Exception { in.close(); return stringbuilder.toString(); } + + public DeploymentMethod getDeploymentMethod() { + return deploymentMethod; + } + + public void setDeploymentMethod(DeploymentMethod deploymentMethod) { + this.deploymentMethod = deploymentMethod; + } + + public String getAktoNLBIp() { + return aktoNLBIp; + } + + public void setAktoNLBIp(String aktoNLBIp) { + this.aktoNLBIp = aktoNLBIp; + } + + public String getAktoMongoConn() { + return aktoMongoConn; + } + + public void setAktoMongoConn(String aktoMongoConn) { + this.aktoMongoConn = aktoMongoConn; + } } \ No newline at end of file diff --git a/apps/dashboard/src/main/java/com/akto/utils/cloud/Utils.java b/apps/dashboard/src/main/java/com/akto/utils/cloud/Utils.java index 45e8ef4d35..194d662e08 100644 --- a/apps/dashboard/src/main/java/com/akto/utils/cloud/Utils.java +++ b/apps/dashboard/src/main/java/com/akto/utils/cloud/Utils.java @@ -2,13 +2,13 @@ import com.amazonaws.services.cloudformation.AmazonCloudFormation; import com.amazonaws.services.cloudformation.AmazonCloudFormationClientBuilder; -import com.amazonaws.services.cloudformation.model.DescribeStacksRequest; -import com.amazonaws.services.cloudformation.model.DescribeStacksResult; -import com.amazonaws.services.cloudformation.model.Tag; +import com.amazonaws.services.cloudformation.model.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; public class Utils { @@ -21,13 +21,23 @@ public static CloudType getCloudType() { } public static List fetchTags(String stackName){ + Stack stack = fetchStack(stackName); + return stack.getTags(); + } + + private static Stack fetchStack(String stackName) { DescribeStacksRequest describeStackRequest = new DescribeStacksRequest(); describeStackRequest.setStackName(stackName); AmazonCloudFormation cloudFormation = AmazonCloudFormationClientBuilder.standard() .build(); DescribeStacksResult result = cloudFormation.describeStacks(describeStackRequest); - com.amazonaws.services.cloudformation.model.Stack stack = result.getStacks().get(0); - return stack.getTags(); + Stack stack = result.getStacks().get(0); + return stack; + } + + public static Map fetchOutputs(String stackName){ + Stack stack = fetchStack(stackName); + return stack.getOutputs().stream().collect(Collectors.toMap(Output::getOutputKey, Output::getOutputValue)); } } diff --git a/apps/dashboard/src/main/resources/cloud_formation_templates/kubernetes_mirroring.template b/apps/dashboard/src/main/resources/cloud_formation_templates/kubernetes_mirroring.template new file mode 100644 index 0000000000..2ba227a628 --- /dev/null +++ b/apps/dashboard/src/main/resources/cloud_formation_templates/kubernetes_mirroring.template @@ -0,0 +1,808 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "This template does a simple setup for all Akto modules. It sets up all modules on a single instance. If you want a scalable and flexible setup, please contact support@akto.io.", + "Parameters": { + "SubnetId": { + "Type": "AWS::EC2::Subnet::Id" + }, + "KeyPair": { + "Type": "AWS::EC2::KeyPair::KeyName" + }, + "MongoIp": { + "Type": "String" + } + }, + "Mappings": { + "RegionMap": { + "af-south-1": { + "AMI": "ami-0adee70ff4394e3d5" + }, + "eu-north-1": { + "AMI": "ami-04e8b0e36ed3403dc" + }, + "ap-south-1": { + "AMI": "ami-09de362f44ba0a166" + }, + "eu-west-3": { + "AMI": "ami-0614433a16ab15878" + }, + "eu-west-2": { + "AMI": "ami-030770b178fa9d374" + }, + "eu-south-1": { + "AMI": "ami-0432f14b68c3e0273" + }, + "eu-west-1": { + "AMI": "ami-0bba0a4cb75835f71" + }, + "ap-northeast-3": { + "AMI": "ami-0253beba286f3e848" + }, + "ap-northeast-2": { + "AMI": "ami-0e1d09d8b7c751816" + }, + "me-south-1": { + "AMI": "ami-07a68e42e669daed0" + }, + "ap-northeast-1": { + "AMI": "ami-06ce6680729711877" + }, + "sa-east-1": { + "AMI": "ami-0656df2cc0dfd150a" + }, + "ca-central-1": { + "AMI": "ami-04c12937e87474def" + }, + "ap-east-1": { + "AMI": "ami-0b751f901b93720a5" + }, + "ap-southeast-1": { + "AMI": "ami-0adf622550366ea53" + }, + "ap-southeast-2": { + "AMI": "ami-03b836d87d294e89e" + }, + "eu-central-1": { + "AMI": "ami-094c442a8e9a67935" + }, + "ap-southeast-3": { + "AMI": "ami-0483d92a8124da6c9" + }, + "us-east-1": { + "AMI": "ami-065efef2c739d613b" + }, + "us-east-2": { + "AMI": "ami-07251f912d2a831a3" + }, + "us-west-1": { + "AMI": "ami-09b2f6d85764ec71b" + }, + "us-west-2": { + "AMI": "ami-0d08ef957f0e4722b" + } + } + }, + "Resources": { + "GetAktoSetupDetailsLambdaBasicExecutionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + }, + "Action": "sts:AssumeRole" + } + ] + }, + "Path": "/", + "Policies": [ + { + "PolicyName": "GetAktoSetupDetailsExecuteLambda", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeTrafficMirrorSessions", + "ec2:DescribeInstances", + "ec2:DescribeVpcs", + "elasticloadbalancing:DescribeLoadBalancers", + "elasticloadbalancing:DescribeTargetGroups", + "elasticloadbalancing:DescribeTargetHealth" + ], + "Resource": "*" + } + ] + } + } + ] + } + }, + "GetAktoSetupDetails": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Runtime": "nodejs12.x", + "Timeout": 60, + "Role": { + "Fn::GetAtt": [ + "GetAktoSetupDetailsLambdaBasicExecutionRole", + "Arn" + ] + }, + "Handler": "index.handler", + "Environment": { + "Variables": { + "TARGET_LB": { + "Ref": "AktoNLB" + } + } + }, + "Code": { + "S3Bucket": { + "Fn::Sub": "akto-setup-${AWS::Region}" + }, + "S3Key": "templates/get-akto-setup-details.zip" + } + } + }, + "GetVpcDetailsLambdaRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + }, + "Action": [ + "sts:AssumeRole" + ] + } + ] + }, + "Path": "/", + "Policies": [ + { + "PolicyName": "DescribeAssetsPolicy", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:DescribeVpcs", + "ec2:DescribeSubnets" + ], + "Resource": "*" + } + ] + } + } + ] + } + }, + "GetVpcDetailsLambda": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Description": "Look up info from a VPC", + "Handler": "index.handler", + "Runtime": "nodejs12.x", + "Timeout": 30, + "Role": { + "Fn::GetAtt": [ + "GetVpcDetailsLambdaRole", + "Arn" + ] + }, + "Environment": { + "Variables": { + "SUBNET_ID": { + "Ref": "SubnetId" + } + } + }, + "Code": { + "ZipFile": "var SUBNET_ID = process.env.SUBNET_ID; var aws = require('aws-sdk'); var response = require('cfn-response'); var ec2 = new aws.EC2(); exports.handler = async function(event, context) {\n if (event.RequestType == 'Delete') {\n await response.send(event, context, 'SUCCESS');\n return;\n }\n var params = {\n SubnetIds: [SUBNET_ID] \n };\n var subnets = await ec2.describeSubnets(params).promise().catch(err => {\n console.error(err);\n });\n var vpcId = subnets['Subnets'][0]['VpcId'];\n var vpcs = await ec2.describeVpcs({VpcIds: [vpcId]}).promise().catch(err => {\n console.error(err);\n });\n await response.send(event, context, 'SUCCESS', {CidrBlock: vpcs['Vpcs'][0]['CidrBlock'], VpcId: vpcId})\n};\n" + } + } + }, + "CustomSourceGetVpcDetails": { + "Type": "AWS::CloudFormation::CustomResource", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "GetVpcDetailsLambda", + "Arn" + ] + } + } + }, + "IamInstanceProfile": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Path": "/", + "Roles": [ + { + "Ref": "RefreshHandlerLambdaBasicExecutionRole" + } + ] + } + }, + "AktoContextAnalyzerSecurityGroup": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "VpcId": { + "Fn::GetAtt": [ + "CustomSourceGetVpcDetails", + "VpcId" + ] + }, + "GroupDescription": "Enable the ports Akto requires (22, 9092)", + "SecurityGroupIngress": [ + { + "IpProtocol": "tcp", + "FromPort": 22, + "ToPort": 22, + "CidrIp": { + "Fn::GetAtt": [ + "CustomSourceGetVpcDetails", + "CidrBlock" + ] + } + }, + { + "IpProtocol": "tcp", + "FromPort": 9092, + "ToPort": 9092, + "CidrIp": { + "Fn::GetAtt": [ + "CustomSourceGetVpcDetails", + "CidrBlock" + ] + } + } + ], + "SecurityGroupEgress": [] + } + }, + "AktoContextAnalyzerASGLaunchConfiguration": { + "Type": "AWS::AutoScaling::LaunchConfiguration", + "Properties": { + "ImageId": { + "Fn::FindInMap": [ + "RegionMap", + { + "Ref": "AWS::Region" + }, + "AMI" + ] + }, + "InstanceType": "m5a.xlarge", + "KeyName": { + "Ref": "KeyPair" + }, + "AssociatePublicIpAddress": "false", + "SecurityGroups": [ + { + "Ref": "AktoContextAnalyzerSecurityGroup" + } + ], + "BlockDeviceMappings": [ + { + "DeviceName": "/dev/xvda", + "Ebs": { + "VolumeType": "gp2", + "DeleteOnTermination": "true", + "VolumeSize": "50", + "Encrypted": true + } + } + ], + "MetadataOptions": { + "HttpTokens": "required" + }, + "UserData": { + "Fn::Base64": { + "Fn::Join": [ + "\n", + [ + "#!/bin/bash -xe", + { + "Fn::Sub": "export AKTO_MONGO_CONN='${MongoIp}'" + }, + "touch /tmp/hello.txt", + "touch ~/hello.txt", + "sudo yum update -y", + "sudo yum install -y python python-setuptools", + "sudo yum install -y docker", + "sudo dockerd&", + "sudo mkdir -p /opt/aws/bin", + "export COMPOSE_FILE=docker-compose-context-analyser.yml", + "sudo wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz", + "sudo python -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-latest.tar.gz", + "curl -fsSL 'https://raw.githubusercontent.com/akto-api-security/infra/feature/segregation_2/cf-deploy-akto' > cf-deploy-akto", + "sudo chmod 700 cf-deploy-akto", + "./cf-deploy-akto < <(echo 'test')", + "sudo echo >> ~/akto/infra/docker-context-analyser.env", + "sudo echo AKTO_MONGO_CONN=$AKTO_MONGO_CONN >> ~/akto/infra/docker-context-analyser.env", + "export TOKEN=$(curl -X PUT 'http://169.254.169.254/latest/api/token' -H 'X-aws-ec2-metadata-token-ttl-seconds: 600')", + { + "Fn::Join": [ + ":", + [ + "export AKTO_CURRENT_INSTANCE_IP=$(curl -H \"X-aws-ec2-metadata-token", + "$TOKEN\" -v http://169.254.169.254/latest/meta-data/local-ipv4)" + ] + ] + }, + "echo AKTO_CURRENT_INSTANCE_IP=$AKTO_CURRENT_INSTANCE_IP >> ~/akto/infra/docker-context-analyser.env", + "curl -fsSL 'https://raw.githubusercontent.com/akto-api-security/infra/feature/segregation_2/cf-deploy-akto-start' > cf-deploy-akto-start", + "sudo chmod 700 cf-deploy-akto-start", + "./cf-deploy-akto-start < <(echo 'test')" + ] + ] + } + } + } + }, + "AktoContextAnalyzerAutoScalingGroup": { + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Properties": { + "LaunchConfigurationName": { + "Ref": "AktoContextAnalyzerASGLaunchConfiguration" + }, + "VPCZoneIdentifier": [ + { + "Ref": "SubnetId" + } + ], + "MaxSize": "1", + "MinSize": "1" + } + }, + "AktoContextAnalyzerInstanceRefreshHandler": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Runtime": "nodejs12.x", + "Timeout": 30, + "Role": { + "Fn::GetAtt": [ + "InstanceRefreshHandlerLambdaRole", + "Arn" + ] + }, + "Code": { + "ZipFile": "var aws = require('aws-sdk'); var autoscaling = new aws.AutoScaling(); exports.handler = function(event, context) {\n var params = {\n AutoScalingGroupName: 'AktoContextAnalyzerAutoScalingGroup', \n Preferences: {\n InstanceWarmup: 200, \n MinHealthyPercentage: 0\n }\n };\n \n autoscaling.startInstanceRefresh(params, function(err, data) {\n if(err) { console.log(err) }\n else { console.log(data) }\n })\n}; \n" + } + } + }, + "RefreshHandlerLambdaBasicExecutionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": "ec2.amazonaws.com" + }, + "Action": "sts:AssumeRole" + } + ] + }, + "Policies": [ + { + "PolicyName": "InvokeLambdaPolicy", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "DashboardInstanceRefreshHandler", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "TrafficMirroringInstanceRefreshHandler", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "AktoContextAnalyzerInstanceRefreshHandler", + "Arn" + ] + } + ], + "Action": "lambda:InvokeFunction" + } + ] + } + } + ] + } + }, + "AktoSecurityGroup": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "VpcId": { + "Fn::GetAtt": [ + "CustomSourceGetVpcDetails", + "VpcId" + ] + }, + "GroupDescription": "Enable the ports Akto requires (22, 4789, 8000, 9092)", + "SecurityGroupIngress": [ + { + "IpProtocol": "tcp", + "FromPort": 22, + "ToPort": 22, + "CidrIp": { + "Fn::GetAtt": [ + "CustomSourceGetVpcDetails", + "CidrBlock" + ] + } + }, + { + "IpProtocol": "tcp", + "FromPort": 9092, + "ToPort": 9092, + "CidrIp": { + "Fn::GetAtt": [ + "CustomSourceGetVpcDetails", + "CidrBlock" + ] + } + }, + { + "IpProtocol": "udp", + "FromPort": 4789, + "ToPort": 4789, + "CidrIp": { + "Fn::GetAtt": [ + "CustomSourceGetVpcDetails", + "CidrBlock" + ] + } + }, + { + "IpProtocol": "tcp", + "FromPort": 8000, + "ToPort": 8000, + "CidrIp": { + "Fn::GetAtt": [ + "CustomSourceGetVpcDetails", + "CidrBlock" + ] + } + } + ], + "SecurityGroupEgress": [] + } + }, + "AktoASGLaunchConfiguration": { + "Type": "AWS::AutoScaling::LaunchConfiguration", + "DependsOn": [ + "AktoNLB" + ], + "Properties": { + "ImageId": { + "Fn::FindInMap": [ + "RegionMap", + { + "Ref": "AWS::Region" + }, + "AMI" + ] + }, + "InstanceType": "m5a.xlarge", + "KeyName": { + "Ref": "KeyPair" + }, + "AssociatePublicIpAddress": "false", + "IamInstanceProfile": { + "Ref": "IamInstanceProfile" + }, + "SecurityGroups": [ + { + "Ref": "AktoSecurityGroup" + } + ], + "BlockDeviceMappings": [ + { + "DeviceName": "/dev/xvda", + "Ebs": { + "VolumeType": "gp2", + "DeleteOnTermination": "true", + "VolumeSize": "50", + "Encrypted": true + } + } + ], + "MetadataOptions": { + "HttpTokens": "required" + }, + "UserData": { + "Fn::Base64": { + "Fn::Join": [ + "\n", + [ + "#!/bin/bash -xe", + { + "Fn::Sub": "export AKTO_MONGO_CONN='${MongoIp}'" + }, + { + "Fn::Sub": "export AKTO_KAFKA_IP='${AktoNLB.DNSName}'" + }, + "touch /tmp/hello.txt", + "touch ~/hello.txt", + "sudo yum update -y", + "sudo yum install -y python python-setuptools", + "sudo yum install -y docker", + "sudo dockerd&", + "sudo mkdir -p /opt/aws/bin", + "export COMPOSE_FILE=docker-compose-runtime.yml", + "sudo wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz", + "sudo python -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-latest.tar.gz", + "curl -fsSL 'https://raw.githubusercontent.com/akto-api-security/infra/feature/segregation_2/cf-deploy-akto' > cf-deploy-akto", + "sudo chmod 700 cf-deploy-akto", + "./cf-deploy-akto < <(echo 'test')", + "sudo echo >> ~/akto/infra/docker-runtime.env", + "sudo echo AKTO_MONGO_CONN=$AKTO_MONGO_CONN >> ~/akto/infra/docker-runtime.env", + "sudo echo AKTO_KAFKA_IP=$AKTO_KAFKA_IP >> ~/akto/infra/.env", + "curl -fsSL 'https://raw.githubusercontent.com/akto-api-security/infra/feature/segregation_2/cf-deploy-akto-start' > cf-deploy-akto-start", + "sudo chmod 700 cf-deploy-akto-start", + "./cf-deploy-akto-start < <(echo 'test')" + ] + ] + } + } + } + }, + "AktoAutoScalingGroup": { + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Properties": { + "LaunchConfigurationName": { + "Ref": "AktoASGLaunchConfiguration" + }, + "VPCZoneIdentifier": [ + { + "Ref": "SubnetId" + } + ], + "TargetGroupARNs": [ + { + "Ref": "AktoTrafficMirroringTargetGroup" + }, + { + "Ref": "AktoKafkaTargetGroup" + } + ], + "MaxSize": "10", + "MinSize": "1" + } + }, + "AktoTargetTrackingNetworkPolicy": { + "Type": "AWS::AutoScaling::ScalingPolicy", + "Properties": { + "PolicyType": "TargetTrackingScaling", + "AutoScalingGroupName": { + "Ref": "AktoAutoScalingGroup" + }, + "EstimatedInstanceWarmup": 30, + "TargetTrackingConfiguration": { + "PredefinedMetricSpecification": { + "PredefinedMetricType": "ASGAverageNetworkIn" + }, + "TargetValue": 200000000 + } + } + }, + "AktoNLB": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "Type": "network", + "Scheme": "internal", + "IpAddressType": "ipv4", + "Subnets": [ + { + "Ref": "SubnetId" + } + ], + "LoadBalancerAttributes": [ + { + "Key": "load_balancing.cross_zone.enabled", + "Value": "true" + } + ] + } + }, + "AktoTrafficMirroringTargetGroup": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": "4789", + "Protocol": "UDP", + "HealthCheckEnabled": "true", + "HealthCheckIntervalSeconds": 10, + "HealthCheckPath": "/metrics", + "HealthCheckPort": "8000", + "HealthCheckProtocol": "HTTP", + "HealthCheckTimeoutSeconds": 6, + "HealthyThresholdCount": 2, + "UnhealthyThresholdCount": 2, + "TargetType": "instance", + "VpcId": { + "Fn::GetAtt": [ + "CustomSourceGetVpcDetails", + "VpcId" + ] + }, + "Targets": [] + } + }, + "AktoKafkaTargetGroup": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": "9092", + "Protocol": "TCP", + "TargetType": "instance", + "HealthCheckEnabled": "true", + "HealthCheckIntervalSeconds": 10, + "HealthCheckPath": "/metrics", + "HealthCheckPort": "8000", + "HealthCheckProtocol": "HTTP", + "HealthCheckTimeoutSeconds": 6, + "HealthyThresholdCount": 2, + "UnhealthyThresholdCount": 2, + "VpcId": { + "Fn::GetAtt": [ + "CustomSourceGetVpcDetails", + "VpcId" + ] + }, + "Targets": [] + } + }, + "AktoKafkaListener": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "LoadBalancerArn": { + "Ref": "AktoNLB" + }, + "Port": "9092", + "Protocol": "TCP", + "DefaultActions": [ + { + "Type": "forward", + "TargetGroupArn": { + "Ref": "AktoKafkaTargetGroup" + } + } + ] + } + }, + "DashboardInstanceRefreshHandler": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Runtime": "nodejs12.x", + "Timeout": 30, + "Role": { + "Fn::GetAtt": [ + "InstanceRefreshHandlerLambdaRole", + "Arn" + ] + }, + "Code": { + "ZipFile": "var aws = require('aws-sdk'); var autoscaling = new aws.AutoScaling(); exports.handler = function(event, context) {\n var params = {\n AutoScalingGroupName: 'AktoDashboardAutoScalingGroup', \n Preferences: {\n InstanceWarmup: 200, \n MinHealthyPercentage: 0\n }\n };\n \n autoscaling.startInstanceRefresh(params, function(err, data) {\n if(err) { console.log(err) }\n else { console.log(data) }\n })\n};\n" + } + } + }, + "TrafficMirroringInstanceRefreshHandler": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Runtime": "nodejs12.x", + "Timeout": 30, + "Role": { + "Fn::GetAtt": [ + "InstanceRefreshHandlerLambdaRole", + "Arn" + ] + }, + "Code": { + "ZipFile": "var aws = require('aws-sdk'); var autoscaling = new aws.AutoScaling(); exports.handler = function(event, context) {\n var params = {\n AutoScalingGroupName: 'AktoAutoScalingGroup', \n Preferences: {\n InstanceWarmup: 200, \n MinHealthyPercentage: 0\n }\n };\n \n autoscaling.startInstanceRefresh(params, function(err, data) {\n if(err) { console.log(err) }\n else { console.log(data) }\n })\n};\n" + } + } + }, + "InstanceRefreshHandlerLambdaRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + }, + "Action": [ + "sts:AssumeRole" + ] + } + ] + }, + "Path": "/service-role/", + "Policies": [ + { + "PolicyName": "lambdaExecution-DashboardInstanceRefreshHandler", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "logs:CreateLogGroup" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "autoscaling:StartInstanceRefresh", + "autoscaling:Describe*", + "autoscaling:UpdateAutoScalingGroup", + "ec2:CreateLaunchTemplateVersion", + "ec2:DescribeLaunchTemplates", + "ec2:RunInstances" + ], + "Resource": "*" + } + ] + } + } + ] + } + } + }, + "Outputs": { + "AktoNLB": { + "Description": "The IP address of the AktoNLB", + "Value": { + "Fn::GetAtt": [ + "AktoNLB", + "DNSName" + ] + }, + "Export": { + "Name": "AktoNLBIP" + } + } + } +} \ No newline at end of file diff --git a/apps/dashboard/src/main/resources/struts.xml b/apps/dashboard/src/main/resources/struts.xml index c8f10a52fb..ea80a53678 100644 --- a/apps/dashboard/src/main/resources/struts.xml +++ b/apps/dashboard/src/main/resources/struts.xml @@ -1488,6 +1488,17 @@ + + + + + + 422 + false + ^actionErrors.* + + + diff --git a/apps/dashboard/web/src/apps/dashboard/shared/icons/k8s.vue b/apps/dashboard/web/src/apps/dashboard/shared/icons/k8s.vue new file mode 100644 index 0000000000..16cb9b2487 --- /dev/null +++ b/apps/dashboard/web/src/apps/dashboard/shared/icons/k8s.vue @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/apps/dashboard/web/src/apps/dashboard/views/quickstart/api.js b/apps/dashboard/web/src/apps/dashboard/views/quickstart/api.js index 0426630eb5..7dfd6af664 100644 --- a/apps/dashboard/web/src/apps/dashboard/views/quickstart/api.js +++ b/apps/dashboard/web/src/apps/dashboard/views/quickstart/api.js @@ -37,11 +37,11 @@ export default{ return resp }) }, - fetchLBs(){ + fetchLBs(data){ return request({ url: '/api/fetchLoadBalancers', method: 'post', - data: {} + data: data }) }, saveLBs(selectedLBs){ @@ -51,11 +51,11 @@ export default{ data: {selectedLBs} }) }, - fetchStackCreationStatus(){ + fetchStackCreationStatus(data){ return request({ url: 'api/checkStackCreationProgress', method: 'post', - data: {} + data }) }, getPostmanCredentials() { @@ -112,5 +112,14 @@ export default{ }).then((resp) => { return resp }) + }, + createKubernetesStack() { + return request({ + url: '/api/createKubernetesStack', + method: 'post', + data: {} + }).then((resp) => { + return resp + }) } } \ No newline at end of file diff --git a/apps/dashboard/web/src/apps/dashboard/views/quickstart/components/DataSourcesContent.vue b/apps/dashboard/web/src/apps/dashboard/views/quickstart/components/DataSourcesContent.vue index e35efc6733..2ff9b54f16 100644 --- a/apps/dashboard/web/src/apps/dashboard/views/quickstart/components/DataSourcesContent.vue +++ b/apps/dashboard/web/src/apps/dashboard/views/quickstart/components/DataSourcesContent.vue @@ -21,6 +21,7 @@ + + + diff --git a/apps/dashboard/web/src/apps/dashboard/views/quickstart/components/LoadBalancers.vue b/apps/dashboard/web/src/apps/dashboard/views/quickstart/components/LoadBalancers.vue index 56e8fd6157..9e0aa27a9b 100644 --- a/apps/dashboard/web/src/apps/dashboard/views/quickstart/components/LoadBalancers.vue +++ b/apps/dashboard/web/src/apps/dashboard/views/quickstart/components/LoadBalancers.vue @@ -373,6 +373,7 @@ export default { ], aktoDashboardRoleName: null, isLocalDeploy: false, + deploymentMethod: "AWS_TRAFFIC_MIRRORING" } }, mounted() { @@ -387,7 +388,7 @@ export default { this.loading = false; this.isLocalDeploy = true; } else { - api.fetchLBs().then((resp) => { + api.fetchLBs({deploymentMethod: this.deploymentMethod}).then((resp) => { if (!resp.dashboardHasNecessaryRole) { for (let i = 0; i < this.quick_start_policy_lines.length; i++) { let line = this.quick_start_policy_lines[i]; @@ -434,7 +435,7 @@ export default { checkStackState() { let intervalId = null; intervalId = setInterval(async () => { - api.fetchStackCreationStatus().then((resp) => { + api.fetchStackCreationStatus({deploymentMethod: this.deploymentMethod}).then((resp) => { if (this.initialCall) { this.initialCall = false; this.loading = false; diff --git a/apps/dashboard/web/src/plugins/vuetify.js b/apps/dashboard/web/src/plugins/vuetify.js index 898d04dfe8..d11e3e0920 100644 --- a/apps/dashboard/web/src/plugins/vuetify.js +++ b/apps/dashboard/web/src/plugins/vuetify.js @@ -11,6 +11,7 @@ import GithubIcon from "../apps/dashboard/shared/icons/GithubIcon" import Postman from "../apps/dashboard/shared/icons/Postman" import AWS from "../apps/dashboard/shared/icons/AWS" import GCP from "../apps/dashboard/shared/icons/GCP" +import k8s from '../apps/dashboard/shared/icons/k8s' import Swagger from "../apps/dashboard/shared/icons/Swagger" import Restapi from "../apps/dashboard/shared/icons/Restapi" import CustomWebhooks from "../apps/dashboard/shared/icons/CustomWebhooks" @@ -222,6 +223,10 @@ faIconsOpts.aws = { component: AWS } +faIconsOpts.k8s = { + component: k8s +} + faIconsOpts.swagger = { component: Swagger }