cfn-vpn 0.5.1 → 1.1.0

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build-gem.yml +25 -0
  3. data/.github/workflows/release-gem.yml +31 -0
  4. data/.github/workflows/release-image.yml +33 -0
  5. data/Gemfile.lock +30 -38
  6. data/README.md +1 -247
  7. data/cfn-vpn.gemspec +3 -2
  8. data/docs/README.md +44 -0
  9. data/docs/certificate-users.md +89 -0
  10. data/docs/getting-started.md +87 -0
  11. data/docs/modifying.md +67 -0
  12. data/docs/routes.md +82 -0
  13. data/docs/scheduling.md +32 -0
  14. data/docs/sessions.md +27 -0
  15. data/lib/cfnvpn.rb +31 -27
  16. data/lib/cfnvpn/{client.rb → actions/client.rb} +5 -6
  17. data/lib/cfnvpn/{embedded.rb → actions/embedded.rb} +15 -15
  18. data/lib/cfnvpn/actions/init.rb +130 -0
  19. data/lib/cfnvpn/actions/modify.rb +149 -0
  20. data/lib/cfnvpn/actions/params.rb +73 -0
  21. data/lib/cfnvpn/{revoke.rb → actions/revoke.rb} +6 -6
  22. data/lib/cfnvpn/actions/routes.rb +144 -0
  23. data/lib/cfnvpn/{sessions.rb → actions/sessions.rb} +5 -5
  24. data/lib/cfnvpn/{share.rb → actions/share.rb} +10 -10
  25. data/lib/cfnvpn/actions/subnets.rb +78 -0
  26. data/lib/cfnvpn/certificates.rb +5 -5
  27. data/lib/cfnvpn/clientvpn.rb +34 -68
  28. data/lib/cfnvpn/compiler.rb +23 -0
  29. data/lib/cfnvpn/config.rb +34 -78
  30. data/lib/cfnvpn/{cloudformation.rb → deployer.rb} +47 -19
  31. data/lib/cfnvpn/log.rb +26 -26
  32. data/lib/cfnvpn/s3.rb +4 -4
  33. data/lib/cfnvpn/string.rb +29 -0
  34. data/lib/cfnvpn/templates/helper.rb +14 -0
  35. data/lib/cfnvpn/templates/vpn.rb +344 -0
  36. data/lib/cfnvpn/version.rb +1 -1
  37. metadata +55 -22
  38. data/lib/cfnvpn/cfhighlander.rb +0 -49
  39. data/lib/cfnvpn/init.rb +0 -109
  40. data/lib/cfnvpn/modify.rb +0 -103
  41. data/lib/cfnvpn/routes.rb +0 -84
  42. data/lib/cfnvpn/templates/cfnvpn.cfhighlander.rb.tt +0 -27
data/lib/cfnvpn.rb CHANGED
@@ -1,14 +1,15 @@
1
1
  require 'thor'
2
2
  require 'cfnvpn/version'
3
- require 'cfnvpn/init'
4
- require 'cfnvpn/modify'
5
- require 'cfnvpn/config'
6
- require 'cfnvpn/client'
7
- require 'cfnvpn/revoke'
8
- require 'cfnvpn/sessions'
9
- require 'cfnvpn/routes'
10
- require 'cfnvpn/share'
11
- require 'cfnvpn/embedded'
3
+ require 'cfnvpn/actions/init'
4
+ require 'cfnvpn/actions/modify'
5
+ require 'cfnvpn/actions/client'
6
+ require 'cfnvpn/actions/revoke'
7
+ require 'cfnvpn/actions/sessions'
8
+ require 'cfnvpn/actions/routes'
9
+ require 'cfnvpn/actions/share'
10
+ require 'cfnvpn/actions/embedded'
11
+ require 'cfnvpn/actions/subnets'
12
+ require 'cfnvpn/actions/params'
12
13
 
13
14
  module CfnVpn
14
15
  class Cli < Thor
@@ -19,32 +20,35 @@ module CfnVpn
19
20
  puts CfnVpn::VERSION
20
21
  end
21
22
 
