cfn-vpn 1.4.5 → 1.5.0

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