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.
- checksums.yaml +4 -4
- data/.github/workflows/build-gem.yml +25 -0
- data/.github/workflows/release-gem.yml +31 -0
- data/.github/workflows/release-image.yml +33 -0
- data/Gemfile.lock +30 -38
- data/README.md +1 -247
- data/cfn-vpn.gemspec +3 -2
- data/docs/README.md +44 -0
- data/docs/certificate-users.md +89 -0
- data/docs/getting-started.md +87 -0
- data/docs/modifying.md +67 -0
- data/docs/routes.md +82 -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} +5 -6
- data/lib/cfnvpn/{embedded.rb → actions/embedded.rb} +15 -15
- 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} +6 -6
- data/lib/cfnvpn/actions/routes.rb +144 -0
- data/lib/cfnvpn/{sessions.rb → actions/sessions.rb} +5 -5
- data/lib/cfnvpn/{share.rb → actions/share.rb} +10 -10
- data/lib/cfnvpn/actions/subnets.rb +78 -0
- data/lib/cfnvpn/certificates.rb +5 -5
- data/lib/cfnvpn/clientvpn.rb +34 -68
- data/lib/cfnvpn/compiler.rb +23 -0
- data/lib/cfnvpn/config.rb +34 -78
- data/lib/cfnvpn/{cloudformation.rb → deployer.rb} +47 -19
- 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 +344 -0
- data/lib/cfnvpn/version.rb +1 -1
- metadata +55 -22
- data/lib/cfnvpn/cfhighlander.rb +0 -49
- data/lib/cfnvpn/init.rb +0 -109
- data/lib/cfnvpn/modify.rb +0 -103
- data/lib/cfnvpn/routes.rb +0 -84
- 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/
|
6
|
-
require 'cfnvpn/
|
7
|
-
require 'cfnvpn/
|
8
|
-
require 'cfnvpn/
|
9
|
-
require 'cfnvpn/
|
10
|
-
require 'cfnvpn/
|
11
|
-
require 'cfnvpn/
|
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::
|
29
|
-
tasks["
|
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::
|
32
|
-
tasks["
|
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::
|
35
|
-
tasks["
|
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::
|
38
|
-
tasks["
|
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::
|
41
|
-
tasks["
|
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::
|
44
|
-
tasks["
|
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::
|
47
|
-
tasks["
|
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
|
-
|
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
|