22
- register CfnVpn::Init, 'init', 'init [name]', 'Create a AWS Client VPN'
23
- tasks["init"].options = CfnVpn::Init.class_options
23
+ register CfnVpn::Actions::Init, 'init', 'init [name]', 'Create a AWS Client VPN'
24
+ tasks["init"].options = CfnVpn::Actions::Init.class_options
24
25
 
25
- register CfnVpn::Modify, 'modify', 'modify [name]', 'Modify your AWS Client VPN'
26
- tasks["modify"].options = CfnVpn::Modify.class_options
26
+ register CfnVpn::Actions::Modify, 'modify', 'modify [name]', 'Modify your AWS Client VPN'
27
+ tasks["modify"].options = CfnVpn::Actions::Modify.class_options
27
28
 
28
- register CfnVpn::Config, 'config', 'config [name]', 'Retrieve the config for the AWS Client VPN'
29
- tasks["config"].options = CfnVpn::Config.class_options
29
+ register CfnVpn::Actions::Client, 'client', 'client [name]', 'Create a new client certificate'
30
+ tasks["client"].options = CfnVpn::Actions::Client.class_options
30
31
 
31
- register CfnVpn::Client, 'client', 'client [name]', 'Create a new client certificate'
32
- tasks["client"].options = CfnVpn::Client.class_options
32
+ register CfnVpn::Actions::Revoke, 'revoke', 'revoke [name]', 'Revoke a client certificate'
33
+ tasks["revoke"].options = CfnVpn::Actions::Revoke.class_options
33
34
 
34
- register CfnVpn::Revoke, 'revoke', 'revoke [name]', 'Revoke a client certificate'
35
- tasks["revoke"].options = CfnVpn::Revoke.class_options
35
+ register CfnVpn::Actions::Sessions, 'sessions', 'sessions [name]', 'List and kill current vpn connections'
36
+ tasks["sessions"].options = CfnVpn::Actions::Sessions.class_options
36
37
 
37
- register CfnVpn::Sessions, 'sessions', 'sessions [name]', 'List and kill current vpn connections'
38
- tasks["sessions"].options = CfnVpn::Sessions.class_options
38
+ register CfnVpn::Actions::Routes, 'routes', 'routes [name]', 'List, add or delete client vpn routes'
39
+ tasks["routes"].options = CfnVpn::Actions::Routes.class_options
39
40
 
40
- register CfnVpn::Routes, 'routes', 'routes [name]', 'List, add or delete client vpn routes'
41
- tasks["routes"].options = CfnVpn::Routes.class_options
41
+ register CfnVpn::Actions::Share, 'share', 'share [name]', 'Provide a user with a s3 signed download for certificates and config'
42
+ tasks["share"].options = CfnVpn::Actions::Share.class_options
42
43
 
43
- register CfnVpn::Share, 'share', 'share [name]', 'Provide a user with a s3 signed download for certificates and config'
44
- tasks["share"].options = CfnVpn::Share.class_options
44
+ register CfnVpn::Actions::Embedded, 'embedded', 'embedded [name]', 'Embed client certs into config and generate S3 presigned URL'
45
+ tasks["embedded"].options = CfnVpn::Actions::Embedded.class_options
45
46
 
46
- register CfnVpn::Embedded, 'embedded', 'embedded [name]', 'Embed client certs into config and generate S3 presigned URL'
47
- tasks["embedded"].options = CfnVpn::Embedded.class_options
47
+ register CfnVpn::Actions::Subnets, 'subnets', 'subnets [name]', 'Manage subnet associations for the client vpn'
48
+ tasks["subnets"].options = CfnVpn::Actions::Subnets.class_options
49
+
50
+ register CfnVpn::Actions::Params, 'params', 'params [name]', 'Display or dump to yaml the current cfnvpn params'
51
+ tasks["params"].options = CfnVpn::Actions::Params.class_options
48
52
 
49
53
  end
50
54
  end
@@ -4,10 +4,9 @@ require 'cfnvpn/log'
4
4
  require 'cfnvpn/s3'
5
5
  require 'cfnvpn/globals'
6
6
 
7
- module CfnVpn
7
+ module CfnVpn::Actions
8
8
  class Client < Thor::Group
9
- include Thor::Actions
10
- include CfnVpn::Log
9
+ include Thor::Actions
11
10
 
12
11
  argument :name
13
12
 
@@ -24,7 +23,7 @@ module CfnVpn
24
23
  end
25
24
 
26
25
  def set_loglevel
27
- Log.logger.level = Logger::DEBUG if @options['verbose']
26
+ CfnVpn::Log.logger.level = Logger::DEBUG if @options['verbose']
28
27
  end
29
28
 
30
29
  def set_directory
@@ -36,9 +35,9 @@ module CfnVpn
36
35
  def create_certificate
37
36
  s3 = CfnVpn::S3.new(@options['region'],@options['bucket'],@name)
38
37
  s3.get_object("#{@cert_dir}/ca.tar.gz")
39
- Log.logger.info "Generating new client certificate #{@options['client_cn']} using openvpn easy-rsa"
38
+ CfnVpn::Log.logger.info "Generating new client certificate #{@options['client_cn']} using openvpn easy-rsa"
40
39
  cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
41
- Log.logger.debug cert.generate_client(@options['client_cn'])
40
+ CfnVpn::Log.logger.debug cert.generate_client(@options['client_cn'])
42
41
  s3.store_object("#{@cert_dir}/#{@options['client_cn']}.tar.gz")
43
42
  end
44
43
 
@@ -2,10 +2,10 @@ require 'cfnvpn/log'
2
2
  require 'cfnvpn/s3'
3
3
  require 'cfnvpn/globals'
4
4
 
5
- module CfnVpn
5
+ module CfnVpn::Actions
6
6
  class Embedded < Thor::Group
7
7
  include Thor::Actions
8
- include CfnVpn::Log
8
+
9
9
 
10
10
  argument :name
11
11
 
@@ -23,13 +23,13 @@ module CfnVpn
23
23
  end
24
24
 
25
25
  def set_loglevel
26
- Log.logger.level = Logger::DEBUG if @options['verbose']
26
+ CfnVpn::Log.logger.level = Logger::DEBUG if @options['verbose']
27
27
  end
28
28
 
29
29
  def create_config_directory
30
30
  @build_dir = "#{CfnVpn.cfnvpn_path}/#{@name}"
31
31
  @config_dir = "#{@build_dir}/config"
32
- Log.logger.debug("Creating config directory #{@config_dir}")
32
+ CfnVpn::Log.logger.debug("Creating config directory #{@config_dir}")
33
33
  FileUtils.mkdir_p(@config_dir)
34
34
  end
35
35
 
@@ -40,18 +40,18 @@ module CfnVpn
40
40
  end
41
41
 
42
42
  if download
43
- Log.logger.info "Downloading certificates for #{@options['client_cn']} to #{@config_dir}"
43
+ CfnVpn::Log.logger.info "Downloading certificates for #{@options['client_cn']} to #{@config_dir}"
44
44
  s3 = CfnVpn::S3.new(@options['region'],@options['bucket'],@name)
45
45
  s3.get_object("#{@config_dir}/#{@options['client_cn']}.tar.gz")
46
46
  cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
47
- Log.logger.debug cert.extract_certificate(@options['client_cn'])
47
+ CfnVpn::Log.logger.debug cert.extract_certificate(@options['client_cn'])
48
48
  end
49
49
  end
50
50
 
51
51
  def download_config
52
52
  vpn = CfnVpn::ClientVpn.new(@name,@options['region'])
53
53
  @endpoint_id = vpn.get_endpoint_id()
54
- Log.logger.debug "downloading client config for #{@endpoint_id}"
54
+ CfnVpn::Log.logger.debug "downloading client config for #{@endpoint_id}"
55
55
  @config = vpn.get_config(@endpoint_id)
56
56
  string = (0...8).map { (65 + rand(26)).chr.downcase }.join
57
57
  @config.sub!(@endpoint_id, "#{string}.#{@endpoint_id}")
@@ -59,17 +59,17 @@ module CfnVpn
59
59
 
60
60
  def add_routes
61
61
  if @options['ignore_routes']
