cfn-vpn 1.1.1 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,6 @@
1
1
  require 'cfndsl'
2
2
  require 'cfnvpn/templates/helper'
3
+ require 'cfnvpn/templates/lambdas'
3
4
 
4
5
  module CfnVpn
5
6
  module Templates
@@ -32,10 +33,17 @@ module CfnVpn
32
33
  {
33
34
  FederatedAuthentication: {
34
35
  SAMLProviderArn: config[:saml_arn],
35
- SelfServiceSAMLProviderArn: config[:saml_arn]
36
+ SelfServiceSAMLProviderArn: config[:saml_self_service_arn].nil? ? config[:saml_arn] : config[:saml_self_service_arn]
36
37
  },
37
38
  Type: 'federated-authentication'
38
39
  }
40
+ elsif config[:type] == 'active-directory'
41
+ {
42
+ ActiveDirectory: {
43
+ DirectoryId: config[:directory_id]
44
+ },
45
+ Type: 'directory-service-authentication'
46
+ }
39
47
  else
40
48
  {
41
49
  MutualAuthentication: {
@@ -62,6 +70,7 @@ module CfnVpn
62
70
  SplitTunnel config[:split_tunnel]
63
71
  }
64
72
 
73
+ network_assoc_dependson = []
65
74
  config[:subnet_ids].each_with_index do |subnet, index|
66
75
  suffix = index == 0 ? "" : "For#{subnet.resource_safe}"
67
76
 
@@ -71,74 +80,112 @@ module CfnVpn
71
80
  SubnetId subnet
72
81
  }
73
82
 
