diff --git a/python/existing-vpc-new-ec2-ebs-userdata/DO_NOT_AUTOTEST b/python/existing-vpc-new-ec2-ebs-userdata/DO_NOT_AUTOTEST new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/python/existing-vpc-new-ec2-ebs-userdata/DO_NOT_AUTOTEST @@ -0,0 +1 @@ + diff --git a/python/existing-vpc-new-ec2-ebs-userdata/README.md b/python/existing-vpc-new-ec2-ebs-userdata/README.md new file mode 100644 index 000000000..5fb9e4615 --- /dev/null +++ b/python/existing-vpc-new-ec2-ebs-userdata/README.md @@ -0,0 +1,17 @@ +# Create EC2 in an existing VPC with AWS CDK Python + +This is a project to create a new EC2 in an existing VPC on AWS with the AWS Cloud Development Kit. + +This project also demonstrates: +* Using customized user data of EC2 +* Customize multiple EBS volume +* Specify AMI id +* Security groups allow SSH access from internet + +## Useful commands + + * `cdk ls` list all stacks in the app + * `cdk synth` emits the synthesized CloudFormation template + * `cdk deploy` deploy this stack to your default AWS account/region + * `cdk diff` compare deployed stack with current state + * `cdk docs` open CDK documentation diff --git a/python/existing-vpc-new-ec2-ebs-userdata/app.py b/python/existing-vpc-new-ec2-ebs-userdata/app.py new file mode 100644 index 000000000..f9e71d52b --- /dev/null +++ b/python/existing-vpc-new-ec2-ebs-userdata/app.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 + +from aws_cdk import core + +from cdk_vpc_ec2.cdk_vpc_ec2_stack import CdkVpcEc2Stack + +# Define your account id to make import vpc work +env_cn = core.Environment(account="YOUR_ACCOUNT_ID_WITHOUT_HYPHEN", region="cn-northwest-1") + +app = core.App() +CdkVpcEc2Stack(app, "cdk-vpc-ec2", env=env_cn) + +app.synth() diff --git a/python/existing-vpc-new-ec2-ebs-userdata/cdk.json b/python/existing-vpc-new-ec2-ebs-userdata/cdk.json new file mode 100644 index 000000000..b4baa1022 --- /dev/null +++ b/python/existing-vpc-new-ec2-ebs-userdata/cdk.json @@ -0,0 +1,3 @@ +{ + "app": "python3 app.py" +} diff --git a/python/existing-vpc-new-ec2-ebs-userdata/cdk_vpc_ec2/cdk_vpc_ec2_stack.py b/python/existing-vpc-new-ec2-ebs-userdata/cdk_vpc_ec2/cdk_vpc_ec2_stack.py new file mode 100644 index 000000000..2fdde6fb1 --- /dev/null +++ b/python/existing-vpc-new-ec2-ebs-userdata/cdk_vpc_ec2/cdk_vpc_ec2_stack.py @@ -0,0 +1,54 @@ +from aws_cdk import core +import aws_cdk.aws_ec2 as ec2 + +vpc_id = "MY-VPC-ID" # Import an Exist VPC +ec2_type = "t2.micro" +key_name = "id_rsa" +linux_ami = ec2.GenericLinuxImage({ + "cn-northwest-1": "AMI-ID-IN-cn-northwest-1-REGION", # Refer to an Exist AMI + "eu-west-1": "AMI-ID-IN-eu-west-1-REGION" +}) +with open("./user_data/user_data.sh") as f: + user_data = f.read() + + +class CdkVpcEc2Stack(core.Stack): + + def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: + super().__init__(scope, id, **kwargs) + + # The code that defines your stack goes here + vpc = ec2.Vpc.from_lookup(self, "VPC", vpc_id=vpc_id) + + host = ec2.Instance(self, "myEC2", + instance_type=ec2.InstanceType( + instance_type_identifier=ec2_type), + instance_name="mySingleHost", + machine_image=linux_ami, + vpc=vpc, + key_name=key_name, + vpc_subnets=ec2.SubnetSelection( + subnet_type=ec2.SubnetType.PUBLIC), + user_data=ec2.UserData.custom(user_data) + ) + # ec2.Instance has no property of BlockDeviceMappings, add via lower layer cdk api: + host.instance.add_property_override("BlockDeviceMappings", [{ + "DeviceName": "/dev/xvda", + "Ebs": { + "VolumeSize": "10", + "VolumeType": "io1", + "Iops": "150", + "DeleteOnTermination": "true" + } + }, { + "DeviceName": "/dev/sdb", + "Ebs": {"VolumeSize": "30"} + } + ]) # by default VolumeType is gp2, VolumeSize 8GB + host.connections.allow_from_any_ipv4( + ec2.Port.tcp(22), "Allow ssh from internet") + host.connections.allow_from_any_ipv4( + ec2.Port.tcp(80), "Allow ssh from internet") + + core.CfnOutput(self, "Output", + value=host.instance_public_ip) diff --git a/python/existing-vpc-new-ec2-ebs-userdata/requirements.txt b/python/existing-vpc-new-ec2-ebs-userdata/requirements.txt new file mode 100644 index 000000000..d6e1198b1 --- /dev/null +++ b/python/existing-vpc-new-ec2-ebs-userdata/requirements.txt @@ -0,0 +1 @@ +-e . diff --git a/python/existing-vpc-new-ec2-ebs-userdata/setup.py b/python/existing-vpc-new-ec2-ebs-userdata/setup.py new file mode 100644 index 000000000..0a20681c8 --- /dev/null +++ b/python/existing-vpc-new-ec2-ebs-userdata/setup.py @@ -0,0 +1,46 @@ +import setuptools + + +with open("README.md") as fp: + long_description = fp.read() + + +setuptools.setup( + name="Import_VPC_Create_EC2", + version="1.0.0", + + description="Import VPC and Create EC2 on it with two EBS and EC2 UserData", + long_description=long_description, + long_description_content_type="text/markdown", + + author="Huang, Zhuobin (James)", + + package_dir={"": "cdk_vpc_ec2"}, + packages=setuptools.find_packages(where="cdk_vpc_ec2"), + + install_requires=[ + "aws-cdk.core", + "aws-cdk.aws-ec2" + ], + + python_requires=">=3.6", + + classifiers=[ + "Development Status :: 4 - Beta", + + "Intended Audience :: Developers", + + "License :: OSI Approved :: Apache Software License", + + "Programming Language :: JavaScript", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + + "Topic :: Software Development :: Code Generators", + "Topic :: Utilities", + + "Typing :: Typed", + ], +) diff --git a/python/existing-vpc-new-ec2-ebs-userdata/user_data/user_data.sh b/python/existing-vpc-new-ec2-ebs-userdata/user_data/user_data.sh new file mode 100644 index 000000000..b9956348f --- /dev/null +++ b/python/existing-vpc-new-ec2-ebs-userdata/user_data/user_data.sh @@ -0,0 +1,5 @@ +#!/bin/bash +sudo yum update -y +sudo yum -y install httpd php +sudo chkconfig httpd on +sudo service httpd start \ No newline at end of file diff --git a/python/new-vpc-alb-asg-mysql/README.md b/python/new-vpc-alb-asg-mysql/README.md new file mode 100644 index 000000000..84acf5f09 --- /dev/null +++ b/python/new-vpc-alb-asg-mysql/README.md @@ -0,0 +1,24 @@ +# Create VPC, EC2 ASG and RDS with AWS CDK Python + +This is a project to create a new VPC, EC2 autoscaling group and RDS on AWS with the AWS Cloud Development Kit. + +This project also demonstrates: +* Create VPC in 3 tier layers of subnets: PUBLIC, PRIVATE and ISOLATED, you can specify the number of AZ and the CIDR. +* Create Bastion instance, NAT Gateway and S3 endpoint +* Create ALB, EC2 Autoscaling group with scaling policy and customize EBS volume +* Creat RDS MySQL M-AZs Database or Aurora +* Create security group and allow access from the other security group: Internet -> ALB -> EC2ASG -> RDS +* Using customized user data of EC2 and specify generation AMI property and do not need to specify the AMI id in every region + +## Architeture +![Architecture](./img_demo_cdk_vpc.png) + +This project create the new VPC part of the architeture. For the existing VPC part, please refer to the project in aws-cdk-examples/existing-vpc-new-ec2-ebs-userdata + +## Useful commands + + * `cdk ls` list all stacks in the app + * `cdk synth` emits the synthesized CloudFormation template + * `cdk deploy` deploy this stack to your default AWS account/region + * `cdk diff` compare deployed stack with current state + * `cdk docs` open CDK documentation diff --git a/python/new-vpc-alb-asg-mysql/app.py b/python/new-vpc-alb-asg-mysql/app.py new file mode 100644 index 000000000..eb0e69750 --- /dev/null +++ b/python/new-vpc-alb-asg-mysql/app.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +from aws_cdk import core + +from cdk_vpc_ec2.cdk_vpc_stack import CdkVpcStack +from cdk_vpc_ec2.cdk_ec2_stack import CdkEc2Stack +from cdk_vpc_ec2.cdk_rds_stack import CdkRdsStack + +app = core.App() + +vpc_stack = CdkVpcStack(app, "cdk-vpc") +ec2_stack = CdkEc2Stack(app, "cdk-ec2", + vpc=vpc_stack.vpc) +rds_stack = CdkRdsStack(app, "cdk-rds", + vpc=vpc_stack.vpc, + asg_security_groups=ec2_stack.asg.connections.security_groups) + +app.synth() diff --git a/python/new-vpc-alb-asg-mysql/cdk.json b/python/new-vpc-alb-asg-mysql/cdk.json new file mode 100644 index 000000000..b4baa1022 --- /dev/null +++ b/python/new-vpc-alb-asg-mysql/cdk.json @@ -0,0 +1,3 @@ +{ + "app": "python3 app.py" +} diff --git a/python/new-vpc-alb-asg-mysql/cdk_vpc_ec2/cdk_ec2_stack.py b/python/new-vpc-alb-asg-mysql/cdk_vpc_ec2/cdk_ec2_stack.py new file mode 100644 index 000000000..3cad10df8 --- /dev/null +++ b/python/new-vpc-alb-asg-mysql/cdk_vpc_ec2/cdk_ec2_stack.py @@ -0,0 +1,82 @@ +from aws_cdk import core +import aws_cdk.aws_ec2 as ec2 +import aws_cdk.aws_elasticloadbalancingv2 as elb +import aws_cdk.aws_autoscaling as autoscaling + +ec2_type = "t2.micro" +key_name = "id_rsa" # Setup key_name for EC2 instance login +linux_ami = ec2.AmazonLinuxImage(generation=ec2.AmazonLinuxGeneration.AMAZON_LINUX, + edition=ec2.AmazonLinuxEdition.STANDARD, + virtualization=ec2.AmazonLinuxVirt.HVM, + storage=ec2.AmazonLinuxStorage.GENERAL_PURPOSE + ) # Indicate your AMI, no need a specific id in the region +with open("./user_data/user_data.sh") as f: + user_data = f.read() + + +class CdkEc2Stack(core.Stack): + + def __init__(self, scope: core.Construct, id: str, vpc, **kwargs) -> None: + super().__init__(scope, id, **kwargs) + + # Create Bastion + bastion = ec2.BastionHostLinux(self, "myBastion", + vpc=vpc, + subnet_selection=ec2.SubnetSelection( + subnet_type=ec2.SubnetType.PUBLIC), + instance_name="myBastionHostLinux", + instance_type=ec2.InstanceType(instance_type_identifier="t2.micro")) + + # Setup key_name for EC2 instance login if you don't use Session Manager + # bastion.instance.instance.add_property_override("KeyName", key_name) + + bastion.connections.allow_from_any_ipv4( + ec2.Port.tcp(22), "Internet access SSH") + + # Create ALB + alb = elb.ApplicationLoadBalancer(self, "myALB", + vpc=vpc, + internet_facing=True, + load_balancer_name="myALB" + ) + alb.connections.allow_from_any_ipv4( + ec2.Port.tcp(80), "Internet access ALB 80") + listener = alb.add_listener("my80", + port=80, + open=True) + + # Create Autoscaling Group with fixed 2*EC2 hosts + self.asg = autoscaling.AutoScalingGroup(self, "myASG", + vpc=vpc, + vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE), + instance_type=ec2.InstanceType(instance_type_identifier=ec2_type), + machine_image=linux_ami, + key_name=key_name, + user_data=ec2.UserData.custom(user_data), + desired_capacity=2, + min_capacity=2, + max_capacity=2, + # block_devices=[ + # autoscaling.BlockDevice( + # device_name="/dev/xvda", + # volume=autoscaling.BlockDeviceVolume.ebs( + # volume_type=autoscaling.EbsDeviceVolumeType.GP2, + # volume_size=12, + # delete_on_termination=True + # )), + # autoscaling.BlockDevice( + # device_name="/dev/sdb", + # volume=autoscaling.BlockDeviceVolume.ebs( + # volume_size=20) + # # 20GB, with default volume_type gp2 + # ) + # ] + ) + + self.asg.connections.allow_from(alb, ec2.Port.tcp(80), "ALB access 80 port of EC2 in Autoscaling Group") + listener.add_targets("addTargetGroup", + port=80, + targets=[self.asg]) + + core.CfnOutput(self, "Output", + value=alb.load_balancer_dns_name) diff --git a/python/new-vpc-alb-asg-mysql/cdk_vpc_ec2/cdk_rds_stack.py b/python/new-vpc-alb-asg-mysql/cdk_vpc_ec2/cdk_rds_stack.py new file mode 100644 index 000000000..3e96c44ce --- /dev/null +++ b/python/new-vpc-alb-asg-mysql/cdk_vpc_ec2/cdk_rds_stack.py @@ -0,0 +1,53 @@ +from aws_cdk import core +import aws_cdk.aws_ec2 as ec2 +import aws_cdk.aws_rds as rds + + +class CdkRdsStack(core.Stack): + + def __init__(self, scope: core.Construct, id: str, vpc, asg_security_groups, **kwargs) -> None: + super().__init__(scope, id, **kwargs) + + # Ceate Aurora Cluster with 2 instances with CDK High Level API + # Secrets Manager auto generate and keep the password, don't put password in cdk code directly + # db_Aurora_cluster = rds.DatabaseCluster(self, "MyAurora", + # default_database_name="MyAurora", + # engine=rds.DatabaseClusterEngine.AURORA_MYSQL, + # engine_version="5.7.12", + # master_user=rds.Login(username="admin"), + # instance_props=rds.InstanceProps( + # vpc=vpc, + # vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.ISOLATED), + # instance_type=ec2.InstanceType(instance_type_identifier="t2.small") + # ), + # instances=2, + # parameter_group=rds.ClusterParameterGroup.from_parameter_group_name( + # self, "para-group-aurora", + # parameter_group_name="default.aurora-mysql5.7" + # ), + # ) + # for asg_sg in asg_security_groups: + # db_Aurora_cluster.connections.allow_default_port_from(asg_sg, "EC2 Autoscaling Group access Aurora") + + # Alternatively, create MySQL RDS with CDK High Level API + db_mysql_easy = rds.DatabaseInstance(self, "MySQL_DB_easy", + engine=rds.DatabaseInstanceEngine.MYSQL, + engine_version="5.7.22", + instance_class=ec2.InstanceType.of( + ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + master_username="admin", + vpc=vpc, + multi_az=True, + allocated_storage=100, + storage_type=rds.StorageType.GP2, + cloudwatch_logs_exports=["audit", "error", "general", "slowquery"], + deletion_protection=False, + delete_automated_backups=False, + backup_retention=core.Duration.days(7), + parameter_group=rds.ParameterGroup.from_parameter_group_name( + self, "para-group-mysql", + parameter_group_name="default.mysql5.7" + ) + ) + for asg_sg in asg_security_groups: + db_mysql_easy.connections.allow_default_port_from(asg_sg, "EC2 Autoscaling Group access MySQL") diff --git a/python/new-vpc-alb-asg-mysql/cdk_vpc_ec2/cdk_vpc_stack.py b/python/new-vpc-alb-asg-mysql/cdk_vpc_ec2/cdk_vpc_stack.py new file mode 100644 index 000000000..9fe2d6685 --- /dev/null +++ b/python/new-vpc-alb-asg-mysql/cdk_vpc_ec2/cdk_vpc_stack.py @@ -0,0 +1,34 @@ +from aws_cdk import core +import aws_cdk.aws_ec2 as ec2 + + +class CdkVpcStack(core.Stack): + + def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: + super().__init__(scope, id, **kwargs) + + # The code that defines your stack goes here + + self.vpc = ec2.Vpc(self, "VPC", + max_azs=2, + cidr="10.10.0.0/16", + # configuration will create 3 groups in 2 AZs = 6 subnets. + subnet_configuration=[ec2.SubnetConfiguration( + subnet_type=ec2.SubnetType.PUBLIC, + name="Public", + cidr_mask=24 + ), ec2.SubnetConfiguration( + subnet_type=ec2.SubnetType.PRIVATE, + name="Private", + cidr_mask=24 + ), ec2.SubnetConfiguration( + subnet_type=ec2.SubnetType.ISOLATED, + name="DB", + cidr_mask=24 + ) + ], + # nat_gateway_provider=ec2.NatProvider.gateway(), + nat_gateways=2, + ) + core.CfnOutput(self, "Output", + value=self.vpc.vpc_id) diff --git a/python/new-vpc-alb-asg-mysql/img_demo_cdk_vpc.png b/python/new-vpc-alb-asg-mysql/img_demo_cdk_vpc.png new file mode 100644 index 000000000..a461d06b5 Binary files /dev/null and b/python/new-vpc-alb-asg-mysql/img_demo_cdk_vpc.png differ diff --git a/python/new-vpc-alb-asg-mysql/requirements.txt b/python/new-vpc-alb-asg-mysql/requirements.txt new file mode 100644 index 000000000..d6e1198b1 --- /dev/null +++ b/python/new-vpc-alb-asg-mysql/requirements.txt @@ -0,0 +1 @@ +-e . diff --git a/python/new-vpc-alb-asg-mysql/setup.py b/python/new-vpc-alb-asg-mysql/setup.py new file mode 100644 index 000000000..e4de13f7b --- /dev/null +++ b/python/new-vpc-alb-asg-mysql/setup.py @@ -0,0 +1,49 @@ +import setuptools + + +with open("README.md") as fp: + long_description = fp.read() + + +setuptools.setup( + name="Create_VPC_ALB_ASG", + version="1.0.0", + + description="Create new VPC and ALB/AutoscalingGroup in it", + long_description=long_description, + long_description_content_type="text/markdown", + + author="Huang, Zhuobin (James)", + + package_dir={"": "cdk_vpc_ec2"}, + packages=setuptools.find_packages(where="cdk_vpc_ec2"), + + install_requires=[ + "aws-cdk.core", + "aws-cdk.aws-ec2", + "aws-cdk.aws-elasticloadbalancingv2", + "aws-cdk.aws-autoscaling", + "aws-cdk.aws-rds" + ], + + python_requires=">=3.6", + + classifiers=[ + "Development Status :: 4 - Beta", + + "Intended Audience :: Developers", + + "License :: OSI Approved :: Apache Software License", + + "Programming Language :: JavaScript", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + + "Topic :: Software Development :: Code Generators", + "Topic :: Utilities", + + "Typing :: Typed", + ], +) diff --git a/python/new-vpc-alb-asg-mysql/user_data/user_data.sh b/python/new-vpc-alb-asg-mysql/user_data/user_data.sh new file mode 100644 index 000000000..b9956348f --- /dev/null +++ b/python/new-vpc-alb-asg-mysql/user_data/user_data.sh @@ -0,0 +1,5 @@ +#!/bin/bash +sudo yum update -y +sudo yum -y install httpd php +sudo chkconfig httpd on +sudo service httpd start \ No newline at end of file