├── .gitignore ├── README.md ├── app.py ├── cdk.json ├── images └── CDK-VPC-Aurora.png ├── requirements.txt ├── setup.py ├── stacks ├── __init__.py ├── rds_aurora_serverless.py ├── rds_postgres.py └── vpc.py └── user_data ├── bastion.sh └── user_data.sh /.gitignore: -------------------------------------------------------------------------------- 1 | cdk.out 2 | stacks/__pycache__ 3 | stacks/*.egg-info 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python CDK with VPC + Postgres DB 2 | AWS Cloud Development Kit (AWS CDK) is a software development framework for 3 | defining cloud infrastructure in code and provisioning it through AWS 4 | CloudFormation. Here's a python example for building a VPC, Bastion host and a 5 | Postgres database using RDS (provisioned or serverless). Here's a general view of the 6 | architecture. 7 | 8 | ![Arch](images/CDK-VPC-Aurora.png) 9 | 10 | ## Installation 11 | 12 | ### Python virtual environment 13 | ``` 14 | virtualenv aws_cdk.env 15 | cd aws_cdk.env 16 | source bin/activate 17 | ``` 18 | 19 | ### Install AWS CDK 20 | ``` 21 | npm install -g aws-cdk 22 | cdk --version 23 | cdk --help 24 | ``` 25 | No harm to read up the docs: https://docs.aws.amazon.com/cdk 26 | 27 | ### Install the dependencies: 28 | ``` 29 | pip install aws-cdk.aws-s3 30 | pip install aws-cdk.aws-ec2 31 | pip install aws-cdk.aws-rds 32 | pip install aws-cdk.aws-events-targets 33 | pip install -r requirements.txt 34 | ``` 35 | 36 | When new versions come available, no harm in keeping up to date: 37 | ``` 38 | pip install --upgrade aws-cdk.core 39 | pip install --upgrade aws-cdk.aws-s3 40 | pip install --upgrade aws-cdk.aws-ec2 41 | pip install --upgrade aws-cdk.aws-rds 42 | pip install --upgrade aws-cdk.aws-events-targets 43 | ``` 44 | 45 | ### Set up your AWS profile file ~/.aws/config 46 | ``` 47 | [profile cdk_profile] 48 | aws_access_key_id=AKIAI44QH8DHBEXAMPLE 49 | aws_secret_access_key=je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY 50 | region=eu-west-1 51 | ``` 52 | 53 | ## Synthesizing the stacks. 54 | 55 | The --no-version-reporting option removes the `AWS::CDK::Metadata` resources and opts out of 56 | module version reporting to AWS. 57 | . 58 | ``` 59 | cdk --profile cdk_profile --no-version-reporting synth VPC AuroraServerless PostgresRDS 60 | ``` 61 | 62 | ### Debugging a stack 63 | ``` 64 | cdk --profile cdk_profile --no-version-reporting synth VPC > vpc.yaml 65 | aws cloudformation validate-template --template-body file://vpc.yaml 66 | ``` 67 | 68 | ## Deploying the stacks 69 | ``` 70 | cdk --profile cdk_profile --no-version-reporting deploy VPC AuroraServerless PostgresRDS 71 | ``` 72 | 73 | ## Destroying the stacks 74 | ``` 75 | cdk --profile cdk_profile --no-version-reporting destroy VPC AuroraServerless PostgresRDS 76 | ``` 77 | 78 | ### To access the aurora serverless postgres database you've got a few options: 79 | 80 | #### 1. Log into the cluster using the AWS console with secrets manager use AuroraServerless.DatabaseSecretArn above 81 | ``` 82 | https://.console.aws.amazon.com/rds/home?region=#query-editor:/instance/aurora-serverless-postgres-db 83 | ``` 84 | You can execute SQL directly in the console. 85 | 86 | #### 2. Log into cluster from the Bastion (requires database password from secrets manager) 87 | ``` 88 | # Get Bastion id 89 | aws ec2 describe-instances \ 90 | --profile cdk_profile \ 91 | --filter "Name=tag:Name,Values=BastionHost" \ 92 | --query "Reservations[].Instances[?State.Name == 'running'].InstanceId[]" \ 93 | --output text 94 | 95 | aws ssm --profile cdk_profile start-session --target "" 96 | 97 | # Passing user data to CfnDBCluster wasn't possible so needed to install postgresql 98 | sudo yum -y update 99 | sudo yum install -y postgresql.x86_64 100 | 101 | psql \ 102 | --host= \ 103 | --port=5432 \ 104 | --username=admin_user \ 105 | --dbname=slsdb 106 | ``` 107 | 108 | #### 3. Log into cluster with psql locally 109 | 110 | a. Configure ssh locally to proxy commands through ssm 111 | ``` 112 | # Add the following to the .ssh/config file 113 | host i-* mi-* 114 | ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'" 115 | ``` 116 | 117 | b. Get Bastion id (see above) 118 | 119 | c. Log into Bastion and place your id_rsa.pub key in .ssh/authorized_keys file of the ssm-user. 120 | ``` 121 | aws ssm --profile cdk_profile start-session --target "" 122 | cd /home/ssm-user 123 | mkdir .ssh ; vi .ssh/authorized_keys # paste key 124 | cd /home/ssm-user 125 | chmod 700 .ssh; chmod 640 .ssh/authorized_keys 126 | ``` 127 | 128 | d. Locally create the ssh tunnel 129 | ``` 130 | ssh -N \ 131 | -L "localhost:5432::5432" \ 132 | ssm-user@ 133 | ``` 134 | 135 | e. Using a new shell, log into Aurora with psql. This same setup can be used in your favourite IDE such as 136 | pgAdmin/DataGrip/PyCharm/etc. 137 | 138 | ``` 139 | psql \ 140 | --host=localhost \ 141 | --port=5432 \ 142 | --username=admin_user \ 143 | --dbname=slsdb 144 | ``` 145 | 146 | (References) Some useful blogs and docs: 147 | http://wrschneider.github.io/2019/09/10/ssm-ssh-tunnel.html 148 | 149 | https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-getting-started-enable-ssh-connections.html 150 | 151 | https://aws.amazon.com/blogs/aws/new-port-forwarding-using-aws-system-manager-sessions-manager/ 152 | 153 | ## CDK Examples 154 | https://github.com/aws-samples/aws-cdk-examples/tree/master/python 155 | 156 | https://github.com/aws-samples/aws-cdk-examples/tree/master/python/new-vpc-alb-asg-mysql 157 | 158 | https://github.com/aws-samples/aws-aurora-serverless-data-api-sam/blob/master/deploy_scripts/rds_cfn_template.yaml 159 | 160 | ## CDK Python API 161 | https://docs.aws.amazon.com/cdk/api/latest/python 162 | 163 | https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_ec2/Vpc.html 164 | 165 | https://docs.aws.amazon.com/cdk/api/latest/docs/aws-events-readme.html 166 | 167 | ## Blogs 168 | https://blog.codecentric.de/en/2019/09/aws-cdk-create-custom-vpc/ 169 | 170 | https://blog.codecentric.de/en/2019/10/aws-cdk-part-2-s3-bucket/ 171 | 172 | https://blog.codecentric.de/en/2019/09/aws-cdk-versus-terraform-and-serverless-framework/ 173 | 174 | https://stackoverflow.com/questions/55818680/how-to-set-dbparametergroup-family-property-for-postgres-10-6/55818740 175 | 176 | https://sanderknape.com/2019/05/building-serverless-applications-aws-cdk/ 177 | 178 | https://labs.consol.de/development/2019/11/04/introduction-to-aws-cdk.html 179 | 180 | https://jimmydqv.com/aws/cloudformation/infrastructure/cdk/2019/08/14/aws-cdk-first-impression.html 181 | 182 | https://dev.to/hoangleitvn/top-reasons-why-we-use-aws-cdk-over-cloudformation-2b2f 183 | 184 | https://aws.amazon.com/blogs/aws/new-data-api-for-amazon-aurora-serverless/ 185 | 186 | https://madabout.cloud/2019/09/01/aws-data-api-for-amazon-aurora-serverless/ 187 | 188 | https://read.acloud.guru/getting-started-with-the-amazon-aurora-serverless-data-api-6b84e466b109 189 | 190 | ## Docs 191 | https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.html 192 | 193 | https://aws.amazon.com/blogs/database/using-the-data-api-to-interact-with-an-amazon-aurora-serverless-mysql-database/ 194 | 195 | ## Tools 196 | https://studio.infviz.io/ 197 | 198 | ## CIDR Blocks 199 | http://jodies.de/ipcalc?host=10.0.0.0&mask1=16&mask2= 200 | 201 | https://cloudacademy.com/course/aws-virtual-private-cloud-subnets-and-routing/vpc-cidr-blocks/ 202 | 203 | ## Aurora Serverless 204 | https://github.com/chanzuckerberg/sqlalchemy-aurora-data-api 205 | 206 | https://www.npmjs.com/package/@cfn-modules/rds-aurora-serverless-postgres 207 | 208 | https://stackoverflow.com/questions/51879688/creating-an-aurora-serverless-cluster-from-cloudformation 209 | 210 | https://stackoverflow.com/questions/59409935/create-cfndbcluster-in-non-default-vpc?rq=1 211 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | from aws_cdk import core 4 | 5 | from stacks.vpc import VpcStack 6 | from stacks.rds_aurora_serverless import AuroraServerlessStack 7 | from stacks.rds_postgres import RDSPostgresStack 8 | 9 | # https://docs.aws.amazon.com/cdk/latest/guide/environments.html 10 | env_EU = core.Environment( 11 | account=os.environ.get("CDK_DEPLOY_ACCOUNT", os.environ["CDK_DEFAULT_ACCOUNT"]), 12 | region=os.environ.get("CDK_DEPLOY_REGION", os.environ["CDK_DEFAULT_REGION"]) 13 | ) 14 | 15 | app = core.App() 16 | 17 | vpc_ec2_stack = VpcStack( 18 | scope=app, 19 | id="VPC", 20 | env=env_EU 21 | ) 22 | 23 | aurora_stack = AuroraServerlessStack( 24 | scope=app, 25 | id="AuroraServerless", 26 | vpc=vpc_ec2_stack.vpc, 27 | env=env_EU 28 | ) 29 | 30 | postgres = RDSPostgresStack( 31 | scope=app, 32 | id="PostgresRDS", 33 | vpc=vpc_ec2_stack.vpc, 34 | env=env_EU 35 | ) 36 | 37 | app.synth() 38 | -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "python3 app.py" 3 | } 4 | -------------------------------------------------------------------------------- /images/CDK-VPC-Aurora.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martinbpeters/cdk-vpc-postgres/0cff3ccbf4c7af49fa1fa356ce58d7dd3ec80e7c/images/CDK-VPC-Aurora.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | -e . 2 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | 4 | with open("README.md") as fp: 5 | long_description = fp.read() 6 | 7 | 8 | setuptools.setup( 9 | name="vpc_postgres", 10 | version="0.0.1", 11 | 12 | description="Python CDK - VPC + Postgres", 13 | long_description=long_description, 14 | long_description_content_type="text/markdown", 15 | 16 | # tweaks from https://github.com/aws-samples/aws-cdk-examples/tree/master/python/new-vpc-alb-asg-mysql 17 | author="Martin Peters", 18 | 19 | package_dir={"": "stacks"}, 20 | packages=setuptools.find_packages(where="stacks"), 21 | 22 | install_requires=[ 23 | "aws-cdk.core", 24 | "aws-cdk.aws-ec2", 25 | "aws-cdk.aws-elasticloadbalancingv2", 26 | "aws-cdk.aws-autoscaling", 27 | "aws-cdk.aws-rds", 28 | "aws-cdk.aws-secretsmanager", 29 | "aws-cdk.aws-lambda", 30 | "aws-cdk.aws-events-targets", 31 | "aws-cdk.aws-cloudwatch" 32 | ], 33 | 34 | python_requires=">=3.6", 35 | 36 | classifiers=[ 37 | "Development Status :: 4 - Beta", 38 | 39 | "Intended Audience :: Developers", 40 | 41 | "License :: OSI Approved :: Apache Software License", 42 | 43 | "Programming Language :: JavaScript", 44 | "Programming Language :: Python :: 3 :: Only", 45 | "Programming Language :: Python :: 3.6", 46 | "Programming Language :: Python :: 3.7", 47 | "Programming Language :: Python :: 3.8", 48 | 49 | "Topic :: Software Development :: Code Generators", 50 | "Topic :: Utilities", 51 | 52 | "Typing :: Typed", 53 | ], 54 | ) 55 | -------------------------------------------------------------------------------- /stacks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martinbpeters/cdk-vpc-postgres/0cff3ccbf4c7af49fa1fa356ce58d7dd3ec80e7c/stacks/__init__.py -------------------------------------------------------------------------------- /stacks/rds_aurora_serverless.py: -------------------------------------------------------------------------------- 1 | from aws_cdk import ( 2 | aws_ec2 as ec2, 3 | aws_rds as rds, 4 | aws_secretsmanager as sm, 5 | core 6 | ) 7 | 8 | 9 | class AuroraServerlessStack(core.Stack): 10 | """ 11 | 12 | """ 13 | def __init__(self, scope: core.Construct, id: str, vpc, **kwargs) -> None: 14 | super().__init__(scope, id, **kwargs) 15 | 16 | db_master_user_name="admin_user" 17 | 18 | secret = rds.DatabaseSecret( 19 | self, 20 | id="MasterUserSecret", 21 | username=db_master_user_name 22 | ) 23 | 24 | subnet_ids = [] 25 | for subnet in vpc.isolated_subnets: 26 | subnet_ids.append(subnet.subnet_id) 27 | 28 | subnet_group = rds.CfnDBSubnetGroup( 29 | self, 30 | id="AuroraServerlessSubnetGroup", 31 | db_subnet_group_description='Aurora Postgres Serverless Subnet Group', 32 | subnet_ids=subnet_ids, 33 | db_subnet_group_name='auroraserverlesssubnetgroup' # needs to be all lowercase 34 | ) 35 | 36 | db_cluster_name="aurora-serverless-postgres-db" 37 | 38 | security_group = ec2.SecurityGroup( 39 | self, 40 | id="SecurityGroup", 41 | vpc=vpc, 42 | description="Allow ssh access to ec2 instances", 43 | allow_all_outbound=True 44 | ) 45 | security_group.add_ingress_rule(ec2.Peer.ipv4('10.0.0.0/16'), ec2.Port.tcp(5432), "allow psql through") 46 | 47 | self.db = rds.CfnDBCluster( 48 | self, 49 | id="AuroraServerlessDB", 50 | engine=rds.DatabaseClusterEngine.AURORA_POSTGRESQL.name, 51 | engine_mode="serverless", 52 | db_subnet_group_name=subnet_group.db_subnet_group_name, 53 | 54 | vpc_security_group_ids=[security_group.security_group_id], 55 | availability_zones=vpc.availability_zones, 56 | 57 | db_cluster_identifier=db_cluster_name, 58 | #db_cluster_parameter_group_name= 59 | 60 | database_name="slsdb", 61 | master_username=secret.secret_value_from_json("username").to_string(), 62 | master_user_password=secret.secret_value_from_json("password").to_string(), 63 | 64 | port=5432, 65 | 66 | deletion_protection=False, 67 | scaling_configuration=rds.CfnDBCluster.ScalingConfigurationProperty( 68 | auto_pause=True, 69 | min_capacity=2, 70 | max_capacity=16, 71 | seconds_until_auto_pause=300 72 | ), 73 | 74 | enable_cloudwatch_logs_exports=[ 75 | "error", 76 | "general", 77 | "slowquery", 78 | "audit" 79 | ], 80 | enable_http_endpoint=True 81 | #kms_key_id= 82 | #tags= 83 | ) 84 | self.db.node.add_dependency(subnet_group) 85 | self.db.node.add_dependency(security_group) 86 | 87 | #secret_attached = secret.attach(target=self) 88 | #secret.add_target_attachment(id="secret_attachment", target=self.db) 89 | 90 | secret_attached = sm.CfnSecretTargetAttachment( 91 | self, 92 | id="secret_attachment", 93 | secret_id=secret.secret_arn, 94 | target_id=self.db.ref, 95 | target_type="AWS::RDS::DBCluster", 96 | ) 97 | secret_attached.node.add_dependency(self.db) 98 | 99 | core.CfnOutput( 100 | self, 101 | id="StackName", 102 | value=self.stack_name, 103 | description="Stack Name", 104 | export_name=f"{self.region}:{self.account}:{self.stack_name}:stack-name" 105 | ) 106 | 107 | core.CfnOutput( 108 | self, 109 | id="DatabaseName", 110 | value=self.db.database_name, 111 | description="Database Name", 112 | export_name=f"{self.region}:{self.account}:{self.stack_name}:database-name" 113 | ) 114 | 115 | core.CfnOutput( 116 | self, 117 | id="DatabaseClusterArn", 118 | value=f"arn:aws:rds:{self.region}:{self.account}:cluster:{self.db.ref}", 119 | description="Database Cluster Arn", 120 | export_name=f"{self.region}:{self.account}:{self.stack_name}:database-cluster-arn" 121 | ) 122 | 123 | core.CfnOutput( 124 | self, 125 | id="DatabaseSecretArn", 126 | value=secret.secret_arn, 127 | description="Database Secret Arn", 128 | export_name=f"{self.region}:{self.account}:{self.stack_name}:database-secret-arn" 129 | ) 130 | 131 | core.CfnOutput( 132 | self, 133 | id="DatabaseClusterID", 134 | value=self.db.db_cluster_identifier, 135 | description="Database Cluster Id", 136 | export_name=f"{self.region}:{self.account}:{self.stack_name}:database-cluster-id" 137 | ) 138 | 139 | core.CfnOutput( 140 | self, 141 | id="AuroraEndpointAddress", 142 | value=self.db.attr_endpoint_address, 143 | description="Aurora Endpoint Address", 144 | export_name=f"{self.region}:{self.account}:{self.stack_name}:aurora-endpoint-address" 145 | ) 146 | 147 | core.CfnOutput( 148 | self, 149 | id="DatabaseMasterUserName", 150 | value=db_master_user_name, 151 | description="Database Master User Name", 152 | export_name=f"{self.region}:{self.account}:{self.stack_name}:database-master-username" 153 | ) 154 | -------------------------------------------------------------------------------- /stacks/rds_postgres.py: -------------------------------------------------------------------------------- 1 | from aws_cdk import ( 2 | aws_ec2 as ec2, 3 | aws_rds as rds, 4 | aws_lambda as _lambda, 5 | aws_events_targets as targets, 6 | aws_cloudwatch as cloudwatch, 7 | core 8 | ) 9 | 10 | 11 | class RDSPostgresStack(core.Stack): 12 | """ 13 | 14 | """ 15 | def __init__(self, scope: core.Construct, id: str, vpc, **kwargs) -> None: 16 | super().__init__(scope, id, **kwargs) 17 | 18 | db = rds.DatabaseInstance( 19 | self, 20 | id="RDSPostgresDB", 21 | engine=rds.DatabaseInstanceEngine.POSTGRES, 22 | engine_version="11", 23 | instance_class=ec2.InstanceType.of( 24 | ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), 25 | master_username="admin", 26 | vpc=vpc, 27 | vpc_placement=ec2.SubnetSelection( 28 | subnet_type=ec2.SubnetType.ISOLATED 29 | ), 30 | multi_az=True, 31 | allocated_storage=100, 32 | storage_type=rds.StorageType.GP2, 33 | cloudwatch_logs_exports=["audit", "error", "general", "slowquery"], 34 | deletion_protection=False, 35 | delete_automated_backups=False, 36 | backup_retention=core.Duration.days(7), 37 | parameter_group=rds.ParameterGroup.from_parameter_group_name( 38 | self, 39 | id="para-group-postgres", 40 | parameter_group_name="postgres11" 41 | ) 42 | ) 43 | 44 | # Rotate the master user password every 30 days 45 | db.add_rotation_single_user() 46 | 47 | # Add alarm for high CPU 48 | cloudwatch.Alarm( 49 | self, 50 | id="HighCPU", 51 | metric=db.metric_cpu_utilization(), 52 | threshold=90, 53 | evaluation_periods=1 54 | ) 55 | 56 | # Trigger Lambda function on instance availability events 57 | fn = _lambda.Function(self, 58 | id="PostgresAvailibilityFunction", 59 | code=_lambda.Code.from_inline("exports.handler = (event) => console.log(event);"), 60 | handler="index.handler", 61 | runtime=_lambda.Runtime.NODEJS_10_X 62 | ) 63 | 64 | availability_rule = db.on_event( 65 | "Availability", 66 | target=targets.LambdaFunction(fn)) 67 | 68 | availability_rule.add_event_pattern( 69 | detail={ 70 | "EventCategories": [ 71 | "availability" 72 | ] 73 | } 74 | ) -------------------------------------------------------------------------------- /stacks/vpc.py: -------------------------------------------------------------------------------- 1 | from aws_cdk import ( 2 | aws_ec2 as ec2, 3 | core 4 | ) 5 | 6 | ec2_type = "t3.micro" 7 | key_name = "id_rsa" # Setup key_name for EC2 instance login 8 | 9 | with open("./user_data/bastion.sh") as f: 10 | user_data = f.read() 11 | 12 | class VpcStack(core.Stack): 13 | 14 | def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: 15 | super().__init__(scope, id, **kwargs) 16 | 17 | self.vpc = ec2.Vpc( 18 | self, 19 | id="VPC", 20 | cidr="10.0.0.0/16", 21 | max_azs=2, 22 | nat_gateways=1, 23 | subnet_configuration=[ 24 | ec2.SubnetConfiguration( 25 | name="public", cidr_mask=24, 26 | reserved=False, subnet_type=ec2.SubnetType.PUBLIC), 27 | ec2.SubnetConfiguration( 28 | name="private", cidr_mask=24, 29 | reserved=False, subnet_type=ec2.SubnetType.PRIVATE), 30 | ec2.SubnetConfiguration( 31 | name="DB", cidr_mask=24, 32 | reserved=False, subnet_type=ec2.SubnetType.ISOLATED 33 | ), 34 | # ec2.SubnetConfiguration( 35 | # name="DB2", cidr_mask=24, 36 | # reserved=False, subnet_type=ec2.SubnetType.ISOLATED 37 | # ) 38 | ], 39 | enable_dns_hostnames=True, 40 | enable_dns_support=True 41 | ) 42 | 43 | core.Tag(key="Application", value=self.stack_name) \ 44 | .add(self.vpc, key="Application", value=self.stack_name) 45 | # core.Tag("Network", "Public").add(vpc) 46 | # core.Tag("Name", "VPCName-Environment").add(vpc) 47 | # core.Tag("Environment", "Environment").add(vpc) 48 | 49 | bastion = ec2.BastionHostLinux( 50 | self, 51 | id="BastionHost", 52 | vpc=self.vpc, 53 | instance_name="BastionHost", 54 | instance_type=ec2.InstanceType(ec2_type), 55 | subnet_selection=ec2.SubnetSelection( 56 | subnet_type=ec2.SubnetType.PUBLIC 57 | ) 58 | ) 59 | bastion.allow_ssh_access_from(ec2.Peer.any_ipv4()) 60 | 61 | # Setup key_name for EC2 instance login if you don't use Session Manager 62 | #bastion.instance.instance.add_property_override("KeyName", key_name) 63 | 64 | ec2.CfnEIP(self, id="BastionHostEIP", domain="vpc", instance_id=bastion.instance_id) 65 | 66 | core.CfnOutput( 67 | self, 68 | id="VPCId", 69 | value=self.vpc.vpc_id, 70 | description="VPC ID", 71 | export_name=f"{self.region}:{self.account}:{self.stack_name}:vpc-id" 72 | ) 73 | 74 | core.CfnOutput( 75 | self, 76 | id="BastionPrivateIP", 77 | value=bastion.instance_private_ip, 78 | description="BASTION Private IP", 79 | export_name=f"{self.region}:{self.account}:{self.stack_name}:bastion-private-ip" 80 | ) 81 | 82 | core.CfnOutput( 83 | self, 84 | id="BastionPublicIP", 85 | value=bastion.instance_public_ip, 86 | description="BASTION Public IP", 87 | export_name=f"{self.region}:{self.account}:{self.stack_name}:bastion-public-ip" 88 | ) 89 | -------------------------------------------------------------------------------- /user_data/bastion.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | sudo yum -y update 3 | sudo yum install -y postgresql.x86_64 4 | sudo yum install -y telnet -------------------------------------------------------------------------------- /user_data/user_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo yum update -y 3 | sudo yum -y install httpd php 4 | sudo chkconfig httpd on 5 | sudo service httpd start --------------------------------------------------------------------------------