74
- if config[:default_groups].any?
75
- config[:default_groups].each do |group|
76
- EC2_ClientVpnAuthorizationRule(:"TargetNetworkAuthorizationRule#{suffix}#{group.resource_safe}"[0..255]) {
77
- Condition(:EnableSubnetAssociation)
78
- DependsOn "ClientVpnTargetNetworkAssociation#{suffix}"
79
- Description FnSub("#{name} client-vpn auth rule for subnet association")
80
- AccessGroupId group
81
- ClientVpnEndpointId Ref(:ClientVpnEndpoint)
82
- TargetNetworkCidr CfnVpn::Templates::Helper.get_auth_cidr(config[:region], subnet)
83
- }
84
- end
85
- else
86
- EC2_ClientVpnAuthorizationRule(:"TargetNetworkAuthorizationRule#{suffix}") {
83
+ network_assoc_dependson << "ClientVpnTargetNetworkAssociation#{suffix}"
84
+ end
85
+
86
+ if config[:default_groups].any?
87
+ config[:default_groups].each do |group|
88
+ EC2_ClientVpnAuthorizationRule(:"TargetNetworkAuthorizationRule#{group.resource_safe}"[0..255]) {
87
89
  Condition(:EnableSubnetAssociation)
88
- DependsOn "ClientVpnTargetNetworkAssociation#{suffix}"
90
+ DependsOn network_assoc_dependson if network_assoc_dependson.any?
89
91
  Description FnSub("#{name} client-vpn auth rule for subnet association")
90
- AuthorizeAllGroups true
92
+ AccessGroupId group
91
93
  ClientVpnEndpointId Ref(:ClientVpnEndpoint)
92
- TargetNetworkCidr CfnVpn::Templates::Helper.get_auth_cidr(config[:region], subnet)
94
+ TargetNetworkCidr CfnVpn::Templates::Helper.get_auth_cidr(config[:region], config[:subnet_ids].first)
93
95
  }
94
96
  end
97
+ else
98
+ EC2_ClientVpnAuthorizationRule(:"TargetNetworkAuthorizationRule") {
99
+ Condition(:EnableSubnetAssociation)
100
+ DependsOn network_assoc_dependson if network_assoc_dependson.any?
101
+ Description FnSub("#{name} client-vpn auth rule for subnet association")
102
+ AuthorizeAllGroups true
103
+ ClientVpnEndpointId Ref(:ClientVpnEndpoint)
104
+ TargetNetworkCidr CfnVpn::Templates::Helper.get_auth_cidr(config[:region], config[:subnet_ids].first)
105
+ }
106
+ end
95
107
 
96
- if subnet == config[:internet_route]
97
- EC2_ClientVpnRoute(:RouteToInternet) {
98
- Condition(:EnableSubnetAssociation)
99
- DependsOn "ClientVpnTargetNetworkAssociation#{suffix}"
100
- Description 'Route to the internet'
101
- ClientVpnEndpointId Ref(:ClientVpnEndpoint)
102
- DestinationCidrBlock '0.0.0.0/0'
103
- TargetVpcSubnetId config[:internet_route]
108
+ if !config[:internet_route].nil?
109
+ EC2_ClientVpnRoute(:RouteToInternet) {
110
+ Condition(:EnableSubnetAssociation)
111
+ DependsOn network_assoc_dependson if network_assoc_dependson.any?
112
+ Description "Route to the internet through subnet #{config[:internet_route]}"
113
+ ClientVpnEndpointId Ref(:ClientVpnEndpoint)
114
+ DestinationCidrBlock '0.0.0.0/0'
115
+ TargetVpcSubnetId config[:internet_route]
116
+ }
117
+
118
+ EC2_ClientVpnAuthorizationRule(:RouteToInternetAuthorizationRule) {
119
+ Condition(:EnableSubnetAssociation)
120
+ DependsOn network_assoc_dependson if network_assoc_dependson.any?
121
+ Description "Internet route authorization from subnet #{config[:internet_route]}"
122
+ AuthorizeAllGroups true
123
+ ClientVpnEndpointId Ref(:ClientVpnEndpoint)
124
+ TargetNetworkCidr '0.0.0.0/0'
125
+ }
126
+
127
+ output(:InternetRoute, config[:internet_route])
128
+ end
129
+
130
+ dns_routes = config[:routes].select {|route| route.has_key?(:dns)}
131
+ cidr_routes = config[:routes].select {|route| route.has_key?(:cidr)}
132
+
133
+ if dns_routes.any?
134
+ auto_route_populator(name, config[:bucket])
135
+
136
+ dns_routes.each do |route|
137
+ input = {
138
+ Record: route[:dns],
139
+ ClientVpnEndpointId: "${ClientVpnEndpoint}",
140
+ TargetSubnet: route[:subnet],
141
+ Description: route[:desc]
104
142
  }
105
-
106
- EC2_ClientVpnAuthorizationRule(:RouteToInternetAuthorizationRule) {
107
- Condition(:EnableSubnetAssociation)
108
- DependsOn "ClientVpnTargetNetworkAssociation#{suffix}"
109
- Description 'Route to the internet'
110
- AuthorizeAllGroups true
111
- ClientVpnEndpointId Ref(:ClientVpnEndpoint)
112
- TargetNetworkCidr '0.0.0.0/0'
143
+
144
+ if route[:groups].any?
145
+ input[:Groups] = route[:groups]
146
+ end
147
+
148
+ Events_Rule(:"CfnVpnAutoRoutePopulatorEvent#{route[:dns].resource_safe}"[0..255]) {
149
+ State 'ENABLED'
150
+ Description "cfnvpn auto route populator schedule for #{route[:dns]}"
151
+ ScheduleExpression "rate(5 minutes)"
152
+ Targets([
153
+ {
154
+ Arn: FnGetAtt(:CfnVpnAutoRoutePopulator, :Arn),
155
+ Id: "cfnvpnautoroutepopulator#{route[:dns].event_id_safe}",
156
+ Input: FnSub(input.to_json)
157
+ }
158
+ ])
113
159
  }
114
-
115
- output(:InternetRoute, config[:internet_route])
116
160
  end
117
161
  end
118
162
 
119
- config[:routes].each do |route|
120
- EC2_ClientVpnRoute(:"#{route[:cidr].resource_safe}VpnRoute") {
121
- Description route[:desc]
122
- ClientVpnEndpointId Ref(:ClientVpnEndpoint)
123
- DestinationCidrBlock route[:cidr]
124
- TargetVpcSubnetId route[:subnet]
125
- }
126
- if route[:groups].any?
127
- route[:groups].each do |group|
128
- EC2_ClientVpnAuthorizationRule(:"#{route[:cidr].resource_safe}AuthorizationRule#{group.resource_safe}"[0..255]) {
129
- Description route[:desc]
130
- AccessGroupId group
163
+ if cidr_routes.any?
164
+ cidr_routes.each do |route|
165
+ EC2_ClientVpnRoute(:"#{route[:cidr].resource_safe}VpnRoute") {
166
+ Description "cfnvpn static route for #{route[:cidr]}. #{route[:desc]}".strip
167
+ ClientVpnEndpointId Ref(:ClientVpnEndpoint)
168
+ DestinationCidrBlock route[:cidr]
169
+ TargetVpcSubnetId route[:subnet]
170
+ }
171
+
172
+ if route[:groups].any?
173
+ route[:groups].each do |group|
174
+ EC2_ClientVpnAuthorizationRule(:"#{route[:cidr].resource_safe}AuthorizationRule#{group.resource_safe}"[0..255]) {
175
+ Description "cfnvpn static authorization rule for group #{group} to route #{route[:cidr]}. #{route[:desc]}".strip
176
+ AccessGroupId group
177
+ ClientVpnEndpointId Ref(:ClientVpnEndpoint)
178
+ TargetNetworkCidr route[:cidr]
179
+ }
180
+ end
181
+ else
182
+ EC2_ClientVpnAuthorizationRule(:"#{route[:cidr].resource_safe}AllowAllAuthorizationRule") {
183
+ Description "cfnvpn static allow all authorization rule to route #{route[:cidr]}. #{route[:desc]}".strip
184
+ AuthorizeAllGroups true
131
185
  ClientVpnEndpointId Ref(:ClientVpnEndpoint)
132
186
  TargetNetworkCidr route[:cidr]
133
187
  }
134
188
  end
135
- else
136
- EC2_ClientVpnAuthorizationRule(:"#{route[:cidr].resource_safe}AllowAllAuthorizationRule") {
137
- Description route[:desc]
138
- AuthorizeAllGroups true
139
- ClientVpnEndpointId Ref(:ClientVpnEndpoint)
140
- TargetNetworkCidr route[:cidr]
141
- }
142
189
  end
143
190
  end
144
191
 
@@ -149,13 +196,13 @@ module CfnVpn
149
196
  Type 'String'
150
197
  Value config.to_json
151
198
  Tags({
152
- Name: "#{name}-cfnvpn-config",
199
+ Name: "#{name}-cfnvpn-config",
153
200
  Environment: 'cfnvpn'
154
201
  })
155
202
  }
156
203
 
157
204
  if config[:start] || config[:stop]
158
- scheduler(name, config[:start], config[:stop])
205
+ scheduler(name, config[:start], config[:stop], config[:bucket])
159
206
  output(:Start, config[:start]) if config[:start]
160
207
  output(:Stop, config[:stop]) if config[:stop]
161
208
  end
@@ -170,6 +217,8 @@ module CfnVpn
170
217
 
171
218
  if config[:type] == 'federated'
172
219
  output(:SamlArn, config[:saml_arn])
220
+ elsif config[:type] == 'active-directory'
221
+ output(:DirectoryId, config[:directory_id])
173
222
  else
174
223
  output(:ClientCertArn, config[:client_cert_arn])
175
224
  end
@@ -179,7 +228,92 @@ module CfnVpn
179
228
  Output(name) { Value value }
180
229
  end
181
230
 
182
- def scheduler(name, start, stop)
231
+ def auto_route_populator(name, bucket)
232
+ IAM_Role(:CfnVpnAutoRoutePopulatorRole) {
233
+ AssumeRolePolicyDocument({
234
+ Version: '2012-10-17',
235
+ Statement: [{
236
+ Effect: 'Allow',
237
+ Principal: { Service: [ 'lambda.amazonaws.com' ] },
238
+ Action: [ 'sts:AssumeRole' ]
239
+ }]
240
+ })
241
+ Path '/cfnvpn/'
242
+ Policies([
243
+ {
244
+ PolicyName: 'client-vpn',
245
+ PolicyDocument: {
246
+ Version: '2012-10-17',
247
+ Statement: [{
248
+ Effect: 'Allow',
249
+ Action: [
250
+ 'ec2:AuthorizeClientVpnIngress',
251
+ 'ec2:RevokeClientVpnIngress',
252
+ 'ec2:DescribeClientVpnAuthorizationRules',
253
+ 'ec2:DescribeClientVpnEndpoints',
254
+ 'ec2:DescribeClientVpnRoutes',
255
+ 'ec2:CreateClientVpnRoute',
256
+ 'ec2:DeleteClientVpnRoute'
257
+ ],
258
+ Resource: '*'
259
+ }]
260
+ }
261
+ },
262
+ {
263
+ PolicyName: 'logging',
264
+ PolicyDocument: {
265
+ Version: '2012-10-17',
266
+ Statement: [{
267
+ Effect: 'Allow',
268
+ Action: [
269
+ 'logs:DescribeLogGroups',
270
+ 'logs:CreateLogGroup',
271
+ 'logs:CreateLogStream',
272
+ 'logs:DescribeLogStreams',
273
+ 'logs:PutLogEvents'
274
+ ],
275
+ Resource: '*'
276
+ }]
277
+ }
278
+ }
279
+ ])
280
+ Tags([
281
+ { Key: 'Name', Value: "#{name}-cfnvpn-auto-route-populator-role" },
282
+ { Key: 'Environment', Value: 'cfnvpn' }
283
+ ])
284
+ }
285
+
286
+ s3_key = CfnVpn::Templates::Lambdas.package_lambda(name: name, bucket: bucket, func: 'auto_route_populator', files: ['app.py'])
287
+
288
+ Lambda_Function(:CfnVpnAutoRoutePopulator) {
289
+ Runtime 'python3.8'
290
+ Role FnGetAtt(:CfnVpnAutoRoutePopulatorRole, :Arn)
291
+ MemorySize '128'
292
+ Handler 'app.handler'
293
+ Timeout 60
294
+ Code({
295
+ S3Bucket: bucket,
296
+ S3Key: s3_key
297
+ })
298
+ Tags([
299
+ { Key: 'Name', Value: "#{name}-cfnvpn-auto-route-populator" },
300
+ { Key: 'Environment', Value: 'cfnvpn' }
301
+ ])
302
+ }
303
+
304
+ Logs_LogGroup(:CfnVpnAutoRoutePopulatorLogGroup) {
305
+ LogGroupName FnSub("/aws/lambda/${CfnVpnAutoRoutePopulator}")
306
+ RetentionInDays 30
307
+ }
308
+
309
+ Lambda_Permission(:CfnVpnAutoRoutePopulatorFunctionPermissions) {
310
+ FunctionName Ref(:CfnVpnAutoRoutePopulator)
311
+ Action 'lambda:InvokeFunction'
312
+ Principal 'events.amazonaws.com'
313
+ }
314
+ end
315
+
316
+ def scheduler(name, start, stop, bucket)
183
317
  IAM_Role(:ClientVpnSchedulerRole) {
184
318
  AssumeRolePolicyDocument({
185
319
  Version: '2012-10-17',
@@ -249,46 +383,17 @@ module CfnVpn
249
383
  ])
250
384
  }
251
385
 
386
+ s3_key = CfnVpn::Templates::Lambdas.package_lambda(name: name, bucket: bucket, func: 'scheduler', files: ['app.py'])
387
+
252
388
  Lambda_Function(:ClientVpnSchedulerFunction) {
253
- Runtime 'python3.7'
389
+ Runtime 'python3.8'
254
390
  Role FnGetAtt(:ClientVpnSchedulerRole, :Arn)
255
391
  MemorySize '128'
256
- Handler 'index.handler'
392
+ Handler 'app.handler'
393
+ Timeout 60
257
394
  Code({
258
- ZipFile: <<~EOS
259
- import boto3
260
-
261
- def handler(event, context):
262
-
263
- print(f"updating cfn-vpn stack {event['StackName']} parameter AssociateSubnets with value {event['AssociateSubnets']}")
264
-
265
- if event['AssociateSubnets'] == 'false':
266
- print(f"terminating current vpn sessions to {event['ClientVpnEndpointId']}")
267
- ec2 = boto3.client('ec2')
268
- resp = ec2.describe_client_vpn_connections(ClientVpnEndpointId=event['ClientVpnEndpointId'])
269
- for conn in resp['Connections']:
270
- if conn['Status']['Code'] == 'active':
271
- ec2.terminate_client_vpn_connections(
272
- ClientVpnEndpointId=event['ClientVpnEndpointId'],
273
- ConnectionId=conn['ConnectionId']
274
- )
275
- print(f"terminated session {conn['ConnectionId']}")
276
-
277
- client = boto3.client('cloudformation')
278
- print(client.update_stack(
279
- StackName=event['StackName'],
280
- UsePreviousTemplate=True,
281
- Capabilities=['CAPABILITY_IAM'],
282
- Parameters=[
283
- {
284
- 'ParameterKey': 'AssociateSubnets',
285
- 'ParameterValue': event['AssociateSubnets']
286
- }
287
- ]
288
- ))
289
-
290
- return 'OK'
291
- EOS
395
+ S3Bucket: bucket,
396
+ S3Key: s3_key
292
397
  })
293
398
  Tags([
294
399
  { Key: 'Name', Value: "#{name}-cfnvpn-scheduler-function" },
@@ -1,4 +1,4 @@
1
1
  module CfnVpn
2
- VERSION = "1.1.1".freeze
2
+ VERSION = "1.3.3".freeze
3
3
  CHANGE_SET_VERSION = VERSION.gsub('.', '-').freeze
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cfn-vpn
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guslington
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-15 00:00:00.000000000 Z
11
+ date: 2021-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -78,6 +78,20 @@ dependencies:
78
78
  - - '='
79
79
  - !ruby/object:Gem::Version
80
80
  version: 2.0.4
81
+ - !ruby/object:Gem::Dependency
82
+ name: rubyzip
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '2.3'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '2.3'
81
95
  - !ruby/object:Gem::Dependency
82
96
  name: aws-sdk-ec2
83
97
  requirement: !ruby/object:Gem::Requirement
@@ -254,8 +268,12 @@ files:
254
268
  - lib/cfnvpn/globals.rb
255
269
  - lib/cfnvpn/log.rb
256
270
  - lib/cfnvpn/s3.rb
271
+ - lib/cfnvpn/s3_bucket.rb
257
272
  - lib/cfnvpn/string.rb
258
273
  - lib/cfnvpn/templates/helper.rb
274
+ - lib/cfnvpn/templates/lambdas.rb
275
+ - lib/cfnvpn/templates/lambdas/auto_route_populator/app.py
276
+ - lib/cfnvpn/templates/lambdas/scheduler/app.py
259
277
  - lib/cfnvpn/templates/vpn.rb
260
278
  - lib/cfnvpn/version.rb
261
279
  homepage: https://github.com/base2services/aws-client-vpn
@@ -279,7 +297,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
279
297
  - !ruby/object:Gem::Version
280
298
  version: '0'
281
299
  requirements: []
282
- rubygems_version: 3.1.4
300
+ rubygems_version: 3.1.6
283
301
  signing_key:
284
302
  specification_version: 4
285
303
  summary: creates and manages resources for the aws client vpn