knife-bastion 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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