knife-bastion 1.0.0 → 1.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.
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # knife-bastion
2
2
 
3
+ [![Code Climate](https://codeclimate.com/github/eligible/knife-bastion/badges/gpa.svg)](https://codeclimate.com/github/eligible/knife-bastion)
4
+ [![Gem Version](https://badge.fury.io/rb/knife-bastion.svg)](https://badge.fury.io/rb/knife-bastion)
5
+
3
6
  This plugin allows Knife to access Chef server over a secure SSH connection,
4
7
  without exposing Chef server port to your VPN network.
5
8
 
@@ -83,6 +86,27 @@ wrong with your box):
83
86
  knife bastion status
84
87
  ```
85
88
 
89
+ ### Using knife-bastion Outside of Chef
90
+
91
+ This gem can be used to connect to any server utilizing generic
92
+ proxy client. The bastion should be started the same way as it is
93
+ described above.
94
+
95
+ Example:
96
+
97
+ ```ruby
98
+ require 'knife-bastion/client_proxy'
99
+ require 'rest_client'
100
+
101
+ # initialize RestClient::Resource object and wrap it into a bastion proxy
102
+ api = KnifeBastion::ClientProxy.new(
103
+ RestClient::Resource.new('https://domain.com/api/v1')
104
+ )
105
+
106
+ # use api the same way as it would be used as a RestClient::Resource
107
+ api['posts/1/comments'].post 'Good article.', content_type: 'text/plain'
108
+ ```
109
+
86
110
  ## Contributing
87
111
 
88
112
  1. Fork it
@@ -1,3 +1,5 @@
1
+ require_relative 'client_proxy'
2
+
1
3
  # Load socksify gem, required to make Chef work with SOCKS proxy
2
4
  begin
3
5
  require 'socksify'
@@ -7,47 +9,6 @@ rescue LoadError
7
9
  exit! 1
8
10
  end
9
11
 
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
12
  # Override `http_client` method in `Chef::HTTP` to return proxy object instead
52
13
  # of normal client object.
53
14
  Chef::HTTP.class_eval do
@@ -57,6 +18,16 @@ Chef::HTTP.class_eval do
57
18
  protected
58
19
 
59
20
  def http_client(*args)
60
- BastionChefClientProxy.new(http_client_without_bastion(*args))
21
+ client = http_client_without_bastion(*args)
22
+ options = {
23
+ local_port: ::Chef::Config[:knife][:bastion_local_port],
24
+ error_handler: -> (_) {
25
+ puts ::HighLine.color("WARNING:", [:bold, :red]) + " Failed to contact Chef server!"
26
+ puts "You might need to start bastion connection with #{::HighLine.color("knife bastion start", [:bold, :magenta])} to access Chef."
27
+ puts
28
+ raise
29
+ }
30
+ }
31
+ KnifeBastion::ClientProxy.new(client, options)
61
32
  end
62
33
  end
@@ -0,0 +1,60 @@
1
+ require 'socket'
2
+ require 'timeout'
3
+ require 'highline'
4
+ require 'openssl'
5
+
6
+ module KnifeBastion
7
+ # Simple class, that delegates all the calls to the base client
8
+ # object. The latter is overwritten to first configure SOCKS proxy,
9
+ # and if connection fails - show warning about the bastion setup.
10
+ class ClientProxy < BasicObject
11
+ NETWORK_ERRORS = [
12
+ ::SocketError,
13
+ ::Errno::ETIMEDOUT,
14
+ ::Errno::ECONNRESET,
15
+ ::Errno::ECONNREFUSED,
16
+ ::Timeout::Error,
17
+ ::OpenSSL::SSL::SSLError,
18
+ ].freeze
19
+
20
+ # Initializes an instance of the generic client proxy which sends all the
21
+ # network traffic through the SOCKS proxy.
22
+ # @param [Object] client the client object which communicates with the
23
+ # server over the network.
24
+ # @param [Hash] options the configuration of the client proxy.
25
+ # @option options [Integer] :local_port (4443) The local port of the SOCKS
26
+ # proxy.
27
+ # @option options [Proc] :error_handler network errors handler.
28
+ # By default it prints out a message which explains that the error may
29
+ # occur becase the bastion proxy has not been started.
30
+ def initialize(client, options = {})
31
+ @client = client
32
+
33
+ @local_port = options[:local_port] || 4443
34
+ @network_errors_handler = options[:error_handler] || -> (_) {
35
+ ::Kernel.puts ::HighLine.color("WARNING:", [:bold, :red]) + " Failed to contact server!"
36
+ ::Kernel.puts "You might need to start bastion connection with #{::HighLine.color("knife bastion start", [:bold, :magenta])} to access server."
37
+ ::Kernel.puts
38
+ ::Kernel.raise
39
+ }
40
+ end
41
+
42
+ # Wraps all original client calls into a with_socks_proxy method.
43
+ def method_missing(method, *args, &block)
44
+ with_socks_proxy do
45
+ @client.send(method, *args, &block)
46
+ end
47
+ end
48
+
49
+ # Routes all network connections through the bastion proxy.
50
+ def with_socks_proxy
51
+ old_socks_server, old_socks_port = ::TCPSocket::socks_server, ::TCPSocket::socks_port
52
+ ::TCPSocket::socks_server, ::TCPSocket::socks_port = '127.0.0.1', @local_port
53
+ yield
54
+ rescue *NETWORK_ERRORS => e
55
+ @network_errors_handler.call(e)
56
+ ensure
57
+ ::TCPSocket::socks_server, ::TCPSocket::socks_port = old_socks_server, old_socks_port
58
+ end
59
+ end
60
+ end
@@ -1,6 +1,6 @@
1
1
  module Knife
2
2
  module Bastion
3
- VERSION = "1.0.0"
3
+ VERSION = "1.1.0"
4
4
  MAJOR, MINOR, TINY = VERSION.split('.')
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-bastion
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmytro Shteflyuk
@@ -30,7 +30,7 @@ cert_chain:
30
30
  DHSQkPQADqf52XlDQ7I6fBAn6E2bH38Wvwpu593AvE02KRKqaK8XEtBBldE4d/It
31
31
  2ysZ/sPJras9LFb2MpjJNRCdXr3z2ed6QwuLnsyEfuk=
32
32
  -----END CERTIFICATE-----
33
- date: 2016-08-22 00:00:00.000000000 Z
33
+ date: 2016-08-30 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: chef
@@ -110,7 +110,9 @@ executables: []
110
110
  extensions: []
111
111
  extra_rdoc_files: []
112
112
  files:
113
+ - ".codeclimate.yml"
113
114
  - ".gitignore"
115
+ - ".rubocop.yml"
114
116
  - Gemfile
115
117
  - LICENSE.txt
116
118
  - README.md
@@ -123,6 +125,7 @@ files:
123
125
  - lib/chef/knife/bastion_stop.rb
124
126
  - lib/knife-bastion/activate.rb
125
127
  - lib/knife-bastion/chef_socks_proxy.rb
128
+ - lib/knife-bastion/client_proxy.rb
126
129
  - lib/knife-bastion/version.rb
127
130
  homepage: https://github.com/eligible/knife-bastion
128
131
  licenses:
metadata.gz.sig CHANGED
Binary file