62
- Log.logger.debug "Ignoring routes pushed by the client vpn"
62
+ CfnVpn::Log.logger.debug "Ignoring routes pushed by the client vpn"
63
63
  @config.concat("\nroute-nopull\n")
64
64
  vpn = CfnVpn::ClientVpn.new(@name,@options['region'])
65
65
  routes = vpn.get_route_with_mask
66
- Log.logger.debug "Found routes #{routes}"
66
+ CfnVpn::Log.logger.debug "Found routes #{routes}"
67
67
  routes.each do |r|
68
68
  @config.concat("route #{r[:route]} #{r[:mask]}\n")
69
69
  end
70
70
  dns_servers = vpn.get_dns_servers()
71
71
  if dns_servers.any?
72
- Log.logger.debug "Found DNS servers #{dns_servers.join(' ')}"
72
+ CfnVpn::Log.logger.debug "Found DNS servers #{dns_servers.join(' ')}"
73
73
  @config.concat("dhcp-option DNS #{dns_servers.first}\n")
74
74
  end
75
75
  end
@@ -77,11 +77,11 @@ module CfnVpn
77
77
 
78
78
  def embed_certs
79
79
  cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
80
- Log.logger.debug cert.extract_certificate(@options['client_cn'])
81
- Log.logger.debug "Reading extracted certificate and private key"
80
+ CfnVpn::Log.logger.debug cert.extract_certificate(@options['client_cn'])
81
+ CfnVpn::Log.logger.debug "Reading extracted certificate and private key"
82
82
  key = File.read("#{@config_dir}/#{@options['client_cn']}.key")
83
83
  crt = File.read("#{@config_dir}/#{@options['client_cn']}.crt")
84
- Log.logger.debug "Embedding certificate and private key into config"
84
+ CfnVpn::Log.logger.debug "Embedding certificate and private key into config"
85
85
  @config.concat("\n<key>\n#{key}\n</key>\n")
86
86
  @config.concat("\n<cert>\n#{crt}\n</cert>\n")
87
87
  end
@@ -94,11 +94,11 @@ module CfnVpn
94
94
  def get_presigned_url
95
95
  @cn = @options['client_cn']
96
96
  @config_url = @s3.get_url("#{@name}_#{@cn}.config.ovpn")
97
- Log.logger.debug "Config presigned url: #{@config_url}"
97
+ CfnVpn::Log.logger.debug "Config presigned url: #{@config_url}"
98
98
  end
99
99
 
100
100
  def display_url
101
- Log.logger.info "Share the below instructions with the user..."
101
+ CfnVpn::Log.logger.info "Share the below instructions with the user..."
102
102
  say "\nDownload the embedded config from the below presigned URL which will expire in 1 hour."
103
103
  say "\nConfig:\n"
104
104
  say "\tcurl #{@config_url} > #{@name}_#{@cn}.config.ovpn", :cyan
