cfn-vpn 0.1.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 +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +17 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +75 -0
- data/LICENSE.txt +21 -0
- data/README.md +74 -0
- data/Rakefile +2 -0
- data/cfn-vpn.gemspec +48 -0
- data/exe/cfn-vpn +4 -0
- data/lib/cfnvpn.rb +26 -0
- data/lib/cfnvpn/acm.rb +49 -0
- data/lib/cfnvpn/certificates.rb +55 -0
- data/lib/cfnvpn/cfhighlander.rb +49 -0
- data/lib/cfnvpn/clientvpn.rb +36 -0
- data/lib/cfnvpn/cloudformation.rb +75 -0
- data/lib/cfnvpn/config.rb +77 -0
- data/lib/cfnvpn/init.rb +93 -0
- data/lib/cfnvpn/log.rb +38 -0
- data/lib/cfnvpn/ssm.rb +50 -0
- data/lib/cfnvpn/templates/cfnvpn.cfhighlander.rb.tt +14 -0
- data/lib/cfnvpn/version.rb +4 -0
- metadata +231 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4e3b6334f24037b79137a09d3d93325a2513162f4e151b1e565875e74352aac7
|
4
|
+
data.tar.gz: d0e7e304876a4bcccab2b082fc8c298f8fc74b0769b4eb9338fdc98b5d5842a1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c75ae0f97eb239c6db309b98d09d5b08a688bde621aa5f23b091face28fab3737369d67d6d40c9f13e7615ba8f58c4ee3553fe24a55715ac0282f889b72946fd
|
7
|
+
data.tar.gz: d543e66f8ce62534e64de754d09be061c4a92b50bff6d8ddfbd0f8df03a48f830217c501024986e8810e4f2a300fa503a9631efb7ad0cb4a22c6c47019456df6
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
sudo: required
|
2
|
+
dist: trusty
|
3
|
+
language: ruby
|
4
|
+
rvm:
|
5
|
+
- 2.5
|
6
|
+
script:
|
7
|
+
- bundle install
|
8
|
+
- gem build cfn-vpn.gemspec
|
9
|
+
- gem install cfn-vpn-*.gem
|
10
|
+
- cfn-vpn help
|
11
|
+
deploy:
|
12
|
+
provider: rubygems
|
13
|
+
api_key: "${RUBYGEMS_API_KEY}"
|
14
|
+
gem: cfn-vpn
|
15
|
+
on:
|
16
|
+
all_branches: true
|
17
|
+
condition: $TRAVIS_BRANCH =~ ^develop|master && $TRAVIS_EVENT_TYPE =~ ^push|api$ && $TRAVIS_REPO_SLUG == "base2services/aws-client-vpn"
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
cfn-vpn (0.1.0)
|
5
|
+
aws-sdk-acm (~> 1, < 2)
|
6
|
+
aws-sdk-cloudformation (~> 1, < 2)
|
7
|
+
aws-sdk-ec2 (~> 1.95, < 2)
|
8
|
+
aws-sdk-ssm (~> 1, < 2)
|
9
|
+
cfhighlander (~> 0.9, < 1)
|
10
|
+
cfndsl (~> 0.17, < 1)
|
11
|
+
thor (~> 0.20)
|
12
|
+
|
13
|
+
GEM
|
14
|
+
remote: https://rubygems.org/
|
15
|
+
specs:
|
16
|
+
aws-eventstream (1.0.3)
|
17
|
+
aws-partitions (1.176.0)
|
18
|
+
aws-sdk-acm (1.23.0)
|
19
|
+
aws-sdk-core (~> 3, >= 3.56.0)
|
20
|
+
aws-sigv4 (~> 1.1)
|
21
|
+
aws-sdk-cloudformation (1.23.0)
|
22
|
+
aws-sdk-core (~> 3, >= 3.56.0)
|
23
|
+
aws-sigv4 (~> 1.1)
|
24
|
+
aws-sdk-core (3.56.0)
|
25
|
+
aws-eventstream (~> 1.0, >= 1.0.2)
|
26
|
+
aws-partitions (~> 1.0)
|
27
|
+
aws-sigv4 (~> 1.1)
|
28
|
+
jmespath (~> 1.0)
|
29
|
+
aws-sdk-ec2 (1.95.0)
|
30
|
+
aws-sdk-core (~> 3, >= 3.56.0)
|
31
|
+
aws-sigv4 (~> 1.1)
|
32
|
+
aws-sdk-kms (1.22.0)
|
33
|
+
aws-sdk-core (~> 3, >= 3.56.0)
|
34
|
+
aws-sigv4 (~> 1.1)
|
35
|
+
aws-sdk-s3 (1.43.0)
|
36
|
+
aws-sdk-core (~> 3, >= 3.56.0)
|
37
|
+
aws-sdk-kms (~> 1)
|
38
|
+
aws-sigv4 (~> 1.1)
|
39
|
+
aws-sdk-ssm (1.50.0)
|
40
|
+
aws-sdk-core (~> 3, >= 3.56.0)
|
41
|
+
aws-sigv4 (~> 1.1)
|
42
|
+
aws-sigv4 (1.1.0)
|
43
|
+
aws-eventstream (~> 1.0, >= 1.0.2)
|
44
|
+
cfhighlander (0.9.0)
|
45
|
+
aws-sdk-cloudformation (~> 1, < 2)
|
46
|
+
aws-sdk-core (~> 3, < 4)
|
47
|
+
aws-sdk-ec2 (~> 1, < 2)
|
48
|
+
aws-sdk-s3 (~> 1, < 2)
|
49
|
+
cfndsl (~> 0.16, < 1)
|
50
|
+
duplicate (~> 1.1)
|
51
|
+
git (~> 1.4, < 2)
|
52
|
+
highline (>= 1.7.10, < 1.8)
|
53
|
+
netaddr (~> 1.5, >= 1.5.1)
|
54
|
+
rubyzip (>= 1.2.1, < 2)
|
55
|
+
thor (~> 0.20, < 1)
|
56
|
+
cfndsl (0.17.0)
|
57
|
+
duplicate (1.1.1)
|
58
|
+
git (1.5.0)
|
59
|
+
highline (1.7.10)
|
60
|
+
jmespath (1.4.0)
|
61
|
+
netaddr (1.5.1)
|
62
|
+
rake (10.5.0)
|
63
|
+
rubyzip (1.2.3)
|
64
|
+
thor (0.20.3)
|
65
|
+
|
66
|
+
PLATFORMS
|
67
|
+
ruby
|
68
|
+
|
69
|
+
DEPENDENCIES
|
70
|
+
bundler (~> 2.0)
|
71
|
+
cfn-vpn!
|
72
|
+
rake (~> 10.0)
|
73
|
+
|
74
|
+
BUNDLED WITH
|
75
|
+
2.0.1
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Guslington
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# CfnVpn
|
2
|
+
|
3
|
+
Manages the resources required to create a client vpn in AWS.
|
4
|
+
Uses cloudformation to manage the state of the vpn resources.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Install `cfn-vpn` gem
|
9
|
+
|
10
|
+
```bash
|
11
|
+
gem install cfn-vpn
|
12
|
+
```
|
13
|
+
|
14
|
+
Install [docker](https://docs.docker.com/install/)
|
15
|
+
|
16
|
+
Docker is required to generate the certificates required for the client vpn.
|
17
|
+
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) dokcer image.
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### help
|
22
|
+
|
23
|
+
Displays all possible commands
|
24
|
+
|
25
|
+
```bash
|
26
|
+
Commands:
|
27
|
+
cfn-vpn --version, -v # print the version
|
28
|
+
cfn-vpn help [COMMAND] # Describe available commands or one specific command
|
29
|
+
cfn-vpn init [name] --server-cn=SERVER_CN --subnet-id=SUBNET_ID # Ciinabox configuration initialization
|
30
|
+
```
|
31
|
+
|
32
|
+
### init
|
33
|
+
|
34
|
+
Initialises a new client vpn and creates all required resources to get it running.
|
35
|
+
|
36
|
+
```bash
|
37
|
+
Usage:
|
38
|
+
cfn-vpn init [name] --server-cn=SERVER_CN --subnet-id=SUBNET_ID
|
39
|
+
|
40
|
+
Options:
|
41
|
+
p, [--profile=PROFILE] # AWS Profile
|
42
|
+
r, [--region=REGION] # AWS Region
|
43
|
+
--server-cn=SERVER_CN # server certificate common name
|
44
|
+
[--client-cn=CLIENT_CN] # client certificate common name
|
45
|
+
--subnet-id=SUBNET_ID # subnet id to associate your vpn with
|
46
|
+
[--cidr=CIDR] # cidr from which to assign client IP addresses
|
47
|
+
# Default: 10.250.0.0/16
|
48
|
+
|
49
|
+
Ciinabox configuration initialization
|
50
|
+
```
|
51
|
+
|
52
|
+
### config
|
53
|
+
|
54
|
+
Downloads the opvn config file for the client vpn
|
55
|
+
|
56
|
+
```bash
|
57
|
+
Usage:
|
58
|
+
cfn-vpn config [name]
|
59
|
+
|
60
|
+
Options:
|
61
|
+
[--profile=PROFILE] # AWS Profile
|
62
|
+
[--region=REGION] # AWS Region
|
63
|
+
# Default: ap-southeast-2
|
64
|
+
|
65
|
+
Ciinabox configuration initialization
|
66
|
+
```
|
67
|
+
|
68
|
+
## Contributing
|
69
|
+
|
70
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/base2services/aws-client-vpn.
|
71
|
+
|
72
|
+
## License
|
73
|
+
|
74
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/cfn-vpn.gemspec
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "cfnvpn/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cfn-vpn"
|
8
|
+
spec.version = CfnVpn::VERSION
|
9
|
+
spec.authors = ["Guslington"]
|
10
|
+
spec.email = ["guslington@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{creates and manages resources for the aws client vpn}
|
13
|
+
spec.description = %q{creates and manages resources for the aws client vpn}
|
14
|
+
spec.homepage = "https://github.com/base2services/aws-client-vpn"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
+
if spec.respond_to?(:metadata)
|
20
|
+
spec.metadata["allowed_push_host"] = 'https://rubygems.org'
|
21
|
+
|
22
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
23
|
+
spec.metadata["source_code_uri"] = "https://github.com/base2services/aws-client-vpn"
|
24
|
+
else
|
25
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
26
|
+
"public gem pushes."
|
27
|
+
end
|
28
|
+
|
29
|
+
# Specify which files should be added to the gem when it is released.
|
30
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
31
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
32
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
33
|
+
end
|
34
|
+
spec.bindir = "exe"
|
35
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
36
|
+
spec.require_paths = ["lib"]
|
37
|
+
|
38
|
+
spec.add_dependency "thor", "~> 0.20"
|
39
|
+
spec.add_dependency 'cfhighlander', '~> 0.9', '<1'
|
40
|
+
spec.add_dependency 'cfndsl', '~> 0.17', '<1'
|
41
|
+
spec.add_runtime_dependency 'aws-sdk-ec2', '~> 1.95', '<2'
|
42
|
+
spec.add_runtime_dependency 'aws-sdk-acm', '~> 1', '<2'
|
43
|
+
spec.add_runtime_dependency 'aws-sdk-ssm', '~> 1', '<2'
|
44
|
+
spec.add_runtime_dependency 'aws-sdk-cloudformation', '~> 1', '<2'
|
45
|
+
|
46
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
47
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
48
|
+
end
|
data/exe/cfn-vpn
ADDED
data/lib/cfnvpn.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'cfnvpn/version'
|
3
|
+
require 'cfnvpn/init'
|
4
|
+
require 'cfnvpn/config'
|
5
|
+
|
6
|
+
module CfnVpn
|
7
|
+
class Cli < Thor
|
8
|
+
|
9
|
+
map %w[--version -v] => :__print_version
|
10
|
+
desc "--version, -v", "print the version"
|
11
|
+
def __print_version
|
12
|
+
puts CfnVpn::VERSION
|
13
|
+
end
|
14
|
+
|
15
|
+
# Initializes ciinabox configuration
|
16
|
+
register CfnVpn::Init, 'init', 'init [name]', 'Ciinabox configuration initialization'
|
17
|
+
tasks["init"].options = CfnVpn::Init.class_options
|
18
|
+
|
19
|
+
register CfnVpn::Config, 'config', 'config [name]', 'Ciinabox configuration initialization'
|
20
|
+
tasks["config"].options = CfnVpn::Config.class_options
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
# Aws.config[:retry_limit] = if ENV.key? 'CFNVPN_AWS_RETRY_LIMIT' then (ENV['CFNVPN_AWS_RETRY_LIMIT'].to_i) else 10 end
|
25
|
+
|
26
|
+
end
|
data/lib/cfnvpn/acm.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'aws-sdk-acm'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module CfnVpn
|
5
|
+
class Acm
|
6
|
+
|
7
|
+
def initialize(region,cert_dir)
|
8
|
+
@client = Aws::ACM::Client.new(region: region)
|
9
|
+
@cert_dir = cert_dir
|
10
|
+
end
|
11
|
+
|
12
|
+
def import_certificate(cert,key,ca)
|
13
|
+
cert_body = load_certificate(cert)
|
14
|
+
key_body = load_certificate(key)
|
15
|
+
ca_body = load_certificate(ca)
|
16
|
+
|
17
|
+
resp = @client.import_certificate({
|
18
|
+
certificate: cert_body,
|
19
|
+
private_key: key_body,
|
20
|
+
certificate_chain: ca_body
|
21
|
+
})
|
22
|
+
return resp.certificate_arn
|
23
|
+
end
|
24
|
+
|
25
|
+
def tag_certificate(arn,name,type,cfnvpn_name)
|
26
|
+
@client.add_tags_to_certificate({
|
27
|
+
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
|
+
]
|
33
|
+
})
|
34
|
+
end
|
35
|
+
|
36
|
+
def load_certificate(cert)
|
37
|
+
File.read("#{@cert_dir}/#{cert}")
|
38
|
+
end
|
39
|
+
|
40
|
+
def certificate_exists?(name)
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_certificate(name)
|
45
|
+
return 'arn'
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'cfnvpn/acm'
|
3
|
+
require 'cfnvpn/ssm'
|
4
|
+
require 'cfnvpn/log'
|
5
|
+
|
6
|
+
module CfnVpn
|
7
|
+
class Certificates
|
8
|
+
include CfnVpn::Log
|
9
|
+
|
10
|
+
def initialize(build_dir,cfnvpn_name)
|
11
|
+
@cfnvpn_name = cfnvpn_name
|
12
|
+
@config_dir = "#{build_dir}/config"
|
13
|
+
@cert_dir = "#{build_dir}/certificates"
|
14
|
+
FileUtils.mkdir_p(@cert_dir)
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate(server_cn,client_cn)
|
18
|
+
cmd = ["docker", "run", "-it", "--rm"]
|
19
|
+
cmd << "-e EASYRSA_REQ_CN=#{server_cn}"
|
20
|
+
cmd << "-e EASYRSA_CLIENT_CN=#{client_cn}"
|
21
|
+
cmd << "-v #{@cert_dir}:/easy-rsa/output"
|
22
|
+
cmd << "base2/aws-client-vpn:3.0.5"
|
23
|
+
return `#{cmd.join(' ')}`
|
24
|
+
end
|
25
|
+
|
26
|
+
def upload_certificates(region,cert,type,cn=nil)
|
27
|
+
cn = cn.nil? ? cert : cn
|
28
|
+
acm = CfnVpn::Acm.new(region, @cert_dir)
|
29
|
+
arn = acm.import_certificate("#{cert}.crt", "#{cert}.key", "ca.crt")
|
30
|
+
Log.logger.debug "Uploaded #{type} certificate to ACM #{arn}"
|
31
|
+
acm.tag_certificate(arn,cn,type,@cfnvpn_name)
|
32
|
+
return arn
|
33
|
+
end
|
34
|
+
|
35
|
+
def store_certificate(region,cert)
|
36
|
+
ssm = CfnVpn::SSM.new(@cfnvpn_name, region, @cert_dir)
|
37
|
+
ssm.put_parameter(cert)
|
38
|
+
end
|
39
|
+
|
40
|
+
def write_certificate(cert_body,name,force)
|
41
|
+
file = "#{@config_dir}/#{name}"
|
42
|
+
if File.file?(file)
|
43
|
+
if force
|
44
|
+
Log.logger.warn "overriding existing #{name}"
|
45
|
+
File.write(file, cert_body)
|
46
|
+
else
|
47
|
+
Log.logger.info "#{name} already exists"
|
48
|
+
end
|
49
|
+
else
|
50
|
+
File.write(file, cert_body)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'cfhighlander.publisher'
|
2
|
+
require 'cfhighlander.factory'
|
3
|
+
require 'cfhighlander.validator'
|
4
|
+
|
5
|
+
require 'cfnvpn/version'
|
6
|
+
|
7
|
+
module CfnVpn
|
8
|
+
class CfHiglander
|
9
|
+
|
10
|
+
def initialize(region, name, config, output_dir)
|
11
|
+
@component_name = name
|
12
|
+
@region = region
|
13
|
+
@config = config
|
14
|
+
@cfn_output_format = 'yaml'
|
15
|
+
ENV['CFHIGHLANDER_WORKDIR'] = output_dir
|
16
|
+
end
|
17
|
+
|
18
|
+
def render()
|
19
|
+
component = load_component(@component_name)
|
20
|
+
compiled = compile_component(component)
|
21
|
+
validate_component(component,compiled.cfn_template_paths)
|
22
|
+
cfn_template_paths = compiled.cfn_template_paths
|
23
|
+
return cfn_template_paths.select { |path| path.match(@component_name) }.first
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def load_component(component_name)
|
29
|
+
factory = Cfhighlander::Factory::ComponentFactory.new
|
30
|
+
component = factory.loadComponentFromTemplate(component_name)
|
31
|
+
component.config = @config
|
32
|
+
component.version = CfnVpn::VERSION
|
33
|
+
component.load()
|
34
|
+
return component
|
35
|
+
end
|
36
|
+
|
37
|
+
def compile_component(component)
|
38
|
+
component_compiler = Cfhighlander::Compiler::ComponentCompiler.new(component)
|
39
|
+
component_compiler.compileCloudFormation(@cfn_output_format)
|
40
|
+
return component_compiler
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate_component(component,template_paths)
|
44
|
+
component_validator = Cfhighlander::Cloudformation::Validator.new(component)
|
45
|
+
component_validator.validate(template_paths, @cfn_output_format)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'aws-sdk-ec2'
|
2
|
+
require 'cfnvpn/log'
|
3
|
+
|
4
|
+
module CfnVpn
|
5
|
+
class ClientVpn
|
6
|
+
include CfnVpn::Log
|
7
|
+
|
8
|
+
def initialize(name,region)
|
9
|
+
@client = Aws::EC2::Client.new(region: region)
|
10
|
+
@name = name
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_endpoint()
|
14
|
+
resp = @client.describe_client_vpn_endpoints({
|
15
|
+
filters: [{ name: "tag:cfnvpn:name", values: [@name] }]
|
16
|
+
})
|
17
|
+
if resp.client_vpn_endpoints.empty?
|
18
|
+
Log.logger.error "unable to find endpoint with tag Key: cfnvpn:name with Value: #{@name}"
|
19
|
+
raise "Unable to find client vpn"
|
20
|
+
end
|
21
|
+
resp.client_vpn_endpoints.first
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_endpoint_id()
|
25
|
+
return get_endpoint().client_vpn_endpoint_id
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_config(endpoint_id)
|
29
|
+
resp = @client.export_client_vpn_client_configuration({
|
30
|
+
client_vpn_endpoint_id: endpoint_id
|
31
|
+
})
|
32
|
+
return resp.client_configuration
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'aws-sdk-cloudformation'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'cfnvpn/version'
|
4
|
+
require 'cfnvpn/log'
|
5
|
+
|
6
|
+
module CfnVpn
|
7
|
+
class Cloudformation
|
8
|
+
include CfnVpn::Log
|
9
|
+
|
10
|
+
def initialize(region,name)
|
11
|
+
@name = name
|
12
|
+
@stack_name = "#{@name}-cfnvpn"
|
13
|
+
@client = Aws::CloudFormation::Client.new(region: region)
|
14
|
+
end
|
15
|
+
|
16
|
+
# TODO: check for REVIEW_IN_PROGRESS
|
17
|
+
def does_cf_stack_exist()
|
18
|
+
begin
|
19
|
+
resp = @client.describe_stacks({
|
20
|
+
stack_name: @stack_name,
|
21
|
+
})
|
22
|
+
rescue Aws::CloudFormation::Errors::ValidationError
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
return resp.size > 0
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_change_set_type()
|
29
|
+
return does_cf_stack_exist() ? 'UPDATE' : 'CREATE'
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_change_set(template_path)
|
33
|
+
change_set_name = "#{@stack_name}-#{CfnVpn::CHANGE_SET_VERSION}"
|
34
|
+
change_set_type = get_change_set_type()
|
35
|
+
template_body = File.read(template_path)
|
36
|
+
Log.logger.debug "Creating changeset"
|
37
|
+
change_set = @client.create_change_set({
|
38
|
+
stack_name: @stack_name,
|
39
|
+
template_body: template_body,
|
40
|
+
tags: [
|
41
|
+
{
|
42
|
+
key: "cfnvpn:version",
|
43
|
+
value: CfnVpn::VERSION,
|
44
|
+
},
|
45
|
+
{
|
46
|
+
key: "cfnvpn:name",
|
47
|
+
value: @name,
|
48
|
+
}
|
49
|
+
],
|
50
|
+
change_set_name: change_set_name,
|
51
|
+
change_set_type: change_set_type
|
52
|
+
})
|
53
|
+
return change_set, change_set_type
|
54
|
+
end
|
55
|
+
|
56
|
+
def wait_for_changeset(change_set_id)
|
57
|
+
Log.logger.debug "Waiting for changeset to be created"
|
58
|
+
@client.wait_until :change_set_create_complete, change_set_name: change_set_id
|
59
|
+
end
|
60
|
+
|
61
|
+
def execute_change_set(change_set_id)
|
62
|
+
Log.logger.debug "Executing the changeset"
|
63
|
+
stack = @client.execute_change_set({
|
64
|
+
change_set_name: change_set_id
|
65
|
+
})
|
66
|
+
end
|
67
|
+
|
68
|
+
def wait_for_execute(change_set_type)
|
69
|
+
waiter = change_set_type == 'CREATE' ? :stack_create_complete : :stack_update_complete
|
70
|
+
Log.logger.info "Waiting for changeset to #{change_set_type}"
|
71
|
+
resp = @client.wait_until waiter, stack_name: @stack_name
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'cfnvpn/clientvpn'
|
2
|
+
require 'cfnvpn/ssm'
|
3
|
+
require 'cfnvpn/log'
|
4
|
+
|
5
|
+
module CfnVpn
|
6
|
+
class Config < Thor::Group
|
7
|
+
include Thor::Actions
|
8
|
+
include CfnVpn::Log
|
9
|
+
|
10
|
+
argument :name
|
11
|
+
|
12
|
+
class_option :profile, desc: 'AWS Profile'
|
13
|
+
class_option :region, default: ENV['AWS_REGION'], desc: 'AWS Region'
|
14
|
+
class_option :force, default: false, type: :boolean, desc: 'AWS Region'
|
15
|
+
class_option :verbose, desc: 'set log level to debug', type: :boolean
|
16
|
+
|
17
|
+
def self.source_root
|
18
|
+
File.dirname(__FILE__)
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_loglevel
|
22
|
+
Log.logger.level = Logger::DEBUG if @options['verbose']
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_config_directory
|
26
|
+
@home_dir = "#{ENV['HOME']}/.cfnvpn/#{@name}"
|
27
|
+
@config_dir = "#{@home_dir}/config"
|
28
|
+
Log.logger.debug("Creating config directory #{@config_dir}")
|
29
|
+
FileUtils.mkdir_p(@config_dir)
|
30
|
+
end
|
31
|
+
|
32
|
+
def download_config
|
33
|
+
vpn = CfnVpn::ClientVpn.new(@name,@options['region'])
|
34
|
+
@endpoint_id = vpn.get_endpoint_id()
|
35
|
+
Log.logger.info "downloading client config for #{@endpoint_id}"
|
36
|
+
@config = vpn.get_config(@endpoint_id)
|
37
|
+
end
|
38
|
+
|
39
|
+
def download_certificate
|
40
|
+
ssm = CfnVpn::SSM.new(@name,@options['region'],@home_dir)
|
41
|
+
cert_body = ssm.get_parameter("#{@name}.crt")
|
42
|
+
if cert_body
|
43
|
+
cert = CfnVpn::Certificates.new(@home_dir,@name)
|
44
|
+
cert.write_certificate(cert_body,"#{@name}.crt",@options['force'])
|
45
|
+
Log.logger.info "downloaded client certificate #{@name}.crt"
|
46
|
+
else
|
47
|
+
Log.logger.error "unable to find client certificate #{@name}.crt"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def download_key
|
52
|
+
ssm = CfnVpn::SSM.new(@name,@options['region'],@home_dir)
|
53
|
+
cert_body = ssm.get_parameter("#{@name}.key")
|
54
|
+
if cert_body
|
55
|
+
cert = CfnVpn::Certificates.new(@home_dir,@name)
|
56
|
+
cert.write_certificate(cert_body,"#{@name}.key",@options['force'])
|
57
|
+
Log.logger.info "downloaded client key #{@name}.key"
|
58
|
+
else
|
59
|
+
Log.logger.error "unable to find client certificate #{@name}.crt"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def alter_config
|
64
|
+
string = (0...8).map { (65 + rand(26)).chr.downcase }.join
|
65
|
+
@config.sub!(@endpoint_id, "#{string}.#{@endpoint_id}")
|
66
|
+
@config.concat("\n\ncert #{@config_dir}/#{@name}.crt")
|
67
|
+
@config.concat("\nkey #{@config_dir}/#{@name}.key\n")
|
68
|
+
end
|
69
|
+
|
70
|
+
def write_config
|
71
|
+
config_file = "#{@config_dir}/#{@name}.ovpn"
|
72
|
+
File.write(config_file, @config)
|
73
|
+
Log.logger.info "downloaded client config #{config_file}"
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
data/lib/cfnvpn/init.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'cfnvpn/cloudformation'
|
4
|
+
require 'cfnvpn/certificates'
|
5
|
+
require 'cfnvpn/cfhighlander'
|
6
|
+
require 'cfnvpn/cloudformation'
|
7
|
+
require 'cfnvpn/log'
|
8
|
+
require 'cfnvpn/clientvpn'
|
9
|
+
|
10
|
+
module CfnVpn
|
11
|
+
class Init < Thor::Group
|
12
|
+
include Thor::Actions
|
13
|
+
include CfnVpn::Log
|
14
|
+
|
15
|
+
argument :name
|
16
|
+
|
17
|
+
class_option :profile, aliases: :p, desc: 'AWS Profile'
|
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 :server_cn, required: true, desc: 'server certificate common name'
|
22
|
+
class_option :client_cn, desc: 'client certificate common name'
|
23
|
+
|
24
|
+
class_option :subnet_id, required: true, desc: 'subnet id to associate your vpn with'
|
25
|
+
class_option :cidr, default: '10.250.0.0/16', desc: 'cidr from which to assign client IP addresses'
|
26
|
+
|
27
|
+
def self.source_root
|
28
|
+
File.dirname(__FILE__)
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_loglevel
|
32
|
+
Log.logger.level = Logger::DEBUG if @options['verbose']
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_build_directory
|
36
|
+
@build_dir = "#{ENV['HOME']}/.cfnvpn/#{@name}"
|
37
|
+
Log.logger.debug "creating directory #{@build_dir}"
|
38
|
+
FileUtils.mkdir_p(@build_dir)
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize_config
|
42
|
+
@config = {}
|
43
|
+
@config['subnet_id'] = @options['subnet_id']
|
44
|
+
@config['cidr'] = @options['cidr']
|
45
|
+
end
|
46
|
+
|
47
|
+
def stack_exist
|
48
|
+
@cfn = CfnVpn::Cloudformation.new(@options['region'],@name)
|
49
|
+
if @cfn.does_cf_stack_exist()
|
50
|
+
Log.logger.error "#{@name}-cfnvpn stack already exists in this account in region #{@options['region']}"
|
51
|
+
exit 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# create certificates
|
56
|
+
def generate_server_certificates
|
57
|
+
Log.logger.info "Generating certificates using openvpn easy-rsa"
|
58
|
+
cert = CfnVpn::Certificates.new(@build_dir,@name)
|
59
|
+
@client_cn = @options['client_cn'] ? @options['client_cn'] : "#{@name}.#{@options['server_cn']}"
|
60
|
+
Log.logger.debug cert.generate(@options['server_cn'],@client_cn)
|
61
|
+
end
|
62
|
+
|
63
|
+
def upload_certificates
|
64
|
+
cert = CfnVpn::Certificates.new(@build_dir,@name)
|
65
|
+
@config['server_cert_arn'] = cert.upload_certificates(@options['region'],'server','server',@options['server_cn'])
|
66
|
+
@config['client_cert_arn'] = cert.upload_certificates(@options['region'],@client_cn,'client')
|
67
|
+
cert.store_certificate(@options['region'],"#{@client_cn}.crt")
|
68
|
+
cert.store_certificate(@options['region'],"#{@client_cn}.key")
|
69
|
+
end
|
70
|
+
|
71
|
+
def deploy_vpn
|
72
|
+
template('templates/cfnvpn.cfhighlander.rb.tt', "#{@build_dir}/#{@name}.cfhighlander.rb", @config)
|
73
|
+
Log.logger.debug "Generating cloudformation from #{@build_dir}/#{@name}.cfhighlander.rb"
|
74
|
+
cfhl = CfnVpn::CfHiglander.new(@options['region'],@name,@config,@build_dir)
|
75
|
+
template_path = cfhl.render()
|
76
|
+
Log.logger.debug "Cloudformation template #{template_path} generated and validated"
|
77
|
+
Log.logger.info "Launching cloudformation stack #{@name}-cfnvpn in #{@options['region']}"
|
78
|
+
cfn = CfnVpn::Cloudformation.new(@options['region'],@name)
|
79
|
+
change_set, change_set_type = cfn.create_change_set(template_path)
|
80
|
+
cfn.wait_for_changeset(change_set.id)
|
81
|
+
cfn.execute_change_set(change_set.id)
|
82
|
+
cfn.wait_for_execute(change_set_type)
|
83
|
+
Log.logger.debug "Changeset #{change_set_type} complete"
|
84
|
+
end
|
85
|
+
|
86
|
+
def finish
|
87
|
+
vpn = CfnVpn::ClientVpn.new(@name,@options['region'])
|
88
|
+
@endpoint_id = vpn.get_endpoint_id()
|
89
|
+
Log.logger.info "Client VPN #{@endpoint_id} created. Run `cfn-vpn config #{@name}` to setup the client config"
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
data/lib/cfnvpn/log.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module CfnVpn
|
4
|
+
module Log
|
5
|
+
|
6
|
+
def self.colors
|
7
|
+
@colors ||= {
|
8
|
+
ERROR: 31, # red
|
9
|
+
WARN: 33, # yellow
|
10
|
+
INFO: 0,
|
11
|
+
DEBUG: 32 # grenn
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.logger
|
16
|
+
if @logger.nil?
|
17
|
+
@logger = Logger.new(STDOUT)
|
18
|
+
@logger.level = Logger::INFO
|
19
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
20
|
+
"\e[#{colors[severity.to_sym]}m#{severity}: - #{msg}\e[0m\n"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
@logger
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.logger=(logger)
|
27
|
+
@logger = logger
|
28
|
+
end
|
29
|
+
|
30
|
+
levels = %w(debug info warn error fatal)
|
31
|
+
levels.each do |level|
|
32
|
+
define_method("#{level.to_sym}") do |msg|
|
33
|
+
self.logger.send(level, msg)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/cfnvpn/ssm.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'aws-sdk-ssm'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'cfnvpn/log'
|
4
|
+
|
5
|
+
module CfnVpn
|
6
|
+
class SSM
|
7
|
+
include CfnVpn::Log
|
8
|
+
|
9
|
+
def initialize(name,region,cert_dir)
|
10
|
+
@name = name
|
11
|
+
@cert_dir = cert_dir
|
12
|
+
@path_prefix = "/cfnvpn/#{@name}"
|
13
|
+
@client = Aws::SSM::Client.new(region: region)
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_parameter(cert)
|
17
|
+
begin
|
18
|
+
resp = @client.get_parameter({
|
19
|
+
name: "#{@path_prefix}/#{cert}",
|
20
|
+
with_decryption: true
|
21
|
+
})
|
22
|
+
rescue Aws::SSM::Errors::ParameterNotFound
|
23
|
+
Log.logger.debug("Parameter #{@path_prefix}/#{cert} not found")
|
24
|
+
return false
|
25
|
+
end
|
26
|
+
Log.logger.debug("found parameter #{@path_prefix}/#{cert}")
|
27
|
+
return resp.parameter.value
|
28
|
+
end
|
29
|
+
|
30
|
+
def put_parameter(cert)
|
31
|
+
certificate = File.read("#{@cert_dir}/#{cert}")
|
32
|
+
Log.logger.debug("Reading certificate #{@cert_dir}/#{cert}")
|
33
|
+
ext = cert.split('.').last
|
34
|
+
@client.put_parameter({
|
35
|
+
name: "#{@path_prefix}/#{@name}.#{ext}",
|
36
|
+
description: "cfn-vpn #{@name} #{cert}",
|
37
|
+
value: certificate,
|
38
|
+
type: "SecureString",
|
39
|
+
overwrite: false,
|
40
|
+
tags: [
|
41
|
+
{ key: "cfnvpn:name", value: @name },
|
42
|
+
{ key: "cfnvpn:certificate", value: cert }
|
43
|
+
],
|
44
|
+
tier: "Advanced",
|
45
|
+
})
|
46
|
+
Log.logger.info("Stored #{cert} in ssm parameter #{@path_prefix}/#{@name}.#{ext}")
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
CfhighlanderTemplate do
|
2
|
+
|
3
|
+
Parameters do
|
4
|
+
ComponentParam 'EnvironmentName', '<%= @name %>'
|
5
|
+
end
|
6
|
+
|
7
|
+
Component template: 'client-vpn', name: 'vpn', render: Inline do
|
8
|
+
parameter name: 'AssociationSubnetId', value: '<%= @config['subnet_id'] %>'
|
9
|
+
parameter name: 'ClientCidrBlock', value: '<%= @config['cidr'] %>'
|
10
|
+
parameter name: 'ClientCertificateArn', value: '<%= @config['client_cert_arn'] %>'
|
11
|
+
parameter name: 'ServerCertificateArn', value: '<%= @config['server_cert_arn'] %>'
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cfn-vpn
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Guslington
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-06-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.20'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.20'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: cfhighlander
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.9'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '1'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0.9'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: cfndsl
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0.17'
|
54
|
+
- - "<"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '1'
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0.17'
|
64
|
+
- - "<"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '1'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: aws-sdk-ec2
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '1.95'
|
74
|
+
- - "<"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '2'
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '1.95'
|
84
|
+
- - "<"
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '2'
|
87
|
+
- !ruby/object:Gem::Dependency
|
88
|
+
name: aws-sdk-acm
|
89
|
+
requirement: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - "~>"
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '1'
|
94
|
+
- - "<"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2'
|
97
|
+
type: :runtime
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1'
|
104
|
+
- - "<"
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '2'
|
107
|
+
- !ruby/object:Gem::Dependency
|
108
|
+
name: aws-sdk-ssm
|
109
|
+
requirement: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - "~>"
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '1'
|
114
|
+
- - "<"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '2'
|
117
|
+
type: :runtime
|
118
|
+
prerelease: false
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '1'
|
124
|
+
- - "<"
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '2'
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: aws-sdk-cloudformation
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - "~>"
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '1'
|
134
|
+
- - "<"
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '2'
|
137
|
+
type: :runtime
|
138
|
+
prerelease: false
|
139
|
+
version_requirements: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - "~>"
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '1'
|
144
|
+
- - "<"
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '2'
|
147
|
+
- !ruby/object:Gem::Dependency
|
148
|
+
name: bundler
|
149
|
+
requirement: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - "~>"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '2.0'
|
154
|
+
type: :development
|
155
|
+
prerelease: false
|
156
|
+
version_requirements: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - "~>"
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '2.0'
|
161
|
+
- !ruby/object:Gem::Dependency
|
162
|
+
name: rake
|
163
|
+
requirement: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - "~>"
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '10.0'
|
168
|
+
type: :development
|
169
|
+
prerelease: false
|
170
|
+
version_requirements: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - "~>"
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '10.0'
|
175
|
+
description: creates and manages resources for the aws client vpn
|
176
|
+
email:
|
177
|
+
- guslington@gmail.com
|
178
|
+
executables:
|
179
|
+
- cfn-vpn
|
180
|
+
extensions: []
|
181
|
+
extra_rdoc_files: []
|
182
|
+
files:
|
183
|
+
- ".gitignore"
|
184
|
+
- ".travis.yml"
|
185
|
+
- Gemfile
|
186
|
+
- Gemfile.lock
|
187
|
+
- LICENSE.txt
|
188
|
+
- README.md
|
189
|
+
- Rakefile
|
190
|
+
- cfn-vpn.gemspec
|
191
|
+
- exe/cfn-vpn
|
192
|
+
- lib/cfnvpn.rb
|
193
|
+
- lib/cfnvpn/acm.rb
|
194
|
+
- lib/cfnvpn/certificates.rb
|
195
|
+
- lib/cfnvpn/cfhighlander.rb
|
196
|
+
- lib/cfnvpn/clientvpn.rb
|
197
|
+
- lib/cfnvpn/cloudformation.rb
|
198
|
+
- lib/cfnvpn/config.rb
|
199
|
+
- lib/cfnvpn/init.rb
|
200
|
+
- lib/cfnvpn/log.rb
|
201
|
+
- lib/cfnvpn/ssm.rb
|
202
|
+
- lib/cfnvpn/templates/cfnvpn.cfhighlander.rb.tt
|
203
|
+
- lib/cfnvpn/version.rb
|
204
|
+
homepage: https://github.com/base2services/aws-client-vpn
|
205
|
+
licenses:
|
206
|
+
- MIT
|
207
|
+
metadata:
|
208
|
+
allowed_push_host: https://rubygems.org
|
209
|
+
homepage_uri: https://github.com/base2services/aws-client-vpn
|
210
|
+
source_code_uri: https://github.com/base2services/aws-client-vpn
|
211
|
+
post_install_message:
|
212
|
+
rdoc_options: []
|
213
|
+
require_paths:
|
214
|
+
- lib
|
215
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
216
|
+
requirements:
|
217
|
+
- - ">="
|
218
|
+
- !ruby/object:Gem::Version
|
219
|
+
version: '0'
|
220
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
221
|
+
requirements:
|
222
|
+
- - ">="
|
223
|
+
- !ruby/object:Gem::Version
|
224
|
+
version: '0'
|
225
|
+
requirements: []
|
226
|
+
rubyforge_project:
|
227
|
+
rubygems_version: 2.7.6
|
228
|
+
signing_key:
|
229
|
+
specification_version: 4
|
230
|
+
summary: creates and manages resources for the aws client vpn
|
231
|
+
test_files: []
|