cfn-vpn 0.4.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build-gem.yml +25 -0
  3. data/.github/workflows/release-gem.yml +34 -0
  4. data/.github/workflows/release-image.yml +33 -0
  5. data/Dockerfile +26 -0
  6. data/Gemfile.lock +30 -38
  7. data/README.md +1 -232
  8. data/cfn-vpn.gemspec +3 -5
  9. data/docs/README.md +44 -0
  10. data/docs/certificate-users.md +89 -0
  11. data/docs/getting-started.md +128 -0
  12. data/docs/modifying.md +67 -0
  13. data/docs/routes.md +84 -0
  14. data/docs/scheduling.md +32 -0
  15. data/docs/sessions.md +27 -0
  16. data/lib/cfnvpn.rb +31 -27
  17. data/lib/cfnvpn/{client.rb → actions/client.rb} +11 -8
  18. data/lib/cfnvpn/{embedded.rb → actions/embedded.rb} +21 -19
  19. data/lib/cfnvpn/actions/init.rb +140 -0
  20. data/lib/cfnvpn/actions/modify.rb +149 -0
  21. data/lib/cfnvpn/actions/params.rb +73 -0
  22. data/lib/cfnvpn/{revoke.rb → actions/revoke.rb} +10 -8
  23. data/lib/cfnvpn/actions/routes.rb +144 -0
  24. data/lib/cfnvpn/{sessions.rb → actions/sessions.rb} +7 -6
  25. data/lib/cfnvpn/{share.rb → actions/share.rb} +10 -10
  26. data/lib/cfnvpn/actions/subnets.rb +78 -0
  27. data/lib/cfnvpn/certificates.rb +70 -20
  28. data/lib/cfnvpn/clientvpn.rb +34 -68
  29. data/lib/cfnvpn/compiler.rb +23 -0
  30. data/lib/cfnvpn/config.rb +34 -77
  31. data/lib/cfnvpn/{cloudformation.rb → deployer.rb} +48 -20
  32. data/lib/cfnvpn/globals.rb +16 -0
  33. data/lib/cfnvpn/log.rb +26 -26
  34. data/lib/cfnvpn/s3.rb +4 -4
  35. data/lib/cfnvpn/string.rb +29 -0
  36. data/lib/cfnvpn/templates/helper.rb +14 -0
  37. data/lib/cfnvpn/templates/vpn.rb +353 -0
  38. data/lib/cfnvpn/version.rb +1 -1
  39. metadata +56 -42
  40. data/lib/cfnvpn/cfhighlander.rb +0 -49
  41. data/lib/cfnvpn/init.rb +0 -107
  42. data/lib/cfnvpn/modify.rb +0 -102
  43. data/lib/cfnvpn/routes.rb +0 -83
  44. data/lib/cfnvpn/templates/cfnvpn.cfhighlander.rb.tt +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f6be01a5786f8ea62be6d6b7f781ad1036b8edff08ba7d509707565fbeb5862
4
- data.tar.gz: 9a9a2038b6c955871983649f1c2627c6c2eedf9a64cae20ceb04ba73c25a3616
3
+ metadata.gz: 0faff982b39ef508e55845e2861754915ecca87a1db0df635eb75c718850c096
4
+ data.tar.gz: 6956ade9846ca34dab966f382f2c707921acd982be8d04f8f6fac47951a2ae44
5
5
  SHA512:
