How to Automate Acronis Agent Installations

Acronis
Acronis Cyber Disaster Recovery

Automating software installation in IaaS environments to provide additional services to customers (e.g., IaaS or SaaS solutions based on IaaS) is a common challenge for many service providers. Acronis Cyber Protect integrates backup with next-generation, AI-based anti-malware, and endpoint protection management into one solution. This article describes how to automate the installation of the Acronis Cyber Protect Agent.

The article was updated to the latest Acronis Cyber Platform API, C21.11 Acronis Cyber Protect Cloud release.

API usage and security considerations for agents automation installation

Starting from Acronis Cyber Cloud 9.0, the Acronis Cyber Protect Agent can be silently installed and registered in the cloud using time-limited registration codes. You still can use the username and password combination for backward compatibility, but the registration codes give a more secure, advanced, and reliable way to automate Acronis Cyber Protect Agent installations.

Acronis Cyber Protection Agent setup parameters

You can open the setup program parameters dialog for Windows installer with the following command:

./Cyber_Protection_Agent_for_Windows_x64.exe --help

Acronis
Acronis Cyber Protection Agents Setup Program Parameters (Windows)

Notice the parameters that we need for a simple scenario of automating agent installation on Windows:

Parameter
Usage
--quiet
Runs the setup program without showing the user interface (the unattended installation). Do not use with --register-only
--reg-address=<url>
Management service URL
--reg-token=<token>
Registration token. Do not use with --reg-login or --reg-password. Specifying this parameter makes --registration optional

To check the command line parameter for Linux installations, you can run the Linux setup program with this command:

sudo ./Cyber_Protection_Agent_for_Linux_x86_64.bin --help

Acronis
Acronis Cyber Protection Agents Setup Program Parameters (Windows)

Notice the parameters that we need for a simple scenario of automating agent installation on Linux:

Parameter
Usage
-a, --auto
automatic (unattended) setup
--token=STRING
Registration token
-C, --rain=STRING
Cyber Protection service URL

Acronis Account Management API calls to generate a registration token

API Authorization Basis

A JWT token with a limited time-to-live is used to securely manage any API clients' access, like scripts and integrations, for the Acronis Cyber Cloud. Using a login and password for a specific user is not a secure and manageable way to create a token, but technically it's possible.

Acronis Cyber Cloud API Client credentials can be generated in the Management Portal.

A generated client has inherited access rights from the user generating the token, but is disconnected from this user. You don't need to issue a new client when the user account is removed from Acronis Cloud.

Acronis
Acronis Cyber Cloud API Clients at the Management Portal

To issue a token, /idp/token endpoint is called using POST request with grant_type param equal client_credentials and Content-Type application/x-www-form-urlencoded with Basic Authorization using a client_id as username and a client_secret as password.

Note: Each token has a time-to-live and must be renewed/refreshed before it expires. The best practice is to check before starting any API calls sequence and renew/refresh if needed.

Note: Currently, the default time-to-live for a token is two hours.

The successful answer is a JSON with the following fields: 

  • id_token
  • access_token
  • expires_on
  • token_type

expires_on is when the token expires in Unix time format – seconds from January 1, 1970.

Use the received access_token with the Bearer Authorization for all following API requests.

Generate an agent registration token

The  /api/2/tenants/{customer_tenant_id}/registration_tokens endpoint is used to generate an Agent registration token, customer_tenant_id is an id of a customer tenant for which a user belongs for which the agent should be registered.  This endpoint requires Bearer Authorization with a valid JWT token created using the /idp/token endpoint.

To generate a token, the /api/2/{tenant_id}/registration_tokens endpoint is called using POST request with Content-Type application/json and a JSON body contains 2 fields and 1 array:

  • personal_tenant_id
  • expires_in
  • scopes

personal_tenant_id   is an id of a user tenant where the agent should be registered.   

expires_in is the time interval before the token expires in seconds.

scopes are initial registration token access scope. In the example below, the token receives rights to register the Agent for a specified tenant. 

Here is an example of a token generated for a user with a personal tenant with id 1628fcea-554e-4d57-9715-30a42b9d1451  which is belong to a tenant with 65f92900-6cb2-499e-ac3b-39421b350eeb id and  valid for 3 days.

POST /api/2/tenants/65f92900-6cb2-499e-ac3b-39421b350eeb/registration_tokens

Content-Type: application/json

{

"expires_in": 259200,

"scopes": [

"urn:acronis.com:tenant-id:1628fcea-554e-4d57-9715-30a42b9d1451:backup_agent_admin"

]

}

Another way to manage tokens is to generate a token with a long life-time and use it for all or a specific group of machines to install the Agent. In that case, it would be much simple to use the Service Management Console to generate a token then write code to generate it.

Acronis
Generate a token at the Service Management Portal

Script security considerations

As API Client credentials, client_id and client_secret must be treated as username and password. You should never distribute client_id and client_secret with your automation scripts.

The most reliable and scalable solution is to run a web-service that is either internal or open only for specific trusted IPs. This service produces agent installation tokens for scripts to automate installation. This solution can be universal as you can use a machine or a client or any other identifying information to find a tenant where the agent is registered. In this case, a script makes an https call to your service and receives a registration token for agent installation.

Another secure way to use registration tokens is to use a pre-generated list of tokens and inject them in automation scripts using either environment variables or any other tooling you use for your automation deployment. You need to select the time-to-live for these token according to your installation practices.

Base scripts to install the Acronis agent on a Windows computer

The following scripts provide the base flow of API calls to perform Acronis agent installation. You should keep in mind security recommendations when implementing your solution.

The following part should be run as a protected web-service or in another secure way outside of automated script execution.

# check if a token is valid and renew if needed

if (-Not (Confirm-Token)) {

$accessToken = Update-Token -BaseUrl $baseUrl

}

else {

# Read an token info from file

$token = Get-Content "api_token.json" | ConvertFrom-Json

$accessToken = $token.access_token

}

# Manually construct Bearer

$bearerAuthValue = "Bearer $accessToken"

$headers = @{ "Authorization" = $bearerAuthValue }

# The request contains body with JSON

$headers.Add("Content-Type", "application/json")

$headers.Add("User-Agent", "ACP 1.0/Acronis Cyber Platform PowerShell Examples")

# Body JSON to create an installation token

$json = @"

{

"tenant_id": "$tenantID",

"expires_in": 3600,

"scopes": [

"urn:acronis.com:tenant-id::backup_agent_admin"

]

}

"@

# issue a token

$token = Invoke-RestMethod -Method Post -Uri "${baseUrl}bc/api/account_server/registration_tokens" -Headers $headers -Body $json

$token | ConvertTo-Json -Depth 100 | Out-File "agent_installation_token.json"

We expect that the current token is stored in the api_token.json file, and the result with the generated installation token is stored in the agent_installation_token.json file.

As well, you should set the $tenantID variable to a tenant id where the agent registers.

To run the script correctly, you need to provide the $baseUrl parameter, your management server URL.

For your reference below, two used the Update-Token and Confirm-Token functions. The Update-Token function expects that client_id and client_secret are stored in the api_client.json file.

function Update-Token {

[CmdletBinding()]

Param(

[parameter(Mandatory = $true)]

[string]

$BaseUrl

)

# Read an API Client info from a file and store client_idd and client_secret in variables

$client = Get-Content "api_client.json" | ConvertFrom-Json

$clientId = $client.client_id

$clientSecret = $client.client_secret

# Manually construct Basic Authentication Header

$pair = "${clientId}:${clientSecret}"

$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)

$base64 = [System.Convert]::ToBase64String($bytes)

$basicAuthValue = "Basic $base64"

$headers = @{ "Authorization" = $basicAuthValue }

# Use param to tell type of credentials we request

$postParams = @{ grant_type = "client_credentials" }

# Add the request content type to the headers

$headers.Add("Content-Type", "application/x-www-form-urlencoded")

$headers.Add("User-Agent", "ACP 1.0/Acronis Cyber Platform PowerShell Examples")

$token = Invoke-RestMethod -Method Post -Uri "${BaseUrl}api/2/idp/token" -Headers $headers -Body $postParams

# Save the Token info to file for further usage

# YOU MUST STORE YOUR CREDENTIALS IN SECURE PLACE

# A FILE USES FOR CODE SIMPLICITY

# PLEASE CHECK TOKEN VALIDITY AND REFRESH IT IF NEEDED

$token | ConvertTo-Json -Depth 100 | Out-File "api_token.json"

$token.access_token

}

# Check if the token valid at least 15 minutes

function Confirm-Token {

[CmdletBinding()]

Param(

)

# Read token info from

$token = Get-Content "api_token.json" | ConvertFrom-Json

$unixTime = $token.expires_on

$expireOnTime = Convert-FromUnixDate -UnixTime $unixTime

$timeDifference = New-TimeSpan -End $expireOnTime

$timeDifference.TotalMinutes -gt 15

}

function Convert-FromUnixDate {

[CmdletBinding()]

Param(

[parameter(Mandatory = $true)]

[int]

$UnixTime

)

[timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($UnixTime))

}

This sample solution with PowerShell scripts might be used as a base for a secure solution with an SMB share or FTP where the script can put JSON files with installation tokens for installations scripts to use.

The following part should be run as a part of the installation script. We assume that we have the agent_installation_token.json file delivered to a machine where the agent should be installed in this sample.

$tokenInfo = Get-Content "agent_installation_token.json" | ConvertFrom-Json

$token = $tokenInfo.token

.\Cyber_Protection_Agent_for_Windows_x64.exe --quiet --registration by-token --reg-token $token --reg-address $baseUrl

For the script to run successfully, you need to provide the $baseUrl parameter, your management server URL.

Base scripts to install Acronis agent on a Linux computer

The following scripts provide the base flow of API calls to perform an Acronis agent installation. You should keep security recommendations in mind when implementing your solution.

The following part should be run as a protected web-service or be secured in another way outside of the automated script execution.

We expect that the current token is stored in the api_token.json file, and the result with the generated installation token is stored in the agent_installation_token.json file.

You should also set the _tenant_id variable to a tenant id where the agent registers.

For the script to run successfully, you need to provide the _base_url parameter, your management server URL.

# POST API call with Basic Authentication

# $1 - an API endpoint to call

# $2 - login for Basic Authentication

# $3 - a password for Basic Authentication

# $4 - POST data

# $5 - Content-Type

_post_api_call_basic () {

local _response_body

local _response_code

_call \

curl -s \

-X POST \

--url "${_base_url}${1}" \

-u "${2}:${3}" \

-H "Accept: application/json" \

-H "User-Agent: ACP 1.0/Acronis Cyber Platform Bash Examples" \

-H "Content-type: $5" \

--data-raw "$4" \

-w "\n%{http_code}" | {

read -r _response_body

read -r _response_code

_response "${_response_body}"

if [[ $_response_code = 20* ]] ; then

echo "${_response_body}"

else

_die "The POST API Call with the endpoint ${1} is unsuccessful with response code: ${_response_code}." "${_response_body}"

fi

}

}

# Issue an authorization token

# Expect that an API client information are stored

# in native API output format in api_client.json file

# $1 - base URL

_issue_token() {

local _client_id

local _client_secret

# Pipe JSON from file, extract JSON property, remove trilling quotas from the property's value

_client_id=$(jq '.client_id' < api_client.json | sed -e 's/^"//' -e 's/"$//')

_client_secret=$(jq '.client_secret' < api_client.json | sed -e 's/^"//' -e 's/"$//')

# POST call to issue an authorization token

# To use it you need have the following parameters passed

# $1 - an API endpoint to call

# $2 - a login for Basic Authentication

# $3 - a password for Basic Authentication

# $4 - POST data

# $5 - Content-Type

_post_api_call_basic "api/2/idp/token" \

"${_client_id}" "${_client_secret}" \

"grant_type=client_credentials" \

"application/x-www-form-urlencoded" > api_token.json

}

# Check if an authorization token invalid next 15 minutes (900 sec)

# And if it's not, a new token will be issued

# Expect that an authorization token information is stored

# in native API output format in api_token.json file

# Still works correctly if you didn't have a token file

_renew_token_if_needed() {

local _expires_on

local _current_unix_time

local _time_left

if test -f api_token.json; then

# Pipe JSON from file, extract JSON property

_expires_on=$(jq '.expires_on' < api_token.json)

_current_unix_time=$(date +%s)

_time_left=$_expires_on-$_current_unix_time

if [[ $_time_left -le 900 ]] ; then

_issue_token

fi

else

_issue_token

fi

}

# Print errors info to STDERR and exit execution

_die() { printf ":: %s\n\n" "$*" >&2; exit 1; }

# Pipe JSON from file, extract JSON property, remove quotas from the property's value

_get_access_token_from_file(){ jq '.access_token' < "${1}" | sed -e 's/^"//' -e 's/"$//'; }

# POST API call with Bearer Authentication for Backup Console requests

# To handle addition CR in JSON response

# $1 - an API endpoint to call

# $2 - a bearer token Bearer Authentication

# $3 - Content-Type

# $4 - POST data

_post_api_call_bearer_bc () {

local _response_body

local _response_body_end

local _response_code

_call \

curl -s \

-X POST \

--url "${_base_url}${1}" \

-H "Authorization: Bearer ${2}" \

-H "Accept: application/json" \

-H "User-Agent: ACP 1.0/Acronis Cyber Platform Bash Examples" \

-H "Content-type: ${3}" \

--data-raw "${4}" \

-w "\n%{http_code}" | {

read -r _response_body

read -r _response_body_end

read -r _response_code

_response "${_response_body}${_response_body_end}"

if [[ $_response_code = 20* ]] ; then

echo "${_response_body}${_response_body_end}"

else

_die "The POST API Call with the endpoint ${1} is unsuccessful with response code: ${_response_code}." "${_response_body}${_response_body_end}"

fi

}

}

# Basic checks to ensure needed file availability

if test -f api_client.json ; then

_check_tenant_id=$(_get_tenant_id_from_file api_client.json)

if [[ "$_check_tenant_id" = "null" ]]; then

_die "The file api_client.json has incorrect format. Please call 01.create-api-client.sh to create it."

fi

else

_die "The file api_client.json doesn't exist. Please call 01.create-api-client.sh to create it."

fi

# Check an authorization token and renew if needed

# Need to have valid api_client.json

_renew_token_if_needed

# Construct JSON to request a token

_json='{

"tenant_id": "'$_tenant_id'",

"expires_in": 3600,

"scopes": [

"urn:acronis.com:tenant-id::backup_agent_admin"

]

}'

# To create an agent installation token

# POST API call using function defined in basis_functions.sh

# with following parameters

# $1 - an API endpoint to call

# $2 - a bearer token Bearer Authentication

# $3 - Content-Type

# $4 - POST data

# The result is stored in created_report.json file

_post_api_call_bearer_bc "bc/api/account_server/registration_tokens" \

"${_access_token}" \

"application/json" \

"${_json}" > agent_installation_token.json

This sample solution with bash scripts might be used as a base for a secure solution with an NFS share or FTP where the script can put JSON files with installation tokens for installations scripts to use.

The following part should be run as a part of the installation script, provided that you have the agent_installation_token.json file delivered to the machine where the Acronis agent should be installed.

# Pipe JSON from file, extract JSON property, remove quotas from the property's value

_get_installation_token_from_file(){ jq '.token' < "${1}" | sed -e 's/^"//' -e 's/"$//'; }

# Get installation token for the agent installation

_installation_token=$(_get_installation_token_from_file agent_installation_token.json)

export HISTIGNORE='*sudo -S*'

echo "" | sudo -S -k ./Cyber_Protection_Agent_for_Linux_x86_64.bin -a --rain "${_base_url}" --token "${_installation_token}"

For the script to run successfully, you need to provide the _base_url parameter, your management server URL.

Summary

Now you know how to automate the Acronis Cyber Protection Agent installation and have practical examples of how to proceed with this task for Windows and Linux environments.

For further API learning, register at our Platform Program or Developer Network on https://developer.acronis.com site.

Find our public Postman API collection for standard automation and integration tasks https://explore.postman.com/grey-rocket-585331 or use our GitHub examples https://github.com/acronis.

About Acronis

A Swiss company founded in Singapore in 2003, Acronis has 15 offices worldwide and employees in 50+ countries. Acronis Cyber Protect Cloud is available in 26 languages in 150 countries and is used by over 20,000 service providers to protect over 750,000 businesses.