Skip to content

Commit

Permalink
Merge pull request #26 from base2Services/feature/renew-certificate
Browse files Browse the repository at this point in the history
renew certificates
  • Loading branch information
Guslington committed Feb 7, 2023
2 parents 6172dab + 8c8b255 commit 617eafd
Show file tree
Hide file tree
Showing 15 changed files with 347 additions and 39 deletions.
11 changes: 7 additions & 4 deletions .github/workflows/build-gem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: set up ruby 2.6
uses: actions/setup-ruby@v1
- uses: actions/checkout@v3

- name: Set up ruby 2.7
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6.x
ruby-version: 2.7

- name: rspec
run: |
gem install rspec
rspec
- name: build gem
run: |
gem build cfn-vpn.gemspec
8 changes: 4 additions & 4 deletions .github/workflows/release-gem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ jobs:

steps:
- name: Check out the repo
uses: actions/checkout@v2
uses: actions/checkout@v3

- name: Set up Ruby 2.7
uses: actions/setup-ruby@v1
- name: Set up ruby 2.7
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7.x
ruby-version: 2.7

- name: rspec
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:

steps:
- name: Check out the repo
uses: actions/checkout@v2
uses: actions/checkout@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
Expand Down
17 changes: 9 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
FROM ruby:2.7-alpine
FROM ruby:2.7

RUN apk add --no-cache easy-rsa git \
# Hack until easy-rsa 3.0.7 is released https://github.com/OpenVPN/easy-rsa/issues/261
&& sed -i 's/^RANDFILE\s*=\s\$ENV.*/#&/' /usr/share/easy-rsa/openssl-easyrsa.cnf \
RUN apt-get update -qq \
&& apt-get install -qqy \
easy-rsa \
git \
&& ln -s /usr/share/easy-rsa/easyrsa /usr/bin/

ENV EASYRSA=/usr/share/easy-rsa
ENV EASYRSA_BATCH=yes

ARG CFNVPN_VERSION="0.5.0"
ARG CFNVPN_VERSION="1.5.0"

COPY . /src

Expand All @@ -17,9 +18,9 @@ WORKDIR /src
RUN gem build cfn-vpn.gemspec \
&& gem install cfn-vpn-${CFNVPN_VERSION}.gem \
&& rm -rf /src
RUN addgroup -g 1000 cfnvpn && \
adduser -D -u 1000 -G cfnvpn cfnvpn

RUN addgroup --gid 1000 cfnvpn && \
adduser --home /home/cfnvpn --uid 1000 --disabled-password --gecos GECOS --gid 1000 cfnvpn

USER cfnvpn

Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
cfn-vpn (1.4.3)
cfn-vpn (1.5.0)
aws-sdk-acm (~> 1, < 2)
aws-sdk-cloudformation (~> 1, < 2)
aws-sdk-ec2 (~> 1.95, < 2)
Expand Down
3 changes: 2 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ For further information on the authentication types please visit https://docs.aw
5. [Stop and Start Client-VPN](scheduling.md)
6. [Managing Sessions](sessions.md)
7. [Slack Notifications](slack-notifications.md)
8. [YAML Configuration](yaml-config.md)
8. [YAML Configuration](yaml-config.md)
9. [Certificate Renewal](certificate-renewal.md)
69 changes: 69 additions & 0 deletions docs/certificate-renewal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Certificate Renewal

To update the client certificate you can use the `renew` command.

```sh
Usage:
cfn-vpn renew [name]

Options:
r, [--region=REGION] # AWS Region
# Default: ap-southeast-2
[--verbose], [--no-verbose] # set log level to debug
[--easyrsa-local], [--no-easyrsa-local] # run the easyrsa executable from your local rather than from docker
[--certificate-expiry=CERTIFICATE_EXPIRY] # value in days for when the server certificates expire, defaults to 825 days
[--rebuild], [--no-rebuild] # generates new certificates from the existing CA for certiciate type VPNs
[--bucket=BUCKET] # s3 bucket, if not set one will be generated for you
```

## Certificate Authenticated VPN

