cfn-vpn 0.4.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 -232
- data/cfn-vpn.gemspec +3 -5
- data/docs/README.md +44 -0
- data/docs/certificate-users.md +89 -0
- data/docs/getting-started.md +128 -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 +31 -27
- data/lib/cfnvpn/{client.rb → actions/client.rb} +11 -8
- data/lib/cfnvpn/{embedded.rb → actions/embedded.rb} +21 -19
- data/lib/cfnvpn/actions/init.rb +140 -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 +4 -4
- data/lib/cfnvpn/string.rb +29 -0
- data/lib/cfnvpn/templates/helper.rb +14 -0
- data/lib/cfnvpn/templates/vpn.rb +353 -0
- data/lib/cfnvpn/version.rb +1 -1
- metadata +56 -42
- 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
data/lib/cfnvpn/certificates.rb
CHANGED
@@ -1,51 +1,90 @@
|
|
1
1
|
require 'fileutils'
|
2
|
+
require 'mkmf'
|
2
3
|
require 'cfnvpn/acm'
|
3
4
|
require 'cfnvpn/s3'
|
4
5
|
require 'cfnvpn/log'
|
5
6
|
|
6
7
|
module CfnVpn
|
7
8
|
class Certificates
|
8
|
-
|
9
|
+
|
9
10
|
|
10
|
-
def initialize(build_dir,cfnvpn_name)
|
11
|
+
def initialize(build_dir, cfnvpn_name, easyrsa_local = false)
|
11
12
|
@cfnvpn_name = cfnvpn_name
|
13
|
+
@easyrsa_local = easyrsa_local
|
14
|
+
|
15
|
+
if @easyrsa_local
|
16
|
+
unless which('easyrsa')
|
17
|
+
raise "Unable to find `easyrsa` in your path. Check your path or remove the `--easyrsa-local` flag to run from docker"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
@build_dir = build_dir
|
12
22
|
@config_dir = "#{build_dir}/config"
|
13
23
|
@cert_dir = "#{build_dir}/certificates"
|
24
|
+
@pki_dir = "#{build_dir}/pki"
|
14
25
|
@docker_cmd = %w(docker run -it --rm)
|
15
|
-
@easyrsa_image = "base2/aws-client-vpn"
|
26
|
+
@easyrsa_image = " base2/aws-client-vpn"
|
16
27
|
FileUtils.mkdir_p(@cert_dir)
|
28
|
+
FileUtils.mkdir_p(@pki_dir)
|
17
29
|
end
|
18
30
|
|
19
31
|
def generate_ca(server_cn,client_cn)
|
20
|
-
@
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
32
|
+
if @easyrsa_local
|
33
|
+
ENV["EASYRSA_REQ_CN"] = server_cn
|
34
|
+
ENV["EASYRSA_PKI"] = @pki_dir
|
35
|
+
system("easyrsa init-pki")
|
36
|
+
system("easyrsa build-ca nopass")
|
37
|
+
system("easyrsa build-server-full server nopass")
|
38
|
+
system("easyrsa build-client-full #{client_cn} nopass")
|
39
|
+
FileUtils.cp(["#{@pki_dir}/ca.crt", "#{@pki_dir}/issued/server.crt", "#{@pki_dir}/private/server.key", "#{@pki_dir}/issued/#{client_cn}.crt", "#{@pki_dir}/private/#{client_cn}.key"], @cert_dir)
|
40
|
+
system("tar czfv #{@cert_dir}/ca.tar.gz -C #{@build_dir} pki/")
|
41
|
+
else
|
42
|
+
@docker_cmd << "-e EASYRSA_REQ_CN=#{server_cn}"
|
43
|
+
@docker_cmd << "-e EASYRSA_CLIENT_CN=#{client_cn}"
|
44
|
+
@docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
|
45
|
+
@docker_cmd << @easyrsa_image
|
46
|
+
@docker_cmd << "sh -c 'create-ca'"
|
47
|
+
CfnVpn::Log.logger.debug `#{@docker_cmd.join(' ')}`
|
48
|
+
end
|
26
49
|
end
|
27
50
|
|
28
51
|
def generate_client(client_cn)
|
29
|
-
@
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
52
|
+
if @easyrsa_local
|
53
|
+
ENV["EASYRSA_PKI"] = @pki_dir
|
54
|
+
system("tar xzfv #{@cert_dir}/ca.tar.gz --directory #{@build_dir}")
|
55
|
+
system("easyrsa build-client-full #{client_cn} nopass")
|
56
|
+
system("tar czfv #{@cert_dir}/#{client_cn}.tar.gz -C #{@build_dir} pki/issued/#{client_cn}.crt pki/private/#{client_cn}.key pki/reqs/#{client_cn}.req")
|
57
|
+
else
|
58
|
+
@docker_cmd << "-e EASYRSA_CLIENT_CN=#{client_cn}"
|
59
|
+
@docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
|
60
|
+
@docker_cmd << @easyrsa_image
|
61
|
+
@docker_cmd << "sh -c 'create-client'"
|
62
|
+
CfnVpn::Log.logger.debug `#{@docker_cmd.join(' ')}`
|
63
|
+
end
|
34
64
|
end
|
35
65
|
|
36
66
|
def revoke_client(client_cn)
|
37
|
-
@
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
67
|
+
if @easyrsa_local
|
68
|
+
ENV["EASYRSA_PKI"] = @pki_dir
|
69
|
+
system("tar xzfv #{@cert_dir}/ca.tar.gz --directory #{@build_dir}")
|
70
|
+
system("tar xzfv #{@cert_dir}/#{client_cn}.tar.gz --directory #{@build_dir}")
|
71
|
+
system("easyrsa revoke #{client_cn}")
|
72
|
+
system("easyrsa gen-crl")
|
73
|
+
FileUtils.cp("#{@pki_dir}/crl.pem", @cert_dir)
|
74
|
+
else
|
75
|
+
@docker_cmd << "-e EASYRSA_CLIENT_CN=#{client_cn}"
|
76
|
+
@docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
|
77
|
+
@docker_cmd << @easyrsa_image
|
78
|
+
@docker_cmd << "sh -c 'revoke-client'"
|
79
|
+
CfnVpn::Log.logger.debug `#{@docker_cmd.join(' ')}`
|
80
|
+
end
|
42
81
|
end
|
43
82
|
|
44
83
|
def upload_certificates(region,cert,type,cn=nil)
|
45
84
|
cn = cn.nil? ? cert : cn
|
46
85
|
acm = CfnVpn::Acm.new(region, @cert_dir)
|
47
86
|
arn = acm.import_certificate("#{cert}.crt", "#{cert}.key", "ca.crt")
|
48
|
-
Log.logger.debug "Uploaded #{type} certificate to ACM #{arn}"
|
87
|
+
CfnVpn::Log.logger.debug "Uploaded #{type} certificate to ACM #{arn}"
|
49
88
|
acm.tag_certificate(arn,cn,type,@cfnvpn_name)
|
50
89
|
return arn
|
51
90
|
end
|
@@ -65,6 +104,17 @@ module CfnVpn
|
|
65
104
|
`tar xzfv #{tar} -C #{@config_dir} --strip 2`
|
66
105
|
File.delete(tar) if File.exist?(tar)
|
67
106
|
end
|
107
|
+
|
108
|
+
def which(cmd)
|
109
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
110
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
111
|
+
exts.each do |ext|
|
112
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
113
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
nil
|
117
|
+
end
|
68
118
|
|
69
119
|
end
|
70
120
|
end
|
data/lib/cfnvpn/clientvpn.rb
CHANGED
@@ -4,7 +4,7 @@ require 'netaddr'
|
|
4
4
|
|
5
5
|
module CfnVpn
|
6
6
|
class ClientVpn
|
7
|
-
|
7
|
+
|
8
8
|
|
9
9
|
def initialize(name,region)
|
10
10
|
@client = Aws::EC2::Client.new(region: region)
|
@@ -16,7 +16,7 @@ module CfnVpn
|
|
16
16
|
filters: [{ name: "tag:cfnvpn:name", values: [@name] }]
|
17
17
|
})
|
18
18
|
if resp.client_vpn_endpoints.empty?
|
19
|
-
Log.logger.error "unable to find endpoint with tag Key: cfnvpn:name with Value: #{@name}"
|
19
|
+
CfnVpn::Log.logger.error "unable to find endpoint with tag Key: cfnvpn:name with Value: #{@name}"
|
20
20
|
raise "Unable to find client vpn"
|
21
21
|
end
|
22
22
|
return resp.client_vpn_endpoints.first
|
@@ -68,53 +68,6 @@ module CfnVpn
|
|
68
68
|
})
|
69
69
|
end
|
70
70
|
|
71
|
-
def get_target_networks(endpoint_id)
|
72
|
-
resp = @client.describe_client_vpn_target_networks({
|
73
|
-
client_vpn_endpoint_id: endpoint_id
|
74
|
-
})
|
75
|
-
return resp.client_vpn_target_networks.first
|
76
|
-
end
|
77
|
-
|
78
|
-
def add_route(cidr,description)
|
79
|
-
endpoint_id = get_endpoint_id()
|
80
|
-
subnet_id = get_target_networks(endpoint_id).target_network_id
|
81
|
-
|
82
|
-
@client.create_client_vpn_route({
|
83
|
-
client_vpn_endpoint_id: endpoint_id,
|
84
|
-
destination_cidr_block: cidr,
|
85
|
-
target_vpc_subnet_id: subnet_id,
|
86
|
-
description: description
|
87
|
-
})
|
88
|
-
|
89
|
-
resp = @client.authorize_client_vpn_ingress({
|
90
|
-
client_vpn_endpoint_id: endpoint_id,
|
91
|
-
target_network_cidr: cidr,
|
92
|
-
authorize_all_groups: true,
|
93
|
-
description: description
|
94
|
-
})
|
95
|
-
|
96
|
-
return resp.status
|
97
|
-
end
|
98
|
-
|
99
|
-
def del_route(cidr)
|
100
|
-
endpoint_id = get_endpoint_id()
|
101
|
-
subnet_id = get_target_networks(endpoint_id).target_network_id
|
102
|
-
|
103
|
-
revoke = @client.revoke_client_vpn_ingress({
|
104
|
-
revoke_all_groups: true,
|
105
|
-
client_vpn_endpoint_id: endpoint_id,
|
106
|
-
target_network_cidr: cidr
|
107
|
-
})
|
108
|
-
|
109
|
-
route = @client.delete_client_vpn_route({
|
110
|
-
client_vpn_endpoint_id: endpoint_id,
|
111
|
-
target_vpc_subnet_id: subnet_id,
|
112
|
-
destination_cidr_block: cidr
|
113
|
-
})
|
114
|
-
|
115
|
-
return route.status, revoke.status
|
116
|
-
end
|
117
|
-
|
118
71
|
def get_routes()
|
119
72
|
endpoint_id = get_endpoint_id()
|
120
73
|
resp = @client.describe_client_vpn_routes({
|
@@ -124,30 +77,43 @@ module CfnVpn
|
|
124
77
|
return resp.routes
|
125
78
|
end
|
126
79
|
|
127
|
-
def
|
128
|
-
|
129
|
-
|
130
|
-
|
80
|
+
def get_groups_for_route(endpoint, cidr)
|
81
|
+
auth_resp = @client.describe_client_vpn_authorization_rules({
|
82
|
+
client_vpn_endpoint_id: endpoint,
|
83
|
+
filters: [
|
84
|
+
{
|
85
|
+
name: 'destination-cidr',
|
86
|
+
values: [cidr]
|
87
|
+
}
|
88
|
+
]
|
89
|
+
})
|
90
|
+
return auth_resp.authorization_rules.map {|rule| rule.group_id }
|
131
91
|
end
|
132
92
|
|
133
|
-
def
|
134
|
-
|
135
|
-
resp = @client.
|
136
|
-
client_vpn_endpoint_id:
|
137
|
-
max_results: 20
|
93
|
+
def get_associations(endpoint)
|
94
|
+
associations = []
|
95
|
+
resp = @client.describe_client_vpn_target_networks({
|
96
|
+
client_vpn_endpoint_id: endpoint
|
138
97
|
})
|
139
|
-
return resp.routes
|
140
|
-
end
|
141
98
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
99
|
+
resp.client_vpn_target_networks.each do |net|
|
100
|
+
subnet_resp = @client.describe_subnets({
|
101
|
+
subnet_ids: [net.target_network_id]
|
102
|
+
})
|
103
|
+
subnet = subnet_resp.subnets.first
|
104
|
+
groups = get_groups_for_route(endpoint, subnet.cidr_block)
|
105
|
+
|
106
|
+
associations.push({
|
107
|
+
association_id: net.association_id,
|
108
|
+
target_network_id: net.target_network_id,
|
109
|
+
status: net.status.code,
|
110
|
+
cidr: subnet.cidr_block,
|
111
|
+
az: subnet.availability_zone,
|
112
|
+
groups: groups.join(' ')
|
113
|
+
})
|
114
|
+
end
|
148
115
|
|
149
|
-
|
150
|
-
return !(cidr =~ /^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/).nil?
|
116
|
+
return associations
|
151
117
|
end
|
152
118
|
|
153
119
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'cfnvpn/log'
|
2
|
+
require 'cfnvpn/templates/vpn'
|
3
|
+
|
4
|
+
module CfnVpn
|
5
|
+
class Compiler
|
6
|
+
|
7
|
+
def initialize(name, config)
|
8
|
+
@name = name
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def compile
|
13
|
+
CfnVpn::Log.logger.debug "Compiling cloudformation"
|
14
|
+
template = CfnVpn::Templates::Vpn.new()
|
15
|
+
template.render(@name, @config)
|
16
|
+
CfnVpn::Log.logger.debug "Validating cloudformation"
|
17
|
+
valid = template.validate
|
18
|
+
CfnVpn::Log.logger.debug "Clouformation Template\n\n#{JSON.parse(valid.to_json).to_yaml}"
|
19
|
+
return JSON.parse(valid.to_json).to_yaml
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
data/lib/cfnvpn/config.rb
CHANGED
@@ -1,88 +1,45 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'aws-sdk-ssm'
|
2
|
+
require 'json'
|
3
|
+
require 'cfnvpn/deployer'
|
3
4
|
|
4
5
|
module CfnVpn
|
5
|
-
class Config
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
class_option :bucket, required: true, desc: 's3 bucket'
|
15
|
-
class_option :client_cn, required: true, desc: "client certificates to download"
|
16
|
-
|
17
|
-
class_option :ignore_routes, alias: :i, type: :boolean, desc: "Ignore client VPN pushed routes and set routes in config file"
|
18
|
-
|
19
|
-
def self.source_root
|
20
|
-
File.dirname(__FILE__)
|
21
|
-
end
|
22
|
-
|
23
|
-
def set_loglevel
|
24
|
-
Log.logger.level = Logger::DEBUG if @options['verbose']
|
25
|
-
end
|
26
|
-
|
27
|
-
def create_config_directory
|
28
|
-
@build_dir = "#{ENV['HOME']}/.cfnvpn/#{@name}"
|
29
|
-
@config_dir = "#{@build_dir}/config"
|
30
|
-
Log.logger.debug("Creating config directory #{@config_dir}")
|
31
|
-
FileUtils.mkdir_p(@config_dir)
|
32
|
-
end
|
33
|
-
|
34
|
-
def download_config
|
35
|
-
vpn = CfnVpn::ClientVpn.new(@name,@options['region'])
|
36
|
-
@endpoint_id = vpn.get_endpoint_id()
|
37
|
-
Log.logger.info "downloading client config for #{@endpoint_id}"
|
38
|
-
@config = vpn.get_config(@endpoint_id)
|
39
|
-
end
|
40
|
-
|
41
|
-
def download_certificates
|
42
|
-
download = true
|
43
|
-
if File.exists?("#{@config_dir}/#{@options['client_cn']}.crt")
|
44
|
-
download = yes? "Certificates for #{@options['client_cn']} already exist in #{@config_dir}. Do you want to download again? ", :green
|
45
|
-
end
|
46
|
-
|
47
|
-
if download
|
48
|
-
Log.logger.info "Downloading certificates for #{@options['client_cn']} to #{@config_dir}"
|
49
|
-
s3 = CfnVpn::S3.new(@options['region'],@options['bucket'],@name)
|
50
|
-
s3.get_object("#{@config_dir}/#{@options['client_cn']}.tar.gz")
|
51
|
-
cert = CfnVpn::Certificates.new(@build_dir,@name)
|
52
|
-
Log.logger.debug cert.extract_certificate(@options['client_cn'])
|
6
|
+
class Config
|
7
|
+
|
8
|
+
def self.get_config(region, name)
|
9
|
+
client = Aws::SSM::Client.new(region: region)
|
10
|
+
begin
|
11
|
+
resp = client.get_parameter({name: "/cfnvpn/config/#{name}"})
|
12
|
+
return JSON.parse(resp.parameter.value, {:symbolize_names => true})
|
13
|
+
rescue Aws::SSM::Errors::ParameterNotFound => e
|
14
|
+
return self.get_config_from_parameter(region, name)
|
53
15
|
end
|
54
16
|
end
|
55
17
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
18
|
+
# to support upgrade from <=0.5.1 to >1.0
|
19
|
+
def self.get_config_from_parameter(region, name)
|
20
|
+
deployer = CfnVpn::Deployer.new(region, name)
|
21
|
+
parameters = deployer.get_parameters_from_stack_hash()
|
22
|
+
{
|
23
|
+
type: 'certificate',
|
24
|
+
server_cert_arn: parameters[:ServerCertificateArn],
|
25
|
+
client_cert_arn: parameters[:ClientCertificateArn],
|
26
|
+
region: region,
|
27
|
+
subnet_ids: [parameters[:AssociationSubnetId]],
|
28
|
+
cidr: parameters[:ClientCidrBlock],
|
29
|
+
dns_servers: parameters[:DnsServers].split(','),
|
30
|
+
split_tunnel: parameters[:SplitTunnel] == "true",
|
31
|
+
internet_route: parameters[:InternetRoute] == "true" ? parameters[:AssociationSubnetId] : nil,
|
32
|
+
protocol: parameters[:Protocol],
|
33
|
+
routes: []
|
34
|
+
}
|
61
35
|
end
|
62
36
|
|
63
|
-
def
|
64
|
-
|
65
|
-
Log.logger.debug "Ignoring routes pushed by the client vpn"
|
66
|
-
@config.concat("\nroute-nopull\n")
|
67
|
-
vpn = CfnVpn::ClientVpn.new(@name,@options['region'])
|
68
|
-
routes = vpn.get_route_with_mask
|
69
|
-
Log.logger.debug "Found routes #{routes}"
|
70
|
-
routes.each do |r|
|
71
|
-
@config.concat("route #{r[:route]} #{r[:mask]}\n")
|
72
|
-
end
|
73
|
-
dns_servers = vpn.get_dns_servers()
|
74
|
-
if dns_servers.any?
|
75
|
-
Log.logger.debug "Found DNS servers #{dns_servers.join(' ')}"
|
76
|
-
@config.concat("dhcp-option DNS #{dns_servers.first}\n")
|
77
|
-
end
|
78
|
-
end
|
37
|
+
def self.get_config_from_yaml_file(file)
|
38
|
+
YAML.load(File.read(file), symbolize_names: true)
|
79
39
|
end
|
80
40
|
|
81
|
-
def
|
82
|
-
|
83
|
-
File.write(config_file, @config)
|
84
|
-
Log.logger.info "downloaded client config #{config_file}"
|
41
|
+
def self.dump_config_to_yaml_file(name, params)
|
42
|
+
File.write(File.join(Dir.pwd, "cfnvpn.#{name}.yaml"), Hash[params.collect{|k,v| [k.to_s, v]}].to_yaml)
|
85
43
|
end
|
86
|
-
|
87
44
|
end
|
88
|
-
end
|
45
|
+
end
|
@@ -2,10 +2,10 @@ require 'aws-sdk-cloudformation'
|
|
2
2
|
require 'fileutils'
|
3
3
|
require 'cfnvpn/version'
|
4
4
|
require 'cfnvpn/log'
|
5
|
+
require 'cfnvpn/string'
|
5
6
|
|
6
7
|
module CfnVpn
|
7
|
-
class
|
8
|
-
include CfnVpn::Log
|
8
|
+
class Deployer
|
9
9
|
|
10
10
|
def initialize(region,name)
|
11
11
|
@name = name
|
@@ -29,28 +29,25 @@ module CfnVpn
|
|
29
29
|
return does_cf_stack_exist() ? 'UPDATE' : 'CREATE'
|
30
30
|
end
|
31
31
|
|
32
|
-
def create_change_set(
|
32
|
+
def create_change_set(template_body: nil, parameters: {})
|
33
33
|
change_set_name = "#{@stack_name}-#{CfnVpn::CHANGE_SET_VERSION}-#{Time.now.utc.strftime("%Y%m%d%H%M%S")}"
|
34
34
|
change_set_type = get_change_set_type()
|
35
35
|
|
36
|
-
if
|
37
|
-
params = get_parameters_from_template(
|
36
|
+
if !template_body.nil?
|
37
|
+
params = get_parameters_from_template(template_body)
|
38
38
|
else
|
39
39
|
params = get_parameters_from_stack()
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
params.each do |param|
|
43
43
|
if !parameters[param[:parameter_key]].nil?
|
44
|
-
param[
|
45
|
-
param[
|
44
|
+
param[:parameter_value] = parameters[param[:parameter_key]]
|
45
|
+
param[:use_previous_value] = false
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
|
50
|
-
Log.logger.debug "Creating changeset"
|
51
|
-
change_set = @client.create_change_set({
|
49
|
+
changeset_args = {
|
52
50
|
stack_name: @stack_name,
|
53
|
-
template_body: template_body,
|
54
51
|
parameters: params,
|
55
52
|
tags: [
|
56
53
|
{
|
@@ -63,18 +60,28 @@ module CfnVpn
|
|
63
60
|
}
|
64
61
|
],
|
65
62
|
change_set_name: change_set_name,
|
66
|
-
change_set_type: change_set_type
|
67
|
-
|
63
|
+
change_set_type: change_set_type,
|
64
|
+
capabilities: ['CAPABILITY_IAM']
|
65
|
+
}
|
66
|
+
|
67
|
+
if !template_body.nil?
|
68
|
+
changeset_args[:template_body] = template_body
|
69
|
+
else
|
70
|
+
changeset_args[:use_previous_template] = true
|
71
|
+
end
|
72
|
+
|
73
|
+
CfnVpn::Log.logger.debug "Creating changeset"
|
74
|
+
change_set = @client.create_change_set(changeset_args)
|
68
75
|
return change_set, change_set_type
|
69
76
|
end
|
70
77
|
|
71
78
|
def wait_for_changeset(change_set_id)
|
72
|
-
Log.logger.debug "Waiting for changeset to be created"
|
79
|
+
CfnVpn::Log.logger.debug "Waiting for changeset to be created"
|
73
80
|
begin
|
74
81
|
@client.wait_until :change_set_create_complete, change_set_name: change_set_id
|
75
82
|
rescue Aws::Waiters::Errors::FailureStateError => e
|
76
83
|
change_set = get_change_set(change_set_id)
|
77
|
-
Log.logger.error("change set status: #{change_set.status} reason: #{change_set.status_reason}")
|
84
|
+
CfnVpn::Log.logger.error("change set status: #{change_set.status} reason: #{change_set.status_reason}")
|
78
85
|
exit 1
|
79
86
|
end
|
80
87
|
end
|
@@ -86,7 +93,7 @@ module CfnVpn
|
|
86
93
|
end
|
87
94
|
|
88
95
|
def execute_change_set(change_set_id)
|
89
|
-
Log.logger.debug "Executing the changeset"
|
96
|
+
CfnVpn::Log.logger.debug "Executing the changeset"
|
90
97
|
stack = @client.execute_change_set({
|
91
98
|
change_set_name: change_set_id
|
92
99
|
})
|
@@ -94,7 +101,7 @@ module CfnVpn
|
|
94
101
|
|
95
102
|
def wait_for_execute(change_set_type)
|
96
103
|
waiter = change_set_type == 'CREATE' ? :stack_create_complete : :stack_update_complete
|
97
|
-
Log.logger.info "Waiting for changeset to #{change_set_type}"
|
104
|
+
CfnVpn::Log.logger.info "Waiting for changeset to #{change_set_type}"
|
98
105
|
resp = @client.wait_until waiter, stack_name: @stack_name
|
99
106
|
end
|
100
107
|
|
@@ -103,11 +110,32 @@ module CfnVpn
|
|
103
110
|
return resp.parameters.collect { |p| { parameter_key: p.parameter_key, use_previous_value: true } }
|
104
111
|
end
|
105
112
|
|
106
|
-
def get_parameters_from_template(
|
107
|
-
template_body = File.read(template_path)
|
113
|
+
def get_parameters_from_template(template_body)
|
108
114
|
resp = @client.get_template_summary({ template_body: template_body })
|
109
115
|
return resp.parameters.collect { |p| { parameter_key: p.parameter_key, parameter_value: p.default_value } }
|
110
116
|
end
|
111
117
|
|
118
|
+
def get_parameter_value(parameter)
|
119
|
+
resp = @client.describe_stacks({ stack_name: @stack_name })
|
120
|
+
stack = resp.stacks.first
|
121
|
+
parameter = stack.parameters.detect {|p| p.parameter_key == parameter}
|
122
|
+
return parameter ? parameter.parameter_value : nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def get_parameters_from_stack_hash()
|
126
|
+
resp = @client.describe_stacks({
|
127
|
+
stack_name: @stack_name,
|
128
|
+
})
|
129
|
+
stack = resp.stacks.first
|
130
|
+
return Hash[stack.parameters.collect {|parameter| [parameter.parameter_key.to_sym, parameter.parameter_value]}]
|
131
|
+
end
|
132
|
+
|
133
|
+
def get_outputs_from_stack()
|
134
|
+
resp = @client.describe_stacks({
|
135
|
+
stack_name: @stack_name,
|
136
|
+
})
|
137
|
+
stack = resp.stacks.first
|
138
|
+
return Hash[stack.outputs.collect {|output| [output.output_key.underscore.to_sym, output.output_value]}]
|
139
|
+
end
|
112
140
|
end
|
113
141
|
end
|