Access Keys
Both HMAC authentication and API-based keys can be used for automation from release 7.5.0 onwards. This chapter describes how use API keys or HMAC for authentication.
API Keys
To get an API key, you need to create an API key in the system to be used in automation scenarios such as playbooks, etc. For more information, see the Access Keys section in the Security Management chapter of the "Administration Guide."
|
|
The API keys cannot be used to perform all operations related to the API key such as creating or updating API keys and all authentication (/ |
Configuration of API Keys
Use the following APIs to modify the configuration for API Keys, such as, enabling or disabling retrievable mode for API keys, retrieving a list of all setting for the API Key.
Fetch a list of all API key settings
Use this API to retrieve a list of all API key settings.
Request
METHOD: GET
URL: https://{HOSTNAME}/api/auth/config?section=API-KEYS
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json
|
| Content-Type | application/json;charset=UTF-8
|
Parameters
section
|
<section_name>
Used to specify the section from which data needs to be retrieved, which is set to API-KEYS in the sample snippet. |
Update the retrievable mode for API keys
Use this API to enable or disable the retrieval mode for API keys by setting it to true or false. If the retrieval mode is enabled when the API key is being created, then the API key will always be retrievable, even if the retrieval mode is disabled later. If the retrieval mode is disabled when the API key is being created, then the API key cannot be retrieved after its creation.
Request
METHOD: PUT
URL: https://{HOSTNAME}/api/auth/config
BODY:
{
"option" : "retrievable_mode",
"value" : true
}
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json
|
| Content-Type | application/json;charset=UTF-8
|
Management of API Keys
Use the following APIs to manage API keys, such as, creating API keys, retrieving API keys, retrieving roles and teams associated with API keys, etc.
Creation of an API key
Creation of an API key is a two-step process; first create the API key and then associate it with existing teams and roles to define its scope and usability.
Create an API Key
Use this API to create an API key.
Request
METHOD: POST
URL: https://{HOSTNAME}/api/auth/users
BODY:
{
"type" : "9",
"status" : "1",
"api_key_validity" : 2
}
Request Payload
"type" : "9"
|
Indicates that the user is of API key type. |
|
|
Indicates that the user status is 'active'. |
|
|
Indicates the validity of the API Key in days. In this example, validity is set to two days. |
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json
|
| Content-Type | application/json;charset=UTF-8
|
Response
{
"uuid": "<user_id_for_api_key>",
"api_key": {
"key": "<api_key_value>",
"retrievable": false
}
}
Associate an API key with teams and roles
After creating the API key, use this API to associate it with appropriate teams and roles to define its scope and usability. Value of the "uuid" received from the "Create an API" request operation should be specified as the value of the "userId" parameter in this API payload.
METHOD: POST
URL: https://{HOSTNAME}/api/3/api_keys
BODY:
{
"name" : "api_key_for_automation",
"roles" :[
"/api/3/roles/<roleId1>",
"/api/3/roles/<roleId2>",
"/api/3/roles/<roleId3>"
]
,
"teams":[
"/api/3/teams/<teamId1>"
]
,
"userId": "<userId>"
}
Request Payload
name
|
The name of the API key. |
|
|
The list of role IDs to associate with the API key. NOTE: To retrieve the list of role IDs, use the Get all roles API. |
|
|
The list of team IDs to associate with the API key. |
|
|
Value of the " |
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json, text/plain, */*
|
| Content-Type | application/json;charset=UTF-8
|
API keys retrieval
Use these APIs to perform various operations related to API keys retrieval, such as, getting all API keys, a specific API key, a specific scope of a specific API key, etc
Get all scopes of API keys
To retrieve API keys, first use this API to retrieve all the scopes of all existing API keys. This operation returns an array of JSON objects containing the parameters such as "name", "uuid", and "userId".
METHOD: GET
URL: https://{HOSTNAME}/api/3/api_keys
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json, text/plain, */*
|
| Content-Type | application/json;charset=UTF-8
|
Get all API keys
Use this API to retrieve a list of all API keys. Value of the "userId" received from the "Get all scopes of API keys" operation should be specified as the value of the "users" parameter in this API payload.
This operation returns the API key in a "masked" format; to get the actual value of the API use, pass "show_api_key" : true in the body of the API.
METHOD: POST
URL: https://{HOSTNAME}/api/auth/query/users
BODY:
{
"users" : [
"<userId_1>",
"<userId_2>",
"<userId_3>"
]
}
Request Payload
|
|
Value of the " |
|
|
This operation returns the API key in a "masked" format . To get the actual value of the API use, pass |
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json, text/plain, */*
|
| Content-Type | application/json;charset=UTF-8
|
Get scope of a specific API key
Use this API to retrieve the scope of a specific API key using its UUID. Value of the "uuid" received from the "Get all scopes of API keys" operation should be specified as the value of the "uuid" in the path parameter of this API. This operation returns a JSON object containing the parameters such as "name", "uuid", and "userId".
METHOD: GET
URL: https://{HOSTNAME}/api/3/api_keys/<uuid>
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json, text/plain, */*
|
| Content-Type | application/json;charset=UTF-8
|
Parameters
uuid
|
Value of the "uuid" received from the "Get all scopes of API keys" operation should be specified as the value of the "uuid" in the path parameter of this API. |
Get a specific API key
Use this API to retrieve a specific API key using the specified UUID. Value of the "userId" received from the "Get scope of a specific API key" operation should be specified as the value of the "uuid" query parameter in this API.
This operation returns the API key in a "masked" format; to get the actual value of the API use, pass "show_api_key" : true in the query parameter of the API.
METHOD: GET
URL: https://{HOSTNAME}/api/auth/users?uuid=<userId>&show_api_key=true
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json
|
| Content-Type | application/json;charset=UTF-8
|
Parameters
userId
|
Value of the "userId" received from the "Get scope of a specific API key" operation should be specified as the value of the "uuid" query parameter in this API. |
|
|
This operation returns the API key in a "masked" format . To get the actual value of the API use, pass |
Fetching teams and roles required to scope an API key
Use these APIs to retrieve the list of team and role IDs that are used to scope an API key, i.e., associate appropriate teams and roles with the API key.
Get all roles
Use this API to get a list of all existing role IDs.
METHOD: GET
URL: https://{HOSTNAME}/api/3/roles?$limit=30
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json
|
| Content-Type | application/json;charset=UTF-8
|
Parameters
$limit
|
Used to limit the number of roles records to be retrieved, which is set to 30 in the sample snippet. |
Get all teams
Use this API to get a list of all existing team IDs.
METHOD: GET
URL: https://{HOSTNAME}/api/3/teams?$limit=30&$orderby=name
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json
|
| Content-Type | application/json;charset=UTF-8
|
Parameters
$limit
|
Used to limit the number of roles teams to be retrieved, which is set to 30 in the sample snippet. |
|
|
Used to sort the results retrieved by this API based on the specified, which is set to |
Operations to update API keys
Use these APIs to perform operations for updating API keys, such as updating, revoking, regenerating API keys, etc.
Revoke a specific API key
Use this API to permanently deactivate a specific API key and revoke its access based on the specified "uuid". Value of the "userId" received from the "Get scope of a specific API key" operation should be specified as the value of the "uuid" in the API payload.
METHOD: PUT
URL: https://{HOSTNAME}/api/auth/users
BODY:
{
"uuid" : "<uuid>",
"key_type" : "API_KEY",
"operation" : "REVOKE"
}
Request Payload
|
|
Value of the " |
|
|
Used to specify the type of the key, in this case |
|
|
Used to specify the operation to be performed using the API key, |
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json
|
| Content-Type | application/json;charset=UTF-8
|
Activate a specific API key
Use this API to activate a specific API key based on the specified uuid. Value of the "userId" received from the "Get scope of a specific API key" operation should be specified as the value of the "uuid" in the API payload.
METHOD: PUT
URL: https://{HOSTNAME}/api/auth/users
BODY:
{
"uuid" : "<uuid>",
"key_type" : "API_KEY",
"operation" : "ACTIVATE"
}
Request Payload
|
|
Value of the " |
|
|
Used to specify the type of the key, in this case |
|
|
Used to specify the operation to be performed using the API key, |
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json
|
| Content-Type | application/json;charset=UTF-8
|
Deactivate a specific API key
Use this API to deactivate a specific API key based on the specified uuid. Value of the "userId" received from the "Get scope of a specific API key" operation should be specified as the value of the "uuid" in the API payload.
METHOD: PUT
URL: https://{HOSTNAME}/api/auth/users
BODY:
{
"uuid" : "<uuid>",
"key_type" : "API_KEY",
"operation" : "DEACTIVATE"
}
Request Payload
|
|
Value of the " |
|
|
Used to specify the type of the key, in this case |
|
|
Used to specify the operation to be performed using the API key, |
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json
|
| Content-Type | application/json;charset=UTF-8
|
Regenerate a specific API key
Use this API to regenerate a specific API key based on the specified uuid. Value of the "userId" received from the "Get scope of a specific API key" operation should be specified as the value of the "uuid" in the API payload. Additionally, specify the number of days until the regenerated API key will be valid, for example 5 days in the following snippet.
METHOD: PUT
URL: https://{HOSTNAME}/api/auth/users
BODY:
{
"uuid" : "<uuid>",
"key_type" : "API_KEY",
"operation" : "REGENERATE",
"api_key_validity" : 5,
}
Request Payload
|
|
Value of the " |
|
|
Used to specify the type of the key, in this case |
|
|
Used to specify the operation to be performed using the API key, |
|
|
Used to specify the validity of the API key in days. |
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json
|
| Content-Type | application/json;charset=UTF-8
|
Reset validity of a specific API key
Use this API to reset the validity a specific API keybased on the specified uuid. Value of the "userId" received from the "Get scope of a specific API key" operation should be specified as the value of the "uuid" in the API payload. Additionally, specify the number of days until the validity of the specified API key should be reset, for example, the validity of the API key is reset to 10 days in the following snippet.
METHOD: PUT
URL: https://{HOSTNAME}/api/auth/users
BODY:
{
"uuid" : "<uuid>",
"key_type" : "API_KEY",
"operation" : "RESET_VALIDITY",
"api_key_validity" : 10,
}
Request Payload
|
|
Value of the " |
|
|
Used to specify the type of the key, in this case |
|
|
Used to specify the operation to be performed using the API key, |
|
|
Used to specify the validity of the API key in days. |
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json
|
| Content-Type | application/json;charset=UTF-8
|
Update the scope of a specific API key
Use this API to update the scope, i.e., update the name, teams, and/or roles assigned to the specific API key using its "uuid". Value of the "uuid" received from the "Get all scopes of API keys" operation should be specified as the value of the "uuid" in the path parameter of this API. Additionally, specify the field you want to change in the API payload, such as the name of the API key, rolesId, and teamIds.
NOTE: This operation replaces the values of the specified fields in the payload, i.e., the name, roles, teams, etc. specified in the payload will be assigned to the API key, and any previously assigned values will be overwritten.
METHOD: PUT
URL: https://{HOSTNAME}/api/3/api_keys/<uuid>
BODY:
{
"name" : "api_key_for_automation",
"roles" :[
"/api/3/roles/<roleId1>",
"/api/3/roles/<roleId2>",
"/api/3/roles/<roleId3>",
"/api/3/roles/<roleId4>"
],
"teams" :[
"/api/3/teams/<teamId1>",
"/api/3/teams/<teamId2>"
],
"userId" : "<userId1>"
}
Request Payload
name
|
The name of the API key. |
|
|
The list of role IDs to associate with the API key. NOTE: To retrieve the list of role IDs, use the Get all roles API. |
|
|
The list of team IDs to associate with the API key. |
|
|
Value of the " |
Headers
| Authorization | {{userAuth}} or {{hmacAuth}} |
| Accept | application/json, text/plain, */*
|
| Content-Type | application/json;charset=UTF-8
|
Test a created API key
The API key should be set in the Authorization header in API-KEY format. To test a created API key, you can try to retrieve a list of alerts using the API key, or log into FortiSOAR to perform various operations such as, retrieving API key, regenerating API keys, etc.
Get list of module records using API Key
Use this API to retrieve a list of records from the specified module using the API key. The following snippet retrieves a list of alerts using an API key.
METHOD: POST
URL: https://{HOSTNAME}/api/query/<module_name>?$limit=30
BODY:
{"sort":[{"field":"priorityWeight","direction":"DESC","_fieldName":"priorityWeight"}],"limit":30,"logic":"AND","filters":[{"sort":[{"direction":"DESC","field":"priorityWeight","_fieldTitle":"Priority Weight","_fieldName":"priorityWeight"}],"limit":30,"logic":"AND","filters":[]}],"__selectFields":["id","priorityWeight","severity","assignedTo","name","source","type","status","createDate","escalatedtoincident","ackSlaStatus","respSlaStatus","tenant","@id","@type","createUser","modifyUser"]}
Headers
| Authorization | API-KEY <Here goes the api key>
|
| Accept | application/json
|
| Content-Type | application-key/json;charset=UTF-8
|
Parameters
|
|
Used to specify the name of the module from which you want to retrieve the list of records. |
$limit
|
Used to limit the number of alert records to be retrieved, which is set to 30 in the sample snippet. |
|
|
Following is a sample 'curl' command to call an API using API keys: curl -i -X {API_Method_Type} \
'{API_URI}'
-H "Authorization: API-KEY {{KEY_HERE}}" \
-H "Content-Type: application-key/json;charset=UTF-8" \
-H "Accept: application/json" \
-d '{API_Payload}'
|
HMAC Authentication
To get a public/private key, you need to create an appliance in the system to be used in automation scenarios such as playbooks, etc. For more information, see the Access Keys section in the Security Management chapter of the "Administration Guide."
How FortiSOAR Authorizes Payloads with HMAC
To successfully authenticate our payloads, we are required to get a fingerprint as part of the request and compare it locally by recreating the fingerprint. This is subjective and can be defined by the HMAC provider (FortiSOAR). FortiSOAR fingerprinting will be based on hashing the private key against the identifier (NOT THE ACTUAL PAYLOAD).
How to create an Identifier
The FortiSOAR identifier is created in such a way that some pieces will be gathered from the request and others will have to be provided by the requester. Our current identifier simply is: ALGO.VERB.TIMESTAMP.FULL_URI.HASHED_PAYLOAD
The identifier units are separated with periods. Here is a brief explanation of each unit:
- ALGO: The Algorithm the hashing is being done with, for a full list of hashing algorithms available in PHP you can use the hash_algos function.
- VERB: The current request action, GET, POST, PUT, PATCH, DELETE
- TIMESTAMP: The timestamp the fingerprint is created. This is also sent as part of the request.
Note: Timestamp must be in UTC format. - FULL_URI: The full URI of the request, including any parameters
- HASHED_PAYLOAD: The string that is to be fingerprinted. Hashed with the requested ALGO
Once the above is created the fingerprint is created with hash_hmac(algo, identifier, private_key, false). The fingerprint is expected to be represented as a string as opposed to raw binary.
PHP Example
$privateKey = "our_private_key";
$publicKey = "our_public_key"; // used in the example following this
$testAlgo = "sha256";
$testVerb = "GET";
$testTimestampObj = new \DateTime();
$testTimestamp = $testTimestampObj->format('Y-m-d H:i:s');
$testFullUri = "http://example.com/api/1/data/1";
$testPayload = "This is a test string"; // this could be
our_public_key on GET requests
$hashedPayload = hash($testAlgo,$testPayload,false);
$rawFingerprint =
$testAlgo.'.'.
$testVerb.'.'.
$testTimestamp.'.'.
$testFullUri.'.'.
$hashedPayload;
$hashedFingerprint =
hash_hmac(
$testAlgo,
$rawFingerprint,
$privateKey,
false
);
Python Example
import base64
import hashlib
import hmac
from datetime import datetime
import requests
import json
DEFAULT_ALGORITHM = "sha256"
# update below with proper fqhn or ip, and update the route name per the playbook start step settings
API_ROUTE = "https://<fqhn-or-ip>/api/triggers/1/<route>"
with open(
"APPLIANCE_PUBLIC_KEY",
"r",
) as public_key_file:
public_key = public_key_file.read().strip()
with open(
"APPLIANCE_PRIVATE_KEY",
"r",
) as private_key_file:
private_key = private_key_file.read().strip()
def generate_hmac(method, full_uri, payload, private_key, public_key):
if method == "GET":
payload = public_key
timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
payload = payload if type(payload) is bytes else payload.encode()
digest_method = hashlib.new(DEFAULT_ALGORITHM)
digest_method.update(payload)
hashed_payload = digest_method.hexdigest()
raw_fingerprint = "{0}.{1}.{2}.{3}.{4}".format(
DEFAULT_ALGORITHM, method, timestamp, full_uri, hashed_payload
)
hashed = hmac.new(private_key.encode(), raw_fingerprint.encode(), hashlib.sha256)
hashed_fingerprint = hashed.hexdigest()
header = base64.b64encode(
"{0};{1};{2};{3}".format(
DEFAULT_ALGORITHM, timestamp, public_key, hashed_fingerprint
).encode()
)
return "CS {}".format(header.decode())
method = "POST"
payload = {"data": "test"}
auth_header = generate_hmac(
method, API_ROUTE, json.dumps(payload), private_key, public_key
)
headers = {"Authorization": auth_header}
try:
req = requests.request(
method, API_ROUTE, data=json.dumps(payload), headers=headers, verify=False
)
print(req.json())
except Exception as e:
print(e)
Using the Signature
After creating our identifier, we can send the payload to our API. However, the fingerprint alone is not enough. We'll also need to send our public key, the timestamp used to hash our fingerprint, and the algorithm being used in the request. These pieces should be concatenated using semicolons and included in the authorization header base64 encoded.
PHP Example
$header =
base64_encode($testAlgo.';'.$testTimestamp.';'.$publicKey.';'.$hashedFinge
rprint);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Authorization: CS " . $header,
"X-CS-Data: " . $testPayload
));
Python Example
import requests
import json
auth_header = generate_hmac(method,full_url, json.dumps(payload), private_key, public_key)
headers =
{
'Authorization': auth_header
}
try:
req = requests.request(method, full_url, data=payload, headers=headers, verify=False)
print (req)
except Exception as e:
print(e)
If the fingerprint is authorized the request will be delivered to the API; otherwise, a 401 error will be returned.