cfn-vpn 0.5.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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