CyberArk Automation – Adding Users

This entry is part 3 of 3 in the series CyberArk Automation

This time I’ll only be looking at adding a user and their credentials to a particular safe in CyberArk, not creating them locally on the server. While that’s an important part, there’s various methods to do it available to anyone running a system. I will look at different options around scripting user creation at the end of this series, but for now I’m more focused on pushing the details to CyberArk (and making sure the appropriate permitted user has access – note that this may also be an AD group rather than a user if you’re using role based access control).

The other part of this will be generating an initial password. Arguably this could be set to something relatively insecure and reset when CyberArk takes control of the account, but that seems far too easy (and shortcuts never lead anywhere good). Instead I’ll be looking to generate a secure password through script, so that at no point does it exist outside of the system memory, and push that into the safe. For now I’m going to ignore SSH keys, and assume that secure password has already been generated and passed to the function.

We’re not far off assembling all of these for a single script to create a role safe, add an AD account to it, and add local credentials to it now. That’s not the ultimate goal, but is a definite milestone on the way to automating (almost) everything involved.

Before jumping into the scripts, a quick diversion about how this PAM solution works (this is relevant at this point). User accounts on a target server are added to what’s called a ‘safe’ on the CyberArk vault server. I think of these safes as roles, since I’m always in favour of true RBAC, but in fact they’re just groupings of credentials. They could store multiple users for a single server, or single users for multiple servers, or anything in between. In essence, the safe stores connection credentials to target servers. A user who wants to connect is then given access to one or more safes as needed.

This has proven difficult to explain at times and I suspect a lot of it is in the terminology. Credentials to the targets servers are, of course, user accounts. Safes hold user accounts. User accounts are given access to safes. This is where confusion can creep in, and why I’ll usually use the term credentials or access credentials to talk about user accounts on target machines, while I’ll use users to refer to the users who are given access to the safes containing those credentials. Or at least I’ll try to.

PowerShell version
# POST Method - Add Account

function PASREST-AddAccount ([string]$Authorization, [string]$Safe, [string]$PlatformID, [string]$Address, [string]$Password, [string]$Username) {

    # Declaration
    $webServiceGA = "$PVWA_URL/PasswordVault/WebServices/PIMServices.svc/Account"

    # Authorization
    $headerParams = @{}

    $DisableAutoMgmt = $false
    $DisableAutoMgmtReason = $false

    $bodyParams = @{
        account = @{
            safe = $Safe;
            platformID = $PlatformID.Replace(" ","");
            address = $Address;
            accountName = "$Username";
            password = $Password;
            username = $Username;
            disableAutoMgmt = $DisableAutoMgmt;
            disableAutoMgmtReason = $DisableAutoMgmtReason
    } | ConvertTo-JSON

    # Execution
    try {
        $addAccountResult = Invoke-RestMethod -Uri $webServiceGA -Method POST -ContentType "application/json" -Header $headerParams -Body $bodyParams -ErrorVariable addAccountResultErr

        return $addAccountResult
    } catch {
        Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
        Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
        Write-Host "Response:" $_.Exception.Message
        return $false

Python version
import json
import urllib2

def pasrest_add_account (authorization, safe, platform_id, address, password, username, pvwa_url):

	# Build API URL
	web_service_accounts = '{0}/PasswordVault/WebServices/PIMServices.scv/Account'.format(pvwa_url)
	# Add authorization header
	header = {
	disable_auto_mgmt = False
	disable_auto_mgmt_reason = False
	# Assemble body
	body = {
		'account': {
			'safe': safe,
			'platformID': platform_id.replace(" ",""),
			'address': address,
			'accountName': username,
			'password': password,
			'username': username,
			'disableAutoMgmt': disable_auto_mgmt,
			'disableAutoMgmtReason': disable_auto_mgmt_reason
		add_account_request = urllib2(web_service_accounts,body,header)
		add_account_result = urlllib2.urlopen(build_safe_request)
		return True
	except urllib2.error.URLError as e:
		return False
	except urllib2.error.HTTPError as e:
		return False