Helix service on developer hub

Hi all. I am starting to look into the Helix platform. Are there any plans into creating a client library for the Helix API ?

Hey Marco!

You came at the perfect time! Our team is currently working with the Helix engineering team to update their Swagger 2.0 to OpenAPI 3.0 with additional details. We’re going to use this OpenAPI 3.0 spec to start creating our client libraries, and we also plan to release them as MIT licensed on GitHub so developers can contribute to them as well!

May I ask what languages you’d be interested in having a client library for?

Hi Jordan, thanks for the insight! I was interested in either Python or Ruby bindings for the API for web-based projects.

Hey Marco, this is great information to know as we start to determine which languages developers might be most interested in!

Have you or your company used the Helix platform before or is this your first time looking into it?

Yes, we do use Helix. I am interested in APIs for integration with other services, and I see that you already provide OpenAPI 3.0 documentation on the platform. Good to know that you are looking into client libraries as well, they would be very helpful to ease integration (and reduce trivial errors such as parsing of responses etc.).

Hey Marco, just touching base again on this to let you know I haven’t forgotten. We are currently working on moving forward with virtually every product team on providing client libraries for their APIs. I don’t want to make any promises just yet, but my hope is that I will be able to share some specific dates with you in the near future.

Thanks for the update!

Hello. I leverage the REST API with decent results. I originally wrote something similiar for HX that turned into https://github.com/bw-0/Invoke-HX that I just open sourced yesterday.
We dont use Helix as a SOAR, just for alert aggregation, so this isn’t very feature rich it only handles the Alerts and Search endpoints. If you also find this useful I can post it to Github as a module like the HX one

function set-helix_api_auth{

    $read = Read-Host "API Key" -AsSecureString
            
    #try/catch to support PS on Linux. Linux doesn't support convertfrom-securestring
    try {$read | ConvertFrom-SecureString | Out-File $HOME/feye_helix_api.txt -Force}
    catch {
        $cred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "null", ($read)
        $bytes = [System.Text.Encoding]::ascii.GetBytes($cred.GetNetworkCredential().password)
        $b64 =  [Convert]::ToBase64String($Bytes)
        $b64 | Out-File $HOME/feye_helix_api.txt
    }
}

function get-helix_api_auth {

    if (!(get-item "$home/feye_helix_api.txt" -ErrorAction SilentlyContinue)){
        set-helix_api_auth
    }

    $file = "$home/feye_helix_api.txt"

    $g = Get-Content $file

    #check to see if creds are securestring or b64
    if ($g -match "^01000000"){
        $script:auth=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "null", ($g | ConvertTo-SecureString)
    }
    else {
        $script:auth=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "null", ($g | ConvertTo-SecureString -AsPlainText -Force)
    }

    if ($null -eq $script:auth){write-host -f Magenta "Issue with getting creds"}
    
    Clear-Variable g -ErrorAction SilentlyContinue
    Clear-Variable b -ErrorAction SilentlyContinue
    Clear-Variable p -ErrorAction SilentlyContinue
}

function get-helix_api_config {

    [CmdletBinding()]
    Param(
        [switch]$Proxy
    )
    
    $config = Get-Content "$home/feye_helix.ini" -ErrorAction SilentlyContinue

    if (!($config|Where-Object{$_ -match "ID="})){
        $read_id = Read-Host -Prompt "Helix Instance ID"
        "ID=$read_id" | Out-File "$home/feye_helix.ini" -Append
    }
    else {$script:id = (($config|Where-Object{$_ -match "id="}) -split "=")[1]}

    if ($Proxy){
        if (!($config|Where-Object{$_ -match "proxy="})){
            $read_proxy = Read-Host -Prompt "HTTP Proxy"
            "proxy=$read_proxy" | Out-File "$home/feye_helix.ini" -Append
        }
        else {$script:proxy_uri = (($config|Where-Object{$_ -match "^proxy="}) -split "=")[1]}
    }
}

<#
.Synopsis
   Interact with the FireEye Helix API
.DESCRIPTION
   Interact with the FireEye Helix API
.EXAMPLE
   invoke-helix -api search -query "class=http_proxy"
.EXAMPLE
   invoke-helix -api search -query "class=http_proxy" -limit 1000
.EXAMPLE
   helix search "class=http_proxy" -days 1 -limit 1000
.EXAMPLE
   helix search "class=http_proxy" -after 01-01-2019 -before 02-01-2019
.NOTES
    @{"Contact"="Bryon.Wolcott@equifax.com"}
#>
function invoke-helix {

    [CmdletBinding()]
    [Alias("helix")]

    param (
        [switch]$Proxy,

        #API endpoint
        #https://apps.fireeye.com/helix/id/<ID>/api/documentation
        [Parameter(Mandatory=$true,Position=0)]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateSet(
            "Alerts", "Search"
            )
        ]
        $API,

        #Helix Search Query
        [Parameter(Mandatory=$false,Position=1)]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        $query,

        #Specify the amount of hours in the past you want to search relative to now.
        [Parameter(Mandatory=$false,Position=2)]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateRange(1,672)]
        [Alias("h")] 
        [int]$hours,

        #Specify the amount of dayss in the past you want to search relative to now.
        [Parameter(Mandatory=$false)]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateRange(1,16)]
        [Alias("d")] 
        [int]$days,

        #Specify the number of results to return
        [Parameter(Mandatory=$false)]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateRange(1,100000)]
        [Alias("l")] 
        [int]$limit,
         
        #A UTC date to specify the earliest result returned. Enter as a string "mm-dd-yyyy", or "mm-dd-yyyy hh:mm:ss" or "01/01/2019 01:00:00" or "July 14, 2019"
        [Parameter(Mandatory=$false)]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        $start,

        #A UTC date to specify the oldest result returned. Enter as a string "mm-dd-yyyy", or "mm-dd-yyyy hh:mm:ss" or "01/01/2019 01:00:00" or "July 14, 2019"
        [Parameter(Mandatory=$false)]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        $end,
        #For Searching, This switch will return the raw results from Helix search. By default the actual events from Helix will be dug up from several nested layers and returned.
        [switch]$raw
       
        #not used yet
        #[Parameter(Mandatory=$false)]
        #[ValidateNotNull()]
        #[ValidateNotNullOrEmpty()]
        #[ValidateSet(
        #    "get","delete","list","get-children"
        #    )
        #]
        #$action,
    )
    
    begin{

        #region time contraints
        if (
            ($hours -and $days) -or
            ($hours -and $start) -or
            ($hours -and $end) -or
            ($days -and $start) -or
            ($days -and $end)
        ){
            Write-Host -f Red "Time contraints must be hours|days|before|after|before&&after"
        }

        #$after and $before must be before $hours and $days so that $hours and $days are not reformatted to local times.
        if ($start){
            $start = (([datetime]$start).ToString("yyy-MM-ddTHH:mm:ss.000000Z"))
        }
        
        if ($end){
            $end = (([datetime]$end).ToString("yyy-MM-ddTHH:mm:ss.000000Z"))
        }

        #Because $hours and $days are relative to now, we convert the time to UTC.
        if ($hours){
            $start = (([datetime](get-date).AddHours(-$hours)).ToUniversalTime().ToString("yyy-MM-ddTHH:mm:ss.000000Z"))
        }
        
        if ($days){
            $start = (([datetime](get-date).Adddays(-$days)).ToUniversalTime().ToString("yyy-MM-ddTHH:mm:ss.000000Z"))
        }
        #endregion

    }
    
    process{

        $body=@{}

        switch ($API){

            "Alerts"{
                $endpoint = "/v3/alerts/"
                $method = "get"
                
                if ($start){
                    $body += @{
                        "created_at__gte" = $start
                    }
                }
                
                if ($end){
                    $body += @{
                        "created_at__lte" = $end
                    }
                }

                if ($limit){
                    $body += @{
                        "limit" = $limit
                    }
                }
            }

            "Search"{
                if (!$query){Write-Host -ForegroundColor Magenta "No Query Provided";break}

                $endpoint = "/v1/search/"
                $method = "get"

                if ($start){
                    $query = "start=$start " + $query
                }

                if ($end){
                    $query = "end=$end " + $query
                }

                if ($limit){
                    $query = $query + "{page_size=$limit} "
                }

                $body += @{"query" = $query}
            }

            default {"API Endpoint Not Defined, Please Contribute"}
        }

        if (!$auth){get-helix_api_auth}
        $header = @{"x-FireEye-api-key"=$auth.GetNetworkCredential().password}

        #this needs to be cleaned up
        if ($proxy){
            get-helix_api_config -Proxy
			$uri = "https://apps.fireeye.com/helix/id/$id/api"
            $resource = $uri+$endpoint
            Write-Verbose "Query: $query"
            Write-Verbose "Header: $header"
            Write-Verbose "Body: $($body|ConvertTo-Json)"
            $r = Invoke-RestMethod -Method $method -Uri $resource -Headers $header -Body $body -ContentType "application/json" -Proxy $Proxy_uri -ProxyUseDefaultCredentials -Verbose
        }
		else {
			get-helix_api_config
			$uri = "https://apps.fireeye.com/helix/id/$id/api"
            $resource = $uri+$endpoint
            Write-Verbose "Query: $query"
            Write-Verbose "Body: $($body|ConvertTo-Json)"
			$r = Invoke-RestMethod -Method $method -Uri $resource -Headers $header -Body $body -ContentType "application/json" -Verbose
		}
	}
    end{
        if ($raw){return $r}

        if (($API -eq "search") -and ($query -match "groupby")){
            $r.results.aggregations.psobject.Properties.value.buckets | select @{n="count";e={$_.doc_count}}, @{n="name";e={$_.key}}
        }
        else{$r.results.hits.hits._source}
    }
}
1 Like