├── AWS_Control_Tower_vSRX └── README.md ├── CLI_tool ├── README ├── README.md ├── awscli_sample.sh ├── clean.sh ├── cloudwatch.py ├── deploy.py ├── ecs_test.py ├── elb.py ├── images.py ├── junos_config.py ├── launch.sh ├── launch_vsrx_dnat_web_ecs.sh ├── log.txt ├── monitor.py ├── scaleout.py ├── stats.py ├── success_logs.txt ├── syncaddr.py ├── test.py ├── troubleshoot.py ├── util.py ├── vpc.py ├── vsrx-aws └── wait.py ├── IPSec-HA ├── AWS_IPSec_Redundancy.jpg ├── AWS_IPSec_Redundancy.pptx ├── README.md ├── routeChange.py └── vsrx-configs │ ├── vsrx0.conf │ ├── vsrx1.conf │ └── vsrx2.conf ├── LICENSE ├── README.md ├── SRX-GD-Threatfeed ├── LICENSE ├── NOTICE ├── README.md ├── SRX-GD-Threatfeed.zip ├── cc_schema ├── gd_threatfeed │ ├── __init__.py │ ├── config.py │ ├── constants.py │ ├── errors.py │ ├── feed_utils.py │ ├── openapi_client.py │ ├── s3_utils.py │ └── utils.py ├── lambda_function.py ├── manifest.xml ├── requirements.txt └── setup.py ├── TGW-Transit-VPC ├── Juniper vSRX TGW.pptx ├── Readme.md ├── bogus.template ├── lambda.template ├── main.tf ├── tvpc │ ├── README.md │ ├── compute.tf │ ├── eni.tf │ ├── lambda.tf │ ├── sg.tf │ ├── spoke.tf │ ├── tgw.tf │ ├── variables.tf │ └── vpc.tf └── vsrx3-init4.tpl ├── Transit-VPC ├── LICENSE.txt ├── Readme.md ├── multi-account-deployment │ ├── Readme.md │ └── transit-vpc-second-account.template ├── transit-vpc-poller.py ├── transit-vpc-primary-account.legacy.template ├── transit-vpc-primary-account.template └── transit-vpc-push-juniper-config.py ├── vSRX └── vsrx.template ├── vSRX_AWS_GWLB ├── README.md ├── vsrx_cft │ ├── vsrx_aws_gwlb_asg_az │ │ ├── README.md │ │ ├── vsrx_aws_gwlb_app_asg_az.yaml │ │ ├── vsrx_aws_gwlb_asg_az.png │ │ └── vsrx_aws_gwlb_security_asg_az.yaml │ ├── vsrx_aws_gwlb_asg_az_ns_ew │ │ ├── README.md │ │ ├── vsrx_aws_gwlb_app_asg_az_ns_ew.yaml │ │ ├── vsrx_aws_gwlb_security_asg_az_ns_ew.png │ │ └── vsrx_aws_gwlb_security_asg_az_ns_ew.yaml │ ├── vsrx_aws_gwlb_asg_no_az │ │ ├── README.md │ │ ├── vsrx_aws_gwlb_app_asg_no_az.yaml │ │ ├── vsrx_aws_gwlb_asg_no_az.png │ │ └── vsrx_aws_gwlb_security_asg_no_az.yaml │ ├── vsrx_aws_gwlb_no_asg_az │ │ ├── README.md │ │ ├── vsrx_aws_gwlb_app_no_asg_az.yaml │ │ ├── vsrx_aws_gwlb_no_asg_az.png │ │ └── vsrx_aws_gwlb_security_no_asg_az.yaml │ ├── vsrx_aws_gwlb_no_asg_az_ns_ew │ │ ├── README.md │ │ ├── vsrx_aws_gwlb_app_no_asg_az_ns_ew.yaml │ │ ├── vsrx_aws_gwlb_security_no_asg_az_ns_ew.png │ │ └── vsrx_aws_gwlb_security_no_asg_az_ns_ew.yaml │ └── vsrx_aws_gwlb_no_asg_no_az │ │ ├── README.md │ │ ├── vsrx_aws_gwlb_app_no_asg_no_az.yaml │ │ ├── vsrx_aws_gwlb_security_no_asg_no_az.png │ │ └── vsrx_aws_gwlb_security_no_asg_no_az.yaml ├── vsrx_lambda.zip └── vsrx_tf │ ├── vsrx_aws_gwlb_asg_az_ns_ew │ ├── app_scripts │ │ ├── terraform.tfvars │ │ ├── variables.tf │ │ └── vsrx_aws_gwlb_application_asg_az_ns_ew.tf │ └── security_scripts │ │ ├── inlineud.txt │ │ ├── terraform.tfvars │ │ ├── user-data │ │ ├── variables.tf │ │ ├── versions.tf │ │ └── vsrx_aws_gwlb_security_asg_az_ns_ew.tf │ ├── vsrx_aws_gwlb_asg_no_az │ ├── app_scripts │ │ ├── terraform.tfvars │ │ ├── variables.tf │ │ └── vsrx_aws_gwlb_application_asg_no_az.tf │ └── security_scripts │ │ ├── outputs.tf │ │ ├── terraform.tfvars │ │ ├── user-data │ │ ├── variables.tf │ │ └── vsrx_aws_gwlb_security_asg_no_az.tf │ ├── vsrx_aws_gwlb_no_asg_az_ns_ew │ ├── app_scripts │ │ ├── terraform.tfvars │ │ ├── variables.tf │ │ └── vsrx_aws_gwlb_application_no_asg_az_ns_ew.tf │ └── security_scripts │ │ ├── inlineud.txt │ │ ├── terraform.tfvars │ │ ├── user-data │ │ ├── variables.tf │ │ ├── versions.tf │ │ └── vsrx_aws_gwlb_security_no_asg_az_ns_ew.tf │ └── vsrx_aws_gwlb_no_asg_no_az │ ├── app_scripts │ ├── terraform.tfvars │ ├── variables.tf │ └── vsrx_aws_gwlb_application_no_asg_no_az.tf │ └── security_scripts │ ├── outputs.tf │ ├── terraform.tfvars │ ├── user-data │ ├── variables.tf │ └── vsrx_aws_gwlb_security_no_asg_no_az.tf └── vSRX_w_ELB ├── ELB_ASG_CFT_Guide.docx ├── README.md ├── add_eni.py └── vsrx.template /AWS_Control_Tower_vSRX/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | [ AWS_Control_Tower_vSRX repository ](https://github.com/MarkSnyderJNPR/AWS_Control_Tower_vSRX)
5 | 6 | 7 | -------------------------------------------------------------------------------- /CLI_tool/README: -------------------------------------------------------------------------------- 1 | About the CLI tool: 2 | ------------------- 3 | 4 | The tool vsrx-aws aims to be a single CLI option to deploy 5 | 6 | 7 | PREREQUISITE 8 | -------------- 9 | 10 | 1. Install python packages: click boto3 pyyaml tabulate 11 | # sudo pip install click boto3 pyyaml tabulate 12 | 13 | 2. Install docker engine 14 | https://docs.docker.com/install/ 15 | 16 | 3. Activate SAML credentials. For more info on SAML: 17 | https://aws.amazon.com/identity/saml/ 18 | 19 | For Juniper SSO based SAML tokens: 20 | https://it-gitlab.junipercloud.net/cloud-platform/aws-samlapi 21 | 22 | 23 | INSTALLATION STEPS 24 | ------------------ 25 | 26 | Unzip all the contents of the file. If all the packages listed above have been installed, then: 27 | 28 | #./vsrx-aws 29 | Usage: vsrx-aws [OPTIONS] COMMAND [ARGS]... 30 | 31 | vsrx-aws is an orchestration tool for automated provisioning, scaling and 32 | management of vSRX in AWS 33 | 34 | Options: 35 | --help Show this message and exit. 36 | 37 | Commands: 38 | deploy Launch a vSRX instance 39 | images List vSRX images in AWS marketplace 40 | junos-config Load Junos configuration file to vSRX instances 41 | scaleout Scale out performance with vSRX cluster and AWS ELB 42 | stats Display resource usage statistics of running vSRX instances 43 | vpc-create Create a new VPC 44 | vpc-show Show VPC parameters 45 | wait Wait vSRX fpc online 46 | 47 | An example command to create a VPC, subnets, route-tables and deploy a vSRX instance with DestNAT is in the file "launch_vsrx_dnat_web_ecs.sh". 48 | 49 | Edit the file to update the Key filenames before you execute the shell script. 50 | 51 | 52 | -------------------------------------------------------------------------------- /CLI_tool/README.md: -------------------------------------------------------------------------------- 1 | About the CLI tool: 2 | ------------------- 3 | 4 | The tool vsrx-aws aims to be a simple CLI option to deploy the vSRX and other supported solutions such as ELB on AWS. 5 | 6 | The tool is in its Beta stage and there is no planned effort to address any issues that may be reported. 7 | 8 | 9 | PREREQUISITE 10 | -------------- 11 | 12 | 1. Install python packages: click boto3 pyyaml tabulate 13 | #sudo pip install click boto3 pyyaml tabulate 14 | 15 | 2. Install docker engine 16 | https://docs.docker.com/install/ 17 | 18 | 3. Activate SAML credentials. For more info on SAML: 19 | https://aws.amazon.com/identity/saml/ 20 | 21 | For Juniper SSO based SAML tokens: 22 | https://it-gitlab.junipercloud.net/cloud-platform/aws-samlapi 23 | 24 | (OR) 25 | 26 | if you have an indvidual account, you need to execute these after installing aws-cli: 27 | 28 | #aws configure # you will need to provide your access-key ID and secret-access-key as inputs; set the region and leave the format to json 29 | #aws sts get-session-token –duration-seconds 64000 #enter the duration you want to retain the tokens for 30 | 31 | Once done, you will get an output such as: 32 | 33 | $ aws sts get-session-token --duration-seconds 6000 34 | { 35 | "Credentials": { 36 | "AccessKeyId": "AAAAAAH6ET44444444WG", 37 | "SecretAccessKey": "mcem+B111111111111111111n7VjgitGi+jHefo", 38 | "SessionToken": "FwoGZXIvYXdzEHIaDHKLw97y4O99UYO85yKBAasdfasdfasdfc69X8y2NUTwPeOElwwCA6dS2+PGjeinVdibTGWE9ON9PAUqb3scUg5YJ74DO8766rpiCRtClDV1Kf7I0NQPQQK3gAvHcVejp6wrQddGgrQfbX0xzPJLAEqbNh8mAtYZKWQhnq5w36L4AtG/NqTkmrTG9TXHkkSji2JXxBTIoU1jeIRXeHFFlRAT08yCzu7kUUsfGf4aXcF14/vjjkuI/oHaUy6cfpQ==", 39 | "Expiration": "2020-01-20T10:41:22Z" 40 | } 41 | } 42 | 43 | Next, you will need to edit ~/.aws/credentials and enter it in the below format: 44 | 45 | [profile_name] 46 | aws_access_key_id = AAAAAAH6ET44444444WG 47 | aws_secret_access_key = mcem+B1111111111111111n7VjgitGi+jHefo 48 | aws_session_token = FwoGZXIvYXdzEHIaDHKLw97y4O99UYO85yKBAasdfasdfasdfc69X8y2NUTwPeOElwwCA6dS2+PGjeinVdibTGWE9ON9PAUqb3scUg5YJ74DO8766rpiCRtClDV1Kf7I0NQPQQK3gAvHcVejp6wrQddGgrQfbX0xzPJLAEqbNh8mAtYZKWQhnq5w36L4AtG/NqTkmrTG9TXHkkSji2JXxBTIoU1jeIRXeHFFlRAT08yCzu7kUUsfGf4aXcF14/vjjkuI/oHaUy6cfpQ== 49 | aws_security_token = FwoGZXIvYXdzEHIaDHKLw97y4O99UYO85yKBAasdfasdfasdfc69X8y2NUTwPeOElwwCA6dS2+PGjeinVdibTGWE9ON9PAUqb3scUg5YJ74DO8766rpiCRtClDV1Kf7I0NQPQQK3gAvHcVejp6wrQddGgrQfbX0xzPJLAEqbNh8mAtYZKWQhnq5w36L4AtG/NqTkmrTG9TXHkkSji2JXxBTIoU1jeIRXeHFFlRAT08yCzu7kUUsfGf4aXcF14/vjjkuI/oHaUy6cfpQ== 50 | 51 | When you execute the shell script or the command to launch vSRX on AWS, remember to set the argument for –profile to “profile_name” from the credentials file. 52 | 53 | 4. You may need to subscribe to the vSRX image at https://aws.amazon.com/marketplace/pp/B01MS9F1O0 for launching the preferred ami-ID 54 | 55 | 56 | INSTALLATION STEPS 57 | ------------------ 58 | 59 | Unzip all the contents of the file. If all the packages listed above have been installed, then: 60 | 61 | #./vsrx-aws 62 | Usage: vsrx-aws [OPTIONS] COMMAND [ARGS]... 63 | 64 | vsrx-aws is an orchestration tool for automated provisioning, scaling and management of vSRX in AWS 65 | 66 | Options: 67 | --help Show this message and exit. 68 | 69 | Commands: 70 | deploy Launch a vSRX instance 71 | images List vSRX images in AWS marketplace 72 | junos-config Load Junos configuration file to vSRX instances 73 | scaleout Scale out performance with vSRX cluster and AWS ELB 74 | stats Display resource usage statistics of running vSRX instances 75 | vpc-create Create a new VPC 76 | vpc-show Show VPC parameters 77 | wait Wait vSRX fpc online 78 | 79 | EXAMPLE 80 | ------- 81 | 82 | Variables to be defined in the .sh file: 83 | 84 | prefix= 'your_name' 85 | KEY_NAME='key1' 86 | KEY_FILE='key1.pem' << 18: 31 | line_widget_x = 0 32 | line_widget_y += 6 33 | metric_names = [] 34 | for metric in metrics: 35 | metric_names.append(metric[1]) 36 | metric_name_str = ','.join(metric_names) 37 | info_msg('Adding line widget for metrics - ' + metric_name_str) 38 | return widget 39 | 40 | def create_or_update_dashboard(session, region, dashboard_name, widgets): 41 | body = {'widgets' : widgets} 42 | body_json = json.dumps(body) 43 | client = session.client("cloudwatch", region_name=region) 44 | response = client.put_dashboard(DashboardName = dashboard_name, 45 | DashboardBody = body_json) 46 | debug_msg('put_dashboard response:' + json.dumps(response)) 47 | 48 | def configure_cloudwatch_dashbord(session, region, instance, metric_ns): 49 | widgets = [] 50 | ge_interface_num = 0 51 | instance_id = instance.instance_id 52 | info_msg('Creating CloudWatch dashboard for instance %s, namespace %s'\ 53 | % (instance_id,metric_ns)) 54 | if len(instance.network_interfaces) > 0: 55 | ge_interface_num = len(instance.network_interfaces) - 1 56 | dataplane_cpu_num = instance.cpu_options['CoreCount'] * \ 57 | instance.cpu_options['ThreadsPerCore'] - 1 58 | recpu_metrics = [[ metric_ns, "RECPUUtil", "Instance ID", instance_id]] 59 | widgets.append(get_line_widget(False, recpu_metrics, region)) 60 | dpcpu_metrics = [] 61 | for cpuno in range(dataplane_cpu_num): 62 | dp_cpuno = cpuno + 1 63 | metric_name = "DataPlaneCPU%dUtil" % dp_cpuno 64 | metric = [metric_ns, metric_name, "Instance ID", instance_id] 65 | dpcpu_metrics.append(metric) 66 | widgets.append(get_line_widget(True, dpcpu_metrics, region)) 67 | 68 | remem_metrics = [[ metric_ns, "REMemoryUtil", "Instance ID", instance_id ]] 69 | widgets.append(get_line_widget(False, remem_metrics, region)) 70 | 71 | dpmem_metrics = [[ metric_ns, "DataplaneHeapMemoryUtil", "Instance ID", instance_id ]] 72 | widgets.append(get_line_widget(False, dpmem_metrics, region)) 73 | 74 | diskutil_metrics = [[ metric_ns, "DiskUtil", "Instance ID", instance_id ]] 75 | widgets.append(get_line_widget(False, diskutil_metrics, region)) 76 | 77 | sessutil_metric = [[ metric_ns, "FlowSessionUtil", "Instance ID", instance_id ]] 78 | widgets.append(get_line_widget(False, sessutil_metric, region)) 79 | 80 | for ge_id in range(ge_interface_num): 81 | gepps_metrics = [] 82 | metric_name = "Ge00%dInputPPS" % ge_id 83 | gepps_metrics.append([metric_ns, metric_name, "Instance ID", instance_id]) 84 | metric_name = "Ge00%dOutputPPS" % ge_id 85 | gepps_metrics.append([metric_ns, metric_name, "Instance ID", instance_id]) 86 | widgets.append(get_line_widget(True, gepps_metrics, region)) 87 | gekbps_metrics = [] 88 | metric_name = "Ge00%dInputKBPS" % ge_id 89 | gekbps_metrics.append([metric_ns, metric_name, "Instance ID", instance_id]) 90 | metric_name = "Ge00%dOutputKBPS" % ge_id 91 | gekbps_metrics.append([metric_ns, metric_name, "Instance ID", instance_id]) 92 | widgets.append(get_line_widget(True, gekbps_metrics, region)) 93 | 94 | dashboard_name = 'vsrx_%s' % instance_id 95 | create_or_update_dashboard(session, region, dashboard_name, widgets) 96 | info_msg("Created CloudWatch dashboard %s" % dashboard_name) 97 | 98 | -------------------------------------------------------------------------------- /CLI_tool/ecs_test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import boto3 4 | 5 | def register_addrsync_task(client, image, name, role_arn, log_group, region): 6 | definition = {} 7 | definition['family'] = 'addrsync-task-definition' 8 | definition['networkMode'] = 'awsvpc' 9 | definition['requiresCompatibilities'] = ['FARGATE'] 10 | definition['cpu'] = '256' 11 | definition['memory'] = '512' 12 | definition['executionRoleArn'] = role_arn 13 | container = {} 14 | container['essential'] = True 15 | container['image'] = image 16 | container['name'] = name 17 | container['logConfiguration'] = { 18 | "logDriver": "awslogs", 19 | "options": { 20 | "awslogs-group" : log_group, 21 | "awslogs-region": region, 22 | "awslogs-stream-prefix": "ecs" 23 | } 24 | } 25 | container['portMappings'] = [ 26 | { 27 | "containerPort": 80, 28 | "hostPort": 80, 29 | "protocol": "tcp" 30 | } 31 | ] 32 | definition['containerDefinitions'] = [container] 33 | response = client.register_task_definition(**definition) 34 | print response 35 | 36 | def run_addrsync_task(client, task_name, vpc_id, groups, 37 | interval, role_arn, subnet, security_group): 38 | task = {} 39 | task['taskDefinition'] = 'addrsync-task-definition' 40 | command = ['ipprobe', '-d', '/var/lib/nginx/html', '-i', str(interval)] 41 | if groups != None: 42 | for sg in groups: 43 | command.append('-g') 44 | command.append(sg) 45 | command.append(vpc_id) 46 | task['overrides'] = { 47 | 'containerOverrides': [{ 48 | 'name': task_name, 49 | 'command': command, 50 | 'cpu': 256, 51 | 'memory':512 52 | }], 53 | 'taskRoleArn': role_arn 54 | } 55 | task['count'] = 1 56 | task['launchType'] = 'FARGATE' 57 | task['networkConfiguration'] = { 58 | 'awsvpcConfiguration': { 59 | 'subnets': [ 60 | subnet 61 | ], 62 | 'securityGroups': [ 63 | security_group 64 | ], 65 | 'assignPublicIp': 'ENABLED' 66 | } 67 | } 68 | response = client.run_task(**task) 69 | print response 70 | 71 | session = boto3.Session(profile_name='saml') 72 | client = session.client('ecs') 73 | """ 74 | register_addrsync_task(client, '.dkr.ecr.us-east-1.amazonaws.com/addrsync:latest', 75 | 'addrsync', '', 76 | 'addrsync', 'us-east-1') 77 | """ 78 | run_addrsync_task(client, 'addrsync', 'vpc-068c35a6409a957eb', 79 | None, 15, '', 80 | 'subnet-0fa27de913ebab9ae', 'sg-067f30261c90c73e4') 81 | 82 | -------------------------------------------------------------------------------- /CLI_tool/elb.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import boto3 4 | import click 5 | import json 6 | import datetime 7 | import time 8 | import traceback 9 | from util import * 10 | from tabulate import tabulate 11 | from botocore.exceptions import ClientError 12 | from botocore.exceptions import NoCredentialsError 13 | 14 | -------------------------------------------------------------------------------- /CLI_tool/images.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import boto3 4 | import click 5 | import json 6 | from operator import attrgetter 7 | from tabulate import tabulate 8 | from dateutil.parser import parse 9 | import datetime 10 | 11 | @click.command() 12 | @click.option('--profile', help='Use a specific profile from credential file') 13 | @click.option('--region', default='us-east-1', help='Specify AWS region', show_default=True) 14 | @click.option('--json', 'json_output', is_flag=True, help='Display with JSON format') 15 | def images(profile, region, json_output): 16 | """List vSRX images in AWS marketplace""" 17 | if profile != None: 18 | session = boto3.Session(profile_name=profile) 19 | else: 20 | session = boto3.Session() 21 | if region != None: 22 | client = session.client('ec2', region_name=region) 23 | else: 24 | client = session.client('ec2') 25 | image_owner = ['aws-marketplace'] 26 | image_filter = [ 27 | { 28 | 'Name':'name', 29 | 'Values':[ 30 | '*vsrx3*' 31 | ] 32 | } 33 | ] 34 | response = client.describe_images(Owners = image_owner, Filters = image_filter) 35 | if 'Images' not in response: 36 | sys.exit('error get vSRX images from AWS marketplace') 37 | images = response['Images'] 38 | images = sorted(images, key=lambda k: k['CreationDate']) 39 | if json_output == True: 40 | print json.dumps(images, indent = 4) 41 | else: 42 | table = [] 43 | table.append(['IMAGE_ID', 'DESCRIPTION', 'CREATION_DATE', 'ARCHITECTURE']) 44 | for image in images: 45 | creation_datetime = parse(image['CreationDate']) 46 | table.append([image['ImageId'], image['Description'], creation_datetime, image['Architecture']]) 47 | print(tabulate(table, headers="firstrow", tablefmt="grid")) 48 | 49 | -------------------------------------------------------------------------------- /CLI_tool/junos_config.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import boto3 4 | import click 5 | import json 6 | import yaml 7 | from util import * 8 | 9 | 10 | def get_instance_var(session, instance_id): 11 | ec2 = session.resource('ec2') 12 | instance = ec2.Instance(instance_id) 13 | instance_var = {} 14 | ge_interfaces = [] 15 | for interface in instance.network_interfaces: 16 | if interface.attachment['DeviceIndex'] != 0: 17 | interface_param = {} 18 | ge_id = interface.attachment['DeviceIndex'] - 1 19 | subnet_gw,mask_len = get_subnet_gateway(session, interface.subnet_id) 20 | interface_param['name'] = 'ge-0/0/%d' % ge_id 21 | interface_param['private_ip_mask'] = "%s/%d" % (interface.private_ip_address, mask_len) 22 | interface_param['private_ip'] = interface.private_ip_address 23 | instance_var['ge_0_0_%d_private_ip' % ge_id] = interface.private_ip_address 24 | if interface.association_attribute != None and \ 25 | 'PublicIp' in interface.association_attribute: 26 | interface_param['public_ip'] = interface.association_attribute['PublicIp'] 27 | instance_var['ge_0_0_%d_public_ip' % ge_id] = interface.association_attribute['PublicIp'] 28 | ge_interfaces.append(interface_param) 29 | instance_var['ge-interfaces'] = ge_interfaces 30 | if instance.public_ip_address != None: 31 | instance_var['public_ip'] = instance.public_ip_address 32 | instance_var['instance_id'] = instance.instance_id 33 | return instance_var 34 | 35 | def config_instance_with_template(instance_var, junos_config_file, key_file, extra_vars): 36 | abs_key_path = os.path.abspath(key_file) 37 | abs_config_file = os.path.abspath(junos_config_file) 38 | if 'public_ip' not in instance_var: 39 | warning_msg('no public IP address on instance %s' % instance_var['instance_id']) 40 | print instance_var 41 | return False 42 | debug_msg('Instance variables:%s' % json.dumps(instance_var)) 43 | instance_id = instance_var['instance_id'] 44 | param_file = '/tmp/%s-var.yml' % instance_id 45 | fxp0_addr = instance_var['public_ip'] 46 | debug_msg(yaml.dump(instance_var, default_flow_style=True)) 47 | with open(param_file, 'w') as outfile: 48 | yaml.dump(instance_var, outfile, default_flow_style=False) 49 | if extra_vars == None: 50 | ansible_cmd = "docker run -it --rm -v \"$(pwd)/ansible/playbook:/playbooks\" -v \"%s:/host-key.pem\" " + \ 51 | "-v %s:/instance_var.yml -v \"%s:/junos.conf.j2\" " + \ 52 | "-e ANSIBLE_NET_SSH_KEYFILE=/host-key.pem juniper/pyez-ansible " + \ 53 | "ansible-playbook --user ec2-user -i %s, configure_junos_j2.yml" 54 | ansible_cmd = ansible_cmd % (abs_key_path, param_file, abs_config_file, fxp0_addr) 55 | else: 56 | ansible_cmd = "docker run -it --rm -v \"$(pwd)/ansible/playbook:/playbooks\" -v \"%s:/host-key.pem\" " + \ 57 | "-v %s:/instance_var.yml -v \"%s:/junos.conf.j2\" " + \ 58 | "-e ANSIBLE_NET_SSH_KEYFILE=/host-key.pem juniper/pyez-ansible " + \ 59 | "ansible-playbook --user ec2-user --extra-vars '%s' -i %s, configure_junos_j2.yml" 60 | ansible_cmd = ansible_cmd % (abs_key_path, param_file, abs_config_file, extra_vars, fxp0_addr) 61 | 62 | info_msg(ansible_cmd) 63 | os.system(ansible_cmd) 64 | 65 | def config_instance(instance_var, junos_config_file, key_file): 66 | abs_key_path = os.path.abspath(key_file) 67 | abs_config_file = os.path.abspath(junos_config_file) 68 | if 'public_ip' not in instance_var: 69 | warning_msg('not public IP address on instance %s' % instance_var['instance_id']) 70 | #print instance_var 71 | return False 72 | fxp0_addr = instance_var['public_ip'] 73 | debug_msg(yaml.dump(instance_var, default_flow_style=True)) 74 | ansible_cmd = "docker run -it --rm -v \"$(pwd)/ansible/playbook:/playbooks\" -v \"%s:/host-key.pem\" " + \ 75 | "-v \"%s:/junos.conf\" " + \ 76 | "-e ANSIBLE_NET_SSH_KEYFILE=/host-key.pem juniper/pyez-ansible " + \ 77 | "ansible-playbook --user ec2-user -i %s, configure_junos.yml" 78 | ansible_cmd = ansible_cmd % (abs_key_path, abs_config_file, fxp0_addr) 79 | info_msg(ansible_cmd) 80 | os.system(ansible_cmd) 81 | 82 | @click.command() 83 | @click.option('--instance-id', multiple=True, help='The ID of instance') 84 | @click.option('--instance-name', multiple=True, help='The Name of instance') 85 | @click.option('--vpc-id', help='VPC in which the instance is running') 86 | @click.option('--jinja2', '-j', is_flag=True, help='Configuration file is a Jinja2 tempate file') 87 | @click.option('--extra-vars', help='Pass extra variables to ansible playbooks') 88 | @click.option('--key-file', prompt='Private key file to access vSRX instance', type=click.Path(), help='Private key file') 89 | @click.option('--verbose', '-v', is_flag=True, help='Enable verbose mode to get more information') 90 | @click.option('--profile', help='Use a specific profile from credential file') 91 | @click.option('--region', default='us-east-1', help='Specify AWS region', show_default=True) 92 | @click.argument('JUNOS-CONFIG-FILE') 93 | def junos_config(junos_config_file, instance_id, instance_name, vpc_id, jinja2, 94 | extra_vars, key_file, verbose, profile, region): 95 | """Load Junos configuration file to vSRX instances""" 96 | if verbose: 97 | enable_verbose_mode() 98 | info_msg('Configuring Junos ...') 99 | if key_file != None and not os.path.isfile(key_file): 100 | error_msg('Key file "%s" does not exist' % key_file) 101 | sys.exit(1) 102 | if not os.path.isfile(junos_config_file): 103 | error_msg('Junos configuration file "%s" does not exist' % junos_config_file) 104 | sys.exit(1) 105 | session = boto3.Session(profile_name=profile, region_name=region) 106 | id_list_by_name = [] 107 | if len(instance_name) > 0: 108 | id_list_by_name = instance_name_to_ids(session, instance_name, vpc_id) 109 | instance_var_index = {} 110 | instance_var_list = [] 111 | for vsrx_instance_id in instance_id: 112 | if instance_id in instance_var_index: 113 | continue 114 | info_msg('Getting instance %s variables' % vsrx_instance_id) 115 | vsrx_var = get_instance_var(session, vsrx_instance_id) 116 | instance_var_list.append(vsrx_var) 117 | instance_var_index[instance_id] = vsrx_var 118 | for vsrx_instance_id in id_list_by_name: 119 | if instance_id in instance_var_index: 120 | continue 121 | info_msg('Getting instance %s variables' % vsrx_instance_id) 122 | vsrx_var = get_instance_var(session, vsrx_instance_id) 123 | instance_var_list.append(vsrx_var) 124 | instance_var_index[instance_id] = vsrx_var 125 | for vsrx_var in instance_var_list: 126 | if jinja2: 127 | config_instance_with_template(vsrx_var, junos_config_file, key_file, extra_vars) 128 | else: 129 | config_instance(vsrx_var, junos_config_file, key_file) 130 | 131 | 132 | -------------------------------------------------------------------------------- /CLI_tool/launch.sh: -------------------------------------------------------------------------------- 1 | 2 | ./vsrx-aws deploy --region us-east-1 \ 3 | --key-name \ 4 | --key-file \ 5 | --vpc-id \ 6 | --nic subnet-name=mgt-01,public-ip=auto \ 7 | --nic subnet-name=gw-01,public-ip=auto \ 8 | --profile default \ 9 | ami-06b424cccf70e6a94 10 | 11 | 12 | -------------------------------------------------------------------------------- /CLI_tool/launch_vsrx_dnat_web_ecs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | 5 | prefix=`whoami` 6 | VPC_NAME="${prefix}-vpc-test1" 7 | # Enter your KEY_NAME 8 | KEY_NAME='' 9 | # Ensure the publickey file downloaded from your AWS account is accessible 10 | KEY_FILE='' 11 | VPC_CIDR='172.31.0.0/16' 12 | SUBNET_MGT="${prefix}-manage-01" 13 | SUBNET_MGT_CIDR='172.31.10.0/24' 14 | SUBNET_WEB="${prefix}-webtier-01" 15 | SUBNET_WEB_CIDR='172.31.20.0/24' 16 | ROUTE_TABLE_WEB="${prefix}-webtier-rtb" 17 | SUBNET_PUBLIC="${prefix}-public-01" 18 | SUBNET_PUBLIC_CIDR='172.31.30.0/24' 19 | ROUTE_TABLE_PUBLIC="${prefix}-public-rtb" 20 | AVAILABILITY_ZONE='us-east-1a' 21 | INSTANCE_NAME="${prefix}-vsrx-test" 22 | IMAGE_ID='ami-0f0442c45665d343a' 23 | # The saml files have to be created for the VPC and other resources to be created in your account 24 | PROFILE_OPTION='--profile saml' 25 | #VERBOSE_OPTION='--verbose' 26 | USE_EXISTING_VPC='--skip-if-exist' 27 | Topology=" 28 | ge-0/0/0 ge-0/0/1 29 | +-----------------+ 30 | nginx(ECS) +-----+ SUBNET_WEB +--------| vSRX |-------+ SUBNET_PUBLIC +--+-- INTERNET 31 | +--------+--------+ | 32 | | fxp0 | 33 | | | 34 | + | 35 | SUBNET_MGT +-----------------------------+ 36 | " 37 | vpc_id_file="/tmp/$$.vpc.id" 38 | ### Creating VPC 39 | ### if a VPC with same name is existing , it will do nothing 40 | ### Create seperated route table for $SUBNET_WEB and $SUBNET_PUBLIC 41 | ./vsrx-aws vpc-create --name "$VPC_NAME" \ 42 | --subnet $SUBNET_MGT_CIDR,name=$SUBNET_MGT,availability_zone=$AVAILABILITY_ZONE \ 43 | --subnet $SUBNET_WEB_CIDR,name=$SUBNET_WEB,availability_zone=$AVAILABILITY_ZONE,route_table=$ROUTE_TABLE_WEB \ 44 | --subnet $SUBNET_PUBLIC_CIDR,name=$SUBNET_PUBLIC,availability_zone=$AVAILABILITY_ZONE,route_table=$ROUTE_TABLE_PUBLIC \ 45 | --save-vpc-id $vpc_id_file \ 46 | $PROFILE_OPTION \ 47 | $VERBOSE_OPTION \ 48 | $USE_EXISTING_VPC \ 49 | "$VPC_CIDR" 50 | 51 | instance_id_file="/tmp/$$.vsrx.id" 52 | ### Launching a vSRX instance into VPC 53 | ### Configure source NAT and policy with Cloud-init (--junos-config-file ) 54 | ### Configure ge-0/0/0 and ge-0/0/1 automatically with the auto-assigned private address (--config-interface) 55 | ### Wait until pic is only , the traffic can be forwarded between ge-0/0/0 and ge-0/0/1 (--wait-pic-online) 56 | ### Save new instance id to file (--save-instance-id "$instance_id_file") 57 | if [ $? -eq 0 ] 58 | then 59 | vpc_id="`cat $vpc_id_file`" 60 | ./vsrx-aws deploy --instance-name "$INSTANCE_NAME" \ 61 | --key-name "$KEY_NAME" \ 62 | --key-file "$KEY_FILE" \ 63 | --vpc-id "$vpc_id" \ 64 | --nic subnet-name=$SUBNET_MGT,public-ip=auto \ 65 | --nic subnet-name=$SUBNET_WEB,subnet-gateway=self \ 66 | --nic subnet-name=$SUBNET_PUBLIC,public-ip=auto \ 67 | --junos-config-file demo/data/init_src_nat.conf \ 68 | --config-interface \ 69 | --wait-fpc-online \ 70 | --save-instance-id "$instance_id_file" \ 71 | $PROFILE_OPTION \ 72 | $VERBOSE_OPTION \ 73 | $IMAGE_ID 74 | fi 75 | 76 | ### Start a nginx server inside the $SUBNET_WEB 77 | ### This needs to permit internet access of $SUBNET_WEB at first 78 | if [ $? -eq 0 ] 79 | then 80 | nginx_private_ip="`./demo/tools/nginx_ecs_run.py --vpc-id "$vpc_id" --subnet-name $SUBNET_WEB $PROFILE_OPTION`" 81 | echo "nginx task private ip address $nginx_private_ip" 82 | fi 83 | 84 | ### Configure vSRX Junos with destination NAT and security policy 85 | ### Using jinja2 template to set external and internal web server address automatically 86 | if [ $? -eq 0 -a ! -z "$nginx_private_ip" ] 87 | then 88 | instance_id="`cat $instance_id_file`" 89 | ./vsrx-aws junos-config --instance-id "$instance_id" \ 90 | --key-file "$KEY_FILE" \ 91 | --jinja2 \ 92 | --extra-vars "web_server_ip=$nginx_private_ip" \ 93 | $PROFILE_OPTION \ 94 | $VERBOSE_OPTION \ 95 | demo/data/dst_nat_config.j2 96 | fi 97 | 98 | -------------------------------------------------------------------------------- /CLI_tool/monitor.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import boto3 4 | import click 5 | 6 | @click.command() 7 | def monitor(): 8 | """Monitor vSRX instance with CloudWatch or other applications""" 9 | pass 10 | 11 | 12 | -------------------------------------------------------------------------------- /CLI_tool/scaleout.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import click 3 | 4 | @click.command() 5 | def scaleout(): 6 | """Scale out performance with vSRX cluster and AWS ELB""" 7 | pass 8 | 9 | 10 | -------------------------------------------------------------------------------- /CLI_tool/syncaddr.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import boto3 4 | import click 5 | 6 | def get_all_security_groups(): 7 | pass 8 | 9 | @click.command() 10 | @click.option('--security-group', '-g', multiple=True, help='The ID of security group') 11 | @click.option('--profile', help='Use a specific profile from credential file') 12 | @click.option('--region', default='us-east-1', help='Specify AWS region', show_default=True) 13 | @click.argument('instance-id') 14 | def syncaddr(instance_id, security_group, profile, region): 15 | """Synchronize vSRX dynamic address from AWS security group""" 16 | session = boto3.Session(profile_name=profile, region_name=region) 17 | client = session.client('ec2') 18 | ec2 = session.resource('ec2') 19 | for group in ec2.security_groups.all(): 20 | print group.id 21 | -------------------------------------------------------------------------------- /CLI_tool/test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import boto3 4 | import json 5 | from util import * 6 | 7 | def vpc_attach_internet_gateway(session, vpc_id): 8 | info_msg('Checking if there is internet gateway in VPC(%s)' % vpc_id) 9 | ec2 = session.resource('ec2') 10 | vpc = ec2.Vpc(vpc_id) 11 | igws = vpc.internet_gateways.all() 12 | for igw in igws: 13 | info_msg('There is already internet gateway attached') 14 | return igw.internet_gateway_id 15 | igw = ec2.create_internet_gateway() 16 | info_msg('Created internet gateway , id = %s' % igw.internet_gateway_id) 17 | vpc.attach_internet_gateway(InternetGatewayId = igw.internet_gateway_id) 18 | info_msg('Attached internet gateway(%s) to VPC(%s)' % \ 19 | (igw.internet_gateway_id, vpc_id)) 20 | return igw.internet_gateway_id 21 | 22 | def get_route_table_by_subnet(session, subnet_id): 23 | client = session.client('ec2') 24 | filters = [ 25 | { 26 | 'Name': 'association.subnet-id', 27 | 'Values': [ 28 | subnet_id 29 | ] 30 | } 31 | ] 32 | response = client.describe_route_tables(Filters = filters) 33 | debug_msg('response describe_route_tables: %s' % json.dumps(response)) 34 | if len(response['RouteTables']) > 0: 35 | return response['RouteTables'][0]['Associations'][0]['RouteTableId'] 36 | else: 37 | debug_msg('No explict associated route table') 38 | subnet = ec2.Subnet(subnet_id) 39 | vpc = ec2.Vpc(subnet.vpc_id) 40 | for rtb in vpc.route_tables.all(): 41 | for assoc in rtb.associations_attribute: 42 | if assoc['Main']: 43 | debug_msg('main route table %s' % rtb.route_table_id) 44 | return rtb.route_table_id 45 | return None 46 | 47 | def create_route(session, rtb_id, cidr, gw_id): 48 | ec2 = session.resource('ec2') 49 | route_table = ec2.RouteTable(rtb_id) 50 | info_msg('Creating route rtb_id %s, CIDR %s, gw_id %s' % (rtb_id, cidr, gw_id)) 51 | route_table.create_route(DestinationCidrBlock=cidr, GatewayId=gw_id) 52 | 53 | enable_verbose_mode() 54 | session = boto3.Session(profile_name='saml') 55 | client = session.client('ec2') 56 | ec2 = session.resource('ec2') 57 | igw_id = vpc_attach_internet_gateway(session, 'vpc-05b2c027f5c52bcb3') 58 | rtb_id = get_route_table_by_subnet(session, 'subnet-0abd82c8743026a36') 59 | create_route(session, rtb_id, '0.0.0.0/0', igw_id) 60 | rtb_id = get_route_table_by_subnet(session, 'subnet-02d25007e2d220ca7') 61 | create_route(session, rtb_id, '0.0.0.0/0', igw_id) 62 | 63 | 64 | -------------------------------------------------------------------------------- /CLI_tool/troubleshoot.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import click 3 | 4 | @click.command() 5 | def troubleshoot(): 6 | """Check vSRX instance status and collect troubleshoot data""" 7 | pass 8 | 9 | 10 | -------------------------------------------------------------------------------- /CLI_tool/vpc.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import boto3 4 | import click 5 | import json 6 | import datetime 7 | import time 8 | import traceback 9 | from util import * 10 | from tabulate import tabulate 11 | from botocore.exceptions import ClientError 12 | from botocore.exceptions import NoCredentialsError 13 | 14 | def get_name_by_tags(tags, max_len): 15 | for tag in tags: 16 | if tag['Key'] == 'Name': 17 | name = tag['Value'] 18 | return name[:max_len] + (name[max_len:] and '..') 19 | return "" 20 | 21 | def show_vpc_parameters(session, id_list, 22 | show_state, show_subnet_name, show_route_table): 23 | ec2 = session.resource('ec2') 24 | table = [] 25 | head_row = ['VPC_ID', 'VPC_NAME', 'CIDR', 'SUBNETS','SEC_GROUPS'] 26 | if show_route_table: 27 | head_row.append('ROUTE_TABLE') 28 | if show_state: 29 | head_row.append('STATE') 30 | table.append(head_row) 31 | for vpc_id in id_list: 32 | try: 33 | vpc = ec2.Vpc(vpc_id) 34 | except: 35 | error_msg(traceback.format_exc()) 36 | sys.exit(1) 37 | vpc_name = get_name_by_tags(vpc.tags, 16) 38 | vpc_cidr = vpc.cidr_block 39 | vpc_state = vpc.state 40 | vpc_subnets = get_vpc_subnets_str(vpc, show_subnet_name) 41 | vpc_groups = get_vpc_group_str(vpc) 42 | row = [vpc_id, vpc_name, vpc_cidr, vpc_subnets, vpc_groups] 43 | if show_route_table: 44 | vpc_route_tables = get_route_table_str(vpc) 45 | row.append(vpc_route_tables) 46 | if show_state: 47 | row.append(vpc_state) 48 | table.append(row) 49 | print(tabulate(table, headers="firstrow", tablefmt="grid")) 50 | 51 | def get_vpc_subnets_str(vpc, show_subnet_name): 52 | result = '' 53 | for subnet in vpc.subnets.all(): 54 | if show_subnet_name: 55 | name_str = '(%s)' % get_name_by_tags(subnet.tags, 20) 56 | else: 57 | name_str = '' 58 | subnet_str = '%s%s,%s,%s\n' % \ 59 | (subnet.id, name_str, subnet.cidr_block, subnet.availability_zone) 60 | result += subnet_str 61 | return result 62 | 63 | def get_route_table_str(vpc): 64 | result = '' 65 | for rt in vpc.route_tables.all(): 66 | name_str = '(%s)' % get_name_by_tags(rt.tags, 16) 67 | route_table_str = '%s%s\n' % \ 68 | (rt.route_table_id, name_str) 69 | result += route_table_str 70 | return result 71 | 72 | def get_vpc_group_str(vpc): 73 | result = '' 74 | for group in vpc.security_groups.all(): 75 | group_name = group.group_name 76 | short_name = group_name[:22] + (group_name[22:] and '..') 77 | group_str = '%s(%s)\n' % \ 78 | (group.group_id, short_name) 79 | result += group_str 80 | return result 81 | 82 | def parse_vpc_subnets(subnets_conf): 83 | subnets = [] 84 | for subnet_conf in subnets_conf: 85 | subnet = {} 86 | config_items = subnet_conf.split(',') 87 | if len(config_items) > 0 : 88 | subnet['cidr'] = config_items.pop(0) 89 | else: 90 | error_msg('Need to specify subnet CIDR block') 91 | sys.exit(1) 92 | for config_item in config_items: 93 | option = config_item.split('=') 94 | if len(option) != 2: 95 | error_msg('Invalid subnet option %s in configuration %s' \ 96 | % (config_item, subnet_conf)) 97 | sys.exit(1) 98 | option_name = option[0].strip() 99 | option_value = option[1].strip() 100 | if option_name != 'name' and \ 101 | option_name != 'route_table' and \ 102 | option_name != 'availability_zone': 103 | error_msg('Unknown option name "%s" in subnet configuration %s' \ 104 | % (option_name, subnet_conf)) 105 | sys.exit(1) 106 | subnet[option_name] = option_value 107 | subnets.append(subnet) 108 | return subnets 109 | 110 | def write_vpc_id(vpc_id, output_file): 111 | info_msg('Saving vpc_id(%s) to %s' % (vpc_id, output_file)) 112 | with open(output_file, 'w') as outfile: 113 | outfile.write('%s' % vpc_id) 114 | 115 | @click.command() 116 | @click.option('--name', is_flag=True, help='Show VPC by name instead of ID') 117 | @click.option('--show-state', is_flag=True, help='Show VPC state') 118 | @click.option('--show-subnet-name', is_flag=True, help='Show name of subnet') 119 | @click.option('--show-route-table', is_flag=True, help='Show route table in VPC') 120 | @click.option('-v', '--verbose', is_flag=True, help='Enable verbose mode to get more information') 121 | @click.option('--profile', help='Use a specific profile from credential file') 122 | @click.option('--region', default='us-east-1', help='Specify AWS region', show_default=True) 123 | @click.argument('VPC-ID') 124 | def vpc_show(vpc_id, name, show_state, show_subnet_name, show_route_table, \ 125 | verbose, profile, region): 126 | """Show VPC parameters""" 127 | if verbose: 128 | enable_verbose_mode() 129 | session = boto3.Session(profile_name=profile, region_name=region) 130 | ec2 = session.resource('ec2') 131 | vpc_ids = [] 132 | if name != True: 133 | vpc_ids = [] 134 | vpc_ids.append(vpc_id) 135 | else: 136 | vpc_name = vpc_id 137 | vpc_ids = vpc_name_to_ids(session, vpc_name) 138 | show_vpc_parameters(session, vpc_ids, show_state, show_subnet_name, show_route_table) 139 | 140 | @click.command() 141 | @click.option('--name', help='VPC name') 142 | @click.option('--subnet', multiple=True, help='Add a subnet to the VPC') 143 | @click.option('--skip-if-exist', is_flag=True, help='Skip creating VPC if another VPC has the same name') 144 | @click.option('-v', '--verbose', is_flag=True, help='Enable verbose mode to get more information') 145 | @click.option('--save-vpc-id', type=click.Path(), help='Save VP ID to the file') 146 | @click.option('--profile', help='Use a specific profile from credential file') 147 | @click.option('--region', default='us-east-1', help='Specify AWS region', show_default=True) 148 | @click.argument('CIDR-BLOCK') 149 | def vpc_create(cidr_block, name, subnet, skip_if_exist, verbose, save_vpc_id, profile, region): 150 | """Create a new VPC""" 151 | if verbose: 152 | enable_verbose_mode() 153 | subnet_conf_list = parse_vpc_subnets(subnet) 154 | session = boto3.Session(profile_name=profile, region_name=region) 155 | ec2 = session.resource('ec2') 156 | if skip_if_exist and name != None: 157 | info_msg('Checking if there is VPC with the same name') 158 | existing_vpcs = vpc_name_to_ids(session, name) 159 | if len(existing_vpcs) > 0: 160 | info_msg('Existing VPC(s): %s' % json.dumps(existing_vpcs)) 161 | info_msg('Skip create new VPC') 162 | return 0 163 | vpc = ec2.create_vpc(CidrBlock=cidr_block) 164 | if name != None: 165 | vpc.create_tags(Tags=[{"Key": "Name", "Value": name}]) 166 | info_msg("Created VPC, id=%s" % vpc.id) 167 | vpc.wait_until_available() 168 | vpc_id = vpc.id 169 | debug_msg("Creating subnets:%s" % json.dumps(subnet_conf_list)) 170 | for subnet_conf in subnet_conf_list: 171 | subnet_param = {} 172 | subnet_param['VpcId'] = vpc_id 173 | subnet_param['CidrBlock'] = subnet_conf['cidr'] 174 | if 'availability_zone' in subnet_conf: 175 | subnet_param['AvailabilityZone'] = subnet_conf['availability_zone'] 176 | subnet = ec2.create_subnet(**subnet_param) 177 | info_msg('Created subnet, id=%s' % subnet.subnet_id) 178 | if 'route_table' in subnet_conf: 179 | route_table = vpc.create_route_table() 180 | info_msg('Created route table, id=%s' % route_table.id) 181 | route_table.associate_with_subnet(SubnetId=subnet.id) 182 | info_msg('Associated route table to subnet %s' % subnet.id) 183 | route_table.create_tags(Tags=[{"Key": "Name", "Value": subnet_conf['route_table']}]) 184 | if 'name' in subnet_conf: 185 | subnet.create_tags(Tags=[{"Key": "Name", "Value": subnet_conf['name']}]) 186 | if save_vpc_id != None: 187 | write_vpc_id(vpc_id, save_vpc_id) 188 | info_msg('Showing VPC information:') 189 | show_vpc_parameters(session, [vpc_id], False, True, True) 190 | -------------------------------------------------------------------------------- /CLI_tool/vsrx-aws: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | import click 5 | import traceback 6 | from deploy import deploy 7 | from monitor import monitor 8 | from troubleshoot import troubleshoot 9 | from scaleout import scaleout 10 | from syncaddr import syncaddr 11 | from stats import stats 12 | from images import images 13 | from vpc import vpc_show 14 | from vpc import vpc_create 15 | from wait import wait 16 | from junos_config import junos_config 17 | import logging 18 | from botocore.exceptions import ClientError 19 | from botocore.exceptions import NoCredentialsError 20 | from util import error_msg 21 | 22 | @click.group() 23 | def cli(): 24 | """vsrx-aws is an orchestration tool for automated provisioning, 25 | scaling and management of vSRX in AWS""" 26 | pass 27 | 28 | cli.add_command(deploy) 29 | cli.add_command(wait) 30 | #cli.add_command(troubleshoot) 31 | cli.add_command(stats) 32 | cli.add_command(scaleout) 33 | #cli.add_command(syncaddr, 'dyn-addr-sync') 34 | cli.add_command(images) 35 | cli.add_command(junos_config) 36 | cli.add_command(vpc_show, 'vpc-show') 37 | cli.add_command(vpc_create, 'vpc-create') 38 | if __name__ == '__main__': 39 | try: 40 | cli() 41 | except NoCredentialsError: 42 | error_msg('Unable to locate credentials') 43 | error_msg('Please use "aws configure" to configure credentials or ' + \ 44 | 'specify credential profile with "--profile"') 45 | sys.exit(2) 46 | except ClientError as e: 47 | error_msg(e) 48 | sys.exit(3) 49 | -------------------------------------------------------------------------------- /CLI_tool/wait.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import boto3 4 | import click 5 | import json 6 | import datetime 7 | import time 8 | import re 9 | import traceback 10 | from util import * 11 | 12 | def is_fpc_online(fxp0_addrs, key_file): 13 | debug_msg('Checking pic status ...') 14 | abs_key_path = os.path.abspath(key_file) 15 | addr_str = ','.join(fxp0_addrs) 16 | ansible_cmd = "docker run -it --rm -v \"$(pwd)/ansible/playbook/:/playbooks\" -v \"%s:/host-key.pem\" " + \ 17 | "-e ANSIBLE_NET_SSH_KEYFILE=/host-key.pem juniper/pyez-ansible " + \ 18 | "ansible-playbook --user ec2-user -i %s, show_pic_status.yml" 19 | ansible_cmd = ansible_cmd % (abs_key_path, addr_str) 20 | debug_msg(ansible_cmd) 21 | fpc_info = os.popen(ansible_cmd).read() 22 | debug_msg(fpc_info) 23 | all_online = True 24 | for addr in fxp0_addrs: 25 | hit = re.search("%s\s+fpc\s+online" % addr, fpc_info) 26 | if hit: 27 | info_msg("%s fpc is online" % addr) 28 | else: 29 | all_online = False 30 | info_msg("%s fpc is offline" % addr) 31 | return all_online 32 | 33 | @click.command() 34 | @click.option('--instance-id', '-i', 'instance_id', multiple=True, help='The ID of instance') 35 | @click.option('--key-file', prompt='Private key file to access vSRX instance', \ 36 | type=click.Path(), help='Private key file') 37 | @click.option('-v', '--verbose', is_flag=True, help='Enable verbose mode to get more information') 38 | @click.option('--timeout', default=1200, help='Maximum time(seconds) to wait', show_default=True) 39 | @click.option('--profile', help='Use a specific profile from credential file') 40 | @click.option('--region', default='us-east-1', help='Specify AWS region', show_default=True) 41 | def wait(instance_id, key_file, verbose, timeout, profile, region): 42 | """Wait vSRX fpc online""" 43 | if verbose: 44 | enable_verbose_mode() 45 | if key_file != None and not os.path.isfile(key_file): 46 | error_msg('Key file "%s" does not exist' % key_file) 47 | sys.exit(1) 48 | session = boto3.Session(profile_name=profile, region_name=region) 49 | client = session.client('ec2') 50 | ec2 = session.resource('ec2') 51 | public_ip_list = [] 52 | for vsrx_id in instance_id: 53 | instance = ec2.Instance(vsrx_id) 54 | public_ip = instance.public_ip_address 55 | debug_msg("instance %s public IP %s" %(vsrx_id, public_ip)) 56 | public_ip_list.append(public_ip) 57 | all_online = False 58 | if len(public_ip_list) > 0: 59 | wait_start = int(time.time()) 60 | expire_timestamp = wait_start + timeout 61 | while int(time.time()) < expire_timestamp: 62 | all_online = is_fpc_online(public_ip_list, key_file) 63 | if all_online: 64 | break 65 | info_msg('Sleeping 60s') 66 | time.sleep(60) 67 | -------------------------------------------------------------------------------- /IPSec-HA/AWS_IPSec_Redundancy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juniper/vSRX-AWS/4d6c7fd198c78fb89b533fdbfc9e68e07e18d1e8/IPSec-HA/AWS_IPSec_Redundancy.jpg -------------------------------------------------------------------------------- /IPSec-HA/AWS_IPSec_Redundancy.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juniper/vSRX-AWS/4d6c7fd198c78fb89b533fdbfc9e68e07e18d1e8/IPSec-HA/AWS_IPSec_Redundancy.pptx -------------------------------------------------------------------------------- /IPSec-HA/README.md: -------------------------------------------------------------------------------- 1 | # IPSEC/vsrx Redundancy Solution in AWS 2 | 3 | ## Problem Statement 4 | * IPsec redundancy with dual vSRX is one of the critical customer requirements. 5 | * Existing Chassis Cluster/ High Availability solutions rely on L2 layer for session-sync and data failover 6 | * Public clouds such as AWS, Azure, etc. do not support L2 traffic or Multicast 7 | * Traditional methods of session sync will not work in public cloud environments 8 | 9 | ## Design Principles/ considerations 10 | * Reliability: 11 | * Tunnels redundancy 12 | * Firewall nodes redundancy 13 | * Availability Zones/Geo-redundancy 14 | * High Availability Networking 15 | * Leverage AWS services 16 | * CloudWatch for health-check 17 | * Lambda/Server-less compute for VPC internal route change 18 | * Does not need any new effort from Engineering 19 | * Cost effective 20 | * Failover Factors 21 | * Instance Status: Stopping, pending, shutting down 22 | * CloudWatch metrics: vSRX CPU utilization, Interface Input and Output PPS and other metrics… 23 | 24 | ## DEMO 25 | * Topology 26 |
27 | * [Demo Video](https://drive.google.com/open?id=1w8zJaqAa-b_mqv4CNXRkK8JT-uKlbs6d) 28 | * [Presentation/Implementation](AWS_IPSec_Redundancy.pptx) -------------------------------------------------------------------------------- /IPSec-HA/routeChange.py: -------------------------------------------------------------------------------- 1 | import json 2 | import boto3 3 | import logging 4 | 5 | 6 | logger = logging.getLogger() 7 | logger.setLevel(logging.INFO) 8 | 9 | AWS_ACCESS_KEY = '' 10 | AWS_SECRET_KEY = '' 11 | AWS_REGION = '' #e.g. cn-northwest-1 12 | 13 | #intance id and interface id e.g.{'id':'i-05b8bcda0f9e6aeee','server_interface':'eni-0937ac3ddbc376502'} 14 | VSRX1 = {'id':'','server_interface':''} 15 | VSRX2 = {'id':'','server_interface':''} 16 | 17 | 18 | ROUTE_TABLE_ID = '' #e.g. rtb-04baa74a820c42f10 19 | ROUTE_DEST = '' #e.g. 192.167.102.0/24 20 | 21 | def get_new_internal_gateway(failed_instance_id): 22 | logger.info("Getting internal interface of new vSRX...") 23 | logger.info("Fail node: '{}'".format(failed_instance_id)) 24 | if failed_instance_id == VSRX1['id']: 25 | logger.info("Internal interface ID: '{}'".format(VSRX2['server_interface'])) 26 | return VSRX2['server_interface'] 27 | elif failed_instance_id == VSRX2['id']: 28 | logger.info("Internal interface ID: '{}'".format(VSRX1['server_interface'])) 29 | return VSRX1['server_interface'] 30 | else: 31 | logger.warn("No matched instance ID") 32 | return False 33 | 34 | def update_route(route_table_id, destination_cidr, eni): 35 | try: 36 | ec2 = boto3.resource( 37 | 'ec2', 38 | aws_access_key_id=AWS_ACCESS_KEY, 39 | aws_secret_access_key=AWS_SECRET_KEY, 40 | region_name=AWS_REGION 41 | ) 42 | route_resource = ec2.Route(route_table_id, destination_cidr) 43 | except: 44 | logger.exception("Could not get route resource for Route '{}' in Route Table '{}'".format( 45 | destination_cidr, 46 | route_table_id 47 | )) 48 | return False 49 | 50 | logger.info("Updating Route '{}' for Route Table '{}'...".format( 51 | destination_cidr, 52 | route_table_id 53 | )) 54 | try: 55 | route_resource.replace( 56 | DryRun=False, 57 | NetworkInterfaceId=eni 58 | ) 59 | except: 60 | logger.exception("Could not update Route '{}' for Route Table '{}'...".format( 61 | destination_cidr, 62 | route_table_id 63 | )) 64 | return False 65 | logger.info("Route '{}' for Route Table '{}' updated".format( 66 | destination_cidr, 67 | route_table_id 68 | )) 69 | return True 70 | 71 | 72 | def lambda_handler(event, context): 73 | logger.info("Starting Script...") 74 | eni = get_new_internal_gateway(event['detail']['instance-id']) 75 | success = update_route( 76 | route_table_id=ROUTE_TABLE_ID, 77 | destination_cidr=ROUTE_DEST, 78 | eni=eni 79 | ) 80 | 81 | if success is True: 82 | complete_message = "successfully updated." 83 | logger.info(complete_message) 84 | else: 85 | complete_message = "Failed to update." 86 | logger.warn(complete_message) 87 | 88 | return { 89 | "CompleteMessage": complete_message 90 | } 91 | -------------------------------------------------------------------------------- /IPSec-HA/vsrx-configs/vsrx0.conf: -------------------------------------------------------------------------------- 1 | ## Last changed: 2019-09-18 09:08:48 UTC 2 | version 18.4R1.8; 3 | #junos-config 4 | groups { 5 | aws-default { 6 | system { 7 | login { 8 | user ec2-user { 9 | full-name juniper-aws-ec2-user; 10 | uid 100; 11 | class super-user; 12 | authentication { 13 | ssh-rsa "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCVsJ9TSR8g/nJoCcmI6vAKoVtlr7BLmufoETvA1iASRuEOyClGYDy4a2a04xDcHB9Q9O6uDlLKY3CTUEyH7Dt0ejSlkTM7tC5vGAQ7wKwPc7iurl2qrBK6HllJqSHzg7z6ehEZ1BbG+hZnRlCgVHuAuTthOzpZuQOmBpm7HU7KcUs2NW0CfKaW3qefaVdstrAZfV09XKhDkDIKSMLZhOMAIKScS0ZP4ffHkqKRuH4a7DmVXfcNa5ff78gtoqoTF4lSYBRHwBYO0JjcHhSJVcANFmtetpWnIHvN1bRP44mplvpLuay0y8VvOP8L8ouHXfcf6z3i89Y7vrN29M880Isz jkey"; ## SECRET-DATA 14 | } 15 | } 16 | } 17 | root-authentication { 18 | encrypted-password "$6$y03flby9$5iyVY3V3hsX8umDb3Gdb5UJyaPvMc5wpHP6Z8jpxEIF50lcgkZ.oBSec0/VgbO39kOufhJ0hXLtdoJ1brKeYj."; ## SECRET-DATA 19 | } 20 | services { 21 | ssh { 22 | root-login allow; 23 | } 24 | netconf { 25 | ssh; 26 | } 27 | web-management { 28 | https { 29 | system-generated-certificate; 30 | } 31 | } 32 | } 33 | license { 34 | autoupdate { 35 | url https://ae1.juniper.net/junos/key_retrieval; 36 | } 37 | } 38 | } 39 | interfaces { 40 | fxp0 { 41 | unit 0 { 42 | family inet { 43 | dhcp; 44 | } 45 | } 46 | } 47 | } 48 | } 49 | } 50 | apply-groups aws-default; 51 | system { 52 | host-name vsrx0; 53 | } 54 | security { 55 | ike { 56 | proposal ike-proposal { 57 | authentication-method pre-shared-keys; 58 | dh-group group14; 59 | authentication-algorithm sha-256; 60 | encryption-algorithm aes-256-cbc; 61 | } 62 | policy ike-policy { 63 | mode main; 64 | proposals ike-proposal; 65 | pre-shared-key ascii-text "$9$O.l1BEyleWXxdyrYgJZji"; ## SECRET-DATA 66 | } 67 | gateway gw-vsrx1 { 68 | ike-policy ike-policy; 69 | address 52.83.39.252; 70 | dead-peer-detection { 71 | interval 10; 72 | threshold 1; 73 | } 74 | local-identity user-at-hostname "vsrx0@juniper.net"; 75 | remote-identity user-at-hostname "vsrx1@juniper.net"; 76 | external-interface ge-0/0/0.0; 77 | version v2-only; 78 | } 79 | gateway gw-vsrx2 { 80 | ike-policy ike-policy; 81 | address 161.189.16.141; 82 | dead-peer-detection { 83 | interval 10; 84 | threshold 1; 85 | } 86 | local-identity user-at-hostname "vsrx0@juniper.net"; 87 | remote-identity user-at-hostname "vsrx2@juniper.net"; 88 | external-interface ge-0/0/0; 89 | version v2-only; 90 | } 91 | } 92 | ipsec { 93 | proposal ipsec_prop { 94 | protocol esp; 95 | authentication-algorithm hmac-sha-256-128; 96 | encryption-algorithm aes-256-cbc; 97 | } 98 | policy ipsec_pol { 99 | proposals ipsec_prop; 100 | } 101 | vpn ipsec_vpn1 { 102 | bind-interface st0.0; 103 | ike { 104 | gateway gw-vsrx1; 105 | ipsec-policy ipsec_pol; 106 | } 107 | establish-tunnels immediately; 108 | } 109 | vpn ipsec_vpn2 { 110 | bind-interface st0.1; 111 | ike { 112 | gateway gw-vsrx2; 113 | ipsec-policy ipsec_pol; 114 | } 115 | establish-tunnels immediately; 116 | } 117 | } 118 | policies { 119 | default-policy { 120 | permit-all; 121 | } 122 | } 123 | zones { 124 | security-zone trust { 125 | host-inbound-traffic { 126 | system-services { 127 | all; 128 | } 129 | protocols { 130 | all; 131 | } 132 | } 133 | interfaces { 134 | ge-0/0/1.0; 135 | } 136 | } 137 | security-zone untrust { 138 | host-inbound-traffic { 139 | system-services { 140 | all; 141 | } 142 | protocols { 143 | all; 144 | } 145 | } 146 | interfaces { 147 | ge-0/0/0.0; 148 | } 149 | } 150 | security-zone VPN { 151 | host-inbound-traffic { 152 | system-services { 153 | all; 154 | } 155 | protocols { 156 | all; 157 | } 158 | } 159 | interfaces { 160 | st0.0; 161 | st0.1; 162 | } 163 | } 164 | } 165 | } 166 | interfaces { 167 | ge-0/0/0 { 168 | unit 0 { 169 | family inet { 170 | dhcp; 171 | } 172 | } 173 | } 174 | ge-0/0/1 { 175 | unit 0 { 176 | family inet { 177 | dhcp; 178 | } 179 | } 180 | } 181 | st0 { 182 | unit 0 { 183 | family inet { 184 | address 10.1.1.254/24; 185 | } 186 | } 187 | unit 1 { 188 | family inet { 189 | address 10.2.2.254/24; 190 | } 191 | } 192 | } 193 | } 194 | routing-options { 195 | static { 196 | route 0.0.0.0/0 next-hop 192.167.101.1; 197 | route 192.168.30.0/24 { 198 | next-hop st0.0; 199 | qualified-next-hop st0.1 { 200 | preference 6; 201 | } 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /IPSec-HA/vsrx-configs/vsrx1.conf: -------------------------------------------------------------------------------- 1 | ## Last changed: 2019-09-18 09:08:46 UTC 2 | version 18.4R1.8; 3 | #junos-config 4 | groups { 5 | aws-default { 6 | system { 7 | login { 8 | user ec2-user { 9 | full-name juniper-aws-ec2-user; 10 | uid 100; 11 | class super-user; 12 | authentication { 13 | ssh-rsa "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCVsJ9TSR8g/nJoCcmI6vAKoVtlr7BLmufoETvA1iASRuEOyClGYDy4a2a04xDcHB9Q9O6uDlLKY3CTUEyH7Dt0ejSlkTM7tC5vGAQ7wKwPc7iurl2qrBK6HllJqSHzg7z6ehEZ1BbG+hZnRlCgVHuAuTthOzpZuQOmBpm7HU7KcUs2NW0CfKaW3qefaVdstrAZfV09XKhDkDIKSMLZhOMAIKScS0ZP4ffHkqKRuH4a7DmVXfcNa5ff78gtoqoTF4lSYBRHwBYO0JjcHhSJVcANFmtetpWnIHvN1bRP44mplvpLuay0y8VvOP8L8ouHXfcf6z3i89Y7vrN29M880Isz jkey"; ## SECRET-DATA 14 | } 15 | } 16 | } 17 | root-authentication { 18 | encrypted-password "$6$bk.DKrJt$KD.FwQq9tzXq4S2wtw1PiTRrB58rb2siBhbaJfU9GXrvYlqTcdExIiUyrntqWbUQXb6ZVpZMZjviQK13vqgQ0/"; ## SECRET-DATA 19 | } 20 | services { 21 | ssh { 22 | root-login allow; 23 | } 24 | netconf { 25 | ssh; 26 | } 27 | web-management { 28 | https { 29 | system-generated-certificate; 30 | } 31 | } 32 | } 33 | license { 34 | autoupdate { 35 | url https://ae1.juniper.net/junos/key_retrieval; 36 | } 37 | } 38 | } 39 | interfaces { 40 | fxp0 { 41 | unit 0 { 42 | family inet { 43 | dhcp; 44 | } 45 | } 46 | } 47 | } 48 | } 49 | } 50 | apply-groups aws-default; 51 | system { 52 | host-name vsrx1; 53 | } 54 | security { 55 | ike { 56 | proposal ike-proposal { 57 | authentication-method pre-shared-keys; 58 | dh-group group14; 59 | authentication-algorithm sha-256; 60 | encryption-algorithm aes-256-cbc; 61 | } 62 | policy ike-policy { 63 | mode main; 64 | proposals ike-proposal; 65 | pre-shared-key ascii-text "$9$Qa26z6Apu1EhrAtM87Nbw"; ## SECRET-DATA 66 | } 67 | gateway gw-vsrx0 { 68 | ike-policy ike-policy; 69 | address 52.83.83.184; 70 | local-identity user-at-hostname "vsrx1@juniper.net"; 71 | remote-identity user-at-hostname "vsrx0@juniper.net"; 72 | external-interface ge-0/0/0.0; 73 | version v2-only; 74 | } 75 | } 76 | ipsec { 77 | proposal ipsec_prop { 78 | protocol esp; 79 | authentication-algorithm hmac-sha-256-128; 80 | encryption-algorithm aes-256-cbc; 81 | } 82 | policy ipsec_pol { 83 | proposals ipsec_prop; 84 | } 85 | vpn ipsec_vpn { 86 | bind-interface st0.0; 87 | ike { 88 | gateway gw-vsrx0; 89 | ipsec-policy ipsec_pol; 90 | } 91 | } 92 | } 93 | policies { 94 | default-policy { 95 | permit-all; 96 | } 97 | } 98 | zones { 99 | security-zone trust { 100 | host-inbound-traffic { 101 | system-services { 102 | all; 103 | } 104 | protocols { 105 | all; 106 | } 107 | } 108 | interfaces { 109 | ge-0/0/1.0; 110 | } 111 | } 112 | security-zone untrust { 113 | host-inbound-traffic { 114 | system-services { 115 | all; 116 | } 117 | protocols { 118 | all; 119 | } 120 | } 121 | interfaces { 122 | ge-0/0/0.0; 123 | } 124 | } 125 | security-zone VPN { 126 | host-inbound-traffic { 127 | system-services { 128 | all; 129 | } 130 | protocols { 131 | all; 132 | } 133 | } 134 | interfaces { 135 | st0.0; 136 | } 137 | } 138 | } 139 | } 140 | interfaces { 141 | ge-0/0/0 { 142 | unit 0 { 143 | family inet { 144 | dhcp; 145 | } 146 | } 147 | } 148 | ge-0/0/1 { 149 | unit 0 { 150 | family inet { 151 | dhcp; 152 | } 153 | } 154 | } 155 | st0 { 156 | unit 0 { 157 | family inet { 158 | address 10.1.1.1/24; 159 | } 160 | } 161 | } 162 | } 163 | routing-options { 164 | static { 165 | route 0.0.0.0/0 next-hop 192.168.11.1; 166 | route 192.168.30.0/24 next-hop 192.168.12.1; 167 | route 192.167.102.0/24 next-hop st0.0; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /IPSec-HA/vsrx-configs/vsrx2.conf: -------------------------------------------------------------------------------- 1 | ## Last changed: 2019-09-18 09:08:49 UTC 2 | version 18.4R1.8; 3 | #junos-config 4 | groups { 5 | aws-default { 6 | system { 7 | login { 8 | user ec2-user { 9 | full-name juniper-aws-ec2-user; 10 | uid 100; 11 | class super-user; 12 | authentication { 13 | ssh-rsa "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCVsJ9TSR8g/nJoCcmI6vAKoVtlr7BLmufoETvA1iASRuEOyClGYDy4a2a04xDcHB9Q9O6uDlLKY3CTUEyH7Dt0ejSlkTM7tC5vGAQ7wKwPc7iurl2qrBK6HllJqSHzg7z6ehEZ1BbG+hZnRlCgVHuAuTthOzpZuQOmBpm7HU7KcUs2NW0CfKaW3qefaVdstrAZfV09XKhDkDIKSMLZhOMAIKScS0ZP4ffHkqKRuH4a7DmVXfcNa5ff78gtoqoTF4lSYBRHwBYO0JjcHhSJVcANFmtetpWnIHvN1bRP44mplvpLuay0y8VvOP8L8ouHXfcf6z3i89Y7vrN29M880Isz jkey"; ## SECRET-DATA 14 | } 15 | } 16 | } 17 | root-authentication { 18 | encrypted-password "$6$Z/OQzTQE$aBnCBxMPS2UwrraS/emmNT72/46XNpSuBkXzCNjXWYeW4uW41FzkGBPD.GV2s6wr3MnVmj2fpvaPFcfRZ8ATR1"; ## SECRET-DATA 19 | } 20 | services { 21 | ssh { 22 | root-login allow; 23 | } 24 | netconf { 25 | ssh; 26 | } 27 | web-management { 28 | https { 29 | system-generated-certificate; 30 | } 31 | } 32 | } 33 | license { 34 | autoupdate { 35 | url https://ae1.juniper.net/junos/key_retrieval; 36 | } 37 | } 38 | } 39 | interfaces { 40 | fxp0 { 41 | unit 0 { 42 | family inet { 43 | dhcp; 44 | } 45 | } 46 | } 47 | } 48 | } 49 | } 50 | apply-groups aws-default; 51 | system { 52 | host-name vsrx2; 53 | } 54 | security { 55 | ike { 56 | proposal ike-proposal { 57 | authentication-method pre-shared-keys; 58 | dh-group group14; 59 | authentication-algorithm sha-256; 60 | encryption-algorithm aes-256-cbc; 61 | } 62 | policy ike-policy { 63 | mode main; 64 | proposals ike-proposal; 65 | pre-shared-key ascii-text "$9$78Nb24oGji.2gTz6/tp"; ## SECRET-DATA 66 | } 67 | gateway gw-vsrx0 { 68 | ike-policy ike-policy; 69 | address 52.83.83.184; 70 | local-identity user-at-hostname "vsrx2@juniper.net"; 71 | remote-identity user-at-hostname "vsrx0@juniper.net"; 72 | external-interface ge-0/0/0.0; 73 | version v2-only; 74 | } 75 | } 76 | ipsec { 77 | proposal ipsec_prop { 78 | protocol esp; 79 | authentication-algorithm hmac-sha-256-128; 80 | encryption-algorithm aes-256-cbc; 81 | } 82 | policy ipsec_pol { 83 | proposals ipsec_prop; 84 | } 85 | vpn ipsec_vpn { 86 | bind-interface st0.0; 87 | ike { 88 | gateway gw-vsrx0; 89 | ipsec-policy ipsec_pol; 90 | } 91 | establish-tunnels immediately; 92 | } 93 | } 94 | policies { 95 | default-policy { 96 | permit-all; 97 | } 98 | } 99 | zones { 100 | security-zone trust { 101 | host-inbound-traffic { 102 | system-services { 103 | all; 104 | } 105 | protocols { 106 | all; 107 | } 108 | } 109 | interfaces { 110 | ge-0/0/1.0; 111 | } 112 | } 113 | security-zone untrust { 114 | host-inbound-traffic { 115 | system-services { 116 | all; 117 | } 118 | protocols { 119 | all; 120 | } 121 | } 122 | interfaces { 123 | ge-0/0/0.0; 124 | } 125 | } 126 | security-zone VPN { 127 | host-inbound-traffic { 128 | system-services { 129 | all; 130 | } 131 | protocols { 132 | all; 133 | } 134 | } 135 | interfaces { 136 | st0.0; 137 | } 138 | } 139 | } 140 | } 141 | interfaces { 142 | ge-0/0/0 { 143 | unit 0 { 144 | family inet { 145 | dhcp; 146 | } 147 | } 148 | } 149 | ge-0/0/1 { 150 | unit 0 { 151 | family inet { 152 | dhcp; 153 | } 154 | } 155 | } 156 | st0 { 157 | unit 0 { 158 | family inet { 159 | address 10.2.2.1/24; 160 | } 161 | } 162 | } 163 | } 164 | routing-options { 165 | static { 166 | route 0.0.0.0/0 next-hop 192.168.21.1; 167 | route 192.168.30.0/24 next-hop 192.168.22.1; 168 | route 192.167.102.0/24 next-hop st0.0; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Use of files in this repo are governed by the license contained within each separate directory with the file name “LICENSE” 2 | 3 | If such a file does NOT exist within each directory then the below line is applicable to all content: 4 | 5 | All code, templates and other files in this repo are released on an “AS IS” BASIS, WITHOUT WARRANTIES, CONDITIONS, OR SUPPORT OBLIGATIONS OF ANY KIND, EXPRESS OR IMPLIED. 6 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright © 2020 Juniper Networks, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/NOTICE: -------------------------------------------------------------------------------- 1 | NOTICES FOR THIRD-PARTY CODE/DEPENDENCIES 2 | 3 | Name:attrs 4 | ProjectURL: https://www.attrs.org/en/stable/ 5 | License: https://www.attrs.org/en/stable/license.html 6 | 7 | Name:certifi 8 | ProjectURL: https://github.com/certifi/python-certifi 9 | License: https://github.com/certifi/python-certifi/blob/master/LICENSE 10 | 11 | Name:chardet 12 | ProjectURL: https://github.com/chardet/chardet 13 | License: https://github.com/chardet/chardet/blob/master/LICENSE 14 | 15 | Name:configparser 16 | ProjectURL: https://github.com/jaraco/configparser/ 17 | License: https://github.com/jaraco/configparser/blob/master/LICENSE 18 | 19 | Name:contextlib2 20 | ProjectURL: https://github.com/jazzband/contextlib2/tree/v0.6.0 21 | License: https://github.com/jazzband/contextlib2/blob/v0.6.0/LICENSE.txt 22 | 23 | Name:functools32 24 | ProjectURL: https://github.com/MiCHiLU/python-functools32 25 | License: https://github.com/michilu/python-functools32/blob/master/LICENSE 26 | 27 | Name:idna 28 | ProjectURL: https://github.com/kjd/idna 29 | License: https://github.com/kjd/idna/blob/master/LICENSE.md 30 | 31 | Name:importlib_metadata 32 | ProjectURL: https://gitlab.com/python-devs/importlib_metadata 33 | License: https://gitlab.com/python-devs/importlib_metadata/-/blob/master/LICENSE 34 | 35 | Name:jsonschema 36 | ProjectURL:https://github.com/Julian/jsonschema 37 | License: https://github.com/Julian/jsonschema/blob/master/COPYING 38 | 39 | Name:pathlib2 40 | ProjectURL:https://github.com/mcmtroffaes/pathlib2 41 | License: https://github.com/mcmtroffaes/pathlib2/blob/develop/LICENSE.rst 42 | 43 | Name:pyrsistent 44 | ProjectURL:https://github.com/tobgu/pyrsistent/ 45 | License: https://github.com/tobgu/pyrsistent/blob/master/LICENCE.mit 46 | 47 | Name:requests 48 | ProjectURL:https://requests.readthedocs.io/en/master/ 49 | License: https://github.com/psf/requests/blob/master/LICENSE 50 | 51 | Name:scandir 52 | ProjectURL:https://github.com/benhoyt/scandir 53 | License: https://github.com/benhoyt/scandir/blob/master/LICENSE.txt 54 | 55 | Name:setuptools 56 | ProjectURL:https://github.com/pypa/setuptools 57 | License: https://github.com/pypa/setuptools/blob/master/LICENSE 58 | 59 | Name:six 60 | ProjectURL:https://github.com/benjaminp/six 61 | License: https://github.com/benjaminp/six/blob/1.15.0/LICENSE 62 | 63 | Name:urllib3 64 | ProjectURL:https://github.com/urllib3/urllib3 65 | License: https://github.com/urllib3/urllib3/blob/1.24.3/LICENSE.txt 66 | 67 | Name:zipp 68 | ProjectURL:https://github.com/jaraco/zipp 69 | License: https://github.com/jaraco/zipp/blob/v1.2.0/LICENSE 70 | 71 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # SRX-GD-ThreatFeed Overview 4 | 5 | Amazon Web Services (AWS) GuardDuty is a continuous security monitoring service that identifies unexpected, potentially unauthorized, and malicious activity within your AWS environment. The `SRX-GD-Threatfeed` is an AWS Lamda function that sends threats detected by the AWS Guard Duty as a security feed to the VSRX firewalls in your AWS environment. The vSRX firewalls can access the feeds either by directly downloading it from the AWS S3 bucket, or if the firewall device is enrolled with ATP Cloud, the feed is pushed to the firewall device along with the ATP Cloud security intelligence (SecIntel) feeds. In turn, the vSRX firewall enables you to take actions on the feed and block or log connections to the threat sources identified in the feed. 6 | 7 | The threats are sent as a security feed to the SRX Series devices in the your AWS environment. The device can access the feeds either by directly downloading it from the AWS S3 bucket or, if the SRX Series device is enrolled with Juniper ATP Cloud, the feed is pushed to the device along with the security intelligence (SecIntel) feeds. 8 | For more information, see [Integrate AWS GuardDuty with vSRX Firewalls.](https://www.juniper.net/documentation/en_US/release-independent/sky-atp/topics/topic-map/sky-atp-guardduty-srx-integration.html) 9 | 10 | ## Prerequisite Knowledge 11 | Installing and configuring the `SRX-GD-ThreatFeed` requires knowledge of the following: 12 | 13 | - AWS GuardDuty, Lambda function, S3 bucket, DynamoDB and IAM 14 | 15 | ## Dependency third party packages 16 | 17 | The following python packages are included in Pre-packaged ZIP file. 18 | 19 | attrs 20 | certifi 21 | chardet 22 | configparser 23 | contextlib2 24 | functools32 25 | idna 26 | importlib_metadata 27 | jsonschema 28 | pathlib2 29 | pyrsistent 30 | requests 31 | scandir 32 | setuptools 33 | six 34 | urllib3 35 | zipp 36 | 37 | ## Installation 38 | 39 | For detailed installation steps, see [Integrate AWS GuardDuty with vSRX Firewalls.](https://www.juniper.net/documentation/en_US/release-independent/sky-atp/topics/topic-map/sky-atp-guardduty-srx-integration.html) 40 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/SRX-GD-Threatfeed.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juniper/vSRX-AWS/4d6c7fd198c78fb89b533fdbfc9e68e07e18d1e8/SRX-GD-Threatfeed/SRX-GD-Threatfeed.zip -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/cc_schema: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/gd_threatfeed/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juniper/vSRX-AWS/4d6c7fd198c78fb89b533fdbfc9e68e07e18d1e8/SRX-GD-Threatfeed/gd_threatfeed/__init__.py -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/gd_threatfeed/config.py: -------------------------------------------------------------------------------- 1 | 2 | # Copyright © 2020 Juniper Networks, Inc., All Rights Reserved. 3 | 4 | """Schema for Guardduty configuration""" 5 | 6 | from gd_threatfeed import constants as const 7 | 8 | SKY_CONF_SCHEMA = { 9 | 'title': 'Guardduty configuration with SkyATP license', 10 | 'type': 'object', 11 | 'properties': { 12 | 'token': {'type': 'string', 'title': 'Sky ATP token for Open API'}, 13 | 'base_url': {'type': 'string', 'title': 'OpenAPI base url'} 14 | }, 15 | 'required': ['token', 'base_url'], 16 | } 17 | 18 | NON_SKY_CONF_SCHEMA = { 19 | 'title': 'Guardduty configuration without SkyATP license', 20 | 'type': 'object', 21 | 'properties': { 22 | 'bucket': {'type': 'string', 'title': 'AWS S3 bucket name'}, 23 | 'feed_ttl': {'type': 'integer', 'title': 'CC category feeds TTL', 24 | 'minimum': const.MIN_TTL, 'maximum': const.MAX_TTL, 25 | 'default': const.CC_TTL}, 26 | 'update_interval': {'type': 'integer', 27 | 'title': 'Feed update interval', 28 | 'minimum': const.UPDATE_INTERVAL, 29 | 'maximum': const.MAX_UPDATE_INTERVAL, 30 | 'default': const.UPDATE_INTERVAL}, 31 | 'max_entries': {'type': 'integer', 'title': 'Max feed entries for feed', 32 | 'minimum': const.MIN_MAX_ENTRIES, 33 | 'maximum': const.MAX_MAX_ENTRIES, 34 | 'default': const.DEFAULT_MAX_ENTRIES} 35 | 36 | }, 37 | 'required': ['bucket', 'feed_ttl', 'update_interval', 'max_entries'], 38 | } 39 | 40 | 41 | CONF_SCHEMA = { 42 | '$schema': 'http://json-schema.org/draft-04/schema#', 43 | 'title': 'Guaudduty configuration', 44 | 'type': 'object', 45 | 'properties': { 46 | 'severity': {'type': 'integer', 'title': 'Guard duty event severity', 47 | 'minimum': 1, 'maximum': 10, 'default': 4}, 48 | 'feed_type': {'enum': ['ip_addr', 'dn'], 'title': 'Feed type'}}, 49 | 'required': ['severity', 'feed_type'], 50 | 'oneOf': [SKY_CONF_SCHEMA, NON_SKY_CONF_SCHEMA], 51 | 'anyOf': [ 52 | {'ip_feed': {'type': 'string', 'title': 'IP feed name', 53 | 'pattern': '^[a-zA-Z0-9\\_]{8,64}$'}}, 54 | {'dns_feed': {'type': 'string', 'title': 'DNS feed name', 55 | 'pattern': '^[a-zA-Z0-9\\_]{8,64}$'}} 56 | ], 57 | 'additionalProperties': True, 58 | } 59 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/gd_threatfeed/constants.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2020 Juniper Networks, Inc., All Rights Reserved. 2 | 3 | """Constants for Gaurdduty""" 4 | 5 | CC_TTL = 3456000 # 40 days 6 | MIN_TTL = 86400 # 1 day 7 | MAX_TTL = 31556952 # 1 year 8 | UPDATE_INTERVAL = 300 # 30 minutes 9 | MAX_UPDATE_INTERVAL = 86400 # 1 Day 10 | DEFAULT_MANIFEST_UPDATE_INTERVAL = 60 # 1 minute 11 | DEFAULT_MAX_ENTRIES = 10000 12 | MIN_MAX_ENTRIES = 1000 13 | MAX_MAX_ENTRIES = 100000 14 | DEFAULT_SEVERITY_LEVEL = 8 15 | 16 | DATA_TAG_ADD_N = b'#add\n' 17 | DATA_TAG_DEL_N = b'#del\n' 18 | DATA_TAG_END_N = b'#end\n' 19 | 20 | IP_ADDR = 'ip_addr' 21 | DOMAIN = 'dn' 22 | THREAT_LEVEL = 'threat_level' 23 | PROP = 'properties' 24 | MANIFEST_FILE_NAME = 'manifest.xml' 25 | IP_FEED = 'ip' 26 | DNS_FEED = 'domain' 27 | 28 | CC_CATEGORY = 'CC' 29 | CC_DESC = 'Command and Control data schema' 30 | CC_SCHEMA_VER = 'c66b370237' 31 | 32 | OBJ_CODES = {IP_ADDR: 4, DOMAIN: 1, PROP: 8, THREAT_LEVEL: 9} 33 | IP_OBJ_FIELDS = (IP_ADDR, THREAT_LEVEL) 34 | URL_OBJ_FIELDS = (DOMAIN, THREAT_LEVEL) 35 | 36 | ACTIONS_PATH = {'NETWORK_CONNECTION': ('networkConnectionAction.' 37 | 'remoteIpDetails.ipAddressV4', IP_ADDR), 38 | 'AWS_API_CALL': ('awsApiCallAction.remoteIpDetails.ipAddressV4', 39 | IP_ADDR), 40 | 'DNS_REQUEST': ('dnsRequestAction.domain', DOMAIN), 41 | 'PORT_PROBE': ('portProbeAction.portProbeDetails.*.' 42 | 'remoteIpDetails.ipAddressV4', IP_ADDR)} 43 | 44 | 45 | OPEN_API_CC_URL = 'cc/file/{feed_type}/{feed_name}' 46 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/gd_threatfeed/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2020 Juniper Networks, Inc., All Rights Reserved. 2 | 3 | class CloudFeedsError(Exception): 4 | """Base error""" 5 | 6 | 7 | class IncorrectVersionError(CloudFeedsError): 8 | """Wrong feed version detected.""" 9 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/gd_threatfeed/openapi_client.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2020 Juniper Networks, Inc., All Rights Reserved. 2 | 3 | """Client to interact with OpenAPI API's""" 4 | import os 5 | import json 6 | import logging 7 | 8 | from requests import Session 9 | from requests.adapters import HTTPAdapter 10 | from urllib3.util.retry import Retry 11 | 12 | from gd_threatfeed import errors 13 | from gd_threatfeed import utils 14 | 15 | SUPPORTED_PROTOCOLS = {'HTTP', 'HTTPS'} 16 | RETRY_CFG = {'total': 3, 'backoff_factor': 0.3, 17 | 'status_forcelist': (500, 502, 503, 504), 'raise_on_status': True} 18 | OPEN_API_CC_URL = 'cc/file/{feed_type}/{feed_name}' 19 | 20 | 21 | class OpenAPIClient: 22 | """Client for OpenAPI""" 23 | 24 | def __init__(self, base_url, token): 25 | self.base_url = base_url 26 | self.token = token 27 | 28 | def _make_request(self, method: str, url: str, params: dict=None, 29 | data: dict=None, files: dict=None): 30 | """Make HTTP request to the API server. 31 | 32 | :param method: HTTP method. 33 | :param url: Partial URL . 34 | :param params: Dictionary to be sent as the query string. 35 | :param data: Dictionary to send as the body of the request. 36 | :param files: Files to send. 37 | 38 | """ 39 | with Session() as session: 40 | full_url = os.path.join(self.base_url, url) 41 | logging.info("FULL URL %s", full_url) 42 | retries = Retry(**RETRY_CFG) 43 | headers = {'Authorization': self.token} 44 | openapi_adapter = HTTPAdapter(max_retries=retries) 45 | for protocol in SUPPORTED_PROTOCOLS: 46 | session.mount('%s://' % (protocol,), openapi_adapter) 47 | resp = session.request(method=method, url=full_url, params=params, 48 | data=data, headers=headers, files=files, 49 | verify=False) 50 | return resp.status_code, resp.headers, resp.content 51 | 52 | def _make_json_request(self, method: str, api_url: str, files: dict=None, 53 | data: dict=None): 54 | """Make HTTP request to the API server. Parse JSON response body 55 | and return Python object. 56 | 57 | :param method: HTTP method. 58 | :param api_url: API URL 59 | :param data: Dictionary to send as the body of the request. 60 | :param files: Files to send. 61 | """ 62 | if data is not None: 63 | enc_data = {'params': json.dumps(data)} 64 | logging.info("Sending %s content to OpenAPI", enc_data) 65 | else: 66 | enc_data = None 67 | 68 | status, _, body = self._make_request(method, api_url, files=files, 69 | data=enc_data) 70 | return json.loads(body), status 71 | 72 | def is_feed_exists(self, feed_type: str, feed_name: str): 73 | """ 74 | Check whether the feed is exist or not 75 | :param feed_type: Feed type 76 | :param feed_name: Feed name 77 | """ 78 | url = OPEN_API_CC_URL.format(feed_type=feed_type, feed_name=feed_name) 79 | resp, _ = self._make_json_request('GET', url) 80 | logging.info("Feed exists API response %s", resp) 81 | return resp 82 | 83 | def upload_custom_feed(self, feed_type: str, feed_name: str, 84 | feed_content: str): 85 | """Upload a custom feed to the Cloud Feeds server. 86 | :param feed_type: Feed type 87 | :param feed_name: Feed name 88 | :param feed_content: Feed content 89 | """ 90 | url = OPEN_API_CC_URL.format(feed_type=feed_type, feed_name=feed_name) 91 | resp, _ = self.is_feed_exists(feed_type, feed_name) 92 | if 'err_id' not in resp and 'message' in resp: 93 | logging.info("Set http request method to PATCH") 94 | http_method = 'PATCH' 95 | elif 'err_id' in resp: 96 | http_method = 'POST' 97 | logging.info("Set http request method to POST") 98 | else: 99 | raise errors.CloudFeedsError("Invalid feed status") 100 | return self.upload_custom_feed_helper(http_method, url, 101 | files={'file': feed_content}) 102 | 103 | @utils.retry_status(409) 104 | def upload_custom_feed_helper(self, method: str, url: str, files: dict): 105 | """Upload feed helper function 106 | :param method: Http method 107 | :param url: API URL 108 | :param files: File dictionary""" 109 | return self._make_json_request(method, url, files=files) 110 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/gd_threatfeed/s3_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2020 Juniper Networks, Inc., All Rights Reserved. 2 | 3 | """S3 utils""" 4 | import logging as log 5 | 6 | import boto3 7 | from botocore.exceptions import ClientError 8 | 9 | from gd_threatfeed.errors import CloudFeedsError 10 | 11 | 12 | def upload_data_to_s3(bucket: str, content: bytes, path: str): 13 | """ 14 | Upload data to S3 storage 15 | 16 | :param bucket: Customer Bucket 17 | :param content: Feed content 18 | :param path: Feed path 19 | """ 20 | try: 21 | s3_resource = boto3.resource('s3') 22 | obj = s3_resource.Object(bucket, path) 23 | obj.put(Body=content) 24 | except ClientError as exc: 25 | log.error("Error while uploading content to s3 %s", str(exc)) 26 | raise CloudFeedsError('Failed to upload content in path %s' % path) 27 | 28 | 29 | def download_to_memory(bucket: str, path: str): 30 | """Download s3 file into memory 31 | 32 | :param bucket: Customer Bucket 33 | :param path: File path 34 | """ 35 | try: 36 | s3_resource = boto3.resource('s3') 37 | obj = s3_resource.Object(bucket, path) 38 | body = obj.get()['Body'].read() 39 | return body 40 | except ClientError as exc: 41 | if exc.response['Error']['Code'] != 'NoSuchKey': 42 | log.error("Error while downloading file: %s", str(exc)) 43 | raise CloudFeedsError('Failed to download file %s' % path) 44 | 45 | 46 | def download_manifest(bucket: str, path: str): 47 | 48 | """Download the manifest to memory 49 | :param bucket: Customer Bucket 50 | :param path: File path 51 | """ 52 | 53 | body = download_to_memory(bucket, path) 54 | if not body: 55 | return b'' 56 | return body 57 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/gd_threatfeed/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2020 Juniper Networks, Inc., All Rights Reserved. 2 | 3 | """Common utils""" 4 | import os 5 | import time 6 | import logging as log 7 | from functools import wraps 8 | 9 | import jsonschema 10 | 11 | from gd_threatfeed import constants as const 12 | from gd_threatfeed import config 13 | 14 | NUM_RETRIES = 5 15 | INITIAL_SLEEP_TIME = 5 16 | 17 | 18 | def _gen_dict_extract(target: str, var: dict): 19 | """Looks for a key in a nested dictionary. 20 | """ 21 | if hasattr(var, 'items'): 22 | for key, value in var.items(): 23 | if key == target: 24 | yield value 25 | if isinstance(value, dict): 26 | yield from _gen_dict_extract(target, value) 27 | elif isinstance(value, list): 28 | for item in value: 29 | yield from _gen_dict_extract(target, item) 30 | 31 | 32 | def get_by_path(input_dict, nested_key): 33 | """Get the value based on nested keys""" 34 | internal_dict_value = input_dict 35 | for k in nested_key: 36 | internal_dict_value = internal_dict_value.get(k, None) 37 | if internal_dict_value is None: 38 | log.warning("Invalid path: %s", ".".join(nested_key)) 39 | return None 40 | return internal_dict_value 41 | 42 | 43 | def get_event_details(data: dict, path: str, ftype: str): 44 | """ 45 | Get event info 46 | 47 | :param data: Event dictionary 48 | :param path: Action path 49 | :param ftype: Feed type 50 | """ 51 | res = set() 52 | log.debug("Get action data for action type = %s", data['actionType']) 53 | keys = path.split(".") 54 | if '*' in keys: 55 | split_idx = keys.index('*') 56 | parent, child = keys[:split_idx], keys[split_idx + 1:] 57 | val = get_by_path(data, parent) 58 | if isinstance(val, list): 59 | for item in val: 60 | val = get_by_path(item, child) 61 | if ftype == const.IP_ADDR: 62 | log.debug('Received IP V4 address %s', val) 63 | res.add((const.IP_ADDR, val, const.THREAT_LEVEL, 10)) 64 | else: 65 | log.debug('Received Domain %s', val) 66 | res.add((const.DOMAIN, val, const.THREAT_LEVEL, 10)) 67 | else: 68 | log.warning("Invalid path: %s ", path) 69 | else: 70 | val = get_by_path(data, keys) 71 | if ftype == const.IP_ADDR: 72 | log.debug('Received IP V4 address %s', val) 73 | res.add((const.IP_ADDR, val, const.THREAT_LEVEL, 10)) 74 | else: 75 | log.debug('Received Domain %s', val) 76 | res.add((const.DOMAIN, val, const.THREAT_LEVEL, 10)) 77 | return res 78 | 79 | 80 | def validate_args(conf): 81 | """Validate arguments based on configuration""" 82 | try: 83 | jsonschema.validate(conf, config.CONF_SCHEMA) 84 | except jsonschema.ValidationError as err: 85 | log.error("Invalid Guardduty configuration: %s", str(err)) 86 | return False 87 | return True 88 | 89 | 90 | def validate_event(event, ftype, conf): 91 | """Validate event based on configuration""" 92 | valid = False 93 | if event['detail']['severity'] < conf['severity']: 94 | log.info('Ignoring event lesser than set threshold %d', 95 | conf['severity']) 96 | elif ftype == const.IP_ADDR and not conf['ip_feed']: 97 | log.info("Ignoring ip feed event as its not configured") 98 | elif ftype == const.DOMAIN and not conf['dns_feed']: 99 | log.info("Ignoring domain feed event as its not configured") 100 | else: 101 | valid = True 102 | return valid 103 | 104 | 105 | def retry_status(status): 106 | """Retry API call based on status value""" 107 | def wrapper(func): 108 | @wraps(func) 109 | def func_wrapper(*args, **kwargs): 110 | retries_left = NUM_RETRIES 111 | sleep_time = INITIAL_SLEEP_TIME 112 | resp, code = func(*args, **kwargs) 113 | while code == status and retries_left > 0: 114 | retries_left -= 1 115 | log.info("Retry status response %s, %d", resp, code) 116 | log.info('Retry status left %d and sleeping %d sec before make ' 117 | 'another try', retries_left, sleep_time) 118 | time.sleep(sleep_time) 119 | sleep_time *= 2 120 | resp, code = func(*args, **kwargs) 121 | return resp, code 122 | return func_wrapper 123 | return wrapper 124 | 125 | 126 | def get_lambda_config(): 127 | 128 | conf = {'ip_feed': os.environ.get('IP_FEED'), 129 | 'dns_feed': os.environ.get('DNS_FEED')} 130 | conf['severity'] = int(os.environ.get('SEVERITY_LEVEL', 131 | const.DEFAULT_SEVERITY_LEVEL)) 132 | base_url = os.environ.get('SKY_OPENAPI_BASE_PATH') 133 | if base_url: 134 | conf['base_url'] = base_url 135 | conf['token'] = os.environ.get('SKY_APPLICATION_TOKEN') 136 | else: 137 | conf.update({'bucket': os.environ.get('S3_BUCKET'), 138 | 'feed_ttl': int(os.environ.get('FEED_TTL', const.CC_TTL)), 139 | 'update_interval': int(os.environ.get('FEED_UPDATE_INTERVAL', 140 | const.UPDATE_INTERVAL)), 141 | 'max_entries': int(os.environ.get('MAX_ENTRIES', 142 | const.DEFAULT_MAX_ENTRIES))}) 143 | return conf 144 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/lambda_function.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2020 Juniper Networks, Inc., All Rights Reserved. 2 | 3 | """Extracts remote IPs from GuardDuty events and writes them to configured 4 | S3 file or send to SkyATP using Open API's 5 | """ 6 | import logging 7 | import time 8 | 9 | from gd_threatfeed import constants as const 10 | from gd_threatfeed import utils 11 | from gd_threatfeed import s3_utils 12 | from gd_threatfeed import feed_utils 13 | from gd_threatfeed import errors 14 | from gd_threatfeed.openapi_client import OpenAPIClient 15 | 16 | __author__ = 'Juniper Networks' 17 | 18 | 19 | def _log_response_message(status: int, resp: dict): 20 | if status == 429: 21 | logging.warning('Too many requests in a given amount of time, API ' 22 | 'quota exceeded') 23 | elif status == 202: 24 | logging.info('Successfully sent request to OpenAPI and response ' 25 | 'is : %s', resp) 26 | else: 27 | logging.error('Failed to process the feed content status code %d and ' 28 | 'response %s', status, resp) 29 | 30 | 31 | def lambda_handler(event, _): 32 | """ 33 | Lambda handler for events generated by Guardduty 34 | """ 35 | log = logging.getLogger() 36 | log.setLevel(logging.INFO) 37 | log.debug("Received event: %s", event) 38 | start_ts = int(time.time()) 39 | log.info(" Startedfeed processing for event with finding id %s", 40 | event['detail']['id']) 41 | 42 | action_info = event['detail']['service']['action'] 43 | path, ftype = const.ACTIONS_PATH.get(action_info['actionType']) 44 | 45 | conf = utils.get_lambda_config() 46 | conf['feed_type'] = ftype 47 | 48 | if not utils.validate_args(conf) or not utils.validate_event(event, ftype, 49 | conf): 50 | log.error("Skipping to process the feed due to specified config") 51 | return 52 | 53 | res = utils.get_event_details(action_info, path, ftype) 54 | if not res: 55 | log.info("Skipping to process the feed as feed content is empty") 56 | return 57 | 58 | if conf.get('base_url', None): 59 | log.info("Configured Lambda to send feed to SkyATP") 60 | try: 61 | client = OpenAPIClient(base_url=conf['base_url'], 62 | token=conf['token']) 63 | body = '\n'.join(['{},{}'.format(v[1], v[-1]) for v in res]) 64 | if ftype == const.IP_ADDR and conf['ip_feed'] and body: 65 | resp, status = client.upload_custom_feed( 66 | feed_type=const.IP_FEED, feed_name=conf['ip_feed'], 67 | feed_content=body) 68 | _log_response_message(status, resp) 69 | 70 | elif ftype == const.DOMAIN and conf['dns_feed'] and body: 71 | resp, status = client.upload_custom_feed( 72 | feed_type=const.DNS_FEED, feed_name=conf['dns_feed'], 73 | feed_content=body) 74 | _log_response_message(status, resp) 75 | 76 | else: 77 | raise errors.CloudFeedsError('Invalid params') 78 | except errors.CloudFeedsError as err: 79 | log.error("Failed to upload feed to SkyATP with error : %s", str(err)) 80 | else: 81 | log.info("Configured Lambda to send feed to customer S3 bucket") 82 | try: 83 | if conf['ip_feed'] and conf['dns_feed']: 84 | ips, dns = (res, set()) if ftype == const.IP_ADDR else (set(), 85 | res) 86 | ip_feed = feed_utils.publish_object(category='CC', 87 | feed_name=conf['ip_feed'], 88 | feed_type=const.IP_ADDR, 89 | in_data=ips, 90 | conf=conf) 91 | dns_feed = feed_utils.publish_object(category='CC', 92 | feed_name=conf['dns_feed'], 93 | feed_type=const.DOMAIN, 94 | in_data=dns, 95 | conf=conf) 96 | feeds = [ip_feed, dns_feed] 97 | else: 98 | fname = conf['ip_feed'] or conf['dns_feed'] 99 | ftype = const.IP_ADDR if const.IP_FEED else const.DOMAIN 100 | feed = feed_utils.publish_object(category='CC', feed_name=fname, 101 | feed_type=ftype, in_data=res, 102 | conf=conf) 103 | feeds = [feed] 104 | manifest_xml = feed_utils.create_manifest(feeds, conf) 105 | s3_utils.upload_data_to_s3(conf['bucket'], 106 | manifest_xml, const.MANIFEST_FILE_NAME) 107 | except errors.CloudFeedsError as err: 108 | log.error("Failed to upload feed to customer S3 bucket with " 109 | "error : %s", str(err)) 110 | log.info("Completed feed processing for event with finding id %s and time " 111 | "taken to process the feed %d seconds", event['detail']['id'], 112 | int(time.time()) - start_ts) 113 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.21.0 2 | jsonschema==3.2.0 3 | -------------------------------------------------------------------------------- /SRX-GD-Threatfeed/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright © 2020 Juniper Networks, Inc., All Rights Reserved. 2 | 3 | from setuptools import setup, find_packages 4 | 5 | 6 | with open('README.md') as f: 7 | readme = f.read() 8 | 9 | with open('LICENSE') as f: 10 | license = f.read() 11 | 12 | install_requires = [ 13 | 'requests==2.21.0', 14 | 'jsonschema==3.2.0' 15 | ] 16 | 17 | setup( 18 | name='guardduty', 19 | version='0.1.0', 20 | description='GuardDuty Package', 21 | long_description=readme, 22 | author='Juniper Cloud Security Services', 23 | author_email='secint-aws-guardduty@juniper.net', 24 | license=license, 25 | packages=find_packages(exclude=('tests', )), 26 | install_requires=install_requires, 27 | ) 28 | 29 | -------------------------------------------------------------------------------- /TGW-Transit-VPC/Juniper vSRX TGW.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juniper/vSRX-AWS/4d6c7fd198c78fb89b533fdbfc9e68e07e18d1e8/TGW-Transit-VPC/Juniper vSRX TGW.pptx -------------------------------------------------------------------------------- /TGW-Transit-VPC/Readme.md: -------------------------------------------------------------------------------- 1 | AWS Transit GW based TVPC Solution 2 | 3 | Installing Terraform 4 | 5 | If Terraform 0.11.x is not already installed, use the following instructions: 6 | 7 | sudo apt-get install unzip 8 | sudo mkdir /bin/terraform 9 | 10 | sudo curl -O https://releases.hashicorp.com/terraform/0.11.13/terraform_0.11.13_linux_amd64.zip 11 | sudo unzip terraform_0.11.13_linux_amd64.zip -d /bin/terraform 12 | 13 | export PATH=$PATH:/bin/terraform 14 | Deployment Instructions 15 | 16 | Review/override variables in main.tf 17 | 18 | DO NOT CHANGE 19 | 20 | primary_region = 0 21 | cf_template = "lambda.template" 22 | MAY CHANGE 23 | 24 | region = "us-east-1" 25 | ami_name_filter = "*srx*18.4R1.8--pm*" 26 | CHANGE - Provide path to public SSH key 27 | 28 | public_key_path = "./akbhat_transit_vsrx.pub" 29 | Initialize Terraform providers: 30 | 31 | terraform init 32 | - Found version 1.58.0 of terraform-aws-modules/vpc/aws on registry.terraform.io 33 | - Found version 1.19.0 of terraform-aws-modules/ec2-instance/aws on registry.terraform.io 34 | - Downloading plugin for provider "aws" (2.4.0)... 35 | - Downloading plugin for provider "template" (2.1.0)... 36 | 37 | Run Terraform plan to ensure there are no errors: 38 | 39 | terraform plan 40 | Deploy the template to AWS: 41 | 42 | terraform apply -auto-approve 43 | NOTE: This module provisions two spoke VPCs alongwith EC2 instances, attaches them to the TGW for testing purposes 44 | 45 | Destroy all the deployed resources: 46 | 47 | terraform destroy 48 | -------------------------------------------------------------------------------- /TGW-Transit-VPC/bogus.template: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters" : { 3 | "bogus" : { 4 | "Description" : "Bogus parameter", 5 | "Type" : "String" 6 | } 7 | }, 8 | "Conditions" : { 9 | "AlwaysFalse" : { 10 | "Fn::Equals" : ["true", "false"] 11 | } 12 | }, 13 | "Resources" : { 14 | "MyInstance" : { 15 | "Type" : "AWS::EC2::Instance", 16 | "Condition" : "AlwaysFalse", 17 | "Properties" : { 18 | "AvailabilityZone" : "us-east-1a", 19 | "ImageId" : "ami-7fd4e10b" 20 | } 21 | } 22 | }, 23 | "Outputs" : { 24 | "VSRXPUBKEY" : { 25 | "Description" : "vSRX Lambda SSH Public Key", 26 | "Value" : "DELETE" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /TGW-Transit-VPC/main.tf: -------------------------------------------------------------------------------- 1 | #data "aws_region" "current" {} 2 | 3 | #terraform { 4 | # backend "s3" { 5 | # bucket = "akbhat-transit-gw-solution" 6 | # key = "akbhat/tvpc/terraform.tfstate" 7 | # region = "us-east-1" 8 | # } 9 | #} 10 | 11 | #data "terraform_remote_state" "aws_tvpc_global" { 12 | # backend = "s3" 13 | # config { 14 | # region = "us-east-1" 15 | # bucket = "akbhat-transit-gw-solution" 16 | # key = "akbhat/terraform/tvpc/terraform.tfstate" 17 | # } 18 | #} 19 | 20 | module "tvpc-us-east-1" { 21 | source = "./tvpc" 22 | primary_region = 1 23 | public_key_path = "./akbhat_transit_vsrx.pub" 24 | cf_template = "lambda.template" 25 | # region = "${var.primary_region_with_lambdas}" 26 | region = "us-east-1" 27 | # ami_name_filter = "*junos-vsrx3-x86-64-19.1R1.6-std--pm.img" 28 | ami_name_filter = "*srx*18.4R1.8--pm*" 29 | } 30 | 31 | module "tvpc-us-west-2" { 32 | source = "./tvpc" 33 | primary_region = 0 34 | public_key_path = "./akbhat_transit_vsrx.pub" 35 | region = "us-west-2" 36 | # ami_name_filter = "*junos-vsrx3-x86-64-19.1R1.6-std--pm.img" 37 | spoke_vpc1_cidr = "10.170.0.0/16" 38 | spoke_vpc1_subnet = "10.170.2.0/24" 39 | spoke_vpc2_cidr = "10.180.0.0/16" 40 | spoke_vpc2_subnet = "10.180.2.0/24" 41 | } 42 | -------------------------------------------------------------------------------- /TGW-Transit-VPC/tvpc/README.md: -------------------------------------------------------------------------------- 1 | Module to create Transit VPC alongwith Transit Gateway 2 | -------------------------------------------------------------------------------- /TGW-Transit-VPC/tvpc/compute.tf: -------------------------------------------------------------------------------- 1 | data "aws_ami" "vsrx3_ami" { 2 | most_recent = true 3 | owners = ["679593333241", "298183613488"] 4 | 5 | filter { 6 | name = "name" 7 | values = ["${var.ami_name_filter}"] 8 | } 9 | } 10 | 11 | resource "aws_eip" "vsrx1_data_eip" { 12 | vpc = true 13 | } 14 | 15 | resource "aws_eip" "vsrx2_data_eip" { 16 | vpc = true 17 | } 18 | 19 | resource "aws_eip" "vSRXEip12" { 20 | vpc = true 21 | } 22 | 23 | resource "aws_eip" "vSRXEip22" { 24 | vpc = true 25 | } 26 | 27 | # vSRX1 management public IP address 28 | resource "aws_eip_association" "mgmt_eip_assoc_vsrx1" { 29 | network_interface_id = "${aws_network_interface.vSRXInterface11.id}" 30 | allocation_id = "${aws_eip.vSRXEip12.id}" 31 | 32 | depends_on = ["aws_internet_gateway.igw"] 33 | } 34 | 35 | # vSRX2 management public IP address 36 | resource "aws_eip_association" "mgmt_eip_assoc_vsrx2" { 37 | network_interface_id = "${aws_network_interface.vSRXInterface21.id}" 38 | allocation_id = "${aws_eip.vSRXEip22.id}" 39 | 40 | depends_on = ["aws_internet_gateway.igw"] 41 | } 42 | 43 | # These are assigned to the vSRX if load balancing is disabled 44 | # In case of LB, these IPs are assigned directly to the NLB 45 | # TODO: When NLB supports IPSec 46 | resource "aws_eip_association" "data_eip_assoc_vsrx1" { 47 | # count = "${1 - var.enable_load_balancing}" 48 | network_interface_id = "${aws_network_interface.vSRXInterface12.id}" 49 | allocation_id = "${aws_eip.vsrx1_data_eip.id}" 50 | 51 | depends_on = ["aws_internet_gateway.igw"] 52 | } 53 | 54 | resource "aws_eip_association" "data_eip_assoc_vsrx2" { 55 | # count = "${1 - var.enable_load_balancing}" 56 | network_interface_id = "${aws_network_interface.vSRXInterface22.id}" 57 | allocation_id = "${aws_eip.vsrx2_data_eip.id}" 58 | 59 | depends_on = ["aws_internet_gateway.igw"] 60 | } 61 | 62 | resource "aws_key_pair" "vsrx_key" { 63 | key_name = "vsrx-key" 64 | public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDW3fBHRMTQ3CUxWUnYD2XmjNjO8J6T038rYqjzUCNTYbWWCbH9sfdBu/GJpnh207hEB+PzRpKJnhsvPogb/wNNi0KzarWoUPKtqt0VQkpZg4fsIUcscyFiR3cb9pzKR4UOJzQo7ZTO0ulKqFeyrmDHM89bFMcC6ATz5lIvO5ZNukdtZ1+gnKqTLMoq8VcPYIllnOFNTiEpQyr+COmLMjNN7CVRqCmAo0vIw2mNZpA2hk/Nmstv7gxEGch2VNdJw6nOIaO9XXX+DcJagPoyJsjeuVb0yKi/DmEgPTZXhAsZ9Sgv8/pdj0vDf3O/G2LelohJ315q1p5h4pL2HGbVrnbf akbhat@ubuntu" 65 | } 66 | 67 | data "template_file" "vsrx3-conf1" { 68 | # count = "${1 - var.enable_auto_scaling}" 69 | template = "${file("vsrx3-init4.tpl")}" 70 | 71 | vars { 72 | SshPublicKey = "${trimspace("${file(var.public_key_path)}")}" 73 | PrimaryPrivateMgmtIpAddress = "${element(aws_network_interface.vSRXInterface12.private_ips,0)}" 74 | PrimaryPrivateIngressIpAddress = "${element(aws_network_interface.vSRXInterface13.private_ips,0)}" 75 | PrimaryPrivateEgressIpAddress = "${element(aws_network_interface.vSRXInterface14.private_ips,0)}" 76 | # LambdaSshPublicKey = "${var.primary_region ? format("%s %s", "ssh-rsa",aws_cloudformation_stack.lambdas.outputs["VSRXPUBKEY"]) : file(var.public_key_path)}" 77 | LambdaSshPublicKey = "${var.primary_region ? format("%s %s", "ssh-rsa",aws_cloudformation_stack.lambdas.outputs["VSRXPUBKEY"]) : "ssh-rsa SAFETODELETE"}" 78 | } 79 | } 80 | 81 | data "template_file" "vsrx3-conf2" { 82 | # count = "${1 - var.enable_auto_scaling}" 83 | template = "${file("vsrx3-init4.tpl")}" 84 | 85 | vars { 86 | SshPublicKey = "${trimspace("${file(var.public_key_path)}")}" 87 | PrimaryPrivateMgmtIpAddress = "${element(aws_network_interface.vSRXInterface22.private_ips,0)}" 88 | PrimaryPrivateIngressIpAddress = "${element(aws_network_interface.vSRXInterface23.private_ips,0)}" 89 | PrimaryPrivateEgressIpAddress = "${element(aws_network_interface.vSRXInterface24.private_ips,0)}" 90 | LambdaSshPublicKey = "${var.primary_region ? format("%s %s", "ssh-rsa",aws_cloudformation_stack.lambdas.outputs["VSRXPUBKEY"]) : trimspace(file(var.public_key_path))}" 91 | } 92 | } 93 | 94 | resource "aws_instance" "VpcvSRX1" { 95 | # count = "${1 - var.enable_auto_scaling}" 96 | ami = "${data.aws_ami.vsrx3_ami.id}" 97 | ebs_optimized = true 98 | instance_type = "c4.xlarge" 99 | # key_name = "${aws_key_pair.vsrx_key.key_name}" 100 | disable_api_termination = false 101 | 102 | network_interface { 103 | network_interface_id = "${aws_network_interface.vSRXInterface11.id}" 104 | device_index = 0 105 | } 106 | network_interface { 107 | network_interface_id = "${aws_network_interface.vSRXInterface12.id}" 108 | device_index = 1 109 | } 110 | network_interface { 111 | network_interface_id = "${aws_network_interface.vSRXInterface13.id}" 112 | device_index = 2 113 | } 114 | network_interface { 115 | network_interface_id = "${aws_network_interface.vSRXInterface14.id}" 116 | device_index = 3 117 | } 118 | 119 | user_data_base64 = "${base64encode(data.template_file.vsrx3-conf1.rendered)}" 120 | # primary_network_interface_id = 121 | 122 | depends_on = ["aws_internet_gateway.igw"] 123 | 124 | lifecycle { create_before_destroy = true } 125 | 126 | tags = { 127 | Name = "Transit VPC VSRX1" 128 | } 129 | } 130 | 131 | resource "aws_instance" "VpcvSRX2" { 132 | # count = "${1 - var.enable_auto_scaling}" 133 | ami = "${data.aws_ami.vsrx3_ami.id}" 134 | ebs_optimized = true 135 | instance_type = "c4.xlarge" 136 | # key_name = "${aws_key_pair.vsrx_key.key_name}" 137 | disable_api_termination = false 138 | 139 | network_interface { 140 | network_interface_id = "${aws_network_interface.vSRXInterface21.id}" 141 | device_index = 0 142 | } 143 | network_interface { 144 | network_interface_id = "${aws_network_interface.vSRXInterface22.id}" 145 | device_index = 1 146 | } 147 | network_interface { 148 | network_interface_id = "${aws_network_interface.vSRXInterface23.id}" 149 | device_index = 2 150 | } 151 | network_interface { 152 | network_interface_id = "${aws_network_interface.vSRXInterface24.id}" 153 | device_index = 3 154 | } 155 | 156 | user_data = "${base64encode(data.template_file.vsrx3-conf2.rendered)}" 157 | # primary_network_interface_id = 158 | 159 | depends_on = ["aws_internet_gateway.igw"] 160 | 161 | lifecycle { create_before_destroy = true } 162 | 163 | tags = { 164 | Name = "Transit VPC VSRX2" 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /TGW-Transit-VPC/tvpc/eni.tf: -------------------------------------------------------------------------------- 1 | ################ Additional Data Subnets ###################### 2 | resource "aws_subnet" "VPCPubSub11" { 3 | vpc_id = "${aws_vpc.tvpc.id}" 4 | cidr_block = "${var.pub_mgmt_subnet_az1}" 5 | availability_zone = "${data.aws_availability_zones.available.names[0]}" 6 | } 7 | 8 | resource "aws_subnet" "VPCPubSub12" { 9 | vpc_id = "${aws_vpc.tvpc.id}" 10 | cidr_block = "${var.pub_data_subnet_az1}" 11 | availability_zone = "${data.aws_availability_zones.available.names[0]}" 12 | } 13 | 14 | resource "aws_subnet" "VPCPubSub21" { 15 | vpc_id = "${aws_vpc.tvpc.id}" 16 | cidr_block = "${var.pub_mgmt_subnet_az2}" 17 | availability_zone = "${data.aws_availability_zones.available.names[1]}" 18 | } 19 | 20 | resource "aws_subnet" "VPCPubSub22" { 21 | vpc_id = "${aws_vpc.tvpc.id}" 22 | cidr_block = "${var.pub_data_subnet_az2}" 23 | availability_zone = "${data.aws_availability_zones.available.names[1]}" 24 | } 25 | 26 | resource "aws_subnet" "vsrx1_data_subnet2" { 27 | vpc_id = "${aws_vpc.tvpc.id}" 28 | cidr_block = "10.10.50.0/24" 29 | availability_zone = "${data.aws_availability_zones.available.names[0]}" 30 | } 31 | 32 | resource "aws_subnet" "vsrx2_data_subnet2" { 33 | vpc_id = "${aws_vpc.tvpc.id}" 34 | cidr_block = "10.10.60.0/24" 35 | availability_zone = "${data.aws_availability_zones.available.names[1]}" 36 | } 37 | 38 | resource "aws_subnet" "vsrx1_data_subnet3" { 39 | vpc_id = "${aws_vpc.tvpc.id}" 40 | cidr_block = "10.10.70.0/24" 41 | availability_zone = "${data.aws_availability_zones.available.names[0]}" 42 | } 43 | 44 | resource "aws_subnet" "vsrx2_data_subnet3" { 45 | vpc_id = "${aws_vpc.tvpc.id}" 46 | cidr_block = "10.10.80.0/24" 47 | availability_zone = "${data.aws_availability_zones.available.names[1]}" 48 | } 49 | 50 | resource "aws_route_table_association" "VSRX1IngressSubnet" { 51 | subnet_id = "${aws_subnet.vsrx1_data_subnet2.id}" 52 | route_table_id = "${aws_route_table.VPCIngressTGWRouteTable.id}" 53 | } 54 | 55 | resource "aws_route_table_association" "VSRX2IngressSubnet" { 56 | subnet_id = "${aws_subnet.vsrx2_data_subnet2.id}" 57 | route_table_id = "${aws_route_table.VPCIngressTGWRouteTable.id}" 58 | } 59 | 60 | resource "aws_route_table_association" "VSRX1EgressSubnet" { 61 | subnet_id = "${aws_subnet.vsrx1_data_subnet3.id}" 62 | route_table_id = "${aws_route_table.VPCEgressTGWRouteTable.id}" 63 | } 64 | 65 | resource "aws_route_table_association" "VSRX2EgressSubnet" { 66 | subnet_id = "${aws_subnet.vsrx2_data_subnet3.id}" 67 | route_table_id = "${aws_route_table.VPCEgressTGWRouteTable.id}" 68 | } 69 | 70 | resource "aws_network_interface" "vSRXInterface11" { 71 | subnet_id = "${aws_subnet.VPCPubSub11.id}" 72 | source_dest_check = false 73 | # security_groups = ["${aws_cloudformation_stack.lambdas.outputs["VSRXSecurityGroup"]}"] 74 | security_groups = ["${aws_security_group.VSRXSecurityGroup.id}"] 75 | } 76 | 77 | resource "aws_network_interface" "vSRXInterface12" { 78 | subnet_id = "${aws_subnet.VPCPubSub12.id}" 79 | source_dest_check = false 80 | security_groups = ["${aws_security_group.VSRXSecurityGroup.id}"] 81 | } 82 | 83 | resource "aws_network_interface" "vSRXInterface13" { 84 | subnet_id = "${aws_subnet.vsrx1_data_subnet2.id}" 85 | source_dest_check = false 86 | security_groups = ["${aws_security_group.VSRXSecurityGroup.id}"] 87 | } 88 | 89 | resource "aws_network_interface" "vSRXInterface14" { 90 | subnet_id = "${aws_subnet.vsrx1_data_subnet3.id}" 91 | source_dest_check = false 92 | security_groups = ["${aws_security_group.VSRXSecurityGroup.id}"] 93 | } 94 | 95 | resource "aws_network_interface" "vSRXInterface21" { 96 | subnet_id = "${aws_subnet.VPCPubSub21.id}" 97 | source_dest_check = false 98 | security_groups = ["${aws_security_group.VSRXSecurityGroup.id}"] 99 | } 100 | 101 | resource "aws_network_interface" "vSRXInterface22" { 102 | subnet_id = "${aws_subnet.VPCPubSub22.id}" 103 | source_dest_check = false 104 | security_groups = ["${aws_security_group.VSRXSecurityGroup.id}"] 105 | } 106 | 107 | resource "aws_network_interface" "vSRXInterface23" { 108 | subnet_id = "${aws_subnet.vsrx2_data_subnet2.id}" 109 | source_dest_check = false 110 | security_groups = ["${aws_security_group.VSRXSecurityGroup.id}"] 111 | } 112 | 113 | resource "aws_network_interface" "vSRXInterface24" { 114 | subnet_id = "${aws_subnet.vsrx2_data_subnet3.id}" 115 | source_dest_check = false 116 | security_groups = ["${aws_security_group.VSRXSecurityGroup.id}"] 117 | } 118 | 119 | ##### TVPC Ingress and Egress RT 120 | resource "aws_route_table" "VPCIngressTGWRouteTable" { 121 | vpc_id = "${aws_vpc.tvpc.id}" 122 | 123 | route { 124 | cidr_block = "0.0.0.0/0" 125 | network_interface_id = "${aws_network_interface.vSRXInterface13.id}" 126 | } 127 | } 128 | 129 | resource "aws_route_table" "VPCEgressTGWRouteTable" { 130 | vpc_id = "${aws_vpc.tvpc.id}" 131 | 132 | route { 133 | cidr_block = "0.0.0.0/0" 134 | transit_gateway_id = "${aws_ec2_transit_gateway.tvpc_tgw.id}" 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /TGW-Transit-VPC/tvpc/lambda.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | parameters = { 3 | SshPublicKey = "${file(var.public_key_path)}" 4 | JuniperConfigSecurityGroup = "${aws_security_group.JuniperConfigSecurityGroup.id}" 5 | AllowedSshIpAddress = "${var.allowed_ssh_ipadd}" 6 | TerminationProtection = "${var.enable_term_protection}" 7 | TransitVPC = "${aws_vpc.tvpc.id}" 8 | VPCPubSub11 = "${aws_subnet.VPCPubSub11.id}" 9 | vSRXInterface11PvtIP = "${element(aws_network_interface.vSRXInterface11.private_ips,0)}" 10 | VPCPubSub21 = "${aws_subnet.VPCPubSub21.id}" 11 | vSRXInterface21PvtIP = "${element(aws_network_interface.vSRXInterface21.private_ips,0)}" 12 | PubSubnet12 = "${var.pub_data_subnet_az1}" 13 | PubSubnet22 = "${var.pub_data_subnet_az2}" 14 | vSRXEip11 = "${aws_eip.vsrx1_data_eip.public_ip}" 15 | vSRXEip21 = "${aws_eip.vsrx2_data_eip.public_ip}" 16 | VSRXType = "${var.vsrx_ec2_type}" 17 | PreferredPathTag = "${var.preferred_path_tag}" 18 | SpokeTag = "${var.vpc_spoke_tag}" 19 | SpokeTagValue = "${var.vpc_spoke_tag_value}" 20 | BgpAsn = "${var.bgp_asn}" 21 | S3Prefix = "${var.s3_prefix_key_names}" 22 | AccountId = "${var.accountid}" 23 | } 24 | 25 | params = { 26 | bogus = "bogus" 27 | } 28 | } 29 | 30 | locals { 31 | keys = ["${split(",", var.primary_region ? join(",", keys(local.parameters)) : join(",", keys(local.params)))}"] 32 | values = ["${split(",", var.primary_region ? join(",", values(local.parameters)) : join(",", values(local.params)))}"] 33 | } 34 | 35 | resource "aws_cloudformation_stack" "lambdas" { 36 | name = "akbhat-transit-vpc-lambdas" 37 | capabilities = ["CAPABILITY_IAM"] 38 | 39 | # parameters = "${var.primary_region ? local.parameters : local.params}" 40 | parameters = "${zipmap(local.keys,local.values)}" 41 | # parameters = "${zipmap(coalescelist(local.keys),coalescelist(local.values))}" 42 | 43 | 44 | template_body = "${var.primary_region ? file(var.cf_template) : file("bogus.template")}" 45 | 46 | timeouts { 47 | create = "5m" 48 | delete = "5m" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /TGW-Transit-VPC/tvpc/sg.tf: -------------------------------------------------------------------------------- 1 | data "aws_prefix_list" "private_s3" { 2 | prefix_list_id = "${aws_vpc_endpoint.private_s3.prefix_list_id}" 3 | } 4 | 5 | #TODO: S3 VPC endpoint already in main.tf 6 | resource "aws_vpc_endpoint" "private_s3" { 7 | vpc_id = "${aws_vpc.tvpc.id}" 8 | service_name = "com.amazonaws.${var.region}.s3" 9 | } 10 | 11 | resource "aws_security_group" "VSRXSecurityGroup" { 12 | name = "TVPC vSRX SSH & ICMP" 13 | description = "Allow SSH & ICMP traffic" 14 | vpc_id = "${aws_vpc.tvpc.id}" 15 | 16 | ingress { 17 | from_port = 22 18 | to_port = 22 19 | protocol = "tcp" 20 | cidr_blocks = ["${var.allowed_ssh_ipadd}"] 21 | } 22 | 23 | ingress { 24 | from_port = "-1" 25 | to_port = "-1" 26 | protocol = "icmp" 27 | cidr_blocks = ["${var.allowed_ssh_ipadd}"] 28 | } 29 | 30 | egress { 31 | from_port = 0 32 | to_port = 0 33 | protocol = "-1" 34 | cidr_blocks = ["0.0.0.0/0"] 35 | } 36 | } 37 | 38 | resource "aws_security_group" "JuniperConfigSecurityGroup" { 39 | name = "TVPC Automation SG Rules" 40 | description = "Transit VPC Automation Security Group Rules" 41 | vpc_id = "${aws_vpc.tvpc.id}" 42 | } 43 | 44 | resource "aws_security_group_rule" "SSHtoVSRXSecurityGroup" { 45 | type = "ingress" 46 | from_port = 22 47 | to_port = 22 48 | protocol = "tcp" 49 | 50 | source_security_group_id = "${aws_security_group.JuniperConfigSecurityGroup.id}" 51 | security_group_id = "${aws_security_group.VSRXSecurityGroup.id}" 52 | } 53 | 54 | resource "aws_security_group_rule" "SSHtoVSRX" { 55 | type = "egress" 56 | from_port = 22 57 | to_port = 22 58 | protocol = "tcp" 59 | source_security_group_id = "${aws_security_group.VSRXSecurityGroup.id}" 60 | security_group_id = "${aws_security_group.JuniperConfigSecurityGroup.id}" 61 | } 62 | 63 | resource "aws_security_group_rule" "HTTPSToVPCEndpoint" { 64 | type = "egress" 65 | to_port = 443 66 | from_port = 443 67 | protocol = "tcp" 68 | prefix_list_ids = ["${aws_vpc_endpoint.private_s3.prefix_list_id}"] 69 | security_group_id = "${aws_security_group.JuniperConfigSecurityGroup.id}" 70 | } 71 | -------------------------------------------------------------------------------- /TGW-Transit-VPC/tvpc/spoke.tf: -------------------------------------------------------------------------------- 1 | #provider "aws" { 2 | # region = "us-east-1" 3 | #} 4 | #provider "aws" { 5 | # alias = "eu-central-1" 6 | # region = "eu-central-1" 7 | #} 8 | #module "vpc_ireland" { 9 | # ... 10 | #} 11 | #module "vpc_frankfurt" { 12 | # providers { 13 | # aws = "aws.eu-central-1" 14 | # } 15 | # ... 16 | #} 17 | 18 | resource "aws_security_group" "allow_ssh_icmp_spoke1" { 19 | name = "allow_ssh_icmp" 20 | description = "Allow SSH & ICMP inbound traffic" 21 | vpc_id = "${module.spoke_vpc1.vpc_id}" 22 | 23 | ingress { 24 | from_port = 22 25 | to_port = 22 26 | protocol = "TCP" 27 | cidr_blocks = ["66.129.239.8/29"] 28 | } 29 | 30 | ingress { 31 | from_port = -1 32 | to_port = -1 33 | protocol = "ICMP" 34 | cidr_blocks = ["10.0.0.0/8"] 35 | } 36 | 37 | egress { 38 | from_port = 0 39 | to_port = 0 40 | protocol = "-1" 41 | cidr_blocks = ["0.0.0.0/0"] 42 | } 43 | } 44 | 45 | resource "aws_security_group" "allow_ssh_icmp_spoke2" { 46 | name = "allow_ssh_icmp" 47 | description = "Allow SSH & ICMP inbound traffic" 48 | vpc_id = "${module.spoke_vpc2.vpc_id}" 49 | 50 | ingress { 51 | from_port = 22 52 | to_port = 22 53 | protocol = "TCP" 54 | cidr_blocks = ["66.129.239.8/29"] 55 | } 56 | 57 | ingress { 58 | from_port = -1 59 | to_port = -1 60 | protocol = "ICMP" 61 | cidr_blocks = ["10.0.0.0/8"] 62 | } 63 | 64 | egress { 65 | from_port = 0 66 | to_port = 0 67 | protocol = "-1" 68 | cidr_blocks = ["0.0.0.0/0"] 69 | } 70 | } 71 | 72 | resource "aws_key_pair" "deployer" { 73 | key_name = "akbhat_transit_vsrx" 74 | public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDW3fBHRMTQ3CUxWUnYD2XmjNjO8J6T038rYqjzUCNTYbWWCbH9sfdBu/GJpnh207hEB+PzRpKJnhsvPogb/wNNi0KzarWoUPKtqt0VQkpZg4fsIUcscyFiR3cb9pzKR4UOJzQo7ZTO0ulKqFeyrmDHM89bFMcC6ATz5lIvO5ZNukdtZ1+gnKqTLMoq8VcPYIllnOFNTiEpQyr+COmLMjNN7CVRqCmAo0vIw2mNZpA2hk/Nmstv7gxEGch2VNdJw6nOIaO9XXX+DcJagPoyJsjeuVb0yKi/DmEgPTZXhAsZ9Sgv8/pdj0vDf3O/G2LelohJ315q1p5h4pL2HGbVrnbf akbhat@ubuntu" 75 | } 76 | 77 | module "spoke_vpc1" { 78 | source = "terraform-aws-modules/vpc/aws" 79 | version = "1.58.0" 80 | create_vpc = true 81 | 82 | name = "akbhat-spoke-vpc1" 83 | cidr = "${var.spoke_vpc1_cidr}" 84 | azs = ["${data.aws_availability_zones.available.names[0]}"] 85 | # private_subnets = ["10.150.1.0/24"] 86 | public_subnets = ["${var.spoke_vpc1_subnet}"] 87 | 88 | enable_nat_gateway = true 89 | # enable_vpn_gateway = true 90 | 91 | tags = { 92 | Owner = "akbhat" 93 | Environment = "dev" 94 | } 95 | } 96 | 97 | module "spoke_vpc2" { 98 | source = "terraform-aws-modules/vpc/aws" 99 | version = "1.58.0" 100 | create_vpc = true 101 | 102 | name = "akbhat-spoke-vpc2" 103 | cidr = "${var.spoke_vpc2_cidr}" 104 | 105 | azs = ["${data.aws_availability_zones.available.names[1]}"] 106 | # private_subnets = ["10.160.1.0/24"] 107 | public_subnets = ["${var.spoke_vpc2_subnet}"] 108 | 109 | enable_nat_gateway = true 110 | # enable_vpn_gateway = true 111 | 112 | tags = { 113 | Owner = "akbhat" 114 | Environment = "dev" 115 | } 116 | } 117 | 118 | data "aws_ami" "ubuntu_server" { 119 | most_recent = true 120 | owners = ["099720109477"] 121 | 122 | filter { 123 | name = "name" 124 | values = ["*ubuntu-xenial-16.04-amd64-server-20181114*"] 125 | } 126 | filter { 127 | name = "root-device-type" 128 | values = ["ebs"] 129 | } 130 | 131 | filter { 132 | name = "virtualization-type" 133 | values = ["hvm"] 134 | } 135 | } 136 | 137 | module "ec2_cluster_spoke1" { 138 | source = "terraform-aws-modules/ec2-instance/aws" 139 | version = "1.19.0" 140 | 141 | name = "vpc1-spoke" 142 | instance_count = 1 143 | 144 | ami = "${data.aws_ami.ubuntu_server.id}" 145 | instance_type = "t2.micro" 146 | key_name = "${aws_key_pair.deployer.key_name}" 147 | monitoring = true 148 | vpc_security_group_ids = ["${aws_security_group.allow_ssh_icmp_spoke1.id}"] 149 | subnet_id = "${element(module.spoke_vpc1.public_subnets, 0)}" 150 | associate_public_ip_address = true 151 | 152 | tags = { 153 | Owner = "akbhat" 154 | Environment = "dev" 155 | } 156 | } 157 | 158 | module "ec2_cluster_spoke2" { 159 | source = "terraform-aws-modules/ec2-instance/aws" 160 | version = "1.19.0" 161 | 162 | name = "vpc2-spoke" 163 | instance_count = 1 164 | 165 | # ami = "ami-0f9cf087c1f27d9b1" 166 | ami = "${data.aws_ami.ubuntu_server.id}" 167 | instance_type = "t2.micro" 168 | key_name = "${aws_key_pair.deployer.key_name}" 169 | monitoring = true 170 | vpc_security_group_ids = ["${aws_security_group.allow_ssh_icmp_spoke2.id}"] 171 | subnet_id = "${element(module.spoke_vpc2.public_subnets, 0)}" 172 | associate_public_ip_address = true 173 | 174 | tags = { 175 | Owner = "akbhat" 176 | Environment = "dev" 177 | } 178 | } 179 | 180 | # Ingress Route Table attachments 181 | resource "aws_ec2_transit_gateway_vpc_attachment" "spoke1" { 182 | subnet_ids = ["${module.spoke_vpc1.public_subnets}"] 183 | transit_gateway_id = "${aws_ec2_transit_gateway.tvpc_tgw.id}" 184 | vpc_id = "${module.spoke_vpc1.vpc_id}" 185 | transit_gateway_default_route_table_association = false 186 | transit_gateway_default_route_table_propagation = false 187 | } 188 | 189 | resource "aws_ec2_transit_gateway_vpc_attachment" "spoke2" { 190 | subnet_ids = ["${module.spoke_vpc2.public_subnets}"] 191 | transit_gateway_id = "${aws_ec2_transit_gateway.tvpc_tgw.id}" 192 | vpc_id = "${module.spoke_vpc2.vpc_id}" 193 | transit_gateway_default_route_table_association = false 194 | transit_gateway_default_route_table_propagation = false 195 | } 196 | 197 | resource "aws_ec2_transit_gateway_route_table_association" "spoke1" { 198 | transit_gateway_attachment_id = "${aws_ec2_transit_gateway_vpc_attachment.spoke1.id}" 199 | transit_gateway_route_table_id = "${aws_ec2_transit_gateway_route_table.ingress.id}" 200 | } 201 | 202 | resource "aws_ec2_transit_gateway_route_table_association" "spoke2" { 203 | transit_gateway_attachment_id = "${aws_ec2_transit_gateway_vpc_attachment.spoke2.id}" 204 | transit_gateway_route_table_id = "${aws_ec2_transit_gateway_route_table.ingress.id}" 205 | } 206 | 207 | resource "aws_ec2_transit_gateway_route_table_propagation" "spoke1_to_egress" { 208 | transit_gateway_attachment_id = "${aws_ec2_transit_gateway_vpc_attachment.spoke1.id}" 209 | transit_gateway_route_table_id = "${aws_ec2_transit_gateway_route_table.egress.id}" 210 | } 211 | 212 | resource "aws_ec2_transit_gateway_route_table_propagation" "spoke2_to_egress" { 213 | transit_gateway_attachment_id = "${aws_ec2_transit_gateway_vpc_attachment.spoke2.id}" 214 | transit_gateway_route_table_id = "${aws_ec2_transit_gateway_route_table.egress.id}" 215 | } 216 | 217 | # Default routes pointing to TGW 218 | resource "aws_route" "spoke_route_vpc1" { 219 | route_table_id = "${element(module.spoke_vpc1.public_route_table_ids,0)}" 220 | destination_cidr_block = "${var.spoke_vpc2_cidr}" 221 | transit_gateway_id = "${aws_ec2_transit_gateway.tvpc_tgw.id}" 222 | 223 | depends_on = ["aws_ec2_transit_gateway.tvpc_tgw"] 224 | } 225 | 226 | resource "aws_route" "spoke_route_vpc2" { 227 | route_table_id = "${element(module.spoke_vpc2.public_route_table_ids,0)}" 228 | destination_cidr_block = "${var.spoke_vpc1_cidr}" 229 | transit_gateway_id = "${aws_ec2_transit_gateway.tvpc_tgw.id}" 230 | 231 | depends_on = ["aws_ec2_transit_gateway.tvpc_tgw"] 232 | } 233 | -------------------------------------------------------------------------------- /TGW-Transit-VPC/tvpc/tgw.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ec2_transit_gateway" "tvpc_tgw" { 2 | description = "TVPC TGW" 3 | default_route_table_association = "disable" 4 | default_route_table_propagation = "disable" 5 | tags = { 6 | "transitvpc:spoke" = "false" 7 | } 8 | } 9 | 10 | resource "aws_ec2_transit_gateway_route_table" "ingress" { 11 | transit_gateway_id = "${aws_ec2_transit_gateway.tvpc_tgw.id}" 12 | tags = { 13 | Name = "Ingress RT" 14 | } 15 | } 16 | 17 | resource "aws_ec2_transit_gateway_route_table" "egress" { 18 | transit_gateway_id = "${aws_ec2_transit_gateway.tvpc_tgw.id}" 19 | tags = { 20 | Name = "Egress RT" 21 | } 22 | } 23 | 24 | resource "aws_ec2_transit_gateway_vpc_attachment" "tvpc_egress" { 25 | subnet_ids = ["${aws_subnet.vsrx1_data_subnet2.id}", 26 | "${aws_subnet.vsrx2_data_subnet2.id}"] 27 | transit_gateway_id = "${aws_ec2_transit_gateway.tvpc_tgw.id}" 28 | vpc_id = "${aws_vpc.tvpc.id}" 29 | transit_gateway_default_route_table_association = false 30 | transit_gateway_default_route_table_propagation = false 31 | } 32 | 33 | resource "aws_ec2_transit_gateway_route_table_association" "egress" { 34 | transit_gateway_attachment_id = "${aws_ec2_transit_gateway_vpc_attachment.tvpc_egress.id}" 35 | transit_gateway_route_table_id = "${aws_ec2_transit_gateway_route_table.egress.id}" 36 | } 37 | 38 | resource "aws_ec2_transit_gateway_route" "route_to_tvpc" { 39 | destination_cidr_block = "0.0.0.0/0" 40 | transit_gateway_attachment_id = "${aws_ec2_transit_gateway_vpc_attachment.tvpc_egress.id}" 41 | transit_gateway_route_table_id = "${aws_ec2_transit_gateway_route_table.ingress.id}" 42 | } 43 | -------------------------------------------------------------------------------- /TGW-Transit-VPC/tvpc/variables.tf: -------------------------------------------------------------------------------- 1 | variable "region" { 2 | default = "us-east-1" 3 | } 4 | variable "primary_region" {} 5 | 6 | variable "cf_template" { 7 | default = "lambda.template" 8 | } 9 | variable "public_key_path" {} 10 | 11 | variable "allowed_ssh_ipadd" { 12 | default = "0.0.0.0/0" 13 | } 14 | variable "enable_term_protection" { 15 | default = "No" 16 | } 17 | variable "vpc_cidr" { 18 | default = "10.10.0.0/16" 19 | } 20 | variable "pub_mgmt_subnet_az1" { 21 | default = "10.10.10.0/24" 22 | } 23 | variable "pub_mgmt_subnet_az2" { 24 | default = "10.10.20.0/24" 25 | } 26 | variable "pub_data_subnet_az1" { 27 | default = "10.10.30.0/24" 28 | } 29 | variable "pub_data_subnet_az2" { 30 | default = "10.10.40.0/24" 31 | } 32 | variable "vsrx_ec2_type" { 33 | default = "C5.large" 34 | } 35 | variable "ami_name_filter" { 36 | default = "*srx*18.4R1.8--pm*" 37 | } 38 | 39 | variable "preferred_path_tag" { 40 | default = "transitvpc:preferred-path" 41 | } 42 | variable "vpc_spoke_tag" { 43 | default = "transitvpc:spoke" 44 | } 45 | variable "vpc_spoke_tag_value" { 46 | default = "true" 47 | } 48 | variable "bgp_asn" { 49 | default = "64514" 50 | } 51 | variable "s3_prefix_key_names" { 52 | default = "vpnconfigs/" 53 | } 54 | variable "accountid" { 55 | default = "" 56 | } 57 | 58 | variable "spoke_vpc1_cidr" { 59 | default = "10.150.0.0/16" 60 | } 61 | 62 | variable "spoke_vpc1_subnet" { 63 | default = "10.150.2.0/24" 64 | } 65 | 66 | variable "spoke_vpc2_cidr" { 67 | default = "10.160.0.0/16" 68 | } 69 | 70 | variable "spoke_vpc2_subnet" { 71 | default = "10.160.2.0/24" 72 | } 73 | -------------------------------------------------------------------------------- /TGW-Transit-VPC/tvpc/vpc.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "${var.region}" 3 | } 4 | 5 | data "aws_availability_zones" "available" {} 6 | 7 | resource "aws_vpc" "tvpc" { 8 | cidr_block = "${var.vpc_cidr}" 9 | 10 | tags = { 11 | Name = "Transit VPC" 12 | } 13 | } 14 | 15 | resource "aws_internet_gateway" "igw" { 16 | vpc_id = "${aws_vpc.tvpc.id}" 17 | 18 | tags = { 19 | Name = "Transit VPC IGW" 20 | } 21 | } 22 | 23 | resource "aws_route_table" "VPCRouteTable" { 24 | vpc_id = "${aws_vpc.tvpc.id}" 25 | 26 | route { 27 | cidr_block = "0.0.0.0/0" 28 | gateway_id = "${aws_internet_gateway.igw.id}" 29 | } 30 | 31 | tags = { 32 | Name = "Transit VPC" 33 | } 34 | } 35 | 36 | resource "aws_route_table_association" "VPCPubSubnetRouteTableAssociation1" { 37 | subnet_id = "${aws_subnet.VPCPubSub11.id}" 38 | route_table_id = "${aws_route_table.VPCRouteTable.id}" 39 | } 40 | 41 | resource "aws_route_table_association" "VPCPubSubnetRouteTableAssociation2" { 42 | subnet_id = "${aws_subnet.VPCPubSub12.id}" 43 | route_table_id = "${aws_route_table.VPCRouteTable.id}" 44 | } 45 | 46 | resource "aws_route_table_association" "VPCPubSubnetRouteTableAssociation3" { 47 | subnet_id = "${aws_subnet.VPCPubSub21.id}" 48 | route_table_id = "${aws_route_table.VPCRouteTable.id}" 49 | } 50 | 51 | resource "aws_route_table_association" "VPCPubSubnetRouteTableAssociation4" { 52 | subnet_id = "${aws_subnet.VPCPubSub22.id}" 53 | route_table_id = "${aws_route_table.VPCRouteTable.id}" 54 | } 55 | 56 | resource "aws_vpc_endpoint" "s3" { 57 | vpc_id = "${aws_vpc.tvpc.id}" 58 | service_name = "com.amazonaws.${var.region}.s3" 59 | route_table_ids = ["${aws_route_table.VPCRouteTable.id}"] 60 | policy = <:root" 20 | ] 21 | }, 22 | "Action": [ 23 | "s3:GetObject", 24 | "s3:PutObject", 25 | "s3:PutObjectAcl" 26 | ], 27 | "Resource": "arn:aws:s3::://*" 28 | } 29 | ] 30 | } 31 | 32 | 33 | d) Go to the AWS Identity and Access Management (IAM) console, and in the left navigation pane, choose Encryption Keys. 34 | 35 | 36 | e) Choose the encryption key for this solution (You will see “Transit VPC” in the key description), and in the Key Policy section, choose Switch to policy view 37 | 38 | f) In the list of roles allowed to use the master key, add a new line (shown in bold font in the following code block) for each additional account ID: 39 | 40 | { 41 | "Sid": "Allow use of the key", 42 | "Effect": "Allow", 43 | "Principal": { 44 | "AWS": [ 45 | "arn:aws:iam:: :role/TransitVPC-TransitVpcPollerRole-[cloudformation-id]", 46 | "arn:aws:iam:: :role/TransitVPC-JuniperConfigFunctionRole-[cloudformation-id]", 47 | "arn:aws:iam:: :role/TransitVPC-LambdaLoaderRole-[cloudformation-id]", 48 | "arn:aws:iam:::root" 49 | ] 50 | }, 51 | 52 | 3) Create a CloudFormation stack (from the template downloaded in step 1) in your second account (from which you would like to connect Spoke VPCs). Make sure to fill in the “bucket name” field with the name of the bucket that was created when you first created the transit VPC solution in the primary account. 53 | 4) Tag the spoke VPC that needs to be connected with the appropriate key/value (same as the one that you used in your primary account) 54 | -------------------------------------------------------------------------------- /Transit-VPC/multi-account-deployment/transit-vpc-second-account.template: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description" : "(SO0001p) - Transit VPC: This template creates a TransitVPC poller function to find spoke VPCs to add to the transit network.", 4 | "Parameters" : { 5 | "BucketName" : { 6 | "Description" : "Name of the bucket used to store transit VPC configuration files.", 7 | "Type" : "String", 8 | "Default" : "transit-vpc" 9 | }, 10 | "BucketPrefix" : { 11 | "Description" : "S3 object prefix for storing VPN configuration.", 12 | "Type" : "String", 13 | "Default" : "vpnconfigs/" 14 | } 15 | }, 16 | "Mappings" : { 17 | "Function" : { 18 | "Poller" : { 19 | "CodeLocation" : "juniper-security/transit-vpc/transit-vpc-poller.py", 20 | "Name" : "vgw-poller", 21 | "Description": "Transit VPC: Poller function responsible for identifying specifically tagged VGWs and creating VPN connections to transit VPC.", 22 | "Runtime": "python2.7", 23 | "Timeout": "120", 24 | "MemorySize": "128" 25 | }, 26 | "FindReplace" : { 27 | "S3BucketID" : "%BUCKET_NAME%", 28 | "S3PrefixID" : "%PREFIX%", 29 | "Deliminator" : "|" 30 | } 31 | } 32 | }, 33 | "Resources": { 34 | "SolutionHelperRole": { 35 | "Type": "AWS::IAM::Role", 36 | "Properties": { 37 | "AssumeRolePolicyDocument": { 38 | "Version" : "2012-10-17", 39 | "Statement": [ { 40 | "Effect": "Allow", 41 | "Principal": { 42 | "Service": "lambda.amazonaws.com" 43 | }, 44 | "Action": "sts:AssumeRole" 45 | } ] 46 | }, 47 | "Path": "/", 48 | "Policies": [ { 49 | "PolicyName": "Solution_Helper_Permissions", 50 | "PolicyDocument": { 51 | "Version" : "2012-10-17", 52 | "Statement": [ 53 | { 54 | "Effect": "Allow", 55 | "Action": [ 56 | "logs:CreateLogGroup", 57 | "logs:CreateLogStream", 58 | "logs:PutLogEvents" 59 | ], 60 | "Resource": { "Fn::Join" : ["", ["arn:aws:logs:",{"Ref" : "AWS::Region"},":",{ "Ref" : "AWS::AccountId" }, ":log-group:/aws/lambda/*" ]]} 61 | }, 62 | { 63 | "Effect": "Allow", 64 | "Action": [ 65 | "lambda:*", 66 | "events:*", 67 | "iam:PassRole", 68 | "s3:GetObject", 69 | "s3:PutObject", 70 | "s3:DeleteObject", 71 | "s3:PutBucketNotification", 72 | "ec2:DescribeSecurityGroups", 73 | "ec2:DescribeSubnets" 74 | ], 75 | "Resource": "*" 76 | } 77 | ] 78 | } 79 | } ] 80 | } 81 | }, 82 | "SolutionHelper": { 83 | "Type": "AWS::Lambda::Function", 84 | "Properties": { 85 | "Handler": "solution-helper.lambda_handler", 86 | "Role": { "Fn::GetAtt" : [ "SolutionHelperRole" , "Arn" ] }, 87 | "Description": "Transit VPC: CloudFormation custom resource function invoked during transit VPC CloudFormation create, update, and delete stack operations.", 88 | "Code": { 89 | "S3Bucket": { "Fn::Join": ["", ["solutions-", {"Ref" : "AWS::Region"}]] }, 90 | "S3Key": "library/solution-helper/v2/solution-helper.zip" 91 | }, 92 | "Runtime": "python2.7", 93 | "Timeout": "60" 94 | } 95 | }, 96 | "TransitVpcPollerRole": { 97 | "Type": "AWS::IAM::Role", 98 | "Properties": { 99 | "AssumeRolePolicyDocument": { 100 | "Version" : "2012-10-17", 101 | "Statement": [ { 102 | "Effect": "Allow", 103 | "Principal": { 104 | "Service": "lambda.amazonaws.com" 105 | }, 106 | "Action": "sts:AssumeRole" 107 | } ] 108 | }, 109 | "Path": "/", 110 | "Policies": [ { 111 | "PolicyName": "My_Lambda_Function_Permissions", 112 | "PolicyDocument": { 113 | "Version" : "2012-10-17", 114 | "Statement": [ 115 | { 116 | "Effect": "Allow", 117 | "Action": [ 118 | "logs:CreateLogGroup", 119 | "logs:CreateLogStream", 120 | "logs:PutLogEvents" 121 | ], 122 | "Resource": { "Fn::Join" : ["", ["arn:aws:logs:",{"Ref" : "AWS::Region"},":",{ "Ref" : "AWS::AccountId" }, ":log-group:/aws/lambda/*" ]]} 123 | }, 124 | { 125 | "Effect": "Allow", 126 | "Action": [ 127 | "ec2:Describe*", 128 | "ec2:CreateTags", 129 | "ec2:CreateCustomerGateway", 130 | "ec2:DeleteCustomerGateway", 131 | "ec2:CreateVpnConnection", 132 | "ec2:DeleteVpnConnection" 133 | ], 134 | "Resource": "*" 135 | }, 136 | { 137 | "Effect": "Allow", 138 | "Action": [ 139 | "kms:Decrypt", 140 | "kms:GenerateDataKey*", 141 | "kms:Encrypt" 142 | ], 143 | "Resource": "*" 144 | }, 145 | { 146 | "Effect": "Allow", 147 | "Action": "s3:*", 148 | "Resource": "*" 149 | } 150 | ] 151 | } 152 | } ] 153 | } 154 | }, 155 | "PollerFunct": { 156 | "Type": "Custom::LoadLambda", 157 | "Properties": { 158 | "ServiceToken": { "Fn::GetAtt" : ["SolutionHelper", "Arn"] }, 159 | "Region": { "Ref": "AWS::Region" }, 160 | "LambdaCode": { "Fn::FindInMap" : [ "Function", "Poller", "CodeLocation"]}, 161 | "Deliminator": { "Fn::FindInMap" : [ "Function", "FindReplace", "Deliminator"]}, 162 | "FunctionName": { "Fn::Join": ["", [ { "Ref" : "AWS::StackName" }, "-", { "Fn::FindInMap" : [ "Function", "Poller", "Name"]} ]] }, 163 | "Role": { "Fn::GetAtt" : [ "TransitVpcPollerRole", "Arn" ] }, 164 | "CloudWatchEvent" : { "Fn::Join": ["", [ 165 | "{ 'RuleName' : '",{ "Ref" : "AWS::StackName" },"-VGW-Poller-1min', ", 166 | "'ScheduleExpression' : 'cron(* * * * ? *)',", 167 | "'Description': 'Transit VPC: Rule to trigger VGW-Poller every minute to find VGWs that need to be attached to the transit VPC.' }" 168 | ]] }, 169 | "Runtime": { "Fn::FindInMap" : [ "Function", "Poller", "Runtime"]}, 170 | "Description": { "Fn::FindInMap" : [ "Function", "Poller", "Description"]}, 171 | "Timeout": { "Fn::FindInMap" : [ "Function", "Poller", "Timeout"]}, 172 | "MemorySize": { "Fn::FindInMap" : [ "Function", "Poller", "MemorySize"]}, 173 | "FindReplace" : { "Fn::Join": ["", [ 174 | { "Fn::FindInMap" : [ "Function", "FindReplace", "S3BucketID"]}, 175 | { "Fn::FindInMap" : [ "Function", "FindReplace", "Deliminator"]}, 176 | { "Ref" : "BucketName" },",", 177 | { "Fn::FindInMap" : [ "Function", "FindReplace", "S3PrefixID"]}, 178 | { "Fn::FindInMap" : [ "Function", "FindReplace", "Deliminator"]}, 179 | { "Ref" : "BucketPrefix" } 180 | ]] } 181 | } 182 | } 183 | }, 184 | "Outputs" : { 185 | "PollerFunction" : { 186 | "Description" : "New Lambda function name.", 187 | "Value" : { "Fn::FindInMap" : [ "Function", "Poller", "Name"]} 188 | }, 189 | "PollerFunctionARN" : { 190 | "Description" : "ARN for new Lambda function.", 191 | "Value" : { "Fn::GetAtt" : [ "PollerFunct", "FunctionArn" ] } 192 | }, 193 | "PollerRoleARN" : { 194 | "Description" : "ARN for poller function role.", 195 | "Value" : { "Fn::GetAtt" : [ "TransitVpcPollerRole", "Arn" ] } 196 | } 197 | } 198 | } 199 | 200 | -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_asg_az/README.md: -------------------------------------------------------------------------------- 1 | # vSRX Deployement 2 | 3 | A CloudFormation template to depoy a vSRX in security VPC along with Gateway Load Balancer with Autoscaling group. This creates most of the resources needed to deploy the vSRX to handle the traffic from the Gateway load balancer. The vSRX is bootstrapped with minimal default config to allow the geneve traffic originating from the GWLB. This topolgy deploys resources in two AZ (User choice of AZ's as input). The application VPC can deply the Gateway load balancer endpoint and route traffic to the security VPC by adding the appropriate route entries. 4 | 5 | This template deploys the following resources 6 | 7 | * VPC 8 | * Internet Gateway IGW 9 | * Mgmt subnets 10 | * Data subnets 11 | * Bastion host 12 | * NAT GW 13 | * Route tables 14 | * Add route table entries 15 | * Lambda function 16 | * Gateway Load balancer 17 | * Target group and listener 18 | * Bootstrap vSRX through userData 19 | 20 | # Topology 21 | 22 | Security VPC topology 23 | 24 | ![Alt text](vsrx_aws_gwlb_asg_az.png?raw=true "Topology") -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_asg_az/vsrx_aws_gwlb_asg_az.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juniper/vSRX-AWS/4d6c7fd198c78fb89b533fdbfc9e68e07e18d1e8/vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_asg_az/vsrx_aws_gwlb_asg_az.png -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_asg_az_ns_ew/README.md: -------------------------------------------------------------------------------- 1 | # vSRX Deployement 2 | 3 | A CloudFormation template to depoy a vSRX in security VPC along with Gateway Load Balancer with Autoscaling group. This creates most of the resources needed to deploy the vSRX to handle the traffic from the Gateway load balancer. The vSRX is bootstrapped with minimal default config to allow the geneve traffic originating from the GWLB. This topolgy deploys resources in two AZ (User choice of AZ's as input) and creates a VPC attachment with TGW. 4 | 5 | This template deploys the following resources 6 | 7 | * VPC 8 | * Internet Gateway IGW 9 | * Mgmt subnet 10 | * Data subnet 11 | * Bastion host 12 | * NAT GW 13 | * Route tables 14 | * Add route table entries 15 | * Lambda function 16 | * Gateway Load balancer 17 | * Target group and listener 18 | * Bootstrap vSRX through userData 19 | * VPC attachment with TGW and route tables 20 | * Optional local config sync 21 | 22 | # Topology 23 | 24 | Refer to [AWS Centralized VPC](https://aws.amazon.com/blogs/networking-and-content-delivery/centralized-inspection-architecture-with-aws-gateway-load-balancer-and-aws-transit-gateway/) 25 | 26 | 27 | ![Alt text](vsrx_aws_gwlb_security_asg_az_ns_ew.png?raw=true "Topology") -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_asg_az_ns_ew/vsrx_aws_gwlb_security_asg_az_ns_ew.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juniper/vSRX-AWS/4d6c7fd198c78fb89b533fdbfc9e68e07e18d1e8/vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_asg_az_ns_ew/vsrx_aws_gwlb_security_asg_az_ns_ew.png -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_asg_no_az/README.md: -------------------------------------------------------------------------------- 1 | # vSRX Deployement 2 | 3 | A CloudFormation template to depoy a vSRX in security VPC along with Gateway Load Balancer with Autoscaling group. This creates most of the resources needed to deploy the vSRX to handle the traffic from the Gateway load balancer. The vSRX is bootstrapped with minimal default config to allow the geneve traffic originating from the GWLB. This topolgy deploys resources in a single AZ (User choice of AZ as input). The application VPC can deply the Gateway load balancer endpoint and route traffic to the security VPC by adding the appropriate route entries. 4 | 5 | This template deploys the following resources 6 | 7 | * VPC 8 | * Internet Gateway IGW 9 | * Mgmt subnets 10 | * Data subnets 11 | * Bastion host 12 | * NAT GW 13 | * Route tables 14 | * Add route table entries 15 | * Lambda function 16 | * Gateway Load balancer 17 | * Target group and listener 18 | * Bootstrap vSRX through userData 19 | 20 | # Topology 21 | 22 | Security VPC topology 23 | 24 | ![Alt text](vsrx_aws_gwlb_asg_no_az.png?raw=true "Topology") -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_asg_no_az/vsrx_aws_gwlb_asg_no_az.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juniper/vSRX-AWS/4d6c7fd198c78fb89b533fdbfc9e68e07e18d1e8/vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_asg_no_az/vsrx_aws_gwlb_asg_no_az.png -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_no_asg_az/README.md: -------------------------------------------------------------------------------- 1 | # vSRX Deployement 2 | 3 | A CloudFormation template to depoy a vSRX in security VPC along with Gateway Load Balancer without Autoscaling group. This creates most of the resources needed to deploy the vSRX to handle the traffic from the Gateway load balancer. The vSRX is bootstrapped with minimal default config to allow the geneve traffic originating from the GWLB. This topolgy deploys resources in two AZ's (User choice of AZ's as input). The application VPC can deply the Gateway load balancer endpoint and route traffic to the security VPC by adding the appropriate route entries. 4 | 5 | This template deploys the following resources 6 | 7 | * VPC 8 | * Internet Gateway IGW 9 | * Mgmt subnets 10 | * Data subnets 11 | * Bastion host 12 | * NAT GW 13 | * Route tables 14 | * Add route table entries 15 | * Lambda function 16 | * Gateway Load balancer 17 | * Target group and listener 18 | * Bootstrap vSRX through userData 19 | 20 | # Topology 21 | 22 | Security VPC topology 23 | 24 | ![Alt text](vsrx_aws_gwlb_no_asg_az.png?raw=true "Topology") -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_no_asg_az/vsrx_aws_gwlb_no_asg_az.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juniper/vSRX-AWS/4d6c7fd198c78fb89b533fdbfc9e68e07e18d1e8/vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_no_asg_az/vsrx_aws_gwlb_no_asg_az.png -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_no_asg_az_ns_ew/README.md: -------------------------------------------------------------------------------- 1 | # vSRX Deployement 2 | 3 | A CloudFormation template to depoy a vSRX in security VPC along with Gateway Load Balancer without Autoscaling group. This creates most of the resources needed to deploy the vSRX to handle the traffic from the Gateway load balancer. The vSRX is bootstrapped with minimal default config to allow the geneve traffic originating from the GWLB. This topolgy deploys resources in two AZ (User choice of AZ's as input) and creates a VPC attachment with TGW. 4 | 5 | This template deploys the following resources 6 | 7 | * VPC 8 | * Internet Gateway IGW 9 | * Mgmt subnet 10 | * Data subnet 11 | * Bastion host 12 | * NAT GW 13 | * Route tables 14 | * Add route table entries 15 | * Lambda function 16 | * Gateway Load balancer 17 | * Target group and listener 18 | * Bootstrap vSRX through userData 19 | * VPC attachment with TGW and route tables 20 | 21 | # Topology 22 | 23 | Refer to [AWS Centralized VPC](https://aws.amazon.com/blogs/networking-and-content-delivery/centralized-inspection-architecture-with-aws-gateway-load-balancer-and-aws-transit-gateway/) 24 | 25 | ![Alt text](vsrx_aws_gwlb_security_no_asg_az_ns_ew.png?raw=true "Topology") -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_no_asg_az_ns_ew/vsrx_aws_gwlb_security_no_asg_az_ns_ew.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juniper/vSRX-AWS/4d6c7fd198c78fb89b533fdbfc9e68e07e18d1e8/vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_no_asg_az_ns_ew/vsrx_aws_gwlb_security_no_asg_az_ns_ew.png -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_no_asg_no_az/README.md: -------------------------------------------------------------------------------- 1 | # vSRX Deployement 2 | 3 | A CloudFormation template to depoy a vSRX in security VPC along with Gateway Load Balancer without Autoscaling group. This creates most of the resources needed to deploy the vSRX to handle the traffic from the Gateway load balancer. The vSRX is bootstrapped with minimal default config to allow the geneve traffic originating from the GWLB. This topolgy deploys resources in a single AZ (User choice of AZ as input). The application VPC can deply the Gateway load balancer endpoint and route traffic to the security VPC by adding the appropriate route entries. 4 | 5 | This template deploys the following resources 6 | 7 | * VPC 8 | * Internet Gateway IGW 9 | * Mgmt subnets 10 | * Data subnets 11 | * Bastion host 12 | * NAT GW 13 | * Route tables 14 | * Add route table entries 15 | * Lambda function 16 | * Gateway Load balancer 17 | * Target group and listener 18 | * Bootstrap vSRX through userData 19 | 20 | # Topology 21 | 22 | Security VPC topology 23 | 24 | ![Alt text](vsrx_aws_gwlb_security_no_asg_no_az.png?raw=true "Topology") -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_no_asg_no_az/vsrx_aws_gwlb_security_no_asg_no_az.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juniper/vSRX-AWS/4d6c7fd198c78fb89b533fdbfc9e68e07e18d1e8/vSRX_AWS_GWLB/vsrx_cft/vsrx_aws_gwlb_no_asg_no_az/vsrx_aws_gwlb_security_no_asg_no_az.png -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_lambda.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Juniper/vSRX-AWS/4d6c7fd198c78fb89b533fdbfc9e68e07e18d1e8/vSRX_AWS_GWLB/vsrx_lambda.zip -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_tf/vsrx_aws_gwlb_asg_az_ns_ew/app_scripts/terraform.tfvars: -------------------------------------------------------------------------------- 1 | # Copyright (c) Juniper Networks, Inc., 2023. All rights reserved. 2 | 3 | /*##################### MANDATORY #######################*/ 4 | access_key = "" 5 | secret_key = "" 6 | region = "us-east-1" 7 | deployment_name_p = "" 8 | vpc_cidr_p = "10.128.0.0/16" 9 | availability_zones_p = "" 10 | 11 | # Subnets in AZ1 12 | gwlbe_cidr_p = "10.128.0.0/24" 13 | public_cidr_p = "10.128.1.0/24" 14 | private_cidr_p = "10.128.2.0/24" 15 | 16 | # Precreated Transit gateway ID 17 | tgw_id_p = "" 18 | 19 | # Bastion Host Configuration 20 | ami_id_p = "" 21 | key_pair_p = "" 22 | host_sg_p = "" 23 | instance_type_p = "c5.large" 24 | GwlbServiceNameP = "" 25 | TgwSecurityAttachmentIdP = "" 26 | TgwSecurityRouteTableIdP = "" -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_tf/vsrx_aws_gwlb_asg_az_ns_ew/app_scripts/variables.tf: -------------------------------------------------------------------------------- 1 | # Copyright (c) Juniper Networks, Inc., 2023. All rights reserved. 2 | 3 | /*********************** Secret and Access key ************************/ 4 | variable "access_key" { 5 | description = "AWS access key" 6 | type = string 7 | } 8 | 9 | variable "secret_key" { 10 | description = "AWS secret key" 11 | type = string 12 | } 13 | 14 | variable "region" { 15 | description = "AWS region to deploy the stack" 16 | type = string 17 | } 18 | /*********************** VPC Configuration ************************/ 19 | variable "deployment_name_p" { 20 | description = "Deployement name for the vSRX application VPC " 21 | type = string 22 | } 23 | 24 | variable "vpc_cidr_p" { 25 | description = "CIDR for the vSRX application VPC" 26 | type = string 27 | } 28 | 29 | variable "availability_zones_p" { 30 | description = "AZ to launch vSRX - Needs two AZ's" 31 | type = string 32 | default = "us-east-1a" 33 | } 34 | 35 | variable "public_cidr_p" { 36 | description = "CIDR for mgmt subnet in AZ-1 for vSRX" 37 | type = string 38 | default = "10.0.0.0/24" 39 | } 40 | 41 | variable "private_cidr_p" { 42 | description = "CIDR for data subnet in AZ-1 for vSRX" 43 | type = string 44 | } 45 | 46 | variable "gwlbe_cidr_p" { 47 | description = "CIDR for gwlbe subnet in AZ-1 for vSRX" 48 | type = string 49 | } 50 | 51 | 52 | /*********************** Transit gateway ************************/ 53 | variable "tgw_id_p" { 54 | description = "Transit gateway ID which is in appliance mode" 55 | type = string 56 | } 57 | 58 | /*********************** vSRX configuration **********************/ 59 | variable "ami_id_p" { 60 | description = "AMI-ID for the vSRX for the region" 61 | type = string 62 | } 63 | 64 | variable "key_pair_p" { 65 | description = "Keypair to manage vSRX" 66 | type = string 67 | } 68 | 69 | variable "host_sg_p" { 70 | description = "CIDR or Source IP address to whitelist SSH access, the default is 0.0.0.0/0" 71 | type = string 72 | default = "0.0.0.0/0" 73 | } 74 | 75 | variable "instance_type_p" { 76 | description = "Select instance type" 77 | type = string 78 | default = "c5.large" 79 | } 80 | 81 | variable "GwlbServiceNameP"{ 82 | description = "Enter the service name of the vpce endpoint" 83 | type = string 84 | } 85 | 86 | variable "TgwSecurityAttachmentIdP"{ 87 | description = "Enter the tgw security attachment id" 88 | type = string 89 | } 90 | 91 | variable "TgwSecurityRouteTableIdP"{ 92 | description = "enter the tgw security route table id" 93 | type = string 94 | } -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_tf/vsrx_aws_gwlb_asg_az_ns_ew/security_scripts/inlineud.txt: -------------------------------------------------------------------------------- 1 | base64encode(<<-EOT 2 | #load_balancer=true, 3 | #junos-config 4 | security { 5 | policies { 6 | from-zone AWS to-zone junos-host { 7 | policy SELF { 8 | match { 9 | source-address any; 10 | destination-address any; 11 | application [ junos-geneve junos-http junos-tcp-any junos-https ]; 12 | } 13 | then { 14 | permit { 15 | tunnel-inspection { 16 | AWS-inspection-profile; 17 | } 18 | } 19 | } 20 | } 21 | policy SELF_DHCP { 22 | match { 23 | source-address any; 24 | destination-address any; 25 | application junos-dhcp-client; 26 | } 27 | then { 28 | permit; 29 | } 30 | } 31 | } 32 | policy-set AWS-policy-set { 33 | policy AWS-policy { 34 | match { 35 | source-address any; 36 | destination-address any; 37 | application any; 38 | } 39 | then { 40 | permit; 41 | } 42 | } 43 | } 44 | } 45 | zones { 46 | security-zone AWS { 47 | host-inbound-traffic { 48 | system-services { 49 | http; 50 | https; 51 | rpm; 52 | dhcp; 53 | ssh; 54 | } 55 | protocols { 56 | all; 57 | } 58 | } 59 | interfaces { 60 | ge-0/0/0.0; 61 | } 62 | } 63 | } 64 | tunnel-inspection { 65 | inspection-profile AWS-inspection-profile { 66 | geneve AWS-geneve-profile { 67 | policy-set AWS-policy-set; 68 | vni AWS-vni; 69 | } 70 | } 71 | vni AWS-vni { 72 | vni-id 0; 73 | } 74 | } 75 | } 76 | interfaces { 77 | ge-0/0/0 { 78 | mtu 9120; 79 | unit 0 { 80 | family inet { 81 | dhcp; 82 | } 83 | } 84 | } 85 | } 86 | 87 | 88 | system { 89 | management-instance; 90 | } 91 | routing-instances { 92 | mgmt_junos { 93 | description "Mgmt_network"; 94 | } 95 | } 96 | %{if local.isRpmPortC} 97 | services { 98 | rpm { 99 | probe-server { 100 | tcp { 101 | port 49160 102 | } 103 | } 104 | } 105 | } 106 | 107 | %{ endif } 108 | 109 | %{if local.isScalingC} 110 | security { 111 | cloud { 112 | aws { 113 | cloudwatch { 114 | metric { 115 | collect-interval ${var.metric_collect_interval_p}; 116 | namespace ${var.cloudwatch_namespace_p}; 117 | } 118 | } 119 | } 120 | } 121 | } 122 | %{ endif } 123 | 124 | } 125 | 126 | EOT 127 | ) 128 | -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_tf/vsrx_aws_gwlb_asg_az_ns_ew/security_scripts/terraform.tfvars: -------------------------------------------------------------------------------- 1 | # Copyright (c) Juniper Networks, Inc., 2023. All rights reserved. 2 | 3 | /*##################### MANDATORY #######################*/ 4 | access_key = "" 5 | secret_key = "" 6 | region = "" 7 | deployment_name_p = "" 8 | vpc_cidr_p = "10.0.0.0/16" 9 | #Need two AZ, example - [ "us-east-1a", "us-east-1b" ] 10 | availability_zones_p = [] 11 | 12 | #Subnets in AZ1 13 | mgmt_cidr_az1_p = "10.0.0.0/24" 14 | data_cidr_az1_p = "10.0.2.0/24" 15 | gwlbe_cidr_az1_p = "10.0.3.0/24" 16 | tgw_cidr_az1_p = "10.0.4.0/24" 17 | 18 | #Subnets in AZ2 19 | mgmt_cidr_az2_p = "10.0.8.0/24" 20 | data_cidr_az2_p = "10.0.9.0/24" 21 | gwlbe_cidr_az2_p = "10.0.10.0/24" 22 | tgw_cidr_az2_p = "10.0.12.0/24" 23 | 24 | #Transit gateway 25 | tgw_id_p = "" 26 | 27 | #vSRX Configuration 28 | vsrx_ami_id_p = "" 29 | vsrx_key_pair_p = "" 30 | vsrx_host_sg_p = "" 31 | vsrx_instance_type_p = "c5.large" 32 | vsrx_disk_vol_p = 20 33 | vsrx_gwlb_health_protocol_p = "TCP" 34 | vsrx_gwlb_health_port_p = 49160 35 | 36 | # Preconfigured S3 bucket 37 | s3_bucket_name_p = "" 38 | s3_lambda_zip_p = "vsrx_lambda.zip" 39 | log_level_p = "info" 40 | 41 | #Autoscaling configuration 42 | asg_min_size_p =1 43 | asg_desired_size_p =2 44 | asg_max_size_p =4 45 | 46 | # Autoscaling - Scaling policies configuration 47 | enable_asg_scaling_p = true 48 | scaling_type_p = "disbale" 49 | metric_collect_interval_p =1 50 | cloudwatch_namespace_p ="vsrx_gwlb_asg_metric" 51 | cpu_threshold_p = 50 52 | 53 | # Config Sync across ASG mechanism 54 | configSync_p = "disable" 55 | house_keeping_time_p = 30 56 | TimeOut = {"value"=600} -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_tf/vsrx_aws_gwlb_asg_az_ns_ew/security_scripts/user-data: -------------------------------------------------------------------------------- 1 | #load_balancer=true, 2 | #junos-config 3 | groups { 4 | aws-default-geneve { 5 | security { 6 | policies { 7 | from-zone AWS to-zone junos-host { 8 | policy SELF { 9 | match { 10 | source-address any; 11 | destination-address any; 12 | application [ junos-geneve junos-http junos-tcp-any junos-https ]; 13 | } 14 | then { 15 | permit { 16 | tunnel-inspection { 17 | AWS-inspection-profile; 18 | } 19 | } 20 | } 21 | } 22 | policy SELF_DHCP { 23 | match { 24 | source-address any; 25 | destination-address any; 26 | application junos-dhcp-client; 27 | } 28 | then { 29 | permit; 30 | } 31 | } 32 | } 33 | policy-set AWS-policy-set { 34 | policy AWS-policy { 35 | match { 36 | source-address any; 37 | destination-address any; 38 | application any; 39 | } 40 | then { 41 | permit; 42 | } 43 | } 44 | } 45 | } 46 | zones { 47 | security-zone AWS { 48 | host-inbound-traffic { 49 | system-services { 50 | http; 51 | https; 52 | rpm; 53 | dhcp; 54 | ssh; 55 | } 56 | protocols { 57 | all; 58 | } 59 | } 60 | interfaces { 61 | ge-0/0/0.0; 62 | } 63 | } 64 | } 65 | tunnel-inspection { 66 | inspection-profile AWS-inspection-profile { 67 | geneve AWS-geneve-profile { 68 | policy-set AWS-policy-set; 69 | vni AWS-vni; 70 | } 71 | } 72 | vni AWS-vni { 73 | vni-id 0; 74 | } 75 | } 76 | } 77 | interfaces { 78 | ge-0/0/0 { 79 | mtu 9120; 80 | unit 0 { 81 | family inet { 82 | dhcp; 83 | } 84 | } 85 | } 86 | } 87 | 88 | 89 | system { 90 | management-instance; 91 | } 92 | routing-instances { 93 | mgmt_junos { 94 | description "Mgmt_network"; 95 | } 96 | } 97 | %{if isRpmPortC} 98 | services { 99 | rpm { 100 | probe-server { 101 | tcp { 102 | port 49160 103 | } 104 | } 105 | } 106 | } 107 | %{ endif } 108 | 109 | %{if isScalingC} 110 | security { 111 | cloud { 112 | aws { 113 | cloudwatch { 114 | metric { 115 | collect-interval ${metric_collect_interval_p}; 116 | namespace ${cloudwatch_namespace_p}; 117 | } 118 | } 119 | } 120 | } 121 | } 122 | %{ endif } 123 | } 124 | } 125 | apply-groups aws-default-geneve; -------------------------------------------------------------------------------- /vSRX_AWS_GWLB/vsrx_tf/vsrx_aws_gwlb_asg_az_ns_ew/security_scripts/variables.tf: -------------------------------------------------------------------------------- 1 | # Copyright (c) Juniper Networks, Inc., 2023. All rights reserved. 2 | 3 | /*********************** Secret and Access key ************************/ 4 | variable "access_key" { 5 | description = "AWS access key" 6 | type = string 7 | } 8 | 9 | variable "secret_key" { 10 | description = "AWS secret key" 11 | type = string 12 | } 13 | 14 | variable "region" { 15 | description = "AWS region to deploy the stack" 16 | type = string 17 | } 18 | /*********************** VPC Configuration ************************/ 19 | variable "deployment_name_p" { 20 | description = "Deployement name for the vSRX security VPC stack" 21 | type = string 22 | } 23 | 24 | variable "vpc_cidr_p" { 25 | description = "CIDR for the vSRX Security VPC" 26 | type = string 27 | } 28 | 29 | variable "availability_zones_p" { 30 | description = "AZ to launch vSRX - Needs two AZ's" 31 | type = list(string) 32 | default = ["us-east-1a", "us-east-1b"] 33 | } 34 | 35 | variable "mgmt_cidr_az1_p" { 36 | description = "CIDR for mgmt subnet in AZ-1 for vSRX" 37 | type = string 38 | default = "10.0.0.0/24" 39 | } 40 | 41 | variable "data_cidr_az1_p" { 42 | description = "CIDR for data subnet in AZ-1 for vSRX" 43 | type = string 44 | } 45 | 46 | variable "gwlbe_cidr_az1_p" { 47 | description = "CIDR for gwlbe subnet in AZ-1 for vSRX" 48 | type = string 49 | } 50 | 51 | variable "tgw_cidr_az1_p" { 52 | description = "CIDR for tgw subnet in AZ-1 for vSRX" 53 | type = string 54 | } 55 | 56 | variable "mgmt_cidr_az2_p" { 57 | description = "CIDR for mgmt subnet in AZ-2 for vSRX" 58 | type = string 59 | default ="10.0.8.0/24" 60 | } 61 | 62 | variable "data_cidr_az2_p" { 63 | description = "CIDR for data subnet in AZ-2 for vSRX" 64 | type = string 65 | } 66 | 67 | variable "gwlbe_cidr_az2_p" { 68 | description = "CIDR for gwlbe subnet in AZ-2 for vSRX" 69 | type = string 70 | } 71 | 72 | variable "tgw_cidr_az2_p" { 73 | description = "CIDR for tgw subnet in AZ-2 for vSRX" 74 | type = string 75 | } 76 | /*********************** Transit gateway ************************/ 77 | variable "tgw_id_p" { 78 | description = "Transit gateway ID which is in appliance mode" 79 | type = string 80 | } 81 | 82 | /*********************** vSRX configuration **********************/ 83 | variable "vsrx_ami_id_p" { 84 | description = "AMI-ID for the vSRX for the region" 85 | type = string 86 | } 87 | 88 | variable "vsrx_key_pair_p" { 89 | description = "Keypair to manage vSRX" 90 | type = string 91 | } 92 | 93 | variable "vsrx_host_sg_p" { 94 | description = "CIDR or Source IP address to whitelist SSH access, the default is 0.0.0.0/0" 95 | type = string 96 | default = "0.0.0.0/0" 97 | } 98 | 99 | variable "vsrx_instance_type_p" { 100 | description = <