mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
(#9241) Add SSL verification
Without this patch we were blindly trusting the remote end of our API connection is who they claim to be. This is an insecure state because we leave ourselves open to a man in the middle attack. This patch adds a vsphere_expected_pubkey_hash setting for the Vsphere provider. This setting is expected to be the SHA256 hex digest string of the PEM encoded text of the RSA public key. The first time an end user connects this string is displayed to them in the error message. They need simply copy and paste it into ~/.fog to securely connect to the remote end. For example: :vspherebadpw: :vsphere_server: vc01.acme.lan :vsphere_username: api_login :vsphere_password: badpassword :vsphere_expected_pubkey_hash: 431dd...
This commit is contained in:
parent
98637d39da
commit
ec32398811
2 changed files with 40 additions and 8 deletions
|
@ -7,6 +7,7 @@ module Fog
|
||||||
|
|
||||||
module Errors
|
module Errors
|
||||||
class ServiceError < Fog::Errors::Error; end
|
class ServiceError < Fog::Errors::Error; end
|
||||||
|
class SecurityError < ServiceError; end
|
||||||
end
|
end
|
||||||
|
|
||||||
service(:compute, 'vsphere/compute')
|
service(:compute, 'vsphere/compute')
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
require 'digest/sha2'
|
||||||
|
|
||||||
module Fog
|
module Fog
|
||||||
module Compute
|
module Compute
|
||||||
class Vsphere < Fog::Service
|
class Vsphere < Fog::Service
|
||||||
|
|
||||||
requires :vsphere_username, :vsphere_password, :vsphere_server
|
requires :vsphere_username, :vsphere_password, :vsphere_server
|
||||||
recognizes :vsphere_port, :vsphere_path, :vsphere_ns
|
recognizes :vsphere_port, :vsphere_path, :vsphere_ns
|
||||||
recognizes :vsphere_rev, :vsphere_ssl
|
recognizes :vsphere_rev, :vsphere_ssl, :vsphere_expected_pubkey_hash
|
||||||
|
|
||||||
class Mock
|
class Mock
|
||||||
|
|
||||||
|
@ -16,6 +18,9 @@ module Fog
|
||||||
|
|
||||||
class Real
|
class Real
|
||||||
|
|
||||||
|
attr_reader :vsphere_is_vcenter
|
||||||
|
attr_reader :vsphere_rev
|
||||||
|
|
||||||
def initialize(options={})
|
def initialize(options={})
|
||||||
require 'rbvmomi'
|
require 'rbvmomi'
|
||||||
@vsphere_username = options[:vsphere_username]
|
@vsphere_username = options[:vsphere_username]
|
||||||
|
@ -26,15 +31,31 @@ module Fog
|
||||||
@vsphere_ns = options[:vsphere_ns] || 'urn:vim25'
|
@vsphere_ns = options[:vsphere_ns] || 'urn:vim25'
|
||||||
@vsphere_rev = options[:vsphere_rev] || '4.0'
|
@vsphere_rev = options[:vsphere_rev] || '4.0'
|
||||||
@vsphere_ssl = options[:vsphere_ssl] || true
|
@vsphere_ssl = options[:vsphere_ssl] || true
|
||||||
|
@vsphere_expected_pubkey_hash = options[:vsphere_expected_pubkey_hash]
|
||||||
@vsphere_must_reauthenticate = false
|
@vsphere_must_reauthenticate = false
|
||||||
|
|
||||||
|
@connection = nil
|
||||||
|
# This is a state variable to allow digest validation of the SSL cert
|
||||||
|
bad_cert = false
|
||||||
|
loop do
|
||||||
|
begin
|
||||||
@connection = RbVmomi::VIM.new :host => @vsphere_server,
|
@connection = RbVmomi::VIM.new :host => @vsphere_server,
|
||||||
:port => @vsphere_port,
|
:port => @vsphere_port,
|
||||||
:path => @vsphere_path,
|
:path => @vsphere_path,
|
||||||
:ns => @vsphere_ns,
|
:ns => @vsphere_ns,
|
||||||
:rev => @vsphere_rev,
|
:rev => @vsphere_rev,
|
||||||
:ssl => @vsphere_ssl,
|
:ssl => @vsphere_ssl,
|
||||||
:insecure => true
|
:insecure => bad_cert
|
||||||
|
break
|
||||||
|
rescue OpenSSL::SSL::SSLError
|
||||||
|
raise if bad_cert
|
||||||
|
bad_cert = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if bad_cert then
|
||||||
|
validate_ssl_connection
|
||||||
|
end
|
||||||
|
|
||||||
# Negotiate the API revision
|
# Negotiate the API revision
|
||||||
if not options[:vsphere_rev]
|
if not options[:vsphere_rev]
|
||||||
|
@ -66,6 +87,16 @@ module Fog
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Verify a SSL certificate based on the hashed public key
|
||||||
|
def validate_ssl_connection
|
||||||
|
pubkey = @connection.http.peer_cert.public_key
|
||||||
|
pubkey_hash = Digest::SHA2.hexdigest(pubkey.to_s)
|
||||||
|
expected_pubkey_hash = @vsphere_expected_pubkey_hash
|
||||||
|
if pubkey_hash != expected_pubkey_hash then
|
||||||
|
raise Fog::Vsphere::Errors::SecurityError, "The remote system presented a public key with hash #{pubkey_hash} but we're expecting a hash of #{expected_pubkey_hash || '<unset>'}. If you are sure the remote system is authentic set vsphere_expected_pubkey_hash: <the hash printed in this message> in ~/.fog"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue