cfn-vpn 0.4.1 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build-gem.yml +25 -0
  3. data/.github/workflows/release-gem.yml +34 -0
  4. data/.github/workflows/release-image.yml +33 -0
  5. data/Dockerfile +26 -0
  6. data/Gemfile.lock +30 -38
  7. data/README.md +1 -224
  8. data/cfn-vpn.gemspec +3 -5
  9. data/docs/README.md +44 -0
  10. data/docs/certificate-users.md +89 -0
  11. data/docs/getting-started.md +99 -0
  12. data/docs/modifying.md +67 -0
  13. data/docs/routes.md +84 -0
  14. data/docs/scheduling.md +32 -0
  15. data/docs/sessions.md +27 -0
  16. data/lib/cfnvpn.rb +32 -24
  17. data/lib/cfnvpn/{client.rb → actions/client.rb} +11 -8
  18. data/lib/cfnvpn/actions/embedded.rb +110 -0
  19. data/lib/cfnvpn/actions/init.rb +130 -0
  20. data/lib/cfnvpn/actions/modify.rb +149 -0
  21. data/lib/cfnvpn/actions/params.rb +73 -0
  22. data/lib/cfnvpn/{revoke.rb → actions/revoke.rb} +10 -8
  23. data/lib/cfnvpn/actions/routes.rb +144 -0
  24. data/lib/cfnvpn/{sessions.rb → actions/sessions.rb} +7 -6
  25. data/lib/cfnvpn/{share.rb → actions/share.rb} +10 -10
  26. data/lib/cfnvpn/actions/subnets.rb +78 -0
  27. data/lib/cfnvpn/certificates.rb +70 -20
  28. data/lib/cfnvpn/clientvpn.rb +34 -68
  29. data/lib/cfnvpn/compiler.rb +23 -0
  30. data/lib/cfnvpn/config.rb +34 -77
  31. data/lib/cfnvpn/{cloudformation.rb → deployer.rb} +48 -20
  32. data/lib/cfnvpn/globals.rb +16 -0
  33. data/lib/cfnvpn/log.rb +26 -26
  34. data/lib/cfnvpn/s3.rb +13 -3
  35. data/lib/cfnvpn/string.rb +29 -0
  36. data/lib/cfnvpn/templates/helper.rb +14 -0
  37. data/lib/cfnvpn/templates/vpn.rb +344 -0
  38. data/lib/cfnvpn/version.rb +1 -1
  39. metadata +56 -41
  40. data/lib/cfnvpn/cfhighlander.rb +0 -49
  41. data/lib/cfnvpn/init.rb +0 -107
  42. data/lib/cfnvpn/modify.rb +0 -102
  43. data/lib/cfnvpn/routes.rb +0 -83
  44. data/lib/cfnvpn/templates/cfnvpn.cfhighlander.rb.tt +0 -27
@@ -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
- include CfnVpn::Log
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
- @docker_cmd << "-e EASYRSA_REQ_CN=#{server_cn}"
21
- @docker_cmd << "-e EASYRSA_CLIENT_CN=#{client_cn}"
22
- @docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
23
- @docker_cmd << @easyrsa_image
24
- @docker_cmd << "sh -c 'create-ca'"
25
- return `#{@docker_cmd.join(' ')}`
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
- @docker_cmd << "-e EASYRSA_CLIENT_CN=#{client_cn}"
30
- @docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
31
- @docker_cmd << @easyrsa_image
32
- @docker_cmd << "sh -c 'create-client'"
33
- return `#{@docker_cmd.join(' ')}`
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
- @docker_cmd << "-e EASYRSA_CLIENT_CN=#{client_cn}"
38
- @docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
39
- @docker_cmd << @easyrsa_image
40
- @docker_cmd << "sh -c 'revoke-client'"
41
- return `#{@docker_cmd.join(' ')}`
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
@@ -4,7 +4,7 @@ require 'netaddr'
4
4
 
5
5
  module CfnVpn
6
6
  class ClientVpn
7
- include CfnVpn::Log
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 route_exists?(cidr)
128
- routes = get_routes()
129
- resp = routes.select { |route| route if route.destination_cidr == cidr }
130
- return resp.any?
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 get_routes()
134
- endpoint_id = get_endpoint_id()
135
- resp = @client.describe_client_vpn_routes({
136
- client_vpn_endpoint_id: 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
- def get_route_with_mask()
143
- routes = get_routes()
144
- routes
145
- .select { |r| r if r.destination_cidr != '0.0.0.0/0' }
146
- .collect { |r| { route: r.destination_cidr.split('/').first, mask: NetAddr::IPv4Net.parse(r.destination_cidr).netmask.extended }}
147
- end
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
- def valid_cidr?(cidr)
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 'cfnvpn/clientvpn'
2
- require 'cfnvpn/log'
1
+ require 'aws-sdk-ssm'
2
+ require 'json'
3
+ require 'cfnvpn/deployer'
3
4
 
4
5
  module CfnVpn
5
- class Config < Thor::Group
6
- include Thor::Actions
7
- include CfnVpn::Log
8
-
9
- argument :name
10
-
11
- class_option :profile, desc: 'AWS Profile'
12
- class_option :region, default: ENV['AWS_REGION'], desc: 'AWS Region'
13
- class_option :verbose, desc: 'set log level to debug', type: :boolean
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
- def alter_config
57
- string = (0...8).map { (65 + rand(26)).chr.downcase }.join
58
- @config.sub!(@endpoint_id, "#{string}.#{@endpoint_id}")
59
- @config.concat("\n\ncert #{@config_dir}/#{@options['client_cn']}.crt")
60
- @config.concat("\nkey #{@config_dir}/#{@options['client_cn']}.key\n")
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 add_routes
64
- if @options['ignore_routes']
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 write_config
82
- config_file = "#{@config_dir}/#{@name}.ovpn"
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 Cloudformation
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(template_path,parameters)
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 change_set_type == 'CREATE'
37
- params = get_parameters_from_template(template_path)
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['parameter_value'] = parameters[param[:parameter_key]]
45
- param['use_previous_value'] = false
44
+ param[:parameter_value] = parameters[param[:parameter_key]]
45
+ param[:use_previous_value] = false
46
46
  end
47
47
  end
48
48
 
49
- template_body = File.read(template_path)
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(template_path)
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