-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathapp.py
179 lines (148 loc) · 5.35 KB
/
app.py
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/usr/bin/env python3
from aws_cdk import (
core,
aws_autoscaling as autoscaling,
aws_ec2 as ec2,
aws_elasticloadbalancingv2 as elbv2,
aws_iam as iam,
)
try:
with open('./userdata.sh', 'r') as file:
raw_user_data = file.read()
except OSError:
print('Failed to get UserData script')
class SourceVpc(core.Construct):
def __init__(self, scope: core.Construct, id: str, *, endpoint_service: ec2.CfnVPCEndpoint, **kwargs):
super().__init__(scope, id, **kwargs)
vpc = ec2.Vpc(
self, 'Vpc',
cidr='192.168.0.0/16',
max_azs=2,
nat_gateways=1,
)
role = iam.Role(
self, 'Ec2SsmRole',
assumed_by=iam.ServicePrincipal('ec2.amazonaws.com'),
managed_policies=[
iam.ManagedPolicy.from_aws_managed_policy_name('AmazonSSMManagedInstanceCore')
],
)
user_data = ec2.UserData.for_linux()
user_data.add_commands('echo -e "+noall +answer" > /root/.digrc')
ec2.Instance(
self, 'Instance',
role=role,
vpc=vpc,
user_data=user_data,
instance_type=ec2.InstanceType.of(
instance_class=ec2.InstanceClass.BURSTABLE3_AMD,
instance_size=ec2.InstanceSize.NANO,
),
machine_image=ec2.AmazonLinuxImage(
generation=ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
),
)
sg = ec2.SecurityGroup(
self, 'EndpointSecurityGroup',
vpc=vpc,
)
sg.add_ingress_rule(
ec2.Peer.ipv4('0.0.0.0/0'),
ec2.Port.tcp(80)
)
# ! Python substitution within CDK substitution within CloudFormation substitution !
# First, python replace {endpoint_id} with the value of the logical_id property
# The value of this property is like "${Token[PrivateLinkDemo...]}"
# At `cdk synth` this will resolve to the logical ID in the output CloudFormation template
# Lastly, CloudFormation will perform an Fn::Sub
service_name = core.Fn.sub('com.amazonaws.vpce.${{AWS::Region}}.${{{endpoint_id}}}'.format(
endpoint_id=endpoint_service.logical_id
))
# TODO: replace by CDK construct when available
ec2.CfnVPCEndpoint(
self, 'Endpoint',
service_name=service_name,
vpc_endpoint_type='Interface', # ec2.VpcEndpointType.INTERFACE
vpc_id=vpc.vpc_id,
security_group_ids=[
sg.security_group_id,
],
subnet_ids=[
subnet.subnet_id
for subnet in vpc.private_subnets
],
)
# TODO: make an output with a curl command
# core.CfnOutput(self, 'Command',
# value=core.Fn.get_att(DnsEntries),
# )
class DestinationVpc(core.Construct):
def __init__(self, scope: core.Construct, id: str, **kwargs):
super().__init__(scope, id, **kwargs)
vpc = ec2.Vpc(
self, 'Vpc',
cidr='172.16.0.0/16',
max_azs=2,
nat_gateways=1,
)
user_data = ec2.UserData.for_linux()
user_data.add_commands(raw_user_data)
role = iam.Role(
self, 'Ec2SsmRole',
assumed_by=iam.ServicePrincipal('ec2.amazonaws.com'),
managed_policies=[
iam.ManagedPolicy.from_aws_managed_policy_name('AmazonSSMManagedInstanceCore')
],
)
asg = autoscaling.AutoScalingGroup(
self, 'ASG',
role=role,
vpc=vpc,
user_data=user_data,
instance_type=ec2.InstanceType.of(
instance_class=ec2.InstanceClass.BURSTABLE3_AMD,
instance_size=ec2.InstanceSize.NANO,
),
machine_image=ec2.AmazonLinuxImage(
generation=ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
),
min_capacity=4,
max_capacity=4,
update_type=autoscaling.UpdateType.ROLLING_UPDATE,
)
asg.connections.allow_from_any_ipv4(ec2.Port.tcp(80))
# Only possible with ALB
# asg.scale_on_request_count('AModestLoad',
# target_requests_per_second=1
# )
nlb = elbv2.NetworkLoadBalancer(
self, 'NLB',
vpc=vpc,
internet_facing=False,
cross_zone_enabled=True,
)
listener = nlb.add_listener(
'Listener',
port=80,
)
listener.add_targets(
'Target',
port=80,
deregistration_delay=core.Duration.seconds(10),
targets=[asg],
)
# TODO: replace by CDK construct when available
service = ec2.CfnVPCEndpointService(
self, 'Service',
network_load_balancer_arns=[nlb.load_balancer_arn],
acceptance_required=False,
)
self.endpoint_service = service
class PrivateLinkStack(core.Stack):
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
destination = DestinationVpc(self, 'Destination')
SourceVpc(self, 'Source', endpoint_service=destination.endpoint_service)
app = core.App()
transit_stack = PrivateLinkStack(app, 'PrivateLinkDemo')
app.synth()