6
- metadata.gz: d0a839efc1e6d5826fc9b9edfcd3c608b0eb3a1f6b79df624de1be888b4d817a4c9c6994e9ea806e002998e0affa9cb5b0db1b25c04fa12677181e7d504fc958
7
- data.tar.gz: 051bc8385ced35fafbcffa4b013cb8e4d962dafb74f88c1574df4684f37b64fd074dfa4bdcdba0edafa3bc3dee855bd83217a3c23a00f60be6c18dad6f728052
6
+ metadata.gz: 0dcb165737f775d3a8bb9c9dd649544c801ee397a5e2cb0c800e40de0a88b221b05e3bfd4e8346a0b4287c8f0076462c02715c16c0703ffdd083005d062294e3
7
+ data.tar.gz: a83c04ff87f444e440ea7cb1e99b835a380fb7c92d48013d59e653dec8e00b56d35fd1075f88cfe5d94a81d6766cab3089dd47678e6b9b3f6d00490129db7b9b
@@ -0,0 +1,25 @@
1
+ name: test and build gem
2
+ on:
3
+ push:
4
+ branches: [ master ]
5
+ pull_request:
6
+ branches: [ master ]
7
+
8
+ jobs:
9
+ build:
10
+ name: test + build
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+ - name: set up ruby 2.6
16
+ uses: actions/setup-ruby@v1
17
+ with:
18
+ ruby-version: 2.6.x
19
+ - name: rspec
20
+ run: |
21
+ gem install rspec
22
+ rspec
23
+ - name: build gem
24
+ run: |
25
+ gem build cfn-vpn.gemspec
@@ -0,0 +1,34 @@
1
+ name: release gem
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build + Publish Gem
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - name: Check out the repo
14
+ uses: actions/checkout@v2
15
+
16
+ - name: Set up Ruby 2.7
17
+ uses: actions/setup-ruby@v1
18
+ with:
19
+ ruby-version: 2.7.x
20
+
21
+ - name: rspec
22
+ run: |
23
+ gem install rspec
24
+ rspec
25
+
26
+ - name: build gem
27
+ run: |
28
+ gem build cfn-vpn.gemspec
29
+
30
+ - name: Publish gem
31
+ uses: dawidd6/action-publish-gem@v1
32
+ with:
33
+ api_key: ${{secrets.RUBYGEMS_API_KEY}}
34
+ github_token: ${{secrets.GITHUB_TOKEN}}
@@ -0,0 +1,33 @@
1
+ name: release docker image
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build + Publish Container Image
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - name: Check out the repo
14
+ uses: actions/checkout@v2
15
+
16
+ - name: Set up Docker Buildx
17
+ uses: docker/setup-buildx-action@v1
18
+
19
+ - name: Login to GitHub Container Repository
20
+ uses: docker/login-action@v1
21
+ with:
22
+ registry: ghcr.io
23
+ username: ${{ github.repository_owner }}
24
+ password: ${{ secrets.GHCR_PUSH_TOKEN }}
25
+
26
+ - name: Build and push Container Image to GitHub Container Repository
27
+ uses: docker/build-push-action@v2
28
+ with:
29
+ context: .
30
+ file: ./Dockerfile
31
+ push: true
32
+ tags: ghcr.io/base2services/cfnvpn:${{ github.event.release.tag_name }}
33
+ build-args: CFNVPN_VERSION=${{ github.event.release.tag_name }}
data/Dockerfile ADDED
@@ -0,0 +1,26 @@
1
+ FROM ruby:2.7-alpine
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 \
6
+ && ln -s /usr/share/easy-rsa/easyrsa /usr/bin/
7
+
8
+ ENV EASYRSA=/usr/share/easy-rsa
9
+ ENV EASYRSA_BATCH=yes
10
+
11
+ ARG CFNVPN_VERSION="0.5.0"
12
+
13
+ COPY . /src
14
+
15
+ WORKDIR /src
16
+
17
+ RUN gem build cfn-vpn.gemspec \
18
+ && gem install cfn-vpn-${CFNVPN_VERSION}.gem \
19
+ && rm -rf /src
20
+
21
+ RUN addgroup -g 1000 cfnvpn && \
22
+ adduser -D -u 1000 -G cfnvpn cfnvpn
23
+
24
+ USER cfnvpn
25
+
26
+ RUN cfndsl -u 9.0.0
data/Gemfile.lock CHANGED
@@ -1,66 +1,58 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cfn-vpn (0.2.0)
4
+ cfn-vpn (1.0.0)
5
5
  aws-sdk-acm (~> 1, < 2)
6
6
  aws-sdk-cloudformation (~> 1, < 2)
7
7
  aws-sdk-ec2 (~> 1.95, < 2)
