diff --git a/README.md b/README.md index 1ebb2d98..03130fdc 100644 --- a/README.md +++ b/README.md @@ -282,16 +282,12 @@ remote system's certificate can subject knife commands to spoofing attacks. ## WinRM authentication The default authentication protocol for `knife-windows` subcommands that use -WinRM is the Negotiate protocol. The following commands when executed on a -Windows system show authentication for domain and local accounts respectively: +WinRM is the Negotiate protocol. The following commands show authentication for domain and local accounts respectively: knife bootstrap windows winrm web1.cloudapp.net -r "server::web" -x "proddomain\webuser" -P "super_secret_password" knife bootstrap windows winrm db1.cloudapp.net -r "server::db" -x "localadmin" -P "super_secret_password" -The commands above are using the default plaintext transport for WinRM -- -the default of Negotiate authentication may not be fully supported on -non-Windows systems using the plaintext transport. To work around this, the -remote system can be configured with an SSL WinRM listener instead of a +The remote system may also be configured with an SSL WinRM listener instead of a plaintext listener. Then the above commands should be modified to use the SSL transport as follows using the `-t` (or `--winrm-transport`) option with the `ssl` argument: @@ -299,20 +295,16 @@ transport as follows using the `-t` (or `--winrm-transport`) option with the knife bootstrap windows winrm -t ssl web1.cloudapp.net -r "server::web" -x "proddomain\webuser" -P "super_secret_password" -f ~/mycert.crt knife bootstrap windows winrm -t ssl db1.cloudapp.net -r "server::db" -x "localadmin" -P "super_secret_password" ~/mycert.crt -The commands using SSL above will work from any operating system, not -just Windows. - ### Troubleshooting authentication -For development and testing purposes, unencrypted traffic with Basic -authentication can make it easier to test connectivity. The configuration for +Unencrypted traffic with Basic authentication should only be used for low level wire protocol debugging. The configuration for plain text connectivity to the remote system may be accomplished with the following PowerShell commands: ```powershell set-item wsman:\localhost\service\allowunencrypted $true set-item wsman:\localhost\service\auth\basic $true ``` -To test connectivity via `knife-windows` from another system, the default +To use basic authentication connectivity via `knife-windows`, the default authentication protocol of Negotiate must be overridden using the `--winrm-authentication-protocol` option with the desired protocol, in this case Basic: @@ -325,24 +317,13 @@ authentication; an account local to the remote system must be used. ### Platform WinRM authentication support `knife-windows` supports `Kerberos`, `Negotiate`, and `Basic` authentication -for WinRM communication. However, some of these protocols -may not work with `knife-windows` on non-Windows systems because -`knife-windows` relies on operating system libraries such as GSSAPI to implement -Windows authentication, and some versions of these libraries do not -fully implement the protocols. +for WinRM communication. The following table shows the authentication protocols that can be used with `knife-windows` depending on whether the knife workstation is a Windows system, the transport, and whether or not the target user is a domain user or local to the target Windows system. -| Workstation OS / Account Scope | SSL | Plaintext | -|--------------------------------|------------------------------|----------------------------| -| Windows / Local | Kerberos, Negotiate* , Basic | Kerberos, Negotiate, Basic | -| Windows / Domain | Kerberos, Negotiate | Kerberos, Negotiate | -| Non-Windows / Local | Kerberos, [Negotiate*](https://github.com/chef/knife-windows/issues/176) Basic | Kerberos, Basic | -| Non-Windows / Domain | Kerberos, Negotiate | Kerberos | - > \* There is a known defect in the `knife winrm` and `knife bootstrap windows > winrm` subcommands invoked on any OS platform when authenticating with the Negotiate protocol over > the SSL transport. The defect is tracked by @@ -354,9 +335,7 @@ local to the target Windows system. > This is generally not an issue for bootstrap scenarios, where the > system has yet to be joined to any domain, but can be a problem for remote > management cases after the system is domain joined. Workarounds include using -> a domain account instead, or enabling Basic authentication on the remote -> system (unencrypted communication **does not** need to be enabled to make -> Basic authentication function over SSL). +> a domain account instead or bypassing SSL and using Negotiate authentication. ## General troubleshooting diff --git a/knife-windows.gemspec b/knife-windows.gemspec index 813c1e1c..b774bb5c 100644 --- a/knife-windows.gemspec +++ b/knife-windows.gemspec @@ -14,8 +14,7 @@ Gem::Specification.new do |s| s.description = s.summary s.required_ruby_version = ">= 1.9.1" - s.add_dependency "winrm", "~> 1.5" - s.add_dependency "winrm-s", "~> 0.3.4" + s.add_dependency "winrm", "~> 1.6" s.add_dependency "nokogiri" s.add_development_dependency 'pry' diff --git a/lib/chef/knife/winrm_knife_base.rb b/lib/chef/knife/winrm_knife_base.rb index cc6b9c93..fd9be12e 100644 --- a/lib/chef/knife/winrm_knife_base.rb +++ b/lib/chef/knife/winrm_knife_base.rb @@ -51,17 +51,6 @@ def validate_winrm_options! exit 1 end - if negotiate_auth? && !Chef::Platform.windows? && !(locate_config_value(:winrm_transport) == 'ssl') - ui.warn <<-eos.gsub /^\s+/, "" - You are using '--winrm-authentication-protocol negotiate' with - '--winrm-transport plaintext' on a non-Windows system which results in - unencrypted traffic. To avoid this warning and secure communication, - use '--winrm-transport ssl' instead of the plaintext transport, - or execute this command from a Windows system which enables encrypted - communication over plaintext with the negotiate authentication protocol. - eos - end - warn_no_ssl_peer_verification if resolve_no_ssl_peer_verification end @@ -259,8 +248,8 @@ def resolve_winrm_transport transport = locate_config_value(:winrm_transport).to_sym if config.any? {|k,v| k.to_s =~ /kerberos/ && !v.nil? } transport = :kerberos - elsif Chef::Platform.windows? && transport != :ssl && negotiate_auth? - transport = :sspinegotiate + elsif transport != :ssl && negotiate_auth? + transport = :negotiate end transport @@ -271,7 +260,7 @@ def resolve_no_ssl_peer_verification end def resolve_winrm_disable_sspi - !Chef::Platform.windows? || resolve_winrm_transport == :ssl || !negotiate_auth? + resolve_winrm_transport != :negotiate end def get_password diff --git a/lib/chef/knife/winrm_session.rb b/lib/chef/knife/winrm_session.rb index 239413d8..60de5420 100644 --- a/lib/chef/knife/winrm_session.rb +++ b/lib/chef/knife/winrm_session.rb @@ -41,7 +41,6 @@ def initialize(options) Chef::Log.debug("Endpoint: #{endpoint}") Chef::Log.debug("Transport: #{options[:transport]}") - WinrmSession.load_windows_specific_gems if options[:transport] == :sspinegotiate @winrm_session = WinRM::WinRMWebService.new(@endpoint, options[:transport], opts) @winrm_session.set_timeout(options[:operation_timeout]) if options[:operation_timeout] end @@ -83,12 +82,6 @@ def configure_proxy Chef::Application.new.configure_proxy_environment_variables end end - - def self.load_windows_specific_gems - #checking for windows in case testing on linux - require 'winrm-s' - Chef::Log.debug("Applied 'winrm-s' monkey patch and trying WinRM communication with 'sspinegotiate'") - end end end end \ No newline at end of file diff --git a/spec/unit/knife/winrm_session_spec.rb b/spec/unit/knife/winrm_session_spec.rb index 0d384b8d..289be70e 100644 --- a/spec/unit/knife/winrm_session_spec.rb +++ b/spec/unit/knife/winrm_session_spec.rb @@ -38,15 +38,6 @@ subject { Chef::Knife::WinrmSession.new(options) } describe "#initialize" do - context "when using sspinegotiate transport" do - let(:options) { { transport: :sspinegotiate } } - - it "uses winrm-s" do - expect(Chef::Knife::WinrmSession).to receive(:load_windows_specific_gems) - subject - end - end - context "when a proxy is configured" do let(:proxy_uri) { 'blah.com' } diff --git a/spec/unit/knife/winrm_spec.rb b/spec/unit/knife/winrm_spec.rb index 5ab21d9b..16010d50 100644 --- a/spec/unit/knife/winrm_spec.rb +++ b/spec/unit/knife/winrm_spec.rb @@ -233,7 +233,7 @@ it "defaults to negotiate when on a Windows host" do expect(Chef::Knife::WinrmSession).to receive(:new) do |opts| - expect(opts[:transport]).to eq(:sspinegotiate) + expect(opts[:transport]).to eq(:negotiate) end.and_return(winrm_session) subject.configure_session end @@ -471,23 +471,22 @@ allow(@winrm).to receive(:relay_winrm_command).and_return(0) end - it "sets sspinegotiate transport on windows for 'negotiate' authentication" do + it "sets negotiate transport on windows for 'negotiate' authentication" do @winrm.config[:winrm_authentication_protocol] = "negotiate" allow(Chef::Platform).to receive(:windows?).and_return(true) allow(Chef::Knife::WinrmSession).to receive(:new) do |opts| expect(opts[:disable_sspi]).to be(false) - expect(opts[:transport]).to be(:sspinegotiate) + expect(opts[:transport]).to be(:negotiate) end.and_return(session) @winrm.run end - it "does not have winrm opts transport set to sspinegotiate for unix" do + it "sets negotiate transport on unix for 'negotiate' authentication" do @winrm.config[:winrm_authentication_protocol] = "negotiate" allow(Chef::Platform).to receive(:windows?).and_return(false) - allow(@winrm).to receive(:exit) allow(Chef::Knife::WinrmSession).to receive(:new) do |opts| - expect(opts[:disable_sspi]).to be(true) - expect(opts[:transport]).to be(:plaintext) + expect(opts[:disable_sspi]).to be(false) + expect(opts[:transport]).to be(:negotiate) end.and_return(session) @winrm.run end @@ -506,46 +505,12 @@ @winrm.run end - it "applies winrm monkey patch on windows if 'negotiate' authentication and 'plaintext' transport is specified", :windows_only => true do - @winrm.config[:winrm_authentication_protocol] = "negotiate" - allow(Chef::Platform).to receive(:windows?).and_return(true) - allow(@winrm.ui).to receive(:warn) - @winrm.run - end - it "raises an error if value is other than [basic, negotiate, kerberos]" do @winrm.config[:winrm_authentication_protocol] = "invalid" allow(Chef::Platform).to receive(:windows?).and_return(true) expect(@winrm.ui).to receive(:error) expect { @winrm.run }.to raise_error(SystemExit) end - - it "skips the winrm monkey patch for 'basic' authentication" do - @winrm.config[:winrm_authentication_protocol] = "basic" - allow(Chef::Platform).to receive(:windows?).and_return(true) - @winrm.run - end - - it "skips the winrm monkey patch for 'kerberos' authentication" do - @winrm.config[:winrm_authentication_protocol] = "kerberos" - allow(Chef::Platform).to receive(:windows?).and_return(true) - @winrm.run - end - - it "skips the winrm monkey patch for 'ssl' transport and 'negotiate' authentication" do - @winrm.config[:winrm_authentication_protocol] = "negotiate" - @winrm.config[:winrm_transport] = "ssl" - allow(Chef::Platform).to receive(:windows?).and_return(true) - @winrm.run - end - - it "prints a warning on linux for unencrypted negotiate authentication" do - @winrm.config[:winrm_authentication_protocol] = "negotiate" - @winrm.config[:winrm_transport] = "plaintext" - allow(Chef::Platform).to receive(:windows?).and_return(false) - expect(@winrm.ui).to receive(:warn).once - expect { @winrm.run }.to_not raise_error(SystemExit) - end end end end