Balanced

Brain dump for at least semi-good ideas

Tag: REST API

Fortigate API – FortiOS 6.2

Recently I changed my firewall from Sophos UTM to a Fortigate. Since I have a decent lab setup at home with a bunch of services I decided to try out the Fortigate API. However, to my surprise there was no API documentation openly available online. To get hold of it one had to be a part of the Fortinet Developer Network which requires endorsement from two Fortinet employees. Personally I’m not a bit fan of keeping these things behind closed doors. I think it benefits neither the company, nor the customer.

So in case someone else is in the same situation that I was I thought I’d write a short intro on how to use the API using an admin account using Powershell.

Authentication

First step is to do send a post against /logincheck using form data:

# Authentication against the box
$PostParameters = @{
    "username" = $FortigateSettings.user;
    "secretkey" = $FortigateSettings.password;
}

$Result = Invoke-WebRequest -Method POST "https://10.1.1.1/logincheck" -Body $PostParameters -SessionVariable FortigateSession

The code above also saves the cookies from the response into a session variable called FortigateSession. From this variable we will also extract the CSRFTOKEN cookie value which is required when one wants to change things on the device.

$CSRFTOKEN = ($FortigateSession.Cookies.GetCookies("https://10.1.1.1") | Where-Object { $_.name -eq "ccsrftoken" }).value.replace("`"", "")

Now we’re set to run commands against the Fortigate API by using the session variable.

Examples

# Get the DHCP configuration
Invoke-WebRequest "https://10.1.1.1/api/v2/cmdb/system.dhcp/server/1" -WebSession $FortigateSession

# Get a list of the DNS databases
Invoke-WebRequest "https://10.1.1.1/api/v2/cmdb/system/dns-database/" -WebSession $FortigateSession -Method "GET"

# Get a list of the address objects
Invoke-WebRequest "https://10.1.1.1/api/v2/cmdb/firewall/address" -WebSession $FortigateSession

# Add an address object
$SHost = @{
    "name" = "CloudFlare-1";
    "subnet" = "1.1.1.1/32";
} | ConvertTo-Json -Compress

Invoke-WebRequest "https://10.1.1.1/api/v2/cmdb/firewall/address" -Headers @{"Content-Type" = "application/json"; "X-CSRFTOKEN" = $CSRFTOKEN} -WebSession $FortigateSession -Method "POST" -Body $SHost -ErrorAction SilentlyContinue

Please note that while these examples covers authentication using a normal admin account the Fortigate devices also has support for dedicated REST accounts using tokens. For frequent/production integrations you’d want to look there instead.

The script I used to migrate from Sophos to Fortigate is available here.

Using F5 REST API with roles

I recently learned that with version 12 comes the possibility to use roles with the REST API, but only when using token based authentication.

That’s fantastic! Finally there is a secure way of using the REST API without handing over administrative access.

Adding an example in Powershell and a link to an article on Devcentral about how to do it in Python.

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
	
$User = "myGuestUser"
$Password = "password"
	
#Create the string that is converted to Base64
$pair = $user + ":" + $Password

#Encode the string to base64
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))

#Add the "Basic prefix"
$basicAuthValue = "Basic $encodedCreds"

#Prepare the headers
$headers = @{
	"Authorization" = $basicAuthValue
	"Content-Type" = "application/json"
}

#Create the body of the post
$body = @{"username" = $User; "password" = $Password; "loginProviderName" = "tmos" }

#Convert the body to Json
$body = $Body | ConvertTo-Json

$response  = Invoke-WebRequest -Method "POST" -Headers $headers -Body $body -Uri "https://myltm/mgmt/shared/authn/login" 

#Extract the token from the response
$token = ($response.content | ConvertFrom-Json).Token.token

#Prepare a dictionary with the token
$headers = @{
	"X-F5-Auth-Token" = $token;
}

#Get a list of the ssl profiles of the box
$Response = Invoke-WebRequest -Method "GET" -Headers $headers -Uri "https://myltm.domain.local/mgmt/tm/ltm/profile/client-ssl"
$Profiles = ($response.Content | ConvertFrom-Json).items

Updating with code from the Powershell Guru Joel Newton on how to patch the token to make it valid for 10 hours instead of the default 20 minutes:

#####
#Setup
$LTMName = 'myltm'
$SecPswd = ConvertTo-SecureString "PlainTextPassword" -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential "username", $SecPswd

$AuthURL = "https://$LTMName/mgmt/shared/authn/login"
$JSONBody = @{username = $Credentials.username; password=$Credentials.GetNetworkCredential().password; loginProviderName='tmos'} | ConvertTo-Json
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession

#Request the token
$Result = Invoke-RestMethod -Method POST -Uri $AuthURL -Body $JSONBody -Credential $Credentials -ContentType 'application/json'
$Token = $Result.token.token
#Add the token to our session
$session.Headers.Add('X-F5-Auth-Token', $Token)

#A UUID is returned by LTM v11.6. This is needed for modifying the token.
#For v12+, the name value is used.
if ($Result.token.uuid){
    $TokenReference = $Result.token.uuid;
} else {
    $TokenReference = $Result.token.name;
}

#If we want the token to be valid for a length other than the default of 20 minutes, this is how we modify it
#NB: Max value is 36000 seconds (10 hours)
#Let's set it to 1 hour
$TokenLifespan = 3600
$Body = @{ timeout = $TokenLifespan } | ConvertTo-Json
$Headers = @{
'X-F5-Auth-Token' = $Token
}

Invoke-RestMethod -Method Patch -Uri https://$LTMName/mgmt/shared/authz/tokens/$TokenReference -Headers $Headers -Body $Body -WebSession $session | Out-Null

# Add token expiration time to session
$ts = New-TimeSpan -Minutes ($TokenLifespan/60)
$date = Get-Date -Date $Result.token.startTime
$ExpirationTime = $date + $ts
$session.Headers.Add('Token-Expiration', $ExpirationTime)

I also recommend checking out Joels Powershell module at the Devcentral codeshare!

Powered by WordPress & Theme by Anders Norén