cfn-vpn 0.4.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/build-gem.yml +25 -0
- data/.github/workflows/release-gem.yml +34 -0
- data/.github/workflows/release-image.yml +33 -0
- data/Dockerfile +26 -0
- data/Gemfile.lock +30 -38
- data/README.md +1 -224
- data/cfn-vpn.gemspec +3 -5
- data/docs/README.md +44 -0
- data/docs/certificate-users.md +89 -0
- data/docs/getting-started.md +99 -0
- data/docs/modifying.md +67 -0
- data/docs/routes.md +84 -0
- data/docs/scheduling.md +32 -0
- data/docs/sessions.md +27 -0
- data/lib/cfnvpn.rb +32 -24
- data/lib/cfnvpn/{client.rb → actions/client.rb} +11 -8
- data/lib/cfnvpn/actions/embedded.rb +110 -0
- data/lib/cfnvpn/actions/init.rb +130 -0
- data/lib/cfnvpn/actions/modify.rb +149 -0
- data/lib/cfnvpn/actions/params.rb +73 -0
- data/lib/cfnvpn/{revoke.rb → actions/revoke.rb} +10 -8
- data/lib/cfnvpn/actions/routes.rb +144 -0
- data/lib/cfnvpn/{sessions.rb → actions/sessions.rb} +7 -6
- data/lib/cfnvpn/{share.rb → actions/share.rb} +10 -10
- data/lib/cfnvpn/actions/subnets.rb +78 -0
- data/lib/cfnvpn/certificates.rb +70 -20
- data/lib/cfnvpn/clientvpn.rb +34 -68
- data/lib/cfnvpn/compiler.rb +23 -0
- data/lib/cfnvpn/config.rb +34 -77
- data/lib/cfnvpn/{cloudformation.rb → deployer.rb} +48 -20
- data/lib/cfnvpn/globals.rb +16 -0
- data/lib/cfnvpn/log.rb +26 -26
- data/lib/cfnvpn/s3.rb +13 -3
- data/lib/cfnvpn/string.rb +29 -0
- data/lib/cfnvpn/templates/helper.rb +14 -0
- data/lib/cfnvpn/templates/vpn.rb +344 -0
- data/lib/cfnvpn/version.rb +1 -1
- metadata +56 -41
- data/lib/cfnvpn/cfhighlander.rb +0 -49
- data/lib/cfnvpn/init.rb +0 -107
- data/lib/cfnvpn/modify.rb +0 -102
- data/lib/cfnvpn/routes.rb +0 -83
- data/lib/cfnvpn/templates/cfnvpn.cfhighlander.rb.tt +0 -27
@@ -0,0 +1,16 @@
|
|
1
|
+
module CfnVpn
|
2
|
+
class << self
|
3
|
+
|
4
|
+
# Returns the filepath to the location CfnVpn will use for
|
5
|
+
# storage. Used for certificate generation as well as the
|
6
|
+
# download and upload location. Can be overridden by specifying
|
7
|
+
# a value for the ENV variable
|
8
|
+
# 'CFNVPN_PATH'.
|
9
|
+
#
|
10
|
+
# @return [String]
|
11
|
+
def cfnvpn_path
|
12
|
+
@cfnvpn_path ||= File.expand_path(ENV["CFNVPN_PATH"] || "~/.cfnvpn")
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
data/lib/cfnvpn/log.rb
CHANGED
@@ -1,38 +1,38 @@
|
|
1
1
|
require 'logger'
|
2
2
|
|
3
3
|
module CfnVpn
|
4
|
-
module Log
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
module Log
|
5
|
+
class << self
|
6
|
+
def colors
|
7
|
+
@colors ||= {
|
8
|
+
ERROR: 31, # red
|
9
|
+
WARN: 33, # yellow
|
10
|
+
INFO: 0,
|
11
|
+
DEBUG: 32 # grenn
|
12
|
+
}
|
13
|
+
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
def logger
|
16
|
+
if @logger.nil?
|
17
|
+
@logger = Logger.new(STDOUT)
|
18
|
+
@logger.level = Logger::INFO
|
19
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
20
|
+
"\e[#{colors[severity.to_sym]}m#{severity}: - #{msg}\e[0m\n"
|
21
|
+
end
|
21
22
|
end
|
23
|
+
@logger
|
22
24
|
end
|
23
|
-
@logger
|
24
|
-
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
def logger=(logger)
|
27
|
+
@logger = logger
|
28
|
+
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
levels = %w(debug info warn error fatal)
|
31
|
+
levels.each do |level|
|
32
|
+
define_method("#{level.to_sym}") do |msg|
|
33
|
+
self.logger.send(level, msg)
|
34
|
+
end
|
34
35
|
end
|
35
36
|
end
|
36
|
-
|
37
37
|
end
|
38
38
|
end
|
data/lib/cfnvpn/s3.rb
CHANGED
@@ -14,7 +14,7 @@ module CfnVpn
|
|
14
14
|
def store_object(file)
|
15
15
|
body = File.open(file, 'rb').read
|
16
16
|
file_name = file.split('/').last
|
17
|
-
Log.logger.debug("uploading #{file} to s3://#{@bucket}/#{@path}/#{file_name}")
|
17
|
+
CfnVpn::Log.logger.debug("uploading #{file} to s3://#{@bucket}/#{@path}/#{file_name}")
|
18
18
|
@client.put_object({
|
19
19
|
body: body,
|
20
20
|
bucket: @bucket,
|
@@ -26,7 +26,7 @@ module CfnVpn
|
|
26
26
|
|
27
27
|
def get_object(file)
|
28
28
|
file_name = file.split('/').last
|
29
|
-
Log.logger.debug("downloading s3://#{@bucket}/#{@path}/#{file_name} to #{file}")
|
29
|
+
CfnVpn::Log.logger.debug("downloading s3://#{@bucket}/#{@path}/#{file_name} to #{file}")
|
30
30
|
@client.get_object(
|
31
31
|
response_target: file,
|
32
32
|
bucket: @bucket,
|
@@ -34,7 +34,7 @@ module CfnVpn
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def store_config(config)
|
37
|
-
Log.logger.debug("uploading config to s3://#{@bucket}/#{@path}/#{@name}.config.ovpn")
|
37
|
+
CfnVpn::Log.logger.debug("uploading config to s3://#{@bucket}/#{@path}/#{@name}.config.ovpn")
|
38
38
|
@client.put_object({
|
39
39
|
body: config,
|
40
40
|
bucket: @bucket,
|
@@ -53,5 +53,15 @@ module CfnVpn
|
|
53
53
|
presigner.presigned_url(:get_object, params)
|
54
54
|
end
|
55
55
|
|
56
|
+
def store_embedded_config(config, cn)
|
57
|
+
CfnVpn::Log.logger.debug("uploading config to s3://#{@bucket}/#{@path}/#{@name}_#{cn}.config.ovpn")
|
58
|
+
@client.put_object({
|
59
|
+
body: config,
|
60
|
+
bucket: @bucket,
|
61
|
+
key: "#{@path}/#{@name}_#{cn}.config.ovpn",
|
62
|
+
tagging: "cfnvpn:name=#{@name}"
|
63
|
+
})
|
64
|
+
end
|
65
|
+
|
56
66
|
end
|
57
67
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class String
|
2
|
+
def underscore
|
3
|
+
self.gsub(/::/, '/').
|
4
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
5
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
6
|
+
tr("-", "_").
|
7
|
+
downcase
|
8
|
+
end
|
9
|
+
|
10
|
+
def resource_safe
|
11
|
+
self.gsub(/[^a-zA-Z0-9]/, "").capitalize
|
12
|
+
end
|
13
|
+
|
14
|
+
def colorize(color_code)
|
15
|
+
"\e[#{color_code}m#{self}\e[0m"
|
16
|
+
end
|
17
|
+
|
18
|
+
def red
|
19
|
+
colorize(31)
|
20
|
+
end
|
21
|
+
|
22
|
+
def green
|
23
|
+
colorize(32)
|
24
|
+
end
|
25
|
+
|
26
|
+
def yellow
|
27
|
+
colorize(33)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'aws-sdk-ec2'
|
2
|
+
|
3
|
+
module CfnVpn
|
4
|
+
module Templates
|
5
|
+
class Helper
|
6
|
+
def self.get_auth_cidr(region, subnet_id)
|
7
|
+
client = Aws::EC2::Client.new(region: region)
|
8
|
+
subnets = client.describe_subnets({subnet_ids:[subnet_id]})
|
9
|
+
vpcs = client.describe_vpcs({vpc_ids:[subnets.subnets[0].vpc_id]})
|
10
|
+
return vpcs.vpcs[0].cidr_block
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,344 @@
|
|
1
|
+
require 'cfndsl'
|
2
|
+
require 'cfnvpn/templates/helper'
|
3
|
+
|
4
|
+
module CfnVpn
|
5
|
+
module Templates
|
6
|
+
class Vpn < CfnDsl::CloudFormationTemplate
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def render(name, config)
|
13
|
+
Description "cfnvpn #{name} AWS Client-VPN"
|
14
|
+
Parameter(:AssociateSubnets) {
|
15
|
+
Type 'String'
|
16
|
+
Default 'true'
|
17
|
+
AllowedValues ['true', 'false']
|
18
|
+
Description 'Toggle to false to disassociate all Client VPN subnet associations'
|
19
|
+
}
|
20
|
+
|
21
|
+
Condition(:EnableSubnetAssociation, FnEquals(Ref(:AssociateSubnets), 'true'))
|
22
|
+
|
23
|
+
Logs_LogGroup(:ClientVpnLogGroup) {
|
24
|
+
LogGroupName FnSub("#{name}-ClientVpn")
|
25
|
+
RetentionInDays 30
|
26
|
+
}
|
27
|
+
|
28
|
+
EC2_ClientVpnEndpoint(:ClientVpnEndpoint) {
|
29
|
+
Description FnSub("cfnvpn #{name} AWS Client-VPN")
|
30
|
+
AuthenticationOptions([
|
31
|
+
if config[:type] == 'federated'
|
32
|
+
{
|
33
|
+
FederatedAuthentication: {
|
34
|
+
SAMLProviderArn: config[:saml_arn],
|
35
|
+
SelfServiceSAMLProviderArn: config[:saml_arn]
|
36
|
+
},
|
37
|
+
Type: 'federated-authentication'
|
38
|
+
}
|
39
|
+
else
|
40
|
+
{
|
41
|
+
MutualAuthentication: {
|
42
|
+
ClientRootCertificateChainArn: config[:client_cert_arn]
|
43
|
+
},
|
44
|
+
Type: 'certificate-authentication'
|
45
|
+
}
|
46
|
+
end
|
47
|
+
])
|
48
|
+
ServerCertificateArn config[:server_cert_arn]
|
49
|
+
ClientCidrBlock config[:cidr]
|
50
|
+
ConnectionLogOptions({
|
51
|
+
CloudwatchLogGroup: Ref(:ClientVpnLogGroup),
|
52
|
+
Enabled: true
|
53
|
+
})
|
54
|
+
DnsServers config[:dns_servers].any? ? config[:dns_servers] : Ref('AWS::NoValue')
|
55
|
+
TagSpecifications([{
|
56
|
+
ResourceType: "client-vpn-endpoint",
|
57
|
+
Tags: [
|
58
|
+
{ Key: 'Name', Value: name }
|
59
|
+
]
|
60
|
+
}])
|
61
|
+
TransportProtocol config[:protocol]
|
62
|
+
SplitTunnel config[:split_tunnel]
|
63
|
+
}
|
64
|
+
|
65
|
+
config[:subnet_ids].each_with_index do |subnet, index|
|
66
|
+
suffix = index == 0 ? "" : "For#{subnet.resource_safe}"
|
67
|
+
|
68
|
+
EC2_ClientVpnTargetNetworkAssociation(:"ClientVpnTargetNetworkAssociation#{suffix}") {
|
69
|
+
Condition(:EnableSubnetAssociation)
|
70
|
+
ClientVpnEndpointId Ref(:ClientVpnEndpoint)
|
71
|
+
SubnetId subnet
|
72
|
+
}
|
73
|
+
|
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}") {
|
87
|
+
Condition(:EnableSubnetAssociation)
|
88
|
+
DependsOn "ClientVpnTargetNetworkAssociation#{suffix}"
|
89
|
+
Description FnSub("#{name} client-vpn auth rule for subnet association")
|
90
|
+
AuthorizeAllGroups true
|
91
|
+
ClientVpnEndpointId Ref(:ClientVpnEndpoint)
|
92
|
+
TargetNetworkCidr CfnVpn::Templates::Helper.get_auth_cidr(config[:region], subnet)
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
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]
|
104
|
+
}
|
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'
|
113
|
+
}
|
114
|
+
|
115
|
+
output(:InternetRoute, config[:internet_route])
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
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
|
131
|
+
ClientVpnEndpointId Ref(:ClientVpnEndpoint)
|
132
|
+
TargetNetworkCidr route[:cidr]
|
133
|
+
}
|
134
|
+
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
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
SSM_Parameter(:CfnVpnConfig) {
|
146
|
+
Description "#{name} cfnvpn config"
|
147
|
+
Name "/cfnvpn/config/#{name}"
|
148
|
+
Tier 'Standard'
|
149
|
+
Type 'String'
|
150
|
+
Value config.to_json
|
151
|
+
Tags({
|
152
|
+
Name: "#{name}-cfnvpn-config",
|
153
|
+
Environment: 'cfnvpn'
|
154
|
+
})
|
155
|
+
}
|
156
|
+
|
157
|
+
if config[:start] || config[:stop]
|
158
|
+
scheduler(name, config[:start], config[:stop])
|
159
|
+
output(:Start, config[:start]) if config[:start]
|
160
|
+
output(:Stop, config[:stop]) if config[:stop]
|
161
|
+
end
|
162
|
+
|
163
|
+
output(:ServerCertArn, config[:server_cert_arn])
|
164
|
+
output(:Cidr, config[:cidr])
|
165
|
+
output(:DnsServers, config.fetch(:dns_servers, []).join(','))
|
166
|
+
output(:SubnetIds, config[:subnet_ids].join(','))
|
167
|
+
output(:SplitTunnel, config[:split_tunnel])
|
168
|
+
output(:Protocol, config[:protocol])
|
169
|
+
output(:Type, config[:type])
|
170
|
+
|
171
|
+
if config[:type] == 'federated'
|
172
|
+
output(:SamlArn, config[:saml_arn])
|
173
|
+
else
|
174
|
+
output(:ClientCertArn, config[:client_cert_arn])
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def output(name, value)
|
179
|
+
Output(name) { Value value }
|
180
|
+
end
|
181
|
+
|
182
|
+
def scheduler(name, start, stop)
|
183
|
+
IAM_Role(:ClientVpnSchedulerRole) {
|
184
|
+
AssumeRolePolicyDocument({
|
185
|
+
Version: '2012-10-17',
|
186
|
+
Statement: [{
|
187
|
+
Effect: 'Allow',
|
188
|
+
Principal: { Service: [ 'lambda.amazonaws.com' ] },
|
189
|
+
Action: [ 'sts:AssumeRole' ]
|
190
|
+
}]
|
191
|
+
})
|
192
|
+
Path '/cfnvpn/'
|
193
|
+
Policies([
|
194
|
+
{
|
195
|
+
PolicyName: 'cloudformation',
|
196
|
+
PolicyDocument: {
|
197
|
+
Version: '2012-10-17',
|
198
|
+
Statement: [{
|
199
|
+
Effect: 'Allow',
|
200
|
+
Action: [
|
201
|
+
'cloudformation:UpdateStack'
|
202
|
+
],
|
203
|
+
Resource: FnSub("arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/#{name}-cfnvpn/*")
|
204
|
+
}]
|
205
|
+
}
|
206
|
+
},
|
207
|
+
{
|
208
|
+
PolicyName: 'client-vpn',
|
209
|
+
PolicyDocument: {
|
210
|
+
Version: '2012-10-17',
|
211
|
+
Statement: [{
|
212
|
+
Effect: 'Allow',
|
213
|
+
Action: [
|
214
|
+
'ec2:AssociateClientVpnTargetNetwork',
|
215
|
+
'ec2:DisassociateClientVpnTargetNetwork',
|
216
|
+
'ec2:DescribeClientVpnTargetNetworks',
|
217
|
+
'ec2:AuthorizeClientVpnIngress',
|
218
|
+
'ec2:RevokeClientVpnIngress',
|
219
|
+
'ec2:DescribeClientVpnAuthorizationRules',
|
220
|
+
'ec2:DescribeClientVpnEndpoints',
|
221
|
+
'ec2:DescribeClientVpnConnections',
|
222
|
+
'ec2:TerminateClientVpnConnections'
|
223
|
+
],
|
224
|
+
Resource: '*'
|
225
|
+
}]
|
226
|
+
}
|
227
|
+
},
|
228
|
+
{
|
229
|
+
PolicyName: 'logging',
|
230
|
+
PolicyDocument: {
|
231
|
+
Version: '2012-10-17',
|
232
|
+
Statement: [{
|
233
|
+
Effect: 'Allow',
|
234
|
+
Action: [
|
235
|
+
'logs:DescribeLogGroups',
|
236
|
+
'logs:CreateLogGroup',
|
237
|
+
'logs:CreateLogStream',
|
238
|
+
'logs:DescribeLogStreams',
|
239
|
+
'logs:PutLogEvents'
|
240
|
+
],
|
241
|
+
Resource: '*'
|
242
|
+
}]
|
243
|
+
}
|
244
|
+
}
|
245
|
+
])
|
246
|
+
Tags([
|
247
|
+
{ Key: 'Name', Value: "#{name}-cfnvpn-scheduler-role" },
|
248
|
+
{ Key: 'Environment', Value: 'cfnvpn' }
|
249
|
+
])
|
250
|
+
}
|
251
|
+
|
252
|
+
Lambda_Function(:ClientVpnSchedulerFunction) {
|
253
|
+
Runtime 'python3.7'
|
254
|
+
Role FnGetAtt(:ClientVpnSchedulerRole, :Arn)
|
255
|
+
MemorySize '128'
|
256
|
+
Handler 'index.handler'
|
257
|
+
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
|
292
|
+
})
|
293
|
+
Tags([
|
294
|
+
{ Key: 'Name', Value: "#{name}-cfnvpn-scheduler-function" },
|
295
|
+
{ Key: 'Environment', Value: 'cfnvpn' }
|
296
|
+
])
|
297
|
+
}
|
298
|
+
|
299
|
+
Logs_LogGroup(:ClientVpnSchedulerLogGroup) {
|
300
|
+
LogGroupName FnSub("/aws/lambda/${ClientVpnSchedulerFunction}")
|
301
|
+
RetentionInDays 30
|
302
|
+
}
|
303
|
+
|
304
|
+
Lambda_Permission(:ClientVpnSchedulerFunctionPermissions) {
|
305
|
+
FunctionName Ref(:ClientVpnSchedulerFunction)
|
306
|
+
Action 'lambda:InvokeFunction'
|
307
|
+
Principal 'events.amazonaws.com'
|
308
|
+
}
|
309
|
+
|
310
|
+
if start
|
311
|
+
Events_Rule(:ClientVpnSchedulerStart) {
|
312
|
+
State 'ENABLED'
|
313
|
+
Description "cfnvpn start schedule"
|
314
|
+
ScheduleExpression "cron(#{start})"
|
315
|
+
Targets([
|
316
|
+
{
|
317
|
+
Arn: FnGetAtt(:ClientVpnSchedulerFunction, :Arn),
|
318
|
+
Id: 'cfnvpnschedulerstart',
|
319
|
+
Input: FnSub({ StackName: "#{name}-cfnvpn", AssociateSubnets: 'true', ClientVpnEndpointId: "${ClientVpnEndpoint}" }.to_json)
|
320
|
+
}
|
321
|
+
])
|
322
|
+
}
|
323
|
+
end
|
324
|
+
|
325
|
+
if stop
|
326
|
+
Events_Rule(:ClientVpnSchedulerStop) {
|
327
|
+
State 'ENABLED'
|
328
|
+
Description "cfnvpn stop schedule"
|
329
|
+
ScheduleExpression "cron(#{stop})"
|
330
|
+
Targets([
|
331
|
+
{
|
332
|
+
Arn: FnGetAtt(:ClientVpnSchedulerFunction, :Arn),
|
333
|
+
Id: 'cfnvpnschedulerstop',
|
334
|
+
Input: FnSub({ StackName: "#{name}-cfnvpn", AssociateSubnets: 'false', ClientVpnEndpointId: "${ClientVpnEndpoint}" }.to_json)
|
335
|
+
}
|
336
|
+
])
|
337
|
+
}
|
338
|
+
end
|
339
|
+
|
340
|
+
end
|
341
|
+
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|