Photo by Ferenc Almasi on Unsplash
Managing objects in CyberArk with PowerShell Desired State Configuration
Table of contents
PowerShell Desired State Configuration (DSC) is a tool similar to Ansible, Puppet, and Chef that enables declaratively setting how an environment is configured. PowerShell DSC can be used to ensure resources such as environmental variables, software, files, Active Directory users, and application-specific settings are either present or absent through the use of configurations.
A few of the most obvious, CyberArk-related use cases for PowerShell DSC include making sure that the required software is installed after importing a Universal Connector package or after deploying a CPM plugin as part of a continuous deployment pipeline. It can be used to manage the rules within an PSMConfigureAppLocker.xml
file or invoke the automated installation or upgrade processes for components.
Though with the CyberArkDsc
module, PowerShell DSC can also be used to manage CyberArk Vault objects such as safes, safe memberships, and accounts.
Why use PowerShell DSC to manage Vault objects?
Using PowerShell DSC to manage Vault objects makes sense for the same reasons configuration management makes sense for infrastructure.
Combat configuration drift - Ensure accounts have the intended configurations long after they are created -- particularly useful in a test or lab environment where experimentation may lead to false settings and thus unintended consequences.
Idempotency - Safes, safe memberships, and accounts can be created and configured using scripts, the Password Upload Utility, or PACLI but running executing these when the objects already exist may produce different results or fail entirely.
Treat Vault objects as code - Like with infrastructure as code, Vault objects can be defined in configurations and these configurations can be stored in version control, be included in continuous deployment pipelines, or reviewed by other team members.
Included in PowerShell 5.1 and above - PowerShell DSC is included in PowerShell 5.1 and above which absolves the need to install to install more software, such as Python when dealing with Ansible.
Using PowerShell DSC and CyberArkDsc
to populate an empty Vault
One of the leading use cases for using PowerShell DSC together with CyberArk is that it can be used to quickly create accounts on target systems and onboard them into the Vault.
In the following section, a DSC configuration will be used to create Active Directory users, safes to store them in the Vault, assign the needed safe memberships to make the accounts accessible, and finally onboard the users into the safes with the needed reconcile accounts.
Note: For the sake of brevity, knowledge of PowerShell DSC concepts and terminology such as resources and configurations is assumed.
Installing the CyberArkDsc
and ActiveDirectoryDsc
modules
Installing the ActiveDirectoryDsc
module is straightforward as it can be installed from the PowerShell Gallery like any other PowerShell module. The ActiveDirectoryDsc
wiki has information on getting started.
CyberArkDsc
is not available in the PowerShell Gallery and needs to be manually installed. As by default configurations are executed under the SYSTEM
account, CyberArkDsc
needs to, along with it's dependency psPAS
, exist in a non-user-specific folder location defined in $env:PSModulePath
-- for example: $env:ProgramFiles\WindowsPowerShell\Modules
.
We can use Get-DscResource
to ensure that both DSC modules are installed correctly.
PS > Get-DscResource | Where-Object {$_.Name -eq 'CYA_Account' -or $_.Name -eq 'ADUser'}
ImplementedAs Name ModuleName Version Properties
------------- ---- ---------- ------- ----------
PowerShell ADUser ActiveDirectoryDsc 6.2.0 {DomainName, UserName, AccountNotDelegated, All...
PowerShell CYA_Account CyberArkDsc 0.0.2 {Address, AuthenticationType, Credential, Ensur...
PS >
Writing our configuration
We will keep our DSC configuration relatively short and sweet. We already have LDAP integration configured for the Vault, a user that is in both Vault Admins and Domain Admins groups, and platforms created in the Vault that the accounts will be onboarded with so this just leaves us with:
Creating two users in Active Directory, one to be used as a reconcile account.
Adding the reconcile account as a member to the Domain Admins group in Active Directory so it can reconcile the other.
Creating two safes to store the accounts in: one for the reconcile account, the other.
Assigning a membership to each safe enabling an existing Active Directory group named
CyberArk Administrators
full permissions to the reconcile account safe and another, existing Active Directory group namedWindows Administrators
with list, retrieve, and use accounts to the other.Onboarding both accounts: The reconcile account will be onboarded with the password defined when creating it in Active Directory and the other account will be onboarded with the reconcile account defined as a linked account.
Defining the base of our configuration
Each DSC resource in CyberArkDsc
takes at least four parameters: PvwaUrl
, AuthenticationType
, Credential
, and SkipCertificateCheck.
We define these as parameters our configuration accepts. In addition, we define an InitialPassword
parameter that will be used when creating the reconcile account's Active Directory user and when onboarding into CyberArk.
We will have a single node -- localhost
-- as we will run the DSC configuration on the same machine we compile it on. Our resources will go inside it.
Both Credential
and InitialPassword
will be passed PSCredential
objects. As this is a lab environment I will not go through the effort to have the credentials be properly secured in the resulting, compiled configuration so I set a switch to allow the passwords to be stored plaintext.
Configuration CreateLab_Configuration {
param(
$PvwaUrl,
$AuthenticationType,
$Credential,
$SkipCertificateCheck,
$InitialPassword
)
Node localhost {
}
}
$ConfigData = @{
AllNodes = @(
@{
NodeName = 'localhost'
PSDscAllowDomainUser = $true
PSDscAllowPlainTextPassword = $true
}
)
}
$VaultCredential = New-Object System.Management.Automation.PSCredential('allison', (ConvertTo-SecureString 'Password!' -AsPlainText -Force))
$Password = New-Object System.Management.Automation.PSCredential('banana', (ConvertTo-SecureString 'P@$$W0RD12345' -AsPlainText -Force))
$ConfigurationParameters = @{
ConfigurationData = $ConfigData
PvwaUrl = 'https://192.168.137.101'
AuthenticationType = 'LDAP'
SkipCertificateCheck = $true
Credential = $VaultCredential
InitialPassword = $Password
}
CreateLab_Configuration @ConfigurationParameters
Defining resources
Our configuration will have nine resources. Using documentation, our familiarity with managing Vault objects via psPAS
and Get-DscResource -Name ADUser,ADGroup,CYA_Account,CYA_Safe,CYA_SafeMember -Syntax
to know how to define each resource, our complete configuration looks like:
Configuration CreateLab_Configuration {
param(
$PvwaUrl,
$AuthenticationType,
$Credential,
$SkipCertificateCheck,
$InitialPassword
)
Import-DscResource -ModuleName 'ActiveDirectoryDsc' -Name 'ADUser', 'ADGroup'
Import-DscResource -ModuleName 'CyberArkDsc'
Node 'localhost' {
ADUser 'iosharp\windowsReconcile50' {
Ensure = 'Present'
UserName = 'windowsReconcile50'
DomainName = 'iosharp.dev'
Password = $InitialPassword
PasswordNeverResets = $true
Credential = $Credential
}
ADUser 'iosharp\windowsAdmin50' {
Ensure = 'Present'
UserName = 'windowsAdmin50'
DomainName = 'iosharp.dev'
Password = $InitialPassword
PasswordNeverResets = $true
Credential = $Credential
}
ADGroup 'Domain Admins' {
Ensure = 'Present'
GroupName = 'Domain Admins'
MembersToInclude = 'windowsReconcile50'
Credential = $Credential
DependsOn = '[ADUser]iosharp\windowsReconcile50'
}
CYA_Safe 'WinRec50' {
Ensure = 'Present'
SafeName = 'WinRec50'
Description = 'Windows Reconcile Safe'
ManagingCPM = 'PasswordManager'
NumberOfDaysRetention = '1'
PvwaUrl = $PvwaUrl
AuthenticationType = $AuthenticationType
SkipCertificateCheck = $SkipCertificateCheck
Credential = $Credential
}
CYA_Safe 'WinAdmins50' {
Ensure = 'Present'
SafeName = 'WinAdmins50'
Description = 'Windows Admins Safe'
ManagingCPM = 'PasswordManager'
NumberOfDaysRetention = '1'
PvwaUrl = $PvwaUrl
AuthenticationType = $AuthenticationType
SkipCertificateCheck = $SkipCertificateCheck
Credential = $Credential
}
CYA_SafeMember 'WinRec\CyberArk Administrators' {
Ensure = 'Present'
SafeName = 'WinRec50'
MemberName = 'CyberArk Administrators'
SearchIn = 'iosharp.dev'
UseAccounts = $true
RetrieveAccounts = $true
ListAccounts = $true
AddAccounts = $true
UpdateAccountContent = $true
UpdateAccountProperties = $true
InitiateCPMAccountManagementOperations = $true
SpecifyNextAccountContent = $true
RenameAccounts = $true
DeleteAccounts = $true
UnlockAccounts = $true
ManageSafe = $true
ManageSafeMembers = $true
BackupSafe = $true
ViewAuditLog = $true
ViewSafeMembers = $true
AccessWithoutConfirmation = $true
CreateFolders = $true
DeleteFolders = $true
MoveAccountsAndFolders = $true
RequestsAuthorizationLevel1 = $true
RequestsAuthorizationLevel2 = $false
PvwaUrl = $PvwaUrl
AuthenticationType = $AuthenticationType
SkipCertificateCheck = $SkipCertificateCheck
Credential = $Credential
DependsOn = '[CYA_Safe]WinRec50'
}
CYA_SafeMember 'WinAdmins\Windows Administrators' {
Ensure = 'Present'
SafeName = 'WinAdmins50'
MemberName = 'Windows Administrators'
SearchIn = 'iosharp.dev'
UseAccounts = $true
RetrieveAccounts = $true
ListAccounts = $true
ViewSafeMembers = $true
PvwaUrl = $PvwaUrl
AuthenticationType = $AuthenticationType
SkipCertificateCheck = $SkipCertificateCheck
Credential = $Credential
DependsOn = '[CYA_Safe]WinAdmins50'
}
CYA_Account 'windowsReconcile50' {
Ensure = 'Present'
UserName = 'windowsReconcile50'
Address = 'iosharp.dev'
PlatformId = 'ioSHARPWindowsDomainReconcileAccount'
SafeName = 'WinRec50'
Name = 'windowsReconcile50@iosharp.dev'
Password = $InitialPassword
PvwaUrl = 'https://192.168.137.101'
AuthenticationType = 'LDAP'
SkipCertificateCheck = $true
Credential = $VaultCredential
DependsOn = '[CYA_Safe]WinRec50'
}
CYA_Account 'windowsAdmin50' {
Ensure = 'Present'
UserName = 'windowsAdmin50'
Address = 'iosharp.dev'
PlatformId = 'ioSHARPWindowsDomainAccount'
SafeName = 'WinAdmins50'
Name = 'windowsAdmin50@iosharp.dev'
ReconcileAccount = @{
Name = 'windowsReconcile50@iosharp.dev'
Safe = 'WinRec50'
Folder = 'root'
}
PvwaUrl = 'https://192.168.137.101'
AuthenticationType = 'LDAP'
SkipCertificateCheck = $true
Credential = $VaultCredential
DependsOn = '[CYA_Account]windowsReconcile50', '[CYA_Safe]WinAdmins50'
}
}
}
$ConfigData = @{
AllNodes = @(
@{
NodeName = 'localhost'
PSDscAllowDomainUser = $true
PSDscAllowPlainTextPassword = $true
}
)
}
$VaultCredential = New-Object System.Management.Automation.PSCredential('allison', (ConvertTo-SecureString 'Password!' -AsPlainText -Force))
$Password = New-Object System.Management.Automation.PSCredential('banana', (ConvertTo-SecureString 'P@$$W0RD12345' -AsPlainText -Force))
$ConfigurationParameters = @{
ConfigurationData = $ConfigData
PvwaUrl = 'https://192.168.137.101'
AuthenticationType = 'LDAP'
SkipCertificateCheck = $true
Credential = $VaultCredential
InitialPassword = $Password
}
CreateLab_Configuration @ConfigurationParameters
Compiling and running our configuration
We dot source our saved configuration file to compile it:
PS C:\Users\Tim.IOSHARP\Desktop\DSC> . .\CreateLab.ps1
Directory: C:\Users\Tim.IOSHARP\Desktop\DSC\CreateLab_Configuration
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 9/16/2022 7:43 PM 15494 localhost.mof
PS C:\Users\Tim.IOSHARP\Desktop\DSC>
We can use Test-DscConfiguration
to see if our resources in their desired state.
PS C:\Users\Tim.IOSHARP\Desktop\DSC> Test-DscConfiguration .\CreateLab_Configuration\ | Select-Object -ExpandProperty ResourcesNotInDesiredState | Select-Object ResourceId
ResourceId
----------
[ADUser]iosharp\windowsReconcile50
[ADUser]iosharp\windowsAdmin50
[ADGroup]Domain Admins
[CYA_Safe]WinRec50
[CYA_Safe]WinAdmins50
[CYA_SafeMember]WinRec\CyberArk Administrators
[CYA_SafeMember]WinAdmins\Windows Administrators
[CYA_Account]windowsReconcile50
[CYA_Account]windowsAdmin50
PS C:\Users\Tim.IOSHARP\Desktop\DSC>
No surprise, none of our resources are as they do not even exist.
From there, we can start the configuration using Start-DscConfiguration
and passing the Wait
parameter.
PS C:\Users\Tim.IOSHARP\Desktop\DSC> Start-DscConfiguration .\CreateLab_Configuration\ -Wait
PS C:\Users\Tim.IOSHARP\Desktop\DSC>
We do not get any output from Start-DscConfiguration
which is exactly what we want. Running Test-DscConfiguration
but this time looking at resources in the desired state shows us all nine of them.
PS C:\Users\Tim.IOSHARP\Desktop\DSC> Test-DscConfiguration .\CreateLab_Configuration\ | Select-Object -ExpandProperty ResourcesInDesiredState | Select-Object ResourceId
ResourceId
----------
[ADUser]iosharp\windowsReconcile50
[ADUser]iosharp\windowsAdmin50
[ADGroup]Domain Admins
[CYA_Safe]WinRec50
[CYA_Safe]WinAdmins50
[CYA_SafeMember]WinRec\CyberArk Administrators
[CYA_SafeMember]WinAdmins\Windows Administrators
[CYA_Account]windowsReconcile50
[CYA_Account]windowsAdmin50
PS C:\Users\Tim.IOSHARP\Desktop\DSC>
But what matters is what we see in CyberArk. Browsing to the PVWA, we see our two newly onboarded accounts in our newly created safes. windowsAdmin50
has windowsReconcile50
defined as it's reconcile just as we defined in our DSC configuration.
Changing existing Vault objects with PowerShell DSC
Our configuration creates the objects when they are missing but what happens if they already exist in some form?
We make small changes to our accounts -- change their names, unlink the reconcile account, different platform -- with the goal that running Start-DscConfiguration
will adjust them back to what is defined in our configuration.
A quick Test-DscConfiguration
shows that DSC knows the accounts in the Vault are incorrect based on the configuration:
PS C:\Users\Tim.IOSHARP\Desktop\DSC> Test-DscConfiguration .\CreateLab_Configuration\ | Select-Object -ExpandProperty ResourcesNotInDesiredState | Select-Object ResourceId
ResourceId
----------
[CYA_Account]windowsReconcile50
[CYA_Account]windowsAdmin50
PS C:\Users\Tim.IOSHARP\Desktop\DSC>
Simply running Start-DscConfiguration
'silently' adjusts the accounts in CyberArk to their desired configuration.
There we have it: the same configuration we used to create the Vault objects was used to correct them without having to do any changes.
The CyberArkDsc
module can be found on GitHub. Currently it only has resources for safes, safe memberships, and accounts. Pull requests are welcome!