rmbolger/Posh-IBWAPI

Invoke-RestMethod error when TLS 1.0 is disabled in Infoblox

Closed this issue · 14 comments

(sorry, hit return and opened the issue too early) Continuing my attempt to duplicate my customer's environment, after installing Posh-IBWAPI via iex, I then attempted to run Set-IBWAPIConfig per the instruction in the README. I get the following error:

Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
At C:\Users\macker\Documents\WindowsPowerShell\Modules\Posh-IBWAPI\Public\Invoke-IBWAPI.ps1:55 char:17
+                 Invoke-RestMethod -Uri $Uri @opts
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Note that I have not changed ExecutionPolicy from the default in this test, but I did change it to Unrestricted in a previous test and it didn't seem to make any difference. I will do a retest though just to make sure.

No luck. I tried the following:

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser

and retried Set-IBWAPIConfig. Same error.

Note: I used -Scope CurrentUser because security restrictions on my customer's PC prevent setting ExecutionPolicy for the entire PC. I'll try testing on Windows 10 next.

I tried this on Windows 10 with the following command:

Set-IBWAPIConfig -host gm1.fhecker.com -version latest -cred (Get-Credential) -IgnoreCert

This failed with the same "unexpected error on a send" error as above. The command succeeded when explicitly specifying an API version (connecting to NIOS 8.1.1):

Set-IBWAPIConfig -host gm1.fhecker.com -version 2.6 -cred (Get-Credential) -IgnoreCert

However a subsequent Get-IBObject -type record:host command got the same error.

I tried this as well on Windows 7 SP1/PowerShell 4.0, with the same results: Set-IBWAPIConfig fails when using -version latest and succeeds with -version 2.6, but Get-IBObject fails in all cases.

I think this may be a problem with the underlying environment. That error is occurring on the Invoke-RestMethod call which is a native Powershell cmdlet. Can you try making a standalone call using Invoke-RestMethod to the same host and see what happens? Try something like this:

Invoke-RestMethod "https://gm1.fhecker.com/wapidoc"

The reason it happens with Set-IBWAPIConfig only using -version latest is that setting an explicit version doesn't actually need to query anything. But "latest" has to query infoblox for the supported versions to find the latest.

Using the raw Invoke-RestMethod command you mentioned gets the same error.

I tried Invoke-RestMethod against the httpbin.org test site:

Invoke-RestMethod "https://httpbin.org/ip"

and it works fine.

Could this be an issue with sites with self-signed certificates? I could certainly get a valid certificate for my own site, but that won't help my customers who run with self-signed certs.

In my experience, a self-signed cert issue has a different message that looks like this.

The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

The error you're getting I've never seen before. Does the traffic in that environment need to pass through any sort of proxy server before it hits Infoblox? Or something that would be intercepting/inspecting/modifying the traffic along the way?

No, I'm going direct to the grid master on my local LAN.

Note that I can run the following minimal (and hopefully self-explanatory) Python program from the PowerShell prompt:

import requests
requests.packages.urllib3.disable_warnings()
r = requests.get('https://gm1.fhecker.com/wapi/v2.6/grid',
                 auth=('fhecker', 'xxxxxx'),
                 verify=False)
print r.text

and it returns the JSON-formatted grid object as expected.

So I don't think it's something in my grid setup. It's either in my PowerShell environment or in the Posh-IBWAPI code.

Sorry, d'oh, it can't be in the Posh-IBWAPI code because it fails using Invoke-RestMethod by itself. Anyway, I tried using Invoke-RestMethod by itself on Windows 10 and it doesn't work there either -- or I should say, testing against gm1.fhecker.com doesn't work, but testing against httpbin.org does.

I'll try this against our Infoblox corporate demo grid.

Found it! When I tried Invoke-RestMethod against our Infoblox internal demo grid it gave the expected "Could not establish trust relationship" error message for a site with a self-signed certificate. And that was the key clue...

What is different about my grid is that I had previously changed the grid settings to disable TLS 1.0, using the commands I wrote about at https://community.infoblox.com/t5/Security/Configuring-TLS-1-2-and-ciphersuites-in-NIOS-8-0/m-p/8122/. But as it happens, by default Invoke-RestMethod (in both PowerShell 4 and PowerShell 5) apparently uses (only) TLS 1.0, so if it's not enabled on the server side then it fails with the "unexpected error occurred on a send" message I encountered. The Python requests module (or the underlying Python module doing HTTPS) is more intelligent about handling this situation, which is why it works fine.

After I re-enabled TLS 1.0 the Invoke-RestMethod command gave the expected message for a site with a self-signed certificate. And Set-IBWAPIConfig with the -IgnoreCert option now works fine, as does Get-IBObject.

Since at least some security-conscious Infoblox customers may end up disabling TLS 1.0, I suggest you consider enhancing Posh-IBWAPI to handle that case. One way would be to update Set-IBWAPIConfig to add a new command line option to force use of a particular TLS version. For information on how to do this see http://www.codyhosterman.com/2016/06/force-the-invoke-restmethod-powershell-cmdlet-to-use-tls-1-2/ or https://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.securityprotocol.aspx. But apparently TLS 1.2 isn't supported until .NET 4.5 (?), so you may need to handle errors when someone tries to do this on an older .NET version.

Awesome. I'll take a look at those links and see what I can do. Working around .NET TLS limitations has historically been a pain in the butt.

Also, do you happen to know how far back in NIOS the TLS 1.2 support goes? Like, if I default the module to use 1.2 explicitly. Am I going to break people running on really old NIOS versions?

The release notes aren't 100% clear on this, but to the best of my knowledge TLS 1.2 support in NIOS was not implemented until NIOS 8.0, when we added the ability to explicit specify the TLS versions and ciphersuites used by the grid master. The NIOS 8.0 release notes on this feature reference RFE-5130, which is titled "TLS 1.2 support in the Infoblox DDI GUI" in our internal RFE database.

My conclusion is therefore that any NIOS version prior to 8.0 can support only TLS 1.0. NIOS 8.0 and 8.1 are the only two NIOS releases that currently are fully supported, but we have lots of customers still running 6.x or 7.x releases (including the customer I'm working with on this PowerShell project). So if possible you should continue to support the old way of doing things, either by defaulting to TLS 1.0 or by implementing some sort of scheme where you try TLS 1.2 first and then fall back to TLS 1.1 or TLS 1.0 if needed. (But the latter option I think is a bit too much to ask, given that I expect the needed code would be relatively complicated.)

I've actually found some powershell examples that test the supported TLS protocol versions on a remote host. So trying the highest and falling back might not actually be as hard as it sounds. I'll see what I can do. And that ultimately puts users in a better security posture anyway. So it's worth the time.

I think I have a pretty elegant solution for this now. The [Net.ServicePointManager]::SecurityProtocol seems to default to supporting SSL 3 and TLS 1.0 in most environments even if the underlying .NET framework supports higher levels of TLS. And rather than just explicitly setting TLS 1.2 like in the linked blog post, you can add the additional versions you want to support to the existing list.

So basically when the module loads, I'm modifying the default supported list of protocol versions to add anything supported by the framework beyond TLS 1.0. The framework should then negotiate whatever the highest version is supported by both PowerShell and Infoblox. This should also hypothetically include TLS 1.3 and beyond whenever .NET supports it.