@@ -0,0 +1,130 @@
1
+ require 'thor'
2
+ require 'fileutils'
3
+ require 'cfnvpn/deployer'
4
+ require 'cfnvpn/certificates'
5
+ require 'cfnvpn/compiler'
6
+ require 'cfnvpn/log'
7
+ require 'cfnvpn/clientvpn'
8
+ require 'cfnvpn/globals'
9
+
10
+ module CfnVpn::Actions
11
+ class Init < Thor::Group
12
+ include Thor::Actions
13
+
14
+
15
+ argument :name
16
+
17
+ class_option :region, aliases: :r, default: ENV['AWS_REGION'], desc: 'AWS Region'
18
+ class_option :verbose, desc: 'set log level to debug', type: :boolean
19
+
20
+ class_option :server_cn, required: true, desc: 'server certificate common name'
21
+ class_option :client_cn, desc: 'client certificate common name'
22
+ class_option :easyrsa_local, type: :boolean, default: false, desc: 'run the easyrsa executable from your local rather than from docker'
23
+ class_option :bucket, desc: 's3 bucket'
24
+
25
+ class_option :subnet_ids, required: true, type: :array, desc: 'subnet id to associate your vpn with'
26
+ class_option :default_groups, type: :array, desc: 'groups to allow through the subnet associations when using federated auth'
27
+ class_option :cidr, default: '10.250.0.0/16', desc: 'cidr from which to assign client IP addresses'
28
+ class_option :dns_servers, default: [], type: :array, desc: 'DNS Servers to push to clients.'
29
+
30
+ class_option :split_tunnel, type: :boolean, default: true, desc: 'only push routes to the client on the vpn endpoint'
31
+ class_option :internet_route, type: :string, desc: '[subnet-id] create a default route to the internet through a subnet'
32
+ class_option :protocol, type: :string, default: 'udp', enum: ['udp','tcp'], desc: 'set the protocol for the vpn connections'
33
+
34
+ class_option :start, type: :string, desc: 'cloudwatch event cron schedule in UTC to associate subnets to the client vpn'
35
+ class_option :stop, type: :string, desc: 'cloudwatch event cron schedule in UTC to disassociate subnets to the client vpn'
36
+
37
+ class_option :saml_arn, desc: 'IAM SAML idenditiy providor arn if using SAML federated authentication'
38
+
39
+ def self.source_root
40
+ File.dirname(__FILE__)
41
+ end
42
+
43
+ def set_loglevel
44
+ CfnVpn::Log.logger.level = Logger::DEBUG if @options['verbose']
45
+ end
46
+
47
+ def create_build_directory
48
+ @build_dir = "#{CfnVpn.cfnvpn_path}/#{@name}"
49
+ CfnVpn::Log.logger.debug "creating directory #{@build_dir}"
50
+ FileUtils.mkdir_p(@build_dir)
51
+ end
52
+
53
+ def initialize_config
54
+ @config = {
55
+ region: @options['region'],
56
+ subnet_ids: @options['subnet_ids'],
57
+ cidr: @options['cidr'],
58
+ dns_servers: @options['dns_servers'],
59
+ split_tunnel: @options['split_tunnel'],
60
+ internet_route: @options['internet_route'],
61
+ protocol: @options['protocol'],
62
+ start: @options['start'],
63
+ stop: @options['stop'],
64
+ saml_arn: @options['saml_arn'],
65
+ routes: []
66
+ }
67
+ end
68
+
69
+ def set_type
70
+ @config[:type] = @options['saml_arn'] ? 'federated' : 'certificate'
71
+ @config[:default_groups] = @options['saml_arn'] ? @options['default_groups'] : []
72
+ CfnVpn::Log.logger.info "initialising #{@config[:type]} client vpn"
73
+ end
74
+
75
+ def conditional_options_check
76
+ if @config[:type] == 'certificate'
77
+ if !@options['bucket']
78
+ CfnVpn::Log.logger.error "--bucket option must be specified if creating a client vpn with certificate based authentication"
79
+ exit 1
80
+ end
81
+ end
82
+ end
83
+
84
+ def stack_exist
85
+ @deployer = CfnVpn::Deployer.new(@options['region'],@name)
86
+ if @deployer.does_cf_stack_exist()
87
+ CfnVpn::Log.logger.error "#{@name}-cfnvpn stack already exists in this account in region #{@options['region']}, use the modify command to alter the stack"
88
+ exit 1
89
+ end
90
+ end
91
+
92
+ # create certificates
93
+ def generate_server_certificates
94
+ CfnVpn::Log.logger.info "Generating certificates using openvpn easy-rsa"
95
+ cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
96
+ @client_cn = @options['client_cn'] ? @options['client_cn'] : "client-vpn.#{@options['server_cn']}"
97
+ cert.generate_ca(@options['server_cn'],@client_cn)
98
+ end
99
+
100
+ def upload_certificates
101
+ cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
102
+ @config[:server_cert_arn] = cert.upload_certificates(@options['region'],'server','server',@options['server_cn'])
103
+ if @config[:type] == 'certificate'
104
+ # we only need the server certificate to ACM if it is a SAML federated client vpn
105
+ @config[:client_cert_arn] = cert.upload_certificates(@options['region'],@client_cn,'client')
106
+ # and only need to upload the certs to s3 if using certificate authenitcation
107
+ s3 = CfnVpn::S3.new(@options['region'],@options['bucket'],@name)
108
+ s3.store_object("#{@build_dir}/certificates/ca.tar.gz")
109
+ end
110
+ end
111
+
112
+ def deploy_vpn
113
+ compiler = CfnVpn::Compiler.new(@name, @config)
114
+ template_body = compiler.compile
115
+ CfnVpn::Log.logger.info "Launching cloudformation stack #{@name}-cfnvpn in #{@options['region']}"
116
+ change_set, change_set_type = @deployer.create_change_set(template_body: template_body)
117
+ @deployer.wait_for_changeset(change_set.id)
118
+ @deployer.execute_change_set(change_set.id)
119
+ @deployer.wait_for_execute(change_set_type)
120
+ CfnVpn::Log.logger.info "Changeset #{change_set_type} complete"
121
+ end
122
+
123
+ def finish
124
+ vpn = CfnVpn::ClientVpn.new(@name,@options['region'])
125
+ @endpoint_id = vpn.get_endpoint_id()
126
+ CfnVpn::Log.logger.info "Client VPN #{@endpoint_id} created. Run `cfn-vpn config #{@name}` to setup the client config"
127
+ end
128
+
129
+ end
130
+ end
@@ -0,0 +1,149 @@
1
+ require 'thor'
2
+ require 'fileutils'
3
+ require 'terminal-table'
4
+ require 'cfnvpn/deployer'
5
+ require 'cfnvpn/certificates'
6
+ require 'cfnvpn/compiler'
7
+ require 'cfnvpn/log'
8
+ require 'cfnvpn/clientvpn'
9
+ require 'cfnvpn/globals'
10
+ require 'cfnvpn/config'
11
+
12
+ module CfnVpn::Actions
13
+ class Modify < Thor::Group
14
+ include Thor::Actions
15
+
16
+
17
+ argument :name
18
+
19
+ class_option :region, aliases: :r, default: ENV['AWS_REGION'], desc: 'AWS Region'
20
+ class_option :verbose, desc: 'set log level to debug', type: :boolean
21
+
22
+ class_option :subnet_ids, type: :array, desc: 'overwrite all subnet associations'
23
+ class_option :add_subnet_ids, type: :array, desc: 'add to existing subnet associations'
24
+ class_option :del_subnet_ids, type: :array, desc: 'delete subnet associations'
25
+
26
+ class_option :default_groups, type: :array, desc: 'groups to allow through the subnet associations when using federated auth'
27
+
28
+ class_option :dns_servers, type: :array, desc: 'DNS Servers to push to clients.'
29
+ class_option :no_dns_servers, type: :boolean, desc: 'Remove the DNS Servers from the client vpn'
30
+
31
+ class_option :cidr, desc: 'cidr from which to assign client IP addresses'
32
+ class_option :split_tunnel, type: :boolean, desc: 'only push routes to the client on the vpn endpoint'
33
+ class_option :internet_route, type: :string, desc: '[subnet-id] create a default route to the internet through a subnet'
34
+ class_option :protocol, type: :string, enum: ['udp','tcp'], desc: 'set the protocol for the vpn connections'
35
+
36
+ class_option :start, type: :string, desc: 'cloudwatch event cron schedule in UTC to associate subnets to the client vpn'
37
+ class_option :stop, type: :string, desc: 'cloudwatch event cron schedule in UTC to disassociate subnets to the client vpn'
38
+
39
+ class_option :param_yaml, type: :string, desc: 'pass in cfnvpn params through YAML file'
40
+
41
+ def self.source_root
42
+ File.dirname(__FILE__)
43
+ end
44
+
45
+ def set_loglevel
46
+ CfnVpn::Log.logger.level = Logger::DEBUG if @options['verbose']
47
+ end
48
+
49
+ def create_build_directory
50
+ @build_dir = "#{CfnVpn.cfnvpn_path}/#{@name}"
51
+ CfnVpn::Log.logger.debug "creating directory #{@build_dir}"
52
+ FileUtils.mkdir_p(@build_dir)
53
+ end
54
+
55
+ def stack_exist
56
+ @deployer = CfnVpn::Deployer.new(@options['region'],@name)
57
+ if !@deployer.does_cf_stack_exist()
58
+ CfnVpn::Log.logger.error "#{@name}-cfnvpn stack doesn't exists in this account in region #{@options['region']}\n Try running `cfn-vpn init #{@name}` to setup the stack"
59
+ exit 1
60
+ end
61
+ end
62
+
63
+ def initialize_config
64
+ @config = CfnVpn::Config.get_config(@options[:region], @name)
65
+
66
+ CfnVpn::Log.logger.debug "Current config:\n#{@config}"
67
+
68
+ if @options[:param_yaml]
69
+ CfnVpn::Log.logger.debug "Loading config from YAML file #{@options[:param_yaml]}"
70
+ @config = CfnVpn::Config.get_config_from_yaml_file(@options[:param_yaml])
71
+ else
72
+ CfnVpn::Log.logger.debug "Loading config from options"
73
+ @options.each do |key, value|
74
+ next if [:verbose].include? key
75
+ @config[key.to_sym] = value
76
+ end
77
+
78
+ if @options['add_subnet_ids']
79
+ @config[:subnet_ids].concat @options['add_subnet_ids']
80
+ end
81
+
82
+ if @options['del_subnet_ids']
83
+ @config[:subnet_ids].reject!{ |subnet| @options['del_subnet_ids'].include? subnet }
84
+ end
85
+
86
+ if @options['no_dns_servers']
87
+ @config[:dns_servers] = []
88
+ end
89
+ end
90
+
91
+ if @config[:saml_arn] && @options[:default_groups]
92
+ @config[:default_groups] = @options[:default_groups]
93
+ end
94
+
95
+ CfnVpn::Log.logger.debug "Modified config:\n#{@config}"
96
+ end
97
+
98
+ def deploy_vpn
99
+ compiler = CfnVpn::Compiler.new(@name, @config)
100
+ template_body = compiler.compile
101
+ CfnVpn::Log.logger.info "Creating cloudformation changeset for stack #{@name}-cfnvpn in #{@options['region']}"
102
+ change_set, change_set_type = @deployer.create_change_set(template_body: template_body)
103
+ @deployer.wait_for_changeset(change_set.id)
104
+ changeset_response = @deployer.get_change_set(change_set.id)
105
+
106
+ changes = {"Add" => [], "Modify" => [], "Remove" => []}
107
+ change_colours = {"Add" => "green", "Modify" => 'yellow', "Remove" => 'red'}
108
+
109
+ changeset_response.changes.each do |change|
110
+ action = change.resource_change.action
111
+ changes[action].push([
112
+ change.resource_change.logical_resource_id,
113
+ change.resource_change.resource_type,
114
+ change.resource_change.replacement ? change.resource_change.replacement : 'N/A',
115
+ change.resource_change.details.collect {|detail| detail.target.name }.join(' , ')
116
+ ])
117
+ end
118
+
119
+ changes.each do |type, rows|
120
+ next if !rows.any?
121
+ puts "\n"
122
+ table = Terminal::Table.new(
123
+ :title => type,
124
+ :headings => ['Logical Resource Id', 'Resource Type', 'Replacement', 'Changes'],
125
+ :rows => rows)
126
+ puts table.to_s.send(change_colours[type])
127
+ end
128
+
129
+ CfnVpn::Log.logger.info "Cloudformation changeset changes:"
130
+ puts "\n"
131
+ continue = yes? "Continue?", :green
132
+ if !continue
133
+ CfnVpn::Log.logger.info("Cancelled cfn-vpn modifiy #{@name}")
134
+ exit 1
135
+ end
136
+
137
+ @deployer.execute_change_set(change_set.id)
138
+ @deployer.wait_for_execute(change_set_type)
139
+ CfnVpn::Log.logger.info "Changeset #{change_set_type} complete"
140
+ end
141
+
142
+ def finish
143
+ vpn = CfnVpn::ClientVpn.new(@name,@options['region'])
144
+ @endpoint_id = vpn.get_endpoint_id()
145
+ CfnVpn::Log.logger.info "Client VPN #{@endpoint_id} modified."
146
+ end
147
+
148
+ end
149
+ end