8
8
  aws-sdk-s3 (~> 1, < 2)
9
- cfhighlander (~> 0.9, < 1)
10
- cfndsl (~> 0.17, < 1)
9
+ aws-sdk-ssm (~> 1, < 2)
10
+ cfndsl (~> 1, < 2)
11
+ netaddr (= 2.0.4)
11
12
  terminal-table (~> 1, < 2)
12
13
  thor (~> 0.20)
13
14
 
14
15
  GEM
15
16
  remote: https://rubygems.org/
16
17
  specs:
17
- aws-eventstream (1.0.3)
18
- aws-partitions (1.253.0)
19
- aws-sdk-acm (1.23.0)
20
- aws-sdk-core (~> 3, >= 3.56.0)
18
+ aws-eventstream (1.1.0)
19
+ aws-partitions (1.390.0)
20
+ aws-sdk-acm (1.38.0)
21
+ aws-sdk-core (~> 3, >= 3.109.0)
21
22
  aws-sigv4 (~> 1.1)
22
- aws-sdk-cloudformation (1.29.0)
23
- aws-sdk-core (~> 3, >= 3.71.0)
23
+ aws-sdk-cloudformation (1.44.0)
24
+ aws-sdk-core (~> 3, >= 3.109.0)
24
25
  aws-sigv4 (~> 1.1)
25
- aws-sdk-core (3.85.1)
26
- aws-eventstream (~> 1.0, >= 1.0.2)
26
+ aws-sdk-core (3.109.2)
27
+ aws-eventstream (~> 1, >= 1.0.2)
27
28
  aws-partitions (~> 1, >= 1.239.0)
28
29
  aws-sigv4 (~> 1.1)
29
30
  jmespath (~> 1.0)
30
- aws-sdk-ec2 (1.124.0)
31
- aws-sdk-core (~> 3, >= 3.71.0)
31
+ aws-sdk-ec2 (1.208.0)
32
+ aws-sdk-core (~> 3, >= 3.109.0)
32
33
  aws-sigv4 (~> 1.1)
33
- aws-sdk-kms (1.27.0)
34
- aws-sdk-core (~> 3, >= 3.71.0)
34
+ aws-sdk-kms (1.39.0)
35
+ aws-sdk-core (~> 3, >= 3.109.0)
35
36
  aws-sigv4 (~> 1.1)
36
- aws-sdk-s3 (1.59.0)
37
- aws-sdk-core (~> 3, >= 3.83.0)
37
+ aws-sdk-s3 (1.84.0)
38
+ aws-sdk-core (~> 3, >= 3.109.0)
38
39
  aws-sdk-kms (~> 1)
39
40
  aws-sigv4 (~> 1.1)
40
- aws-sigv4 (1.1.0)
41
- aws-eventstream (~> 1.0, >= 1.0.2)
42
- cfhighlander (0.10.7)
43
- aws-sdk-cloudformation (~> 1, < 2)
44
- aws-sdk-core (~> 3, < 4)
45
- aws-sdk-ec2 (~> 1, < 2)
46
- aws-sdk-s3 (~> 1, < 2)
47
- cfndsl (= 0.17.2)
48
- duplicate (~> 1.1)
49
- git (~> 1.4, < 2)
50
- highline (>= 1.7.10, < 1.8)
51
- rubyzip (>= 2.0.0, < 3)
52
- thor (~> 0.20, < 1)
53
- cfndsl (0.17.2)
54
- duplicate (1.1.1)
55
- git (1.5.0)
56
- highline (1.7.10)
41
+ aws-sdk-ssm (1.97.0)
42
+ aws-sdk-core (~> 3, >= 3.109.0)
43
+ aws-sigv4 (~> 1.1)
44
+ aws-sigv4 (1.2.2)
45
+ aws-eventstream (~> 1, >= 1.0.2)
46
+ cfndsl (1.2.0)
47
+ hana (~> 1.3)
48
+ hana (1.3.6)
57
49
  jmespath (1.4.0)