When renewing the server and client certificates for the Client VPN there are 2 options [renew](#renew) or [rebuild](#rebuild).

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.

The Update process can take as long as 1-2 hours.

### renew

This is the default option and should be used

```sh
cfn-vpn renew [name] --bucket [s3-bucket]
```

### rebuild

This creates new certificates and should only be used if renew doesn't work.

```sh
cfn-vpn renew [name] --bucket [s3-bucket] --rebuild
```

### Updating Client Config

Once the VPN has been updated you will need to retrieve the new vpn endpoint such as

```
*.cvpn-endpoint-<id>.prod.clientvpn.<aws-region>.amazonaws.com
```

Replace the endpoint value in each of the clients opvn configs and reimport them into the vpn client.

```
remote kdipkcte.cvpn-endpoint-<replace-id>.prod.clientvpn.<aws-region>.amazonaws.com 443
```

## VPNs Using Federated Access

run the renew command with the default options

```sh
cfn-vpn renew [name] --bucket [s3-bucket]
```

This will recreate the vpn with the updated server certificate.

This process can take 1-2 hours.

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.
7 changes: 7 additions & 0 deletions docs/certificate-users.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ It will be bundled into a tar and stored encrypted in your provided s3 bucket.
cfn-vpn client myvpn --client-cn user1 --bucket mybucket
```

## Short Term Client

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.

```
cfn-vpn client myvpn --client-cn user1 --bucket mybucket --certificate-expiry 7
```

## Revoke a user

Expand Down
4 changes: 4 additions & 0 deletions lib/cfnvpn.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
require 'cfnvpn/actions/embedded'
require 'cfnvpn/actions/subnets'
require 'cfnvpn/actions/params'
require 'cfnvpn/actions/renew_certificate'

module CfnVpn
class Cli < Thor
Expand All @@ -23,6 +24,9 @@ def __print_version
register CfnVpn::Actions::Init, 'init', 'init [name]', 'Create a AWS Client VPN'
tasks["init"].options = CfnVpn::Actions::Init.class_options

register CfnVpn::Actions::RenewCertificate, 'renew', 'renew [name]', 'Renews a Server and Client certificates from the existing CA'
tasks["renew"].options = CfnVpn::Actions::RenewCertificate.class_options

register CfnVpn::Actions::Modify, 'modify', 'modify [name]', 'Modify your AWS Client VPN'
tasks["modify"].options = CfnVpn::Actions::Modify.class_options

Expand Down
31 changes: 20 additions & 11 deletions lib/cfnvpn/acm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,36 @@ def import_certificate(cert,key,ca)
end

def tag_certificate(arn,name,type,cfnvpn_name)
tags = [
{ key: "Name", value: name },
{ key: "cfnvpn:name", value: cfnvpn_name },
{ key: "cfnvpn:certificate:type", value: type }
]

@client.add_tags_to_certificate({
certificate_arn: arn,
tags: [
{ key: "Name", value: name },
{ key: "cfnvpn:name", value: cfnvpn_name },
{ key: "cfnvpn:certificate:type", value: type }
]
tags: tags
})
end

def load_certificate(cert)
File.read("#{@cert_dir}/#{cert}")
end

def certificate_exists?(name)
return true
end
def get_certificate_tags(certificate_arn,key=nil)
resp = @client.list_tags_for_certificate({
certificate_arn: certificate_arn
})

def get_certificate(name)
return 'arn'
end
if key.nil?
return resp.tags
else
resp.tags.each do |tag|
return tag.value if tag.key == key
end

raise "no tag key #{key} matched the certificate #{certificate_arn}"
end
end
end
end
3 changes: 2 additions & 1 deletion lib/cfnvpn/actions/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Client < Thor::Group
class_option :bucket, desc: 's3 bucket', required: true
class_option :client_cn, desc: 'client certificate common name', required: true
class_option :easyrsa_local, type: :boolean, default: false, desc: 'run the easyrsa executable from your local rather than from docker'
class_option :certificate_expiry, type: :string, desc: 'value in days for when the client certificates expire, defaults to 825 days'

def self.source_root
File.dirname(__FILE__)
Expand All @@ -37,7 +38,7 @@ def create_certificate
s3.get_object("#{@cert_dir}/ca.tar.gz")
CfnVpn::Log.logger.info "Generating new client certificate #{@options['client_cn']} using openvpn easy-rsa"
cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
CfnVpn::Log.logger.debug cert.generate_client(@options['client_cn'])
CfnVpn::Log.logger.debug cert.generate_client(@options['client_cn'],@options['certificate_expiry'])
s3.store_object("#{@cert_dir}/#{@options['client_cn']}.tar.gz")
end

Expand Down
3 changes: 2 additions & 1 deletion lib/cfnvpn/actions/init.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Init < Thor::Group
class_option :server_cn, required: true, desc: 'server certificate common name'
class_option :client_cn, desc: 'client certificate common name'
class_option :easyrsa_local, type: :boolean, default: false, desc: 'run the easyrsa executable from your local rather than from docker'
class_option :certificate_expiry, type: :string, desc: 'value in days for when the server certificates expire, defaults to 825 days'
class_option :bucket, desc: 's3 bucket, if not set one will be generated for you'

class_option :subnet_ids, required: true, type: :array, desc: 'subnet id to associate your vpn with'
Expand Down Expand Up @@ -115,7 +116,7 @@ def generate_server_certificates
CfnVpn::Log.logger.info "Generating certificates using openvpn easy-rsa"
cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
@client_cn = @options['client_cn'] ? @options['client_cn'] : "client-vpn.#{@options['server_cn']}"
cert.generate_ca(@options['server_cn'],@client_cn)
cert.generate_ca(@options['server_cn'],@client_cn,@options['certificate_expiry'])
end

def upload_certificates
Expand Down
Loading

0 comments on commit 617eafd

Please sign in to comment.