├── 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 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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 = <