58
- rake (10.5.0)
59
- rubyzip (2.0.0)
50
+ netaddr (2.0.4)
51
+ rake (13.0.1)
60
52
  terminal-table (1.8.0)
61
53
  unicode-display_width (~> 1.1, >= 1.1.1)
62
54
  thor (0.20.3)
63
- unicode-display_width (1.6.0)
55
+ unicode-display_width (1.7.0)
64
56
 
65
57
  PLATFORMS
66
58
  ruby
@@ -68,7 +60,7 @@ PLATFORMS
68
60
  DEPENDENCIES
69
61
  bundler (~> 2.0)
70
62
  cfn-vpn!
71
- rake (~> 10.0)
63
+ rake (~> 13.0)
72
64
 
73
65
  BUNDLED WITH
74
66
  2.0.1
data/README.md CHANGED
@@ -1,237 +1,6 @@
1
1
  # CfnVpn
2
2
 
3
- Manages the resources required to create a [client vpn](https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/what-is.html) in AWS.
4
- Uses cloudformation to manage the state of the vpn resources.
5
-
6
- ## Platforms
7
-
8
- - osx
9
- - linux
10
-
11
- ## Installation
12
-
13
- Install `cfn-vpn` gem
14
-
15
- ```bash
16
- gem install cfn-vpn
17
- ```
18
-
19
- Install [docker](https://docs.docker.com/install/)
20
-
21
- Docker is required to generate the certificates required for the client vpn.
22
- The gem uses [openvpn/easy-rsa](https://github.com/OpenVPN/easy-rsa) project in [base2/aws-client-vpn](https://hub.docker.com/r/base2/aws-client-vpn) docker image. [repo](https://github.com/base2Services/ciinabox-containers/tree/master/easy-rsa)
23
-
24
- Setup your [AWS credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html) by either setting a profile or exporting them as environment variables.
25
-
26
- ```bash
27
- export AWS_ACCESS_KEY_ID="XXXXXXXXXXXXXXXXXXXXX"
28
- export AWS_SECRET_ACCESS_KEY="XXXXXXXXXXXXXXXXXXXXX"
29
- export AWS_SESSION_TOKEN="XXXXXXXXXXXXXXXXXXXXX"
30
- ```
31
-
32
- Optionally export the AWS region if not providing `--region` flag
33
-
34
- ```bash
35
- export AWS_REGION="us-east-1"
36
- ```
37
-
38
- ## Scenarios
39
-
40
- For further AWS documentation please visit https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/scenario.html
41
-
42
- ### SplitTunnel
43
-
44
- Split tunnel when enabled will only push the routes defined on the client vpn. This is useful if you only want to push routes from your vpc through the vpn.
45
-
46
- ### Public subnet with Internet Access
47
-
48
- This can be setup with default options selected. This will push all routes from through the vpn including all internet traffic. The ENI attached to the vpn client attaches a public IP which is used for natting between the vpn and the internet. This must be placed inside a public subnet with a internet gateway attached to the vpc.
49
- Please read the AWS [documentation](https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/scenario-internet.html) for troubleshooting any networking issues
50
-
51
- ### Private subnet with Internet Access
52
-
53
- This is the same as above but the vpn attached to a subnet in a private subnet with the public route being routed through a nat gateway. **NOTE** the dns on the vpn must be set to the dns server of the vpc you've attached the vpn to, the reserved IP address at the base of the VPC IPv4 network range plus two. For example if you VPC cidr is 10.0.0.0/16 then the dns server for that vpc is 10.0.0.2.
54
-
55
- ```bash
56
- cfn-vpn init myvpn --bucket mybucket --server-cn myvpn.domain.tld --subnet-id subnet-123456ab --dns-servers 10.0.0.2
57
- ```
58
-
59
- If you are experiencing issue connecting to the internet check to see if your local dns configurations are overriding the ones set by the vpn. You can test this by using `dig` to query a domain from the vpc dns server. For example:
60
-
61
- ```bash
62
- dig @10.0.0.2 google.com
63
- ```
64
-
65
- ## Usage
66
-
67
- ```bash
68
- Commands:
69
- cfn-vpn --version, -v # print the version
70
- cfn-vpn client [name] --bucket=BUCKET --client-cn=CLIENT_CN # Create a new client certificate
71
- cfn-vpn config [name] --bucket=BUCKET --client-cn=CLIENT_CN # Retrieve the config for the AWS Client VPN
72
- cfn-vpn embedded [name] --bucket=BUCKET --client-cn=CLIENT_CN # Embed client certs into config and generate S3 presigned URL
73
- cfn-vpn help [COMMAND] # Describe available commands or one specific command
74
- cfn-vpn init [name] --bucket=BUCKET --server-cn=SERVER_CN --subnet-id=SUBNET_ID # Create a AWS Client VPN
75
- cfn-vpn modify [name] # Modify your AWS Client VPN
76
- cfn-vpn revoke [name] --bucket=BUCKET --client-cn=CLIENT_CN # Revoke a client certificate
77
- cfn-vpn routes [name] # List, add or delete client vpn routes
78
- cfn-vpn sessions [name] # List and kill current vpn connections
79
- cfn-vpn share [name] --bucket=BUCKET --client-cn=CLIENT_CN # Provide a user with a s3 signed download for certificates and config
80
- ```
81
-
82
- Global options
83
-
84
- ```bash
85
- p, [--profile=PROFILE] # AWS Profile
86
- r, [--region=REGION] # AWS Region
87
- # Default: ENV['AWS_REGION']
88
- [--verbose], [--no-verbose] # set log level to debug
89
- ```
90
-
91
-
92
- ### Create a new AWS Client VPN
93
-
94
- This will create a new client vpn endpoint, associates it with a subnet and sets up a route to the internet.
95
- During this process a new CA and certificate and keys are generated using [openvpn/easy-rsa](https://github.com/OpenVPN/easy-rsa) and uploaded to ACM.
96
- These keys are bundled in a tar and stored encrypted in your provided s3 bucket.
97
-
98
- ```bash
99
- cfn-vpn init myvpn --bucket mybucket --server-cn myvpn.domain.tld --subnet-id subnet-123456ab
100
- ```
101
-
102
- *Optional:*
103
-
104
- ```bash
105
- [--cidr=CIDR] # cidr from which to assign client IP addresses
106
- # Default: 10.250.0.0/16
107
- [--dns-servers=DNS_SERVERS] # DNS Servers to push to clients.
108
- [--split-tunnel], [--no-split-tunnel] # only push routes to the client on the vpn endpoint
109
- [--internet-route], [--no-internet-route] # create a default route to the internet
110
- # Default: true
111
- [--protocol=PROTOCOL] # set the protocol for the vpn connections
112
- # Default: udp
113
- # Possible values: udp, tcp
114
- ```
115
-
116
- ### Create a new client
117
-
118
- This will generate a new client certificate and key against the CA generated in the `init`.
119
- It will be bundled into a tar and stored encrypted in your provided s3 bucket.
120
-
121
- `cfn-vpn client myvpn --client-cn user1 --bucket mybucket`
122
-
123
-
124
- ### Revoke a client
125
-
126
- This will revoke the client certificate and apply to the client VPN endpoint.
127
- Note this wont terminate the session but will stop the client from reconnecting using the certificate.
128
-
129
- `cfn-vpn revoke myvpn --client-cn user1 --bucket mybucket`
130
-
131
-
132
- ### Download the config file
133
-
134
- This will download the client certificate bundle from s3 and the Client VPN config file from the endpoint.
135
- The config will be modified to include the local path of the client cert and key.
136
-
137
- `cfn-vpn config myvpn --client-cn user1 --bucket mybucket`
138
-
139
-
140
- ### Modify the Client VPN config
141
-
142
- This will modify some attributes of the client vpn endpoint.
143
-
144
- `cfn-vpn config myvpn --dns-servers 8.8.8.8,8.8.4.4`
145
-
146
- *Options:*
147
-
148
- ```bash
149
- [--cidr=CIDR] # cidr from which to assign client IP addresses
150
- # Default: 10.250.0.0/16
151
- [--dns-servers=DNS_SERVERS] # DNS Servers to push to clients.
152
- [--split-tunnel], [--no-split-tunnel] # only push routes to the client on the vpn endpoint
153
- [--internet-route], [--no-internet-route] # create a default route to the internet
154
- # Default: true
155
- [--protocol=PROTOCOL] # set the protocol for the vpn connections
156
- # Default: udp
157
- # Possible values: udp, tcp
158
- ```
159
-
160
-
161
- ### Share client certificates with a user
162
-
163
- This will generate a presigned url for the client's certificate and config file to allow them to download them to their local computer.
164
-
165
- `cfn-vpn share myvpn --client-cn user1 --bucket mybucket`
166
-
167
- You can then share the output with your user
168
-
169
- ```
170
- Download the certificates and config from the bellow presigned URLs which will expire in 1 hour.
171
-
172
- Certificate:
173
- <presigned url>
174
-
175
- Config:
176
- <presigned url>
177
-
178
- Extract the certificates from the tar and place into a safe location.
179
- tar xzfv user1.tar.gz -C <path>
180
-
181
- Modify base2-ciinabox.config.ovpn to include the full location of your extracted certificates
182
- echo "key /<path>/user1.key" >> myvpn.config.ovpn
183
- echo "cert /<path>/user1.crt" >> myvpn.config.ovpn
184
-
185
- Open myvpn.config.ovpn with your favourite openvpn client.
186
- ```
187
-
188
-
189
- ### Show and Kill Current Connections
190
-
191
- This is show a table of current connections on the vpn. You can then kill sessions by using the connection id.
192
-
193
- ```bash
194
- $ cfn-vpn sessions myvpn
195
- +-------------+---------------------+--------+-------------+-----------------------------------+---------------+--------------+
196
- | Common Name | Connected (UTC) | Status | IP Address | Connection ID | Ingress Bytes | Egress Bytes |
197
- +-------------+---------------------+--------+-------------+-----------------------------------+---------------+--------------+
198
- | user1 | 2019-06-28 04:58:19 | active | 10.250.0.98 | cvpn-connection-05bcc579cb3fdf9a3 | 3000 | 2679 |
199
- +-------------+---------------------+--------+-------------+-----------------------------------+---------------+--------------+
200
- ```
201
-
202
- Specify the `--kill` flag with the connection id to kill the session.
203
-
204
- `cfn-vpn sessions myvpn --kill cvpn-connection-05bcc579cb3fdf9a3`
205
-
206
-
207
- ### Show, Add and Remove Routes
208
-
209
- This will display the route table from the Client VPN.
210
-
211
- ```bash
212
- +---------------+-----------------------+--------+-----------------+------+-----------+
213
- | Route | Description | Status | Target | Type | Origin |
214
- +---------------+-----------------------+--------+-----------------+------+-----------+
215
- | 10.0.0.0/16 | Default Route | active | subnet-123456ab | Nat | associate |
216
- | 0.0.0.0/0 | Route to the internet | active | subnet-123456ab | Nat | add-route |
217
- +---------------+-----------------------+--------+-----------------+------+-----------+
218
- ```
219
-
220
- to add a new route specify the `--add` flag with the cidr and a description with the `--desc` flag.
221
-
222
- `cfn-vpn routes myvpn --add 10.10.0.0/16 --desc "route to peered vpc"`
223
-
224
- to delete a route specify the `--del` flag with the cidr you want to delete.
225
-
226
- `cfn-vpn routes myvpn --del 10.10.0.0/16`
227
-
228
-
229
- ### Embed client certificates into config file and share
230
-
231
- This will pull the clients certificate and key archives from S3 and embed them into the config file, upload it back to S3 and generate a presigned URL for the user.
232
- This allows the you to download or share a single, ready to import config file into a OpenVPN client.
233
-
234
- `cfn-vpn embedded myvpn --client-cn user1 --bucket mybucket`
3
+ Click [here](docs/README.md) to view the documentation and getting started guide.
235
4
 
236
5
  ## Contributing
237
6