Skip to content

Commit

Permalink
First commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
KelvinTegelaar committed May 19, 2020
0 parents commit df112de
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
69 changes: 69 additions & 0 deletions Azglue.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using namespace System.Net
param($Request, $TriggerMetadata)
#Check if AZapiKey is correct
if ($request.Headers.'x-api-key' -eq $ENV:AzAPIKey) {
#Comparing the client IP to the Organization list, and checking if it exists.
$ClientIP = ($request.headers.'X-Forwarded-For' -split ':')[0]
$CompareList = import-csv "AzGlueForwarder\OrgList.csv" -delimiter ","
$AllowedOrgs = $comparelist | where-object { $_.ip -eq $ClientIP }
if (!$AllowedOrgs) {
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
headers = @{'content-type' = 'application\json' }
StatusCode = [httpstatuscode]::OK
Body = @{"Error" = "401 - No match found in allowed list" } | convertto-json
})
exit 1
}

#Sending request to ITGlue
#$resource = $request.params.path -replace "AzGlueForwarder/", ""
$resource = $request.url -replace "https://$($ENV:WEBSITE_HOSTNAME)/API", ""
#Replace x-api-key with actual key
$ITGHeaders = @{
"x-api-key" = $ENV:ITGlueAPIKey
}
$Method = $($Request.method)
$ITGBody = $($Request.body)
#write-host ($AllowedOrgs | out-string)
$SuccessfullQuery = $false
$attempt = 3
while ($attempt -gt 0 -and -not $SuccessfullQuery) {
try {
$ITGlueRequest = Invoke-RestMethod -Method $Method -ContentType "application/vnd.api+json" -Uri "$($ENV:ITGlueURI)/$resource" -Body $ITGBody -Headers $ITGHeaders
$SuccessfullQuery = $true
}
catch {
$ITGlueRequest = @{'Errorcode' = $_.Exception.Response.StatusCode.value__ }
$rand = get-random -Minimum 0 -Maximum 10
start-sleep $rand
$attempt--
if ($attempt -eq 0) { $ITGlueRequest = @{'Errorcode' = "Error code $($_.Exception.Response.StatusCode.value__) - Made 3 attempts and upload failed. $($_.Exception.Message) " } }
}
}

#Checking if we can strip the data that does not belong to this client.
#Important so passwords/items can only be retrieved belonging to this organisation.
#Can't do it for all requests, such as get-organisation, but for senstive data it works perfectly. :)

if ($($ITGlueRequest.data.attributes.'organization-id')) {
write-host ($AllowedOrgs.ITGlueOrgID)
$ITGlueRequest.data = $ITGlueRequest.data | where-object { $_.attributes.'organization-id' -in $($AllowedOrgs.ITGlueOrgID) }
}

#Sending the final object back to the client.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
headers = @{'content-type' = 'application\json' }
StatusCode = [httpstatuscode]::OK
Body = $ITGlueRequest
})


}
else {
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
headers = @{'content-type' = 'application\json' }
StatusCode = [httpstatuscode]::OK
Body = @{"Error" = "401 - No API Key entered or API key incorrect." } | convertto-json
})

}
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Azglue - A forwarder hosted in Azure to Secure the IT-Glue API.
See https://www.cyberdrain.com/documenting-with-powershell-handling-it-glue-api-security-and-rate-limiting/ for more information.

After my previous blogs the comment I’ve received most was worries about the API key. If they key gets stolen you’re giving away the keys to the castle. The API has no limitations and with a leaked key all your documentation could be download. I’ve been discussing this issue with IT-Glue for some time but haven’t gotten a real solution yet. This has forced me to look for a solution myself. I gave myself some requirements for the solution.

- The solution needed to be simple and accessible for everyone.
- The solution needed to have multiple levels of authentication; an API key, IP whitelisting, and organization whitelisting.
- The solution needed to block requests for all passwords/files/etc for all organisations.
- The solution needed to allow some form of handling of the API rate limiting, e.g. repeating a request if it was rate limited.
- The solution needed to be able to used, without adapting any scripts (except URLs and API codes.)
- So after some research I decided to use an Azure Function for this. I’ve blogged about Azure Functions before, but the main reason is that running this function in the consumption model will cost us nothing (or next to nothing if you are an extremely heavy user.)

0 comments on commit df112de

Please sign in to comment.