knife-bastion 1.0.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
- checksums.yaml.gz.sig +2 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +98 -0
- data/Rakefile +1 -0
- data/certs/eligible.pem +21 -0
- data/knife-bastion.gemspec +31 -0
- data/lib/chef/knife/bastion_base.rb +75 -0
- data/lib/chef/knife/bastion_start.rb +83 -0
- data/lib/chef/knife/bastion_status.rb +28 -0
- data/lib/chef/knife/bastion_stop.rb +23 -0
- data/lib/knife-bastion/activate.rb +4 -0
- data/lib/knife-bastion/chef_socks_proxy.rb +62 -0
- data/lib/knife-bastion/version.rb +6 -0
- metadata +151 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cde0ad1420a7e4754cbd8a540b711217f7547382
|
4
|
+
data.tar.gz: e99a6bad8478a5ea09b294dbbe882e62dac8ccbe
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0b21d9651473242ddfed9b7de693057020b3b4e2253b317eacab1e22ea9963783adc53eb1f567a119ca64d02dce244b336a4c7a63f29b6e8b2af55ef60f7d19b
|
7
|
+
data.tar.gz: 6bd170228b796ee6195706d30817c86277314818dd753262161595612c94ea1290b5617884f8548295b7f0c487fa72be381be9da3a8043f333dcc78c764fd7c4
|
checksums.yaml.gz.sig
ADDED
data.tar.gz.sig
ADDED
Binary file
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013-2016 Eligible
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# knife-bastion
|
2
|
+
|
3
|
+
This plugin allows Knife to access Chef server over a secure SSH connection,
|
4
|
+
without exposing Chef server port to your VPN network.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your Chef repository's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'knife-bastion'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install knife-bastion
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
Configure your bastion server in `.chef/knife.rb` (at the bottom):
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
# ...
|
28
|
+
# your knife configurations goes here
|
29
|
+
# ...
|
30
|
+
|
31
|
+
# Bastion host SSH settings
|
32
|
+
knife[:bastion_host] = "bastion.mycorp.net"
|
33
|
+
knife[:bastion_user] = ENV["MYCORP_USER"] || ENV["CHEF_USER"] || ENV["USER"]
|
34
|
+
|
35
|
+
# If you have multiple networks, that require different MFA tokens, specify
|
36
|
+
# each network name here. (This configuration is referenced to clarify the
|
37
|
+
# token a user should employ.)
|
38
|
+
# knife[:bastion_network] = "mynet"
|
39
|
+
|
40
|
+
# By default, the proxy server is created on port 4443. You may configure the
|
41
|
+
# local bastion port here:
|
42
|
+
# knife[:bastion_local_port] = 4443
|
43
|
+
|
44
|
+
require "knife-bastion/activate"
|
45
|
+
```
|
46
|
+
|
47
|
+
Now, your workflow will look like this:
|
48
|
+
|
49
|
+
1. Run `knife bastion start` - this command will establish SSH connection to
|
50
|
+
bastion box for 10 minutes, and create a SOCKS proxy on port `4443`, that
|
51
|
+
will forward all Chef requests to Chef server via bastion box.
|
52
|
+
2. Use Chef to do your work.
|
53
|
+
3. At any time you can use `knife bastion status` - which will verify the proxy
|
54
|
+
and make sure everything works as expected.
|
55
|
+
4. After you finished, run `knife bastion stop` to shutdown the connection
|
56
|
+
and turn off the proxy. If you forget to do this, it will die automatically
|
57
|
+
after 10 minutes.
|
58
|
+
|
59
|
+
Sometimes when you work on a big change, default timeout of 10 minutes is too short.
|
60
|
+
You can increase timeout with `--timeout` flag:
|
61
|
+
|
62
|
+
```
|
63
|
+
knife bastion start --timeout 1800
|
64
|
+
```
|
65
|
+
|
66
|
+
Maximum timeout is 3600 (1 hour) for security reasons. You can re-establish bastion
|
67
|
+
connection by executing `knife bastion start` (if the connection is currently active,
|
68
|
+
it will be forcibly closed.)
|
69
|
+
|
70
|
+
### Bastion troubleshooting
|
71
|
+
|
72
|
+
If something is not right, you need to ensure you have access to bastion box.
|
73
|
+
Try connecting to `bastion.mycorp.net` via SSH:
|
74
|
+
|
75
|
+
```bash
|
76
|
+
ssh ${MYCORP_USER-$USER}@bastion.mycorp.net
|
77
|
+
```
|
78
|
+
|
79
|
+
Check current bastion connection status (it will tell you if there is anything
|
80
|
+
wrong with your box):
|
81
|
+
|
82
|
+
```
|
83
|
+
knife bastion status
|
84
|
+
```
|
85
|
+
|
86
|
+
## Contributing
|
87
|
+
|
88
|
+
1. Fork it
|
89
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
90
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
91
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
92
|
+
5. Create new Pull Request
|
93
|
+
|
94
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/eligible/knife-bastion.
|
95
|
+
|
96
|
+
## License
|
97
|
+
|
98
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/certs/eligible.pem
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDfDCCAmSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBCMREwDwYDVQQDDAhzZWN1
|
3
|
+
cml0eTEYMBYGCgmSJomT8ixkARkWCGVsaWdpYmxlMRMwEQYKCZImiZPyLGQBGRYD
|
4
|
+
Y29tMB4XDTE2MDgyMjIxNTI0NVoXDTE3MDgyMjIxNTI0NVowQjERMA8GA1UEAwwI
|
5
|
+
c2VjdXJpdHkxGDAWBgoJkiaJk/IsZAEZFghlbGlnaWJsZTETMBEGCgmSJomT8ixk
|
6
|
+
ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKyXvxbyCjdJ
|
7
|
+
eUPxJzt0cBv+fk9xnXq1Gu+EiFLayUAoADC9KtNDPRLe8Gd0yK5UmQD8F0wL89D4
|
8
|
+
y8vEXOm5hfHpgG7qQ01S11SRM7ksgId8OM0MyZkBTBcvpPqTyU06dbyRSy7Ir4Tn
|
9
|
+
Ro4Qb5+iOfZk3gcE9+StsJYn7l8mQFRHOZVgf8kVaAVTR8FWMLr3PMgKHsHiFJnn
|
10
|
+
Jm7eFlvQPQ8Mf56WnX4fPCO/caNqM4RFRHTjW+LYan3KsA7mg/FAt7LstONfS422
|
11
|
+
sUv0EhwprWRF1483e7b6KBcXhrk8RK447JRyKzqfw9jPONl/d5XodFGGesZ/XNHK
|
12
|
+
d0vvWDsmRSUCAwEAAaN9MHswCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
|
13
|
+
BBYEFGKTLK26F60J6VzTer7W4T/gMN2SMCAGA1UdEQQZMBeBFXNlY3VyaXR5QGVs
|
14
|
+
aWdpYmxlLmNvbTAgBgNVHRIEGTAXgRVzZWN1cml0eUBlbGlnaWJsZS5jb20wDQYJ
|
15
|
+
KoZIhvcNAQEFBQADggEBAF6VvkLEzKE9CPmQ4UXS0aHlRNwCVhSOpYeBfXWVVQqJ
|
16
|
+
ez7ftmxXLFGZ8N1wHxM7gEBFKCOB3Cu80F1uioxVMEPJAg1TT7t17GWNorG0aP7g
|
17
|
+
W5iMS2bfdLMFv8Z9Cljvn12ba+2tTn7hrzplf8gW/sxlaP3Q1lK/2cpiKqFVHLNJ
|
18
|
+
AR7q+NSrOmenHnTiKB4wTD3bRw0lv8iMVOnL97EQ/j8zp7m7dR3bJaGf5xLYeYkc
|
19
|
+
DHSQkPQADqf52XlDQ7I6fBAn6E2bH38Wvwpu593AvE02KRKqaK8XEtBBldE4d/It
|
20
|
+
2ysZ/sPJras9LFb2MpjJNRCdXr3z2ed6QwuLnsyEfuk=
|
21
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'knife-bastion/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "knife-bastion"
|
8
|
+
spec.version = Knife::Bastion::VERSION
|
9
|
+
spec.authors = ["Dmytro Shteflyuk"]
|
10
|
+
spec.email = ["dmytro@eligible.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Access Chef securely via bastion server.}
|
13
|
+
spec.description = %q{Protect your Chef server by restricting direct access to Chef HTTPS port to be only accessible from your internal network.}
|
14
|
+
spec.homepage = "https://github.com/eligible/knife-bastion"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.cert_chain = ['certs/eligible.pem']
|
23
|
+
spec.signing_key = File.expand_path("~/.ssh/gem-eligible.pem") if $0 =~ /gem\z/
|
24
|
+
|
25
|
+
spec.add_runtime_dependency 'chef'
|
26
|
+
spec.add_runtime_dependency 'highline'
|
27
|
+
spec.add_runtime_dependency 'socksify'
|
28
|
+
|
29
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
30
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
31
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class BastionBase < Knife
|
6
|
+
include Chef::Mixin::ShellOut
|
7
|
+
|
8
|
+
def initialize_params
|
9
|
+
@bastion_user = Chef::Config[:knife][:bastion_user] || ENV['CHEF_USER'] || ENV['USER']
|
10
|
+
@bastion_host = Chef::Config[:knife][:bastion_host]
|
11
|
+
@bastion_network = Chef::Config[:knife][:bastion_network]
|
12
|
+
@chef_host = URI.parse(Chef::Config[:chef_server_url]).host
|
13
|
+
@local_port = Chef::Config[:knife][:bastion_local_port] || 4443
|
14
|
+
end
|
15
|
+
|
16
|
+
def tunnel_pid(local_port, raise_on_closed_port = true)
|
17
|
+
# Check if local port is open, get proxy process PID
|
18
|
+
pid_result = shell_out("lsof -nPt -i4TCP:#{local_port} -sTCP:LISTEN")
|
19
|
+
unless pid_result.status.success?
|
20
|
+
if raise_on_closed_port
|
21
|
+
ui.fatal "Tunnel is not open on port #{local_port}"
|
22
|
+
abort
|
23
|
+
end
|
24
|
+
return nil
|
25
|
+
end
|
26
|
+
proxy_pid = pid_result.stdout.chomp
|
27
|
+
|
28
|
+
# Verify tunnel destination
|
29
|
+
bastion_ip_addr = Resolv.getaddress(@bastion_host)
|
30
|
+
dest_result = shell_out("lsof -an -p #{proxy_pid} -i4@#{bastion_ip_addr}:ssh")
|
31
|
+
unless dest_result.status.success?
|
32
|
+
ui.fatal "There is a process with PID #{proxy_pid} listening on port #{local_port}, but it does not look like a tunnel"
|
33
|
+
abort
|
34
|
+
end
|
35
|
+
|
36
|
+
proxy_pid
|
37
|
+
end
|
38
|
+
|
39
|
+
def print_tunnel_info(header, timeout: nil, pid: nil)
|
40
|
+
ui.info <<-INFO
|
41
|
+
#{header}
|
42
|
+
* Bastion host: #{ui.color "#{@bastion_user}@#{@bastion_host}", [:bold, :white]}
|
43
|
+
* Chef host: #{ui.color @chef_host, [:bold, :white]}
|
44
|
+
* Local port: #{ui.color @local_port.to_s, [:bold, :white]}
|
45
|
+
INFO
|
46
|
+
if timeout
|
47
|
+
ui.info <<-INFO
|
48
|
+
* Timeout: #{ui.color timeout.to_s, [:bold, :white]} seconds
|
49
|
+
INFO
|
50
|
+
end
|
51
|
+
if pid
|
52
|
+
ui.info <<-INFO
|
53
|
+
* Proxy PID: #{ui.color pid.to_s, [:bold, :white]}
|
54
|
+
INFO
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def run
|
59
|
+
initialize_params
|
60
|
+
|
61
|
+
# Retrieve proxy process PID. Raises an error if something is wrong
|
62
|
+
proxy_pid = tunnel_pid(@local_port)
|
63
|
+
print_tunnel_info("Found an esablished tunnel:", pid: proxy_pid)
|
64
|
+
|
65
|
+
require 'socksify'
|
66
|
+
TCPSocket::socks_server = "127.0.0.1"
|
67
|
+
TCPSocket::socks_port = @local_port
|
68
|
+
|
69
|
+
# This line will raise an exception if tunnel is broken
|
70
|
+
rest.get_rest("/policies")
|
71
|
+
ui.info ui.color("OK: ", :green) + "The tunnel is up and running"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require_relative 'bastion_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class BastionStart < BastionBase
|
6
|
+
option :timeout,
|
7
|
+
long: "--timeout SECONDS",
|
8
|
+
description: "Sets the tunnel life time, in seconds (10 minutes by default)",
|
9
|
+
default: 600,
|
10
|
+
proc: lambda { |s| s.to_i }
|
11
|
+
|
12
|
+
deps do
|
13
|
+
require 'shellwords'
|
14
|
+
end
|
15
|
+
|
16
|
+
banner "knife bastion start (options)"
|
17
|
+
category "bastion"
|
18
|
+
|
19
|
+
def initialize_params
|
20
|
+
super
|
21
|
+
|
22
|
+
@timeout = config[:timeout]
|
23
|
+
@timeout = 600 if @timeout < 1 # timeout should be greater than 0
|
24
|
+
@timeout = 3600 if @timeout > 3600 # timeout should be less than 1 hour
|
25
|
+
end
|
26
|
+
|
27
|
+
def run
|
28
|
+
initialize_params
|
29
|
+
|
30
|
+
# Check if proxy is already running and restart it
|
31
|
+
kill_proxy_if_running
|
32
|
+
|
33
|
+
print_tunnel_info("Creating a tunnel to Chef server:", timeout: @timeout)
|
34
|
+
|
35
|
+
ui.info "Establishing connection to #{ui.color @bastion_host, [:bold, :white]}"
|
36
|
+
ui.warn "Please make sure to use your #{ui.color @bastion_network, [:bold, :magenta]} token" if @bastion_network
|
37
|
+
|
38
|
+
start_proxy
|
39
|
+
end
|
40
|
+
|
41
|
+
def kill_proxy_if_running
|
42
|
+
proxy_pid = tunnel_pid(@local_port, false)
|
43
|
+
if proxy_pid
|
44
|
+
ui.warn "Proxy on #{@local_port} is up and running. Restarting it"
|
45
|
+
shell_out!("kill -9 '#{proxy_pid}'")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def start_proxy
|
50
|
+
# Not using shell_out! here because it disables tty via Process.setsid,
|
51
|
+
# so it will not be possible to enter password/token for bastion host.
|
52
|
+
system ssh_proxy_command(@timeout)
|
53
|
+
|
54
|
+
if $?.exitstatus == 0
|
55
|
+
ui.info ui.color("OK: ", :green) + "Successfully started proxy on port #{@local_port}"
|
56
|
+
else
|
57
|
+
ui.fatal "Failed to start proxy"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def ssh_proxy_command(timeout)
|
62
|
+
cmd = [
|
63
|
+
"/usr/bin/ssh",
|
64
|
+
# go to background just before command execution
|
65
|
+
"-f",
|
66
|
+
# prevent reading from stdin
|
67
|
+
"-n",
|
68
|
+
# application-level port forwarding (SOCKS proxy)
|
69
|
+
"-D", "127.0.0.1:#{@local_port}",
|
70
|
+
# wait for all remote port forwards to be successfully established
|
71
|
+
"-o", "ExitOnForwardFailure=yes",
|
72
|
+
# Disable sharing of multiple connections
|
73
|
+
"-o", "ControlPath=none",
|
74
|
+
# SSH host to connect to
|
75
|
+
"#{@bastion_user}@#{@bastion_host}",
|
76
|
+
# Enforce tunnel timeout
|
77
|
+
"sleep #{timeout}"
|
78
|
+
]
|
79
|
+
Shellwords.join(cmd)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative 'bastion_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class BastionStatus < BastionBase
|
6
|
+
include Chef::Mixin::ShellOut
|
7
|
+
|
8
|
+
banner "knife bastion status (options)"
|
9
|
+
category "bastion"
|
10
|
+
|
11
|
+
def run
|
12
|
+
initialize_params
|
13
|
+
|
14
|
+
# Retrieve proxy process PID. Raises an error if something is wrong
|
15
|
+
proxy_pid = tunnel_pid(@local_port)
|
16
|
+
print_tunnel_info("Found an esablished tunnel:", pid: proxy_pid)
|
17
|
+
|
18
|
+
require 'socksify'
|
19
|
+
TCPSocket::socks_server = "127.0.0.1"
|
20
|
+
TCPSocket::socks_port = @local_port
|
21
|
+
|
22
|
+
# This line will raise an exception if tunnel is broken
|
23
|
+
rest.get_rest("/policies")
|
24
|
+
ui.info ui.color("OK: ", :green) + "The tunnel is up and running"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'bastion_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class BastionStop < BastionBase
|
6
|
+
include Chef::Mixin::ShellOut
|
7
|
+
|
8
|
+
banner "knife bastion stop (options)"
|
9
|
+
category "bastion"
|
10
|
+
|
11
|
+
def run
|
12
|
+
initialize_params
|
13
|
+
|
14
|
+
# Retrieve proxy process PID. Raises an error if something is wrong
|
15
|
+
pid = tunnel_pid(@local_port)
|
16
|
+
|
17
|
+
shell_out!("kill -9 '#{pid}'")
|
18
|
+
|
19
|
+
ui.info ui.color("OK: ", :green) + "Tunnel closed, you're safe now"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Load socksify gem, required to make Chef work with SOCKS proxy
|
2
|
+
begin
|
3
|
+
require 'socksify'
|
4
|
+
rescue LoadError
|
5
|
+
puts HighLine.color("FATAL:", [:bold, :red]) + " Failed to load #{HighLine.color("socksify", [:bold, :magenta])} gem. Please run #{HighLine.color("bundle install", [:bold, :magenta])} to continue"
|
6
|
+
# Hard exit to skip Chef exception reporting
|
7
|
+
exit! 1
|
8
|
+
end
|
9
|
+
|
10
|
+
# Simple class, that delegates all the calls to the base client object, except
|
11
|
+
# for `request`. The latter is overwritten to first configure SOCKS proxy,
|
12
|
+
# and if connection fails - show warning about the bastion setup.
|
13
|
+
class BastionChefClientProxy < BasicObject
|
14
|
+
NETWORK_ERRORS = [
|
15
|
+
::SocketError,
|
16
|
+
::Errno::ETIMEDOUT,
|
17
|
+
::Errno::ECONNRESET,
|
18
|
+
::Errno::ECONNREFUSED,
|
19
|
+
::Timeout::Error,
|
20
|
+
::OpenSSL::SSL::SSLError,
|
21
|
+
]
|
22
|
+
|
23
|
+
def initialize(client)
|
24
|
+
@client = client
|
25
|
+
end
|
26
|
+
|
27
|
+
def request(*args, &block)
|
28
|
+
with_socks_proxy do
|
29
|
+
@client.request(*args, &block)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def method_missing(method, *args, &block)
|
34
|
+
@client.send(method, *args, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def with_socks_proxy
|
38
|
+
old_socks_server, old_socks_port = ::TCPSocket::socks_server, ::TCPSocket::socks_port
|
39
|
+
::TCPSocket::socks_server, ::TCPSocket::socks_port = '127.0.0.1', ::Chef::Config[:knife][:bastion_local_port] || 4443
|
40
|
+
yield
|
41
|
+
rescue *NETWORK_ERRORS
|
42
|
+
puts ::HighLine.color("WARNING:", [:bold, :red]) + " Failed to contact Chef server!"
|
43
|
+
puts "You might need to start bastion connection with #{::HighLine.color("knife bastion start", [:bold, :magenta])} to access Chef."
|
44
|
+
puts
|
45
|
+
raise
|
46
|
+
ensure
|
47
|
+
::TCPSocket::socks_server, ::TCPSocket::socks_port = old_socks_server, old_socks_port
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Override `http_client` method in `Chef::HTTP` to return proxy object instead
|
52
|
+
# of normal client object.
|
53
|
+
Chef::HTTP.class_eval do
|
54
|
+
alias_method :http_client_without_bastion, :http_client
|
55
|
+
protected :http_client_without_bastion
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
def http_client(*args)
|
60
|
+
BastionChefClientProxy.new(http_client_without_bastion(*args))
|
61
|
+
end
|
62
|
+
end
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: knife-bastion
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dmytro Shteflyuk
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIDfDCCAmSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBCMREwDwYDVQQDDAhzZWN1
|
14
|
+
cml0eTEYMBYGCgmSJomT8ixkARkWCGVsaWdpYmxlMRMwEQYKCZImiZPyLGQBGRYD
|
15
|
+
Y29tMB4XDTE2MDgyMjIxNTI0NVoXDTE3MDgyMjIxNTI0NVowQjERMA8GA1UEAwwI
|
16
|
+
c2VjdXJpdHkxGDAWBgoJkiaJk/IsZAEZFghlbGlnaWJsZTETMBEGCgmSJomT8ixk
|
17
|
+
ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKyXvxbyCjdJ
|
18
|
+
eUPxJzt0cBv+fk9xnXq1Gu+EiFLayUAoADC9KtNDPRLe8Gd0yK5UmQD8F0wL89D4
|
19
|
+
y8vEXOm5hfHpgG7qQ01S11SRM7ksgId8OM0MyZkBTBcvpPqTyU06dbyRSy7Ir4Tn
|
20
|
+
Ro4Qb5+iOfZk3gcE9+StsJYn7l8mQFRHOZVgf8kVaAVTR8FWMLr3PMgKHsHiFJnn
|
21
|
+
Jm7eFlvQPQ8Mf56WnX4fPCO/caNqM4RFRHTjW+LYan3KsA7mg/FAt7LstONfS422
|
22
|
+
sUv0EhwprWRF1483e7b6KBcXhrk8RK447JRyKzqfw9jPONl/d5XodFGGesZ/XNHK
|
23
|
+
d0vvWDsmRSUCAwEAAaN9MHswCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
|
24
|
+
BBYEFGKTLK26F60J6VzTer7W4T/gMN2SMCAGA1UdEQQZMBeBFXNlY3VyaXR5QGVs
|
25
|
+
aWdpYmxlLmNvbTAgBgNVHRIEGTAXgRVzZWN1cml0eUBlbGlnaWJsZS5jb20wDQYJ
|
26
|
+
KoZIhvcNAQEFBQADggEBAF6VvkLEzKE9CPmQ4UXS0aHlRNwCVhSOpYeBfXWVVQqJ
|
27
|
+
ez7ftmxXLFGZ8N1wHxM7gEBFKCOB3Cu80F1uioxVMEPJAg1TT7t17GWNorG0aP7g
|
28
|
+
W5iMS2bfdLMFv8Z9Cljvn12ba+2tTn7hrzplf8gW/sxlaP3Q1lK/2cpiKqFVHLNJ
|
29
|
+
AR7q+NSrOmenHnTiKB4wTD3bRw0lv8iMVOnL97EQ/j8zp7m7dR3bJaGf5xLYeYkc
|
30
|
+
DHSQkPQADqf52XlDQ7I6fBAn6E2bH38Wvwpu593AvE02KRKqaK8XEtBBldE4d/It
|
31
|
+
2ysZ/sPJras9LFb2MpjJNRCdXr3z2ed6QwuLnsyEfuk=
|
32
|
+
-----END CERTIFICATE-----
|
33
|
+
date: 2016-08-22 00:00:00.000000000 Z
|
34
|
+
dependencies:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: chef
|
37
|
+
requirement: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
type: :runtime
|
43
|
+
prerelease: false
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: highline
|
51
|
+
requirement: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
type: :runtime
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: socksify
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
- !ruby/object:Gem::Dependency
|
78
|
+
name: bundler
|
79
|
+
requirement: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '1.12'
|
84
|
+
type: :development
|
85
|
+
prerelease: false
|
86
|
+
version_requirements: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '1.12'
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: rake
|
93
|
+
requirement: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '10.0'
|
98
|
+
type: :development
|
99
|
+
prerelease: false
|
100
|
+
version_requirements: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '10.0'
|
105
|
+
description: Protect your Chef server by restricting direct access to Chef HTTPS port
|
106
|
+
to be only accessible from your internal network.
|
107
|
+
email:
|
108
|
+
- dmytro@eligible.com
|
109
|
+
executables: []
|
110
|
+
extensions: []
|
111
|
+
extra_rdoc_files: []
|
112
|
+
files:
|
113
|
+
- ".gitignore"
|
114
|
+
- Gemfile
|
115
|
+
- LICENSE.txt
|
116
|
+
- README.md
|
117
|
+
- Rakefile
|
118
|
+
- certs/eligible.pem
|
119
|
+
- knife-bastion.gemspec
|
120
|
+
- lib/chef/knife/bastion_base.rb
|
121
|
+
- lib/chef/knife/bastion_start.rb
|
122
|
+
- lib/chef/knife/bastion_status.rb
|
123
|
+
- lib/chef/knife/bastion_stop.rb
|
124
|
+
- lib/knife-bastion/activate.rb
|
125
|
+
- lib/knife-bastion/chef_socks_proxy.rb
|
126
|
+
- lib/knife-bastion/version.rb
|
127
|
+
homepage: https://github.com/eligible/knife-bastion
|
128
|
+
licenses:
|
129
|
+
- MIT
|
130
|
+
metadata: {}
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
requirements: []
|
146
|
+
rubyforge_project:
|
147
|
+
rubygems_version: 2.4.5.1
|
148
|
+
signing_key:
|
149
|
+
specification_version: 4
|
150
|
+
summary: Access Chef securely via bastion server.
|
151
|
+
test_files: []
|
metadata.gz.sig
ADDED
Binary file
|