Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

renew certificates #26

Merged
merged 2 commits into from
Feb 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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