bcome 1.1.4 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cdf4b817e9c7afb1b0b5508a811e2e74a71a6b97
4
- data.tar.gz: 881ae215c6873cc81b5214f2876cd13833ce1ae1
3
+ metadata.gz: 5175174eb843f0f210c02ca12ded004f75d77368
4
+ data.tar.gz: ffd09a8ba7edc0df044a17b55db02d3176e0feee
5
5
  SHA512:
6
- metadata.gz: c67f27ca6e33d761311f9bf8c226e774b10516b9f14d2bade52e8d04e2e9df35b48e0e8ad53c1199b4fa18381e8e7a3fe51ddf9e52d05035aab15024be5c4472
7
- data.tar.gz: c610e971283f6cc178d746a4eb1ceca8b619ac66d4a76bd1353eb2c999ab5da48c4075d7d02f7da4197ac253ab928a02c31a5e4f9cb6ce0a0032017fc73df5ec
6
+ metadata.gz: 855151285002aa2270d025f97ff85c8beead1f3b7aabcad797bcd8eb03885c38f296a2ad1f1e01c2b1be6631a3d9ba724f57fae6046e6132f8ec8e95ae3e9ee9
7
+ data.tar.gz: 09500dc2f2ac59b5a1c70252c07ca0bbc665f32eac78a52fc1ded53d3e9d79ba09d0367ac56921eab5d56d9ddd300665924640733d3e0d436150badbec7f55db
@@ -1,3 +1,3 @@
1
1
  module Bcome
2
- VERSION = '1.1.4'.freeze
2
+ VERSION = '1.3.0'.freeze
3
3
  end
@@ -8,7 +8,7 @@ module Bcome::Command
8
8
  command
9
9
  end
10
10
 
11
- attr_reader :stdout, :stderr
11
+ attr_reader :stdout, :stderr, :process_status
12
12
 
13
13
  def initialize(command, success_exit_codes = [0])
14
14
  @command = command
@@ -1,5 +1,8 @@
1
1
  module Bcome::Driver
2
2
  class Ec2 < Bcome::Driver::Base
3
+
4
+ PATH_TO_FOG_CREDENTIALS = "#{ENV['HOME']}/.fog".freeze
5
+
3
6
  def initialize(*params)
4
7
  super
5
8
  raise Bcome::Exception::Ec2DriverMissingProvisioningRegion, params.inspect unless provisioning_region
@@ -22,6 +25,10 @@ module Bcome::Driver
22
25
  fog_client.servers.all({})
23
26
  end
24
27
 
28
+ def raw_fog_credentials
29
+ @raw_fog_credentials ||= YAML.load_file(PATH_TO_FOG_CREDENTIALS)[credentials_key]
30
+ end
31
+
25
32
  def credentials_key
26
33
  @params[:credentials_key]
27
34
  end
@@ -0,0 +1,99 @@
1
+ module Bcome
2
+ class Encryptor
3
+
4
+ UNENC_SIGNIFIER = "".freeze
5
+ ENC_SIGNIFIER = "enc".freeze
6
+
7
+ include Singleton
8
+
9
+ attr_reader :key
10
+
11
+ def pack
12
+ # Bcome currently works with a single encryption key - the same one - for all files
13
+ # When we attempt an encrypt we'll check first to see if any encrypted files already exists, and
14
+ # we'll try our key on it. If the fails to unpack the file, we abort the encryption attempt.
15
+ prompt_for_key
16
+ if has_files_to_encrypt?
17
+ verify_presented_key if has_encrypted_files?
18
+ toggle_packed_files(all_unencrypted_filenames, :encrypt)
19
+ else
20
+ puts "\nNo unencrypted files to encrypt.\n".warning
21
+ end
22
+ return
23
+ end
24
+
25
+ def prompt_for_key
26
+ message = "Please enter an encryption key (and if your data is already encrypted, you must provide the same key): ".informational
27
+ @key = ::Readline.readline("\n#{message}", true).squeeze('').to_s
28
+ puts "\n"
29
+ end
30
+
31
+ def has_encrypted_files?
32
+ all_encrypted_filenames.any?
33
+ end
34
+
35
+ def has_files_to_encrypt?
36
+ all_unencrypted_filenames.any?
37
+ end
38
+
39
+ def verify_presented_key
40
+ # We attempt a decrypt of any encrypted file in order to verify that a newly presented key
41
+ # matches the key used to previously encrypt. Bcome operates on a one-key-per-implementation basis.
42
+ test_file = all_encrypted_filenames.first
43
+ file_contents = File.read(test_file)
44
+ file_contents.decrypt(@key)
45
+ end
46
+
47
+ def unpack
48
+ prompt_for_key
49
+ toggle_packed_files(all_encrypted_filenames,:decrypt)
50
+ return
51
+ end
52
+
53
+ def toggle_packed_files(filenames, packer_method)
54
+ raise "Missing encryption key. Please set an encryption key" unless @key
55
+ filenames.each do |filename|
56
+ # Get raw
57
+ raw_contents = File.read(filename)
58
+
59
+ if packer_method == :decrypt
60
+ filename =~ /#{path_to_metadata}\/(.+)\.enc/
61
+ opposing_filename = $1
62
+ action = "Unpacking"
63
+ else
64
+ filename =~ /#{path_to_metadata}\/(.*)/
65
+ opposing_filename = "#{$1}.enc"
66
+ action = "Packing"
67
+ end
68
+
69
+ # Write encrypted/decryption action
70
+ enc_decrypt_result = raw_contents.send(packer_method, @key)
71
+ puts "#{action}\s".informational + filename + "\sto\s".informational + "#{path_to_metadata}/" + opposing_filename
72
+ write_file(opposing_filename, enc_decrypt_result)
73
+ end
74
+ puts "\ndone".informational
75
+ end
76
+
77
+ def path_to_metadata
78
+ "bcome/metadata"
79
+ end
80
+
81
+ def write_file(filename, contents)
82
+ filepath = "#{path_to_metadata}/#{filename}"
83
+ File.open("#{filepath}", 'w') { |f| f.write(contents) }
84
+ end
85
+
86
+ def all_unencrypted_filenames
87
+ Dir["#{metadata_path}/*"].reject {|f| f =~ /\.enc/}
88
+ end
89
+
90
+ def all_encrypted_filenames
91
+ Dir["#{metadata_path}/*.enc"]
92
+ end
93
+
94
+ def metadata_path
95
+ "bcome/metadata"
96
+ end
97
+
98
+ end
99
+ end
@@ -0,0 +1,7 @@
1
+ module Bcome::Exception
2
+ class InvalidMetaDataEncryptionKey < ::Bcome::Exception::Base
3
+ def message_prefix
4
+ 'Your metadata encryption key is invalid - your metadata files are encrypted with a different key.'
5
+ end
6
+ end
7
+ end
@@ -113,6 +113,12 @@ module Bcome::WorkspaceMenu
113
113
  meta: {
114
114
  description: 'Print out all metadata related to this node'
115
115
  },
116
+ pack_metadata: {
117
+ description: 'Encrypt your metadata files',
118
+ },
119
+ unpack_metadata: {
120
+ description: 'Decrypt and expose your encrypted metadata files',
121
+ },
116
122
  registry: {
117
123
  description: 'List all user defined commands present in your registry, and available to this namespace',
118
124
  console_only: false
@@ -41,7 +41,7 @@ module Bcome::Node::Attributes
41
41
  def recurse_hash_data_for_instance_var(instance_var_name, parent_key)
42
42
  instance_data = instance_variable_defined?(instance_var_name) ? instance_variable_get(instance_var_name) : {}
43
43
  instance_data ||= {}
44
- instance_data = parent.send(parent_key).merge(instance_data) if has_parent?
44
+ instance_data = parent.send(parent_key).deep_merge(instance_data) if has_parent?
45
45
  instance_data
46
46
  end
47
47
  end
@@ -50,7 +50,7 @@ module Bcome::Node
50
50
  end
51
51
 
52
52
  def enabled_menu_items
53
- [:ls, :lsa, :workon, :enable, :disable, :enable!, :disable!, :run, :tree, :ping, :put, :rsync, :cd, :meta, :registry, :interactive, :execute_script]
53
+ [:ls, :lsa, :workon, :enable, :disable, :enable!, :disable!, :run, :tree, :ping, :put, :rsync, :cd, :meta, :pack_metadata, :unpack_metadata, :registry, :interactive, :execute_script]
54
54
  end
55
55
 
56
56
  def has_proxy?
@@ -91,6 +91,14 @@ module Bcome::Node
91
91
  end
92
92
  results
93
93
  end
94
+
95
+ def pack_metadata
96
+ ::Bcome::Encryptor.instance.pack
97
+ end
98
+
99
+ def unpack_metadata
100
+ ::Bcome::Encryptor.instance.unpack
101
+ end
94
102
 
95
103
  def validate_attributes
96
104
  validate_identifier
@@ -6,6 +6,8 @@ module Bcome::Node
6
6
 
7
7
  CONFIG_PATH = 'bcome'.freeze
8
8
  DEFAULT_CONFIG_NAME = 'networks.yml'.freeze
9
+ SERVER_OVERRIDE_CONFIG_NAME = 'machines-data.yml'.freeze
10
+
9
11
  INVENTORY_KEY = 'inventory'.freeze
10
12
  COLLECTION_KEY = 'collection'.freeze
11
13
  SUBSELECT_KEY = 'inventory-subselect'.freeze
@@ -24,6 +26,10 @@ module Bcome::Node
24
26
  "#{CONFIG_PATH}/#{config_file_name}"
25
27
  end
26
28
 
29
+ def machines_data_path
30
+ "#{CONFIG_PATH}/#{SERVER_OVERRIDE_CONFIG_NAME}"
31
+ end
32
+
27
33
  def config_file_name
28
34
  @config_file_name ||= ENV['CONF'] ? ENV['CONF'] : DEFAULT_CONFIG_NAME
29
35
  end
@@ -46,7 +52,7 @@ module Bcome::Node
46
52
  raise Bcome::Exception::InvalidNetworkConfig, 'missing config type' unless config[:type]
47
53
 
48
54
  klass = klass_for_view_type[config[:type]]
49
-
55
+
50
56
  raise Bcome::Exception::InvalidNetworkConfig, "invalid config type #{config[:type]}" unless klass
51
57
 
52
58
  node = klass.new(views: config, parent: parent)
@@ -84,6 +90,14 @@ module Bcome::Node
84
90
  @estate_config ||= reformat_config(load_estate_config)
85
91
  end
86
92
 
93
+ def machines_data
94
+ @machines_data ||= load_machines_data
95
+ end
96
+
97
+ def machines_data_for_namespace(namespace)
98
+ machines_data[namespace] ? machines_data[namespace] : {}
99
+ end
100
+
87
101
  def rewrite_estate_config(data)
88
102
  File.open(config_path, 'w') do |file|
89
103
  file.write data.to_yaml
@@ -94,12 +108,20 @@ module Bcome::Node
94
108
  config = YAML.load_file(config_path).deep_symbolize_keys
95
109
  return config
96
110
  rescue ArgumentError, Psych::SyntaxError => e
97
- raise Bcome::Exception::InvalidNetworkConfig, 'Invalid yaml in config' + e.message
111
+ raise Bcome::Exception::InvalidNetworkConfig, 'Invalid yaml in network config' + e.message
98
112
  rescue Errno::ENOENT
99
113
  raise Bcome::Exception::DeprecationWarning if is_running_deprecated_configs?
100
114
  raise Bcome::Exception::MissingNetworkConfig, config_path
101
115
  end
102
116
 
117
+ def load_machines_data
118
+ return {} unless File.exist?(machines_data_path)
119
+ config = YAML.load_file(machines_data_path).deep_symbolize_keys
120
+ return config
121
+ rescue ArgumentError, Psych::SyntaxError => e
122
+ raise Bcome::Exception::InvalidNetworkConfig, 'Invalid yaml in machines data config' + e.message
123
+ end
124
+
103
125
  def is_running_deprecated_configs?
104
126
  File.exist?("bcome/config/platform.yml")
105
127
  end
@@ -25,9 +25,11 @@ module Bcome::Node::Meta
25
25
  @data
26
26
  end
27
27
 
28
- def fetch(key)
28
+ def fetch(key, default = nil)
29
29
  if @data.key?(key)
30
30
  @data[key]
31
+ elsif default
32
+ return default
31
33
  else
32
34
  raise Bcome::Exception::CantFindKeyInMetadata, key unless @data.key?(key)
33
35
  end
@@ -8,6 +8,10 @@ module Bcome::Node
8
8
  @all_metadata_filenames = Dir["#{META_DATA_FILE_PATH_PREFIX}/*"]
9
9
  end
10
10
 
11
+ def decryption_key
12
+ @decryption_key
13
+ end
14
+
11
15
  def data
12
16
  @data ||= do_load
13
17
  end
@@ -16,11 +20,29 @@ module Bcome::Node
16
20
  data[namespace.to_sym] ? data[namespace.to_sym] : {}
17
21
  end
18
22
 
23
+ def prompt_for_decryption_key
24
+ message = "Please enter your metadata encryption key: ".informational
25
+ @decryption_key = ::Readline.readline("\n#{message}", true).squeeze('').to_s
26
+ end
27
+
28
+ def load_file_data_for(filepath)
29
+ if filepath =~ /.enc/ # encrypted file contents
30
+ prompt_for_decryption_key unless decryption_key
31
+ encrypted_contents = File.read(filepath)
32
+ decrypted_contents = encrypted_contents.decrypt(decryption_key)
33
+ return YAML.load(decrypted_contents)
34
+ else # unencrypted
35
+ return YAML.load_file(filepath)
36
+ end
37
+ end
38
+
19
39
  def do_load
20
40
  all_meta_data = {}
21
- @all_metadata_filenames.each do |filename|
41
+ @all_metadata_filenames.each do |filepath|
42
+ next if filepath =~ /-unenc/ # we only read from the encrypted, packed files.
43
+
22
44
  begin
23
- filedata = YAML.load_file(filename)
45
+ filedata = load_file_data_for(filepath)
24
46
  all_meta_data.deep_merge!(filedata)
25
47
  rescue Psych::SyntaxError => e
26
48
  raise Bcome::Exception::InvalidMetaDataConfig, "Error: #{e.message}"
@@ -10,6 +10,17 @@ module Bcome::Node::Server
10
10
  @bootstrap = false
11
11
  end
12
12
 
13
+ # override a server namespace's parameters. This enables features such as specific SSH parameters for a specific server, e.g. my use case was a
14
+ # single debian box within an ubuntu network, where I needed to access the machine bootstrapping mode with the 'admin' rather 'ubuntu' username.
15
+ def set_view_attributes
16
+ super
17
+ overridden_attributes = ::Bcome::Node::Factory.instance.machines_data_for_namespace(namespace.to_sym)
18
+ overridden_attributes.each do |override_key, override_value|
19
+ instance_variable_name = "@#{override_key}"
20
+ instance_variable_set(instance_variable_name, override_value)
21
+ end
22
+ end
23
+
13
24
  def bootstrap?
14
25
  @bootstrap ? true : false
15
26
  end
@@ -98,6 +109,10 @@ module Bcome::Node::Server
98
109
  base_items
99
110
  end
100
111
 
112
+ def local_port_forward(start_port, end_port)
113
+ ssh_driver.local_port_forward(start_port, end_port)
114
+ end
115
+
101
116
  def open_ssh_connection
102
117
  ssh_driver.ssh_connection
103
118
  end
@@ -79,6 +79,27 @@ module Bcome::Ssh
79
79
  end
80
80
  end
81
81
 
82
+ def local_port_forward(start_port, end_port)
83
+ if has_proxy?
84
+
85
+ if bootstrap?
86
+ tunnel_command = "ssh -N -L #{start_port}:#{@context_node.internal_ip_address}:#{end_port} -i #{@bootstrap_settings.ssh_key_path} #{bastion_host_user}@#{@proxy_data.host}"
87
+ else
88
+ tunnel_command = "ssh -N -L #{start_port}:#{@context_node.internal_ip_address}:#{end_port} #{bastion_host_user}@#{@proxy_data.host}"
89
+ end
90
+ else
91
+ if bootstrap?
92
+ tunnel_command = "ssh -i #{@bootstrap_settings.ssh_key_path} -N -L #{start_port}:#{@context_node.public_ip_address}:#{end_port}"
93
+ else
94
+ tunnel_command = "ssh -N -L #{start_port}:#{@context_node.public_ip_address}:#{end_port}"
95
+ end
96
+ end
97
+
98
+ tunnel = ::Bcome::Ssh::Tunnel::LocalPortForward.new(tunnel_command)
99
+ tunnel.open!
100
+ return tunnel
101
+ end
102
+
82
103
  def bootstrap_ssh_command
83
104
  if has_proxy?
84
105
  "ssh -i #{@bootstrap_settings.ssh_key_path} -t #{bastion_host_user}@#{@proxy_data.host} ssh -t #{user}@#{@context_node.internal_ip_address}"
@@ -0,0 +1,20 @@
1
+ module Bcome::Ssh::Tunnel
2
+ class LocalPortForward
3
+
4
+ def initialize(tunnel_command)
5
+ @tunnel_command = tunnel_command
6
+ @process_pid = nil
7
+ end
8
+
9
+ def open!
10
+ puts "Opening tunnel: #{@tunnel_command}".informational
11
+ @process_pid = spawn(@tunnel_command)
12
+ end
13
+
14
+ def close!
15
+ puts "Closing tunnel with process pid ##{@process_pid}: #{@tunnel_command}".informational
16
+ ::Process.kill("HUP", @process_pid)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,40 @@
1
+ require 'openssl'
2
+
3
+ # Adapted from https://stackoverflow.com/questions/39033577/opensslcipherciphererror-wrong-final-block-length
4
+
5
+ class String
6
+
7
+ ALGORITHM = 'AES-256-ECB'
8
+
9
+ def encrypt(key)
10
+ begin
11
+ cipher = OpenSSL::Cipher.new(ALGORITHM)
12
+ cipher.encrypt()
13
+ cipher.key = key.as_256_bit_key
14
+ crypt = cipher.update(self) + cipher.final()
15
+ crypt_string = (Base64.encode64(crypt))
16
+ return crypt_string
17
+ rescue Exception => e
18
+ puts "Failed to encrypt: #{e.message}"
19
+ end
20
+ end
21
+
22
+ def decrypt(key)
23
+ begin
24
+ cipher = OpenSSL::Cipher.new(ALGORITHM)
25
+ cipher.decrypt()
26
+ cipher.key = key.as_256_bit_key
27
+ tempkey = Base64.decode64(self)
28
+ crypt = cipher.update(tempkey)
29
+ crypt << cipher.final()
30
+ return crypt
31
+ rescue Exception => e
32
+ raise ::Bcome::Exception::InvalidMetaDataEncryptionKey.new
33
+ end
34
+ end
35
+
36
+ def as_256_bit_key
37
+ ::Digest::SHA256.digest self
38
+ end
39
+
40
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bcome
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guillaume Roderick (Webzakimbo)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-03 00:00:00.000000000 Z
11
+ date: 2018-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -163,6 +163,7 @@ files:
163
163
  - lib/objects/driver/bucket.rb
164
164
  - lib/objects/driver/ec2.rb
165
165
  - lib/objects/driver/static.rb
166
+ - lib/objects/encryptor.rb
166
167
  - lib/objects/exception/argument_error_invoking_method_from_command_line.rb
167
168
  - lib/objects/exception/base.rb
168
169
  - lib/objects/exception/can_only_subselect_on_inventory.rb
@@ -186,6 +187,7 @@ files:
186
187
  - lib/objects/exception/invalid_machines_cache_config.rb
187
188
  - lib/objects/exception/invalid_matcher_query.rb
188
189
  - lib/objects/exception/invalid_meta_data_config.rb
190
+ - lib/objects/exception/invalid_metadata_encryption_key.rb
189
191
  - lib/objects/exception/invalid_network_config.rb
190
192
  - lib/objects/exception/invalid_network_driver_type.rb
191
193
  - lib/objects/exception/invalid_proxy_config.rb
@@ -264,9 +266,11 @@ files:
264
266
  - lib/objects/ssh/driver.rb
265
267
  - lib/objects/ssh/proxy_data.rb
266
268
  - lib/objects/ssh/script_exec.rb
269
+ - lib/objects/ssh/tunnel/local_port_forward.rb
267
270
  - lib/objects/system/local.rb
268
271
  - lib/objects/workspace.rb
269
272
  - patches/irb.rb
273
+ - patches/string-encrypt.rb
270
274
  - patches/string.rb
271
275
  - patches/string_stylesheet.rb
272
276
  homepage: https://github.com/webzakimbo/bcome-kontrol