cfn-vpn 1.4.5 → 1.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 57083b650d15fc8debdddf839cb087de802de336a6604b09dca00b7a32f63ae6
4
- data.tar.gz: d89540882831030ed546c931add1e7c5324e221b353c4fc229c9f5dd80713b6c
3
+ metadata.gz: 03a0a38a10b42f88181de0fe2dc2954d4724f70515fcc3eb529f5a148ff17025
4
+ data.tar.gz: fb22c0da59f79dcf2b5175b31bb0b5c1cbf731568e3c99dc5de85bebe50f0240
5
5
  SHA512:
6
- metadata.gz: 78928edb12dbd6ea507d678bf0f67a46375a59c7222bd313b10273fb1f4f08570ce7656180ad2ad79b5a83254b64986c4fa5cf4c05cb1f9659ea641d11f62b70
7
- data.tar.gz: 4a00d2014443df8dfa53ba840a33dd7a271907a17876362a8d3fa877db3b31fdcc277afde62e0b03b348d3929d26ac5059d6593757f2e3b92612ae1daede082e
6
+ metadata.gz: 424241bf23dd636c2c3930e7475d6840dbd110421160c517fd23b66e08306183f6f398dde96ce3fb595f7bbe3852e1dcb40a45f2a750a00c4f61a76698277217
7
+ data.tar.gz: 8d06e2135f609be0b36bf8672bdc1f8d88bf1d31213763741592cd0f511060c925ce872e5081c30c1ad8a09e4465cc49249a652cd3c360a879da310f05a7d7e1
@@ -11,15 +11,18 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
 
13
13
  steps:
14
- - uses: actions/checkout@v2
15
- - name: set up ruby 2.6
16
- uses: actions/setup-ruby@v1
14
+ - uses: actions/checkout@v3
15
+
16
+ - name: Set up ruby 2.7
17
+ uses: ruby/setup-ruby@v1
17
18
  with:
18
- ruby-version: 2.6.x
19
+ ruby-version: 2.7
20
+
19
21
  - name: rspec
20
22
  run: |
21
23
  gem install rspec
22
24
  rspec
25
+
23
26
  - name: build gem
24
27
  run: |
25
28
  gem build cfn-vpn.gemspec
@@ -11,12 +11,12 @@ jobs:
11
11
 
12
12
  steps:
13
13
  - name: Check out the repo
14
- uses: actions/checkout@v2
14
+ uses: actions/checkout@v3
15
15
 
16
- - name: Set up Ruby 2.7
17
- uses: actions/setup-ruby@v1
16
+ - name: Set up ruby 2.7
17
+ uses: ruby/setup-ruby@v1
18
18
  with:
19
- ruby-version: 2.7.x
19
+ ruby-version: 2.7
20
20
 
21
21
  - name: rspec
22
22
  run: |
@@ -11,7 +11,7 @@ jobs:
11
11
 
12
12
  steps:
13
13
  - name: Check out the repo
14
- uses: actions/checkout@v2
14
+ uses: actions/checkout@v3
15
15
 
16
16
  - name: Set up Docker Buildx
17
17
  uses: docker/setup-buildx-action@v1
data/Dockerfile CHANGED
@@ -1,14 +1,15 @@
1
- FROM ruby:2.7-alpine
1
+ FROM ruby:2.7
2
2
 
3
- RUN apk add --no-cache easy-rsa git \
4
- # Hack until easy-rsa 3.0.7 is released https://github.com/OpenVPN/easy-rsa/issues/261
5
- && sed -i 's/^RANDFILE\s*=\s\$ENV.*/#&/' /usr/share/easy-rsa/openssl-easyrsa.cnf \
3
+ RUN apt-get update -qq \
4
+ && apt-get install -qqy \
5
+ easy-rsa \
6
+ git \
6
7
  && ln -s /usr/share/easy-rsa/easyrsa /usr/bin/
7
8
 
8
9
  ENV EASYRSA=/usr/share/easy-rsa
9
10
  ENV EASYRSA_BATCH=yes
10
11
 
11
- ARG CFNVPN_VERSION="0.5.0"
12
+ ARG CFNVPN_VERSION="1.5.0"
12
13
 
13
14
  COPY . /src
14
15
 
@@ -17,9 +18,9 @@ WORKDIR /src
17
18
  RUN gem build cfn-vpn.gemspec \
18
19
  && gem install cfn-vpn-${CFNVPN_VERSION}.gem \
19
20
  && rm -rf /src
20
-
21
- RUN addgroup -g 1000 cfnvpn && \
22
- adduser -D -u 1000 -G cfnvpn cfnvpn
21
+
22
+ RUN addgroup --gid 1000 cfnvpn && \
23
+ adduser --home /home/cfnvpn --uid 1000 --disabled-password --gecos GECOS --gid 1000 cfnvpn
23
24
 
24
25
  USER cfnvpn
25
26
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cfn-vpn (1.4.3)
4
+ cfn-vpn (1.5.0)
5
5
  aws-sdk-acm (~> 1, < 2)
6
6
  aws-sdk-cloudformation (~> 1, < 2)
7
7
  aws-sdk-ec2 (~> 1.95, < 2)
data/docs/README.md CHANGED
@@ -43,4 +43,5 @@ For further information on the authentication types please visit https://docs.aw
43
43
  5. [Stop and Start Client-VPN](scheduling.md)
44
44
  6. [Managing Sessions](sessions.md)
45
45
  7. [Slack Notifications](slack-notifications.md)
46
- 8. [YAML Configuration](yaml-config.md)
46
+ 8. [YAML Configuration](yaml-config.md)
47
+ 9. [Certificate Renewal](certificate-renewal.md)
@@ -0,0 +1,69 @@
1
+ # Certificate Renewal
2
+
3
+ To update the client certificate you can use the `renew` command.
4
+
5
+ ```sh
6
+ Usage:
7
+ cfn-vpn renew [name]
8
+
9
+ Options:
10
+ r, [--region=REGION] # AWS Region
11
+ # Default: ap-southeast-2
12
+ [--verbose], [--no-verbose] # set log level to debug
13
+ [--easyrsa-local], [--no-easyrsa-local] # run the easyrsa executable from your local rather than from docker
14
+ [--certificate-expiry=CERTIFICATE_EXPIRY] # value in days for when the server certificates expire, defaults to 825 days
15
+ [--rebuild], [--no-rebuild] # generates new certificates from the existing CA for certiciate type VPNs
16
+ [--bucket=BUCKET] # s3 bucket, if not set one will be generated for you
17
+ ```
18
+
19
+ ## Certificate Authenticated VPN
20
+
21
+ When renewing the server and client certificates for the Client VPN there are 2 options [renew](#renew) or [rebuild](#rebuild).
22
+
23
+ In both cases the Client VPN is recreated along with a new vpn endpoint which means once the update is complete each client must [update their config](#updating-client-config) to point to the new VPN endpoint.
24
+
25
+ The Update process can take as long as 1-2 hours.
26
+
27
+ ### renew
28
+
29
+ This is the default option and should be used
30
+
31
+ ```sh
32
+ cfn-vpn renew [name] --bucket [s3-bucket]
33
+ ```
34
+
35
+ ### rebuild
36
+
37
+ This creates new certificates and should only be used if renew doesn't work.
38
+
39
+ ```sh
40
+ cfn-vpn renew [name] --bucket [s3-bucket] --rebuild
41
+ ```
42
+
43
+ ### Updating Client Config
44
+
45
+ Once the VPN has been updated you will need to retrieve the new vpn endpoint such as
46
+
47
+ ```
48
+ *.cvpn-endpoint-<id>.prod.clientvpn.<aws-region>.amazonaws.com
49
+ ```
50
+
51
+ Replace the endpoint value in each of the clients opvn configs and reimport them into the vpn client.
52
+
53
+ ```
54
+ remote kdipkcte.cvpn-endpoint-<replace-id>.prod.clientvpn.<aws-region>.amazonaws.com 443
55
+ ```
56
+
57
+ ## VPNs Using Federated Access
58
+
59
+ run the renew command with the default options
60
+
61
+ ```sh
62
+ cfn-vpn renew [name] --bucket [s3-bucket]
63
+ ```
64
+
65
+ This will recreate the vpn with the updated server certificate.
66
+
67
+ This process can take 1-2 hours.
68
+
69
+ Once complete users will need to log into the self service portal and download new copies of the client config and import them into their vpn client.
@@ -11,6 +11,13 @@ It will be bundled into a tar and stored encrypted in your provided s3 bucket.
11
11
  cfn-vpn client myvpn --client-cn user1 --bucket mybucket
12
12
  ```
13
13
 
14
+ ## Short Term Client
15
+
16
+ By default the expiry of client certificate is 825 days. You can shorten this value with the `--certificate-expiry` flag specify a int value in days for how long you want the certificate to stay valid.
17
+
18
+ ```
19
+ cfn-vpn client myvpn --client-cn user1 --bucket mybucket --certificate-expiry 7
20
+ ```
14
21
 
15
22
  ## Revoke a user
16
23
 
data/docs/routes.md CHANGED
@@ -40,6 +40,8 @@ routes:
40
40
 
41
41
  Dynamic DNS routes takes a dns endpoint and will query the record every 5 minutes to see if the IPs have changed and update the routes in the vpn route table.
42
42
 
43
+ **NOTE** This should not be used for cloutfront endpoints
44
+
43
45
  #### CLI Commands
44
46
 
45
47
  new route run the routes command along with the `--dns` option
@@ -193,4 +195,4 @@ aws service-quotas request-service-quota-increase --service-code ec2 --quota-cod
193
195
 
194
196
  ```sh
195
197
  aws service-quotas request-service-quota-increase --service-code ec2 --quota-code L-9A1BC94B --desired-value [value]
196
- ```
198
+ ```
data/lib/cfnvpn/acm.rb CHANGED
@@ -23,13 +23,15 @@ module CfnVpn
23
23
  end
24
24
 
25
25
  def tag_certificate(arn,name,type,cfnvpn_name)
26
+ tags = [
27
+ { key: "Name", value: name },
28
+ { key: "cfnvpn:name", value: cfnvpn_name },
29
+ { key: "cfnvpn:certificate:type", value: type }
30
+ ]
31
+
26
32
  @client.add_tags_to_certificate({
27
33
  certificate_arn: arn,
28
- tags: [
29
- { key: "Name", value: name },
30
- { key: "cfnvpn:name", value: cfnvpn_name },
31
- { key: "cfnvpn:certificate:type", value: type }
32
- ]
34
+ tags: tags
33
35
  })
34
36
  end
35
37
 
@@ -37,13 +39,20 @@ module CfnVpn
37
39
  File.read("#{@cert_dir}/#{cert}")
38
40
  end
39
41
 
40
- def certificate_exists?(name)
41
- return true
42
- end
42
+ def get_certificate_tags(certificate_arn,key=nil)
43
+ resp = @client.list_tags_for_certificate({
44
+ certificate_arn: certificate_arn
45
+ })
43
46
 
44
- def get_certificate(name)
45
- return 'arn'
46
- end
47
+ if key.nil?
48
+ return resp.tags
49
+ else
50
+ resp.tags.each do |tag|
51
+ return tag.value if tag.key == key
52
+ end
47
53
 
54
+ raise "no tag key #{key} matched the certificate #{certificate_arn}"
55
+ end
56
+ end
48
57
  end
49
58
  end
@@ -17,6 +17,7 @@ module CfnVpn::Actions
17
17
  class_option :bucket, desc: 's3 bucket', required: true
18
18
  class_option :client_cn, desc: 'client certificate common name', required: true
19
19
  class_option :easyrsa_local, type: :boolean, default: false, desc: 'run the easyrsa executable from your local rather than from docker'
20
+ class_option :certificate_expiry, type: :string, desc: 'value in days for when the client certificates expire, defaults to 825 days'
20
21
 
21
22
  def self.source_root
22
23
  File.dirname(__FILE__)
@@ -37,7 +38,7 @@ module CfnVpn::Actions
37
38
  s3.get_object("#{@cert_dir}/ca.tar.gz")
38
39
  CfnVpn::Log.logger.info "Generating new client certificate #{@options['client_cn']} using openvpn easy-rsa"
39
40
  cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
40
- CfnVpn::Log.logger.debug cert.generate_client(@options['client_cn'])
41
+ CfnVpn::Log.logger.debug cert.generate_client(@options['client_cn'],@options['certificate_expiry'])
41
42
  s3.store_object("#{@cert_dir}/#{@options['client_cn']}.tar.gz")
42
43
  end
43
44
 
@@ -21,6 +21,7 @@ module CfnVpn::Actions
21
21
  class_option :server_cn, required: true, desc: 'server certificate common name'
22
22
  class_option :client_cn, desc: 'client certificate common name'
23
23
  class_option :easyrsa_local, type: :boolean, default: false, desc: 'run the easyrsa executable from your local rather than from docker'
24
+ class_option :certificate_expiry, type: :string, desc: 'value in days for when the server certificates expire, defaults to 825 days'
24
25
  class_option :bucket, desc: 's3 bucket, if not set one will be generated for you'
25
26
 
26
27
  class_option :subnet_ids, required: true, type: :array, desc: 'subnet id to associate your vpn with'
@@ -115,7 +116,7 @@ module CfnVpn::Actions
115
116
  CfnVpn::Log.logger.info "Generating certificates using openvpn easy-rsa"
116
117
  cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
117
118
  @client_cn = @options['client_cn'] ? @options['client_cn'] : "client-vpn.#{@options['server_cn']}"
118
- cert.generate_ca(@options['server_cn'],@client_cn)
119
+ cert.generate_ca(@options['server_cn'],@client_cn,@options['certificate_expiry'])
119
120
  end
120
121
 
121
122
  def upload_certificates
@@ -0,0 +1,141 @@
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
+ require 'cfnvpn/s3_bucket'
10
+ require 'cfnvpn/acm'
11
+
12
+ module CfnVpn::Actions
13
+ class RenewCertificate < Thor::Group
14
+ include Thor::Actions
15
+
16
+ argument :name
17
+
18
+ class_option :region, aliases: :r, default: ENV['AWS_REGION'], desc: 'AWS Region'
19
+ class_option :verbose, desc: 'set log level to debug', type: :boolean
20
+
21
+ class_option :easyrsa_local, type: :boolean, default: false, desc: 'run the easyrsa executable from your local rather than from docker'
22
+ class_option :certificate_expiry, type: :string, desc: 'value in days for when the server certificates expire, defaults to 825 days'
23
+ class_option :rebuild, type: :boolean, default: false, desc: 'generates new certificates from the existing CA for certiciate type VPNs'
24
+ class_option :bucket, desc: 's3 bucket, if not set one will be generated for you'
25
+
26
+ def self.source_root
27
+ File.dirname(__FILE__)
28
+ end
29
+
30
+ def set_loglevel
31
+ CfnVpn::Log.logger.level = Logger::DEBUG if @options['verbose']
32
+ end
33
+
34
+ def create_build_directory
35
+ @build_dir = "#{CfnVpn.cfnvpn_path}/#{@name}"
36
+ CfnVpn::Log.logger.debug "creating directory #{@build_dir}"
37
+ FileUtils.mkdir_p(@build_dir)
38
+ @cert_dir = "#{@build_dir}/certificates"
39
+ FileUtils.mkdir_p(@cert_dir)
40
+ end
41
+
42
+ def stack_exist
43
+ @deployer = CfnVpn::Deployer.new(@options['region'],@name)
44
+ if !@deployer.does_cf_stack_exist()
45
+ 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"
46
+ exit 1
47
+ end
48
+ end
49
+
50
+ def initialize_config
51
+ @config = CfnVpn::Config.get_config(@options['region'], @name)
52
+ end
53
+
54
+ def set_client_cn
55
+ @client_cn = nil
56
+ if @config[:type] == 'certificate'
57
+ acm = CfnVpn::Acm.new(@options['region'], @cert_dir)
58
+ @client_cn = acm.get_certificate_tags(@config[:client_cert_arn],'Name')
59
+ CfnVpn::Log.logger.info "Client CN #{@client_cn}"
60
+ end
61
+ end
62
+
63
+ def renew_certificates
64
+ if @config[:type] == 'certificate'
65
+ s3 = CfnVpn::S3.new(@options['region'],@options['bucket'],@name)
66
+ s3.get_object("#{@cert_dir}/ca.tar.gz")
67
+
68
+ if @options['rebuild']
69
+ CfnVpn::Log.logger.info "rebuilding server and #{@client_cn} certificates"
70
+ cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
71
+ cert.rebuild(@config[:server_cn],@client_cn,@options['certificate_expiry'])
72
+ else
73
+ CfnVpn::Log.logger.info "renewing server and #{@client_cn} certificates"
74
+ cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
75
+ cert.renew(@config[:server_cn],@client_cn,@options['certificate_expiry'])
76
+ end
77
+ else
78
+ CfnVpn::Log.logger.info "recreating server and #{@client_cn} certificates with a new CA"
79
+ cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
80
+ cert.generate_ca(@options['server_cn'],@options['certificate_expiry'])
81
+ end
82
+ end
83
+
84
+ def upload_certificates
85
+ cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
86
+ @config[:server_cert_arn] = cert.upload_certificates(@options['region'],'server','server',@config[:server_cn])
87
+ if @config[:type] == 'certificate'
88
+ # we only need the server certificate to ACM if it is a SAML federated client vpn
89
+ @config[:client_cert_arn] = cert.upload_certificates(@options['region'],@client_cn,'client')
90
+ # and only need to upload the certs to s3 if using certificate authenitcation
91
+ s3 = CfnVpn::S3.new(@options['region'],@config[:bucket],@name)
92
+ s3.store_object("#{@build_dir}/certificates/ca.tar.gz")
93
+ end
94
+ end
95
+
96
+ def deploy_vpn
97
+ compiler = CfnVpn::Compiler.new(@name, @config)
98
+ template_body = compiler.compile
99
+ CfnVpn::Log.logger.info "Creating cloudformation changeset for stack #{@name}-cfnvpn in #{@options['region']}"
100
+ change_set, change_set_type = @deployer.create_change_set(template_body: template_body)
101
+ @deployer.wait_for_changeset(change_set.id)
102
+ changeset_response = @deployer.get_change_set(change_set.id)
103
+
104
+ changes = {"Add" => [], "Modify" => [], "Remove" => []}
105
+ change_colours = {"Add" => "green", "Modify" => 'yellow', "Remove" => 'red'}
106
+
107
+ changeset_response.changes.each do |change|
108
+ action = change.resource_change.action
109
+ changes[action].push([
110
+ change.resource_change.logical_resource_id,
111
+ change.resource_change.resource_type,
112
+ change.resource_change.replacement ? change.resource_change.replacement : 'N/A',
113
+ change.resource_change.details.collect {|detail| detail.target.name }.join(' , ')
114
+ ])
115
+ end
116
+
117
+ changes.each do |type, rows|
118
+ next if !rows.any?
119
+ puts "\n"
120
+ table = Terminal::Table.new(
121
+ :title => type,
122
+ :headings => ['Logical Resource Id', 'Resource Type', 'Replacement', 'Changes'],
123
+ :rows => rows)
124
+ puts table.to_s.send(change_colours[type])
125
+ end
126
+
127
+ CfnVpn::Log.logger.info "Cloudformation changeset changes:"
128
+ puts "\n"
129
+ continue = yes? "Continue?", :green
130
+ if !continue
131
+ CfnVpn::Log.logger.info("Cancelled cfn-vpn modifiy #{@name}")
132
+ exit 1
133
+ end
134
+
135
+ @deployer.execute_change_set(change_set.id)
136
+ @deployer.wait_for_execute(change_set_type)
137
+ CfnVpn::Log.logger.info "Changeset #{change_set_type} complete"
138
+ end
139
+
140
+ end
141
+ end
@@ -1,5 +1,5 @@
1
1
  require 'fileutils'
2
- require 'mkmf'
2
+ require 'time'
3
3
  require 'cfnvpn/acm'
4
4
  require 'cfnvpn/s3'
5
5
  require 'cfnvpn/log'
@@ -28,19 +28,25 @@ module CfnVpn
28
28
  FileUtils.mkdir_p(@pki_dir)
29
29
  end
30
30
 
31
- def generate_ca(server_cn,client_cn)
31
+ def generate_ca(server_cn,client_cn,expiry=nil)
32
+ opts = ""
33
+ unless expiry.nil?
34
+ opts += "--days=#{expiry}"
35
+ end
36
+
32
37
  if @easyrsa_local
33
38
  ENV["EASYRSA_REQ_CN"] = server_cn
34
39
  ENV["EASYRSA_PKI"] = @pki_dir
35
40
  system("easyrsa init-pki")
36
41
  system("easyrsa build-ca nopass")
37
- system("easyrsa build-server-full server nopass")
38
- system("easyrsa build-client-full #{client_cn} nopass")
42
+ system("easyrsa #{opts} build-server-full server nopass")
43
+ system("easyrsa #{opts} build-client-full #{client_cn} nopass")
39
44
  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
45
  system("tar czfv #{@cert_dir}/ca.tar.gz -C #{@build_dir} pki/")
41
46
  else
42
47
  @docker_cmd << "-e EASYRSA_REQ_CN=#{server_cn}"
43
48
  @docker_cmd << "-e EASYRSA_CLIENT_CN=#{client_cn}"
49
+ @docker_cmd << "-e EASYRSA_OPTS=\"#{opts}\""
44
50
  @docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
45
51
  @docker_cmd << @easyrsa_image
46
52
  @docker_cmd << "sh -c 'create-ca'"
@@ -48,14 +54,20 @@ module CfnVpn
48
54
  end
49
55
  end
50
56
 
51
- def generate_client(client_cn)
57
+ def generate_client(client_cn,expiry=nil)
58
+ opts = ""
59
+ unless expiry.nil?
60
+ opts += "--days=#{expiry}"
61
+ end
62
+
52
63
  if @easyrsa_local
53
64
  ENV["EASYRSA_PKI"] = @pki_dir
54
65
  system("tar xzfv #{@cert_dir}/ca.tar.gz --directory #{@build_dir}")
55
- system("easyrsa build-client-full #{client_cn} nopass")
66
+ system("easyrsa #{opts} build-client-full #{client_cn} nopass")
56
67
  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
68
  else
58
69
  @docker_cmd << "-e EASYRSA_CLIENT_CN=#{client_cn}"
70
+ @docker_cmd << "-e EASYRSA_OPTS=\"#{opts}\""
59
71
  @docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
60
72
  @docker_cmd << @easyrsa_image
61
73
  @docker_cmd << "sh -c 'create-client'"
@@ -63,6 +75,65 @@ module CfnVpn
63
75
  end
64
76
  end
65
77
 
78
+ def renew(server_cn,client_cn,expiry=nil)
79
+ opts = ""
80
+ unless expiry.nil?
81
+ opts += "--days=#{expiry}"
82
+ end
83
+
84
+ if @easyrsa_local
85
+ ENV["EASYRSA_REQ_CN"] = server_cn
86
+ ENV["EASYRSA_PKI"] = @pki_dir
87
+ system("tar xzfv #{@cert_dir}/ca.tar.gz --directory #{@build_dir}")
88
+ system("easyrsa #{opts} renew server nopass")
89
+ system("easyrsa #{opts} renew #{client_cn} nopass")
90
+ 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)
91
+ system("tar czfv #{@cert_dir}/ca.tar.gz -C #{@build_dir} pki/")
92
+ else
93
+ @docker_cmd << "-e EASYRSA_REQ_CN=#{server_cn}"
94
+ @docker_cmd << "-e EASYRSA_CLIENT_CN=#{client_cn}"
95
+ @docker_cmd << "-e EASYRSA_OPTS=\"#{opts}\""
96
+ @docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
97
+ @docker_cmd << @easyrsa_image
98
+ @docker_cmd << "sh -c 'renew'"
99
+ CfnVpn::Log.logger.debug `#{@docker_cmd.join(' ')}`
100
+ end
101
+ end
102
+
103
+ def rebuild(server_cn,client_cn,expiry=nil)
104
+ timestamp = Time.now.getutc.to_i
105
+ opts = ""
106
+ unless expiry.nil?
107
+ opts += "--days=#{expiry}"
108
+ end
109
+
110
+ if @easyrsa_local
111
+ ENV["EASYRSA_REQ_CN"] = server_cn
112
+ ENV["EASYRSA_PKI"] = @pki_dir
113
+ system("tar xzfv #{@cert_dir}/ca.tar.gz --directory #{@build_dir}")
114
+
115
+ FileUtils.mv("#{@pki_dir}/reqs/server.req", "#{@pki_dir}/reqs/server.req.bak-#{timestamp}")
116
+ FileUtils.mv("#{@pki_dir}/issued/server.crt", "#{@pki_dir}/issued/server.req.bak-#{timestamp}")
117
+ FileUtils.mv("#{@pki_dir}/private/server.key", "#{@pki_dir}/private/server.req.bak-#{timestamp}")
118
+ FileUtils.mv("#{@pki_dir}/reqs/#{client_cn}.req", "#{@pki_dir}/reqs/#{client_cn}.req.bak-#{timestamp}")
119
+ FileUtils.mv("#{@pki_dir}/issued/#{client_cn}.crt", "#{@pki_dir}/issued/#{client_cn}.req.bak-#{timestamp}")
120
+ FileUtils.mv("#{@pki_dir}/private/#{client_cn}.key", "#{@pki_dir}/private/#{client_cn}.req.bak-#{timestamp}")
121
+
122
+ system("easyrsa #{opts} build-server-full server nopass")
123
+ system("easyrsa #{opts} build-client-full #{client_cn} nopass")
124
+ 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)
125
+ system("tar czfv #{@cert_dir}/ca.tar.gz -C #{@build_dir} pki/")
126
+ else
127
+ @docker_cmd << "-e EASYRSA_REQ_CN=#{server_cn}"
128
+ @docker_cmd << "-e EASYRSA_CLIENT_CN=#{client_cn}"
129
+ @docker_cmd << "-e EASYRSA_OPTS=\"#{opts}\""
130
+ @docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
131
+ @docker_cmd << @easyrsa_image
132
+ @docker_cmd << "sh -c 'rebuild'"
133
+ CfnVpn::Log.logger.debug `#{@docker_cmd.join(' ')}`
134
+ end
135
+ end
136
+
66
137
  def revoke_client(client_cn)
67
138
  if @easyrsa_local
68
139
  ENV["EASYRSA_PKI"] = @pki_dir
@@ -1,4 +1,4 @@
1
1
  module CfnVpn
2
- VERSION = "1.4.5".freeze
2
+ VERSION = "1.5.0".freeze
3
3
  CHANGE_SET_VERSION = VERSION.gsub('.', '-').freeze
4
4
  end
data/lib/cfnvpn.rb CHANGED
@@ -10,6 +10,7 @@ require 'cfnvpn/actions/share'
10
10
  require 'cfnvpn/actions/embedded'
11
11
  require 'cfnvpn/actions/subnets'
12
12
  require 'cfnvpn/actions/params'
13
+ require 'cfnvpn/actions/renew_certificate'
13
14
 
14
15
  module CfnVpn
15
16
  class Cli < Thor
@@ -23,6 +24,9 @@ module CfnVpn
23
24
  register CfnVpn::Actions::Init, 'init', 'init [name]', 'Create a AWS Client VPN'
24
25
  tasks["init"].options = CfnVpn::Actions::Init.class_options
25
26
 
27
+ register CfnVpn::Actions::RenewCertificate, 'renew', 'renew [name]', 'Renews a Server and Client certificates from the existing CA'
28
+ tasks["renew"].options = CfnVpn::Actions::RenewCertificate.class_options
29
+
26
30
  register CfnVpn::Actions::Modify, 'modify', 'modify [name]', 'Modify your AWS Client VPN'
27
31
  tasks["modify"].options = CfnVpn::Actions::Modify.class_options
28
32
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cfn-vpn
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.5
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guslington
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-09 00:00:00.000000000 Z
11
+ date: 2023-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -240,6 +240,7 @@ files:
240
240
  - Rakefile
241
241
  - cfn-vpn.gemspec
242
242
  - docs/README.md
243
+ - docs/certificate-renewal.md
243
244
  - docs/certificate-users.md
244
245
  - docs/getting-started.md
245
246
  - docs/modifying.md
@@ -256,6 +257,7 @@ files:
256
257
  - lib/cfnvpn/actions/init.rb
257
258
  - lib/cfnvpn/actions/modify.rb
258
259
  - lib/cfnvpn/actions/params.rb
260
+ - lib/cfnvpn/actions/renew_certificate.rb
259
261
  - lib/cfnvpn/actions/revoke.rb
260
262
  - lib/cfnvpn/actions/routes.rb
261
263
  - lib/cfnvpn/actions/sessions.rb