Automate Acronis Agent Installations

Acronis Cyber Protection Agent Try Monitor

Acronis Cyber Protection Agent Try Monitor

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.

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 Cyber Protection Agents Setup Program Parameters (Windows)

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 Cyber Protection Agents Setup Program Parameters (Windows)

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 Cyber Cloud API Clients at the Management Portal

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  /bc/api/account_server/registration_tokens endpoint is used to generate an Agent registration token. This endpoint requires Bearer Authorization with a valid JWT token created using the /idp/token endpoint.

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

  • tenant_id
  • expires_on
  • scopes

tenant_id is an id of the tenant where the agent should be registered.

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

scopes are initial registration token access scope.

Here is an example of a token generated for the tenant with id 56813229-d0f2-4d07-84d3-8368d79cac82 and valid for one hour.

{
  "tenant_id": "56813229-d0f2-4d07-84d3-8368d79cac82",
  "expires_in": 3600,
  "scopes": [
    "urn:acronis.com:tenant-id::backup_agent_admin"
  ]
}

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.

Updated
Stas Pavlov
Technology Evangelist
Acronis Cyber Platform
Acronis Cyber Agent