API calls timing out

I’m using our MDM, Workspace ONE, to deploy a powershell script that makes a BigFix API call.

$HexComputerID=Get-ItemPropertyValue -Path 'HKLM:\Software\Wow6432Node\BigFix\EnterpriseClient\GlobalOptions\' -Name ComputerId
$ComputerID=[System.BitConverter]::ToInt64($HexComputerID, 0)

$pair = "$($env:username):$($env:password)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))

$basicAuthValue = "Basic $encodedCreds"

$Headers = @{
    Authorization = $basicAuthValue
}

$URL="https://our.bigfix.server.com:52311/api"

$addBody=@"
<?xml version="1.0" encoding="UTF-8"?>
<BES xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="BES.xsd">
    <SourcedFixletAction>
        <SourceFixlet>
            <Sitename>API</Sitename>
            <FixletID>604228</FixletID>
            <Action>Action1</Action>
        </SourceFixlet>
        <Target>
            <ComputerID>$ComputerID</ComputerID>
        </Target>
        <Parameter Name="GroupTag">Podium</Parameter>
    </SourcedFixletAction>
</BES>
"@

Invoke-WebRequest -Headers $Headers -Uri "$URL/actions" -Body $addBody -UseBasicParsing -Method POST

Running the script locally, I seem to have no problems. The action is triggered, runs successfully, and all is well.

However, when I try to deploy through Workspace ONE, the script times out every time. Looking at BESRelay.log, I see the following errors:

Fri, 01 Sep 2023 23:15:00 -0400 - /api/actions (9484) - unexpected eof while reading (class SSL_read_Failed)
Fri, 01 Sep 2023 23:15:00 -0400 - /api/actions (9484) - Uncaught exception in plugin api with client 192.168.26.123: Socket Error: Windows Error 0x0%: The operation completed successfully.
Fri, 01 Sep 2023 23:15:00 -0400 - /api/actions (10236) - unexpected eof while reading (class SSL_read_Failed)
Fri, 01 Sep 2023 23:15:00 -0400 - /api/actions (10236) - Uncaught exception in plugin api with client 192.168.26.254: Socket Error: Windows Error 0x0%: The operation completed successfully.
Fri, 01 Sep 2023 23:15:00 -0400 - /api/actions (10016) - unexpected eof while reading (class SSL_read_Failed)
Fri, 01 Sep 2023 23:15:00 -0400 - /api/actions (10016) - Uncaught exception in plugin api with client 192.168.26.116: Socket Error: Windows Error 0x0%: The operation completed successfully.
Fri, 01 Sep 2023 23:15:01 -0400 - /api/actions (9508) - unexpected eof while reading (class SSL_read_Failed)
Fri, 01 Sep 2023 23:15:01 -0400 - /api/actions (9508) - Uncaught exception in plugin api with client 192.168.26.120: Socket Error: Windows Error 0x0%: The operation completed successfully.

and so on and so forth. Looking at server_audit.log, I see successful sign-ins by our API account for each action, e.g.

1|Fri, 01 Sep 2023 23:43:15 -0400|INFO|APIadmin|RESTAPI|AUTHZ|LOGIN|192.168.26.120|user "APIadmin" (265): Successful log in. (API Connection)

What could be causing this error? Am I being rate-limited?

It’s generally not a great idea to have individual clients connect to the BES API - it means each of those clients has to be able to reach the root server directly. To reduce attack surface I generally recommend clients shouldn’t connect to the root at all, and only access to the infra is through Relays (specifically to block the API connectivity).

That said, it looks like your sessions are connecting since you see the errors in the server log.

This line where you retrieve credentials though -

$pair = "$($env:username):$($env:password)"

That looks like you’re reading the user name and password from environment variables? I expect when deployed through an MDM it won’t have the same environment as your logged-on user session - and if I’m reading that correctly, it is exceedingly dangerous to keep BigFix API credentials set in environment variables.

Hi Jason,

The $env: part is how Workspace ONE stores additional variables, described here in step 5. It’s deployed per-script, and not stored in the endpoint’s environment variables. VMWare specifically describes it as for API keys and service account names or passwords.

Is there any safe way for the endpoints to trigger an action themselves? I know I can have an always-on fixlet scanning for some type of tag, but I thought it would be cleaner to have the machines make the request themselves.

Thanks

Ah, ok. In that case I expect that Workspace is performing the variable substitutions in-line and perhaps the script is dereferencing it too many times with the $ signs? I.e. if the username is ‘apiuser1’ with password ‘mypass’, I think perhaps this line

$pair = "$($env:username):$($env:password)"

Could evaluate as

$pair = "$(apiuser1):$(mypass)"

Try writing it as

$pair = "$env:username:$env:password"

(Or variations on that, maybe write the script out to a file. I’m not conversant on Workspace One but it might be useful to see whether the generated script is really what you expect, or to manually execute the script after they generate it)

I tried poking around to see if the variables were getting passed correctly, and they do seem to be. Also since I’m seeing successful logins that match the times of script executions, I suspect they indeed are, e.g.

1|Fri, 01 Sep 2023 23:43:15 -0400|INFO|APIadmin|RESTAPI|AUTHZ|LOGIN|192.168.26.120|user "APIadmin" (265): Successful log in. (API Connection)

However, my Invoke-Webrequest never gets a response – not 200, not 404, not anything – it just times out.

Eventually, I discovered that Windows 10/11 ships with curl, and for whatever reason, that has been working for me completely without issue.

$HexComputerID=Get-ItemPropertyValue -Path 'HKLM:\Software\Wow6432Node\BigFix\EnterpriseClient\GlobalOptions\' -Name ComputerId
$ComputerID=[System.BitConverter]::ToInt64($HexComputerID, 0)

$pair = "$($env:username):$($env:password)"

$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))

$basicAuthValue = "Basic $encodedCreds"

$Headers = @{
    Authorization = $basicAuthValue
}

$URL="https://our.bigfix.server.com:52311/api"

$addBody=@"
<?xml version='1.0' encoding='UTF-8'?>
<BES xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='BES.xsd'>
    <SourcedFixletAction>
        <SourceFixlet>
            <Sitename>API</Sitename>
            <FixletID>604228</FixletID>
            <Action>Action1</Action>
        </SourceFixlet>
        <Target>
            <ComputerID>$ComputerID</ComputerID>
        </Target>
        <Parameter Name='GroupTag'>Podium</Parameter>
    </SourcedFixletAction>
</BES>
"@

$CURLEXE = 'C:\Windows\system32\curl.exe'

& $CURLEXE -u "$pair" -X 'POST' "$URL/actions" -d "$addBody" -v

I did have to change the double quotes in my .xml to single quotes, but otherwise no changes. I tried again with single quotes and Invoke-WebRequest, but it still failed.

So, I’ll consider this resolved for now. Thanks for looking into this!

1 Like

Good to hear!
If you did want to keep looking at PowerShell, I’d check example 7 at https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-7.3 for retrieving status codes and messages for the result

2 Likes

This is the way. POSH 7 is much better at handling API calls and working with data.
At most I just have to do add param of “SkipCertificateCheck” = $true" depending if needed.

My guess is the OP may need to do something with setting protocols. We have to do this with just about every POSH 5 script.
$AllProtocols = [System.Net.SecurityProtocolType]‘Tls12’
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols

Also I would recommend switching from from Invoke-WebRequest to Invoke-RestMethod

4 Likes