Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,9 @@ the Keyfactor Command Portal
| Universal Orchestrator Version | Latest .NET version installed on the Universal Orchestrator server | `rollForward` condition in `Orchestrator.runtimeconfig.json` | `fortigate-orchestrator` .NET version to download |
| --------- | ----------- | ----------- | ----------- |
| Older than `11.0.0` | | | `net6.0` |
| Between `11.0.0` and `11.5.1` (inclusive) | `net6.0` | `Disable` | `net6.0` |
| Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `LatestMajor` | `net8.0` |
| Between `11.0.0` and `11.5.1` (inclusive) | `net6.0` | | `net6.0` |
| Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `Disable` | `net6.0` || Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `LatestMajor` | `net8.0` |

Copilot AI Apr 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Markdown table row contains || and appears to have two rows merged into one line, which breaks table rendering. Split this into two separate table rows so the compatibility matrix renders correctly.

Suggested change
| Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `Disable` | `net6.0` || Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `LatestMajor` | `net8.0` |
| Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `Disable` | `net6.0` |
| Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `LatestMajor` | `net8.0` |

Copilot uses AI. Check for mistakes.
| `11.6` _and_ newer | `net8.0` | | `net8.0` |

Unzip the archive containing extension assemblies to a known location.

Expand Down Expand Up @@ -236,7 +237,7 @@ the Keyfactor Command Portal
| Category | Select "Fortigate" or the customized certificate store name from the previous step. |
| Container | Optional container to associate certificate store with. |
| Client Machine | The IP address or DNS of the Fortigate server |
| Orchestrator | Select an approved orchestrator capable of managing `Fortigate` certificates. Specifically, one with the `Fortigate` capability. |
| Store Path | Value must contain the VDOM this certificate store will be managing. `root` must be entered to manage the default 'root' VDOM. |
| Store Password | Enter the Fortigate API Token here |
| Orchestrator | Select an approved orchestrator capable of managing `Fortigate` certificates. Specifically, one with the `Fortigate` capability. |

Expand All @@ -262,7 +263,7 @@ the Keyfactor Command Portal
| Category | Select "Fortigate" or the customized certificate store name from the previous step. |
| Container | Optional container to associate certificate store with. |
| Client Machine | The IP address or DNS of the Fortigate server |
| Orchestrator | Select an approved orchestrator capable of managing `Fortigate` certificates. Specifically, one with the `Fortigate` capability. |
| Store Path | Value must contain the VDOM this certificate store will be managing. `root` must be entered to manage the default 'root' VDOM. |
| Store Password | Enter the Fortigate API Token here |
| Orchestrator | Select an approved orchestrator capable of managing `Fortigate` certificates. Specifically, one with the `Fortigate` capability. |

Expand Down
Binary file modified docsource/images/Fortigate-advanced-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/Fortigate-basic-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/Fortigate-custom-fields-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion integration-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "Fortigate",
"status": "production",
"description": "This integration is used to inventory and manage certificates in Fortigate.",
"link_github": false,
"link_github": true,
"support_level": "community",
"update_catalog": false,
"release_project": "Fortigate/Fortigate.csproj",
Expand Down
106 changes: 106 additions & 0 deletions scripts/store_types/bash/curl_create_store_types.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env bash

# Creates all 1 store types via the Keyfactor Command REST API using curl.
#
# Authentication (first matching method is used):
# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN
# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET
# + KEYFACTOR_AUTH_TOKEN_URL
# Basic auth (AD): KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD + KEYFACTOR_DOMAIN
#
# Always required:
# KEYFACTOR_HOSTNAME Command hostname (e.g. my-command.example.com)
#
# Auto-generated by doctool generate-store-type-scripts — do not edit by hand.

if [ -z "${KEYFACTOR_HOSTNAME}" ]; then
echo "ERROR: KEYFACTOR_HOSTNAME is required"
exit 1
fi

BASE_URL="https://${KEYFACTOR_HOSTNAME}/keyfactorapi"

# ---------------------------------------------------------------------------
# Resolve auth
# ---------------------------------------------------------------------------
if [ -n "${KEYFACTOR_AUTH_ACCESS_TOKEN}" ]; then
BEARER_TOKEN="${KEYFACTOR_AUTH_ACCESS_TOKEN}"
elif [ -n "${KEYFACTOR_AUTH_CLIENT_ID}" ] && [ -n "${KEYFACTOR_AUTH_CLIENT_SECRET}" ] && [ -n "${KEYFACTOR_AUTH_TOKEN_URL}" ]; then
echo "Fetching OAuth token..."
BEARER_TOKEN=$(curl -s -X POST "${KEYFACTOR_AUTH_TOKEN_URL}" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=${KEYFACTOR_AUTH_CLIENT_ID}" \
--data-urlencode "client_secret=${KEYFACTOR_AUTH_CLIENT_SECRET}" | jq -r '.access_token')
if [ -z "${BEARER_TOKEN}" ] || [ "${BEARER_TOKEN}" = "null" ]; then
echo "ERROR: Failed to fetch OAuth token from ${KEYFACTOR_AUTH_TOKEN_URL}"
exit 1
fi
Comment on lines +28 to +38

Copilot AI Apr 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script parses the OAuth token response with jq, but it doesn’t check that jq is installed. Add a dependency check (similar to the existing kfutil check in other scripts) or avoid jq by parsing with POSIX tools, otherwise the script will fail with a confusing error on systems without jq.

Copilot uses AI. Check for mistakes.
elif [ -n "${KEYFACTOR_USERNAME}" ] && [ -n "${KEYFACTOR_PASSWORD}" ] && [ -n "${KEYFACTOR_DOMAIN}" ]; then
BEARER_TOKEN=""
else
echo "ERROR: Authentication required. Set one of:"
echo " KEYFACTOR_AUTH_ACCESS_TOKEN"
echo " KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET + KEYFACTOR_AUTH_TOKEN_URL"
echo " KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD + KEYFACTOR_DOMAIN"
exit 1
fi

if [ -n "${BEARER_TOKEN}" ]; then
CURL_AUTH=("-H" "Authorization: Bearer ${BEARER_TOKEN}")
else
CURL_AUTH=("-u" "${KEYFACTOR_USERNAME}@${KEYFACTOR_DOMAIN}:${KEYFACTOR_PASSWORD}")
fi

create_store_type() {
local name="$1"
local body="$2"
echo "Creating ${name} store type..."
response=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "${BASE_URL}/certificatestoretypes" \
-H "Content-Type: application/json" \
-H "x-keyfactor-requested-with: APIClient" \
"${CURL_AUTH[@]}" \
-d "${body}")
if [ "$response" = "200" ] || [ "$response" = "201" ]; then
echo " OK (HTTP ${response})"
else
echo " FAILED (HTTP ${response})"
fi
}

# ---------------------------------------------------------------------------
# Fortigate — The IP address or DNS of the Fortigate server
# ---------------------------------------------------------------------------
create_store_type "Fortigate" '{
"Name": "Fortigate",
"ShortName": "Fortigate",
"Capability": "Fortigate",
"ServerRequired": false,
"BlueprintAllowed": true,
"CustomAliasAllowed": "Required",
"PowerShell": false,
"PrivateKeyAllowed": "Required",
"SupportedOperations": {
"Add": true,
"Create": false,
"Discovery": false,
"Enrollment": false,
"Remove": true
},
"Properties": [],
"EntryParameters": [],
"PasswordOptions": {
"Style": "Default",
"EntrySupported": false,
"StoreRequired": true,
"StorePassword": {
"Description": "Enter the Fortigate API Token here",
"IsPAMEligible": true
}
},
"StorePathDescription": "Value must contain the VDOM this certificate store will be managing. `root` must be entered to manage the default 'root' VDOM."
}'


echo "Completed."
28 changes: 28 additions & 0 deletions scripts/store_types/bash/kfutil_create_store_types.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash

# Creates all 1 store types using kfutil.
# kfutil reads definitions from the Keyfactor integration catalog.
#
# Auth environment variables (first matching method is used):
# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN
# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET
# + KEYFACTOR_AUTH_TOKEN_URL
# Basic auth (AD): KEYFACTOR_HOSTNAME + KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD
# + KEYFACTOR_DOMAIN
#
# Auto-generated by doctool generate-store-type-scripts — do not edit by hand.

if ! command -v kfutil &> /dev/null; then
echo "kfutil could not be found. Please install kfutil"
echo "See https://github.com/Keyfactor/kfutil#quickstart"
exit 1
fi

if [ -z "$KEYFACTOR_HOSTNAME" ]; then
echo "KEYFACTOR_HOSTNAME not set — launching kfutil login"
kfutil login
fi

kfutil store-types create --name "Fortigate"

echo "Done. All store types created."
29 changes: 29 additions & 0 deletions scripts/store_types/powershell/kfutil_create_store_types.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Creates all 1 store types using kfutil.
# kfutil reads definitions from the Keyfactor integration catalog.
#
# Auth environment variables (first matching method is used):
# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN
# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET
# + KEYFACTOR_AUTH_TOKEN_URL
# Basic auth (AD): KEYFACTOR_HOSTNAME + KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD
# + KEYFACTOR_DOMAIN
#
# Auto-generated by doctool generate-store-type-scripts — do not edit by hand.

# Uncomment if kfutil is not in your PATH
# Set-Alias -Name kfutil -Value 'C:\Program Files\Keyfactor\kfutil\kfutil.exe'

if ($null -eq (Get-Command "kfutil" -ErrorAction SilentlyContinue)) {
Write-Host "kfutil could not be found. Please install kfutil"
Write-Host "See https://github.com/Keyfactor/kfutil#quickstart"
exit 1
}

if (-not $env:KEYFACTOR_HOSTNAME) {
Write-Host "KEYFACTOR_HOSTNAME not set — launching kfutil login"
& kfutil login
}

& kfutil store-types create --name "Fortigate"

Write-Host "Done. All store types created."
100 changes: 100 additions & 0 deletions scripts/store_types/powershell/restmethod_create_store_types.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Creates all 1 store types via the Keyfactor Command REST API
# using PowerShell Invoke-RestMethod.
#
# Authentication (first matching method is used):
# OAuth access token: KEYFACTOR_AUTH_ACCESS_TOKEN
# OAuth client creds: KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET
# + KEYFACTOR_AUTH_TOKEN_URL
# Basic auth (AD): KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD + KEYFACTOR_DOMAIN
#
# Always required:
# KEYFACTOR_HOSTNAME Command hostname (e.g. my-command.example.com)
#
# Auto-generated by doctool generate-store-type-scripts — do not edit by hand.

if (-not $env:KEYFACTOR_HOSTNAME) {
Write-Error "KEYFACTOR_HOSTNAME is required"
exit 1
}

$uri = "https://$($env:KEYFACTOR_HOSTNAME)/keyfactorapi/certificatestoretypes"
$headers = @{
'Content-Type' = "application/json"
'x-keyfactor-requested-with' = "APIClient"
}

# ---------------------------------------------------------------------------
# Resolve auth
# ---------------------------------------------------------------------------
if ($env:KEYFACTOR_AUTH_ACCESS_TOKEN) {
$headers['Authorization'] = "Bearer $($env:KEYFACTOR_AUTH_ACCESS_TOKEN)"
} elseif ($env:KEYFACTOR_AUTH_CLIENT_ID -and $env:KEYFACTOR_AUTH_CLIENT_SECRET -and $env:KEYFACTOR_AUTH_TOKEN_URL) {
Write-Host "Fetching OAuth token..."
$tokenBody = @{
grant_type = 'client_credentials'
client_id = $env:KEYFACTOR_AUTH_CLIENT_ID
client_secret = $env:KEYFACTOR_AUTH_CLIENT_SECRET
}
$tokenResp = Invoke-RestMethod -Method Post -Uri $env:KEYFACTOR_AUTH_TOKEN_URL -Body $tokenBody
$headers['Authorization'] = "Bearer $($tokenResp.access_token)"
} elseif ($env:KEYFACTOR_USERNAME -and $env:KEYFACTOR_PASSWORD -and $env:KEYFACTOR_DOMAIN) {
$cred = [System.Convert]::ToBase64String(
[System.Text.Encoding]::ASCII.GetBytes(
"$($env:KEYFACTOR_USERNAME)@$($env:KEYFACTOR_DOMAIN):$($env:KEYFACTOR_PASSWORD)"))
$headers['Authorization'] = "Basic $cred"
} else {
Write-Error ("Authentication required. Set one of:`n" +
" KEYFACTOR_AUTH_ACCESS_TOKEN`n" +
" KEYFACTOR_AUTH_CLIENT_ID + KEYFACTOR_AUTH_CLIENT_SECRET + KEYFACTOR_AUTH_TOKEN_URL`n" +
" KEYFACTOR_USERNAME + KEYFACTOR_PASSWORD + KEYFACTOR_DOMAIN")
exit 1
}

function New-StoreType {
param([string]$Name, [string]$Body)
Write-Host "Creating $Name store type..."
try {
Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $Body -ContentType "application/json" | Out-Null
Write-Host " OK"
} catch {
Write-Warning " FAILED: $($_.Exception.Message)"
}
}

# ---------------------------------------------------------------------------
# Fortigate — The IP address or DNS of the Fortigate server
# ---------------------------------------------------------------------------
New-StoreType "Fortigate" @'
{
"Name": "Fortigate",
"ShortName": "Fortigate",
"Capability": "Fortigate",
"ServerRequired": false,
"BlueprintAllowed": true,
"CustomAliasAllowed": "Required",
"PowerShell": false,
"PrivateKeyAllowed": "Required",
"SupportedOperations": {
"Add": true,
"Create": false,
"Discovery": false,
"Enrollment": false,
"Remove": true
},
"Properties": [],
"EntryParameters": [],
"PasswordOptions": {
"Style": "Default",
"EntrySupported": false,
"StoreRequired": true,
"StorePassword": {
"Description": "Enter the Fortigate API Token here",
"IsPAMEligible": true
}
},
"StorePathDescription": "Value must contain the VDOM this certificate store will be managing. `root` must be entered to manage the default 'root' VDOM."
}
'@


Write-Host "Completed."
Loading