Joseph,
Interesting as I was able to make it a one step process.
Steps:
Master Account1. Create a master unix account - call it db2prov
2. Assign the ability for db2prov to "sudo passwd" and "sudo pwdadm" as NOPASS
3. Test elevated privs in CLI
3. Create pam credential object for db2prov in pam - assign it to use elevated privs
Subordinate accountsSAMPLE / EXAMPLE PowerShell Script (obfuscated and comments removed) to
1. Read in a list of credentials from a flat file C:\creds.txt
2. API: create a unix credential with a generated password
3. API: Assign a mater account to manage the credential
4. API: Synchronize with the authentication server
** NO WARRANTIES - USE AT OWN RISK ** LOL
$deviceId = '000' # ID of device (obtained via API)
$appId = '0000' #ID of dedicated application for subordinate accounts (obtained via API)
$PAM_viewPolicy = '0000' # ID of view policy (obtained via API)
$PAM_otheraccount = '0000' # ID of db2prov (obtained via API)
$pamServer = "foo.bar.com" # either FQDN or IP address
$pamServer = "0.0.0.0" # either FQDN or IP address
#
if (-not ([System.Management.Automation.PSTypeName]"TrustEverything").Type) {
Add-Type -TypeDefinition @"
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
public static class TrustEverything
{
private static bool ValidationCallback(object sender, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors) { return true; }
public static void SetCallback() { System.Net.ServicePointManager.ServerCertificateValidationCallback = ValidationCallback; }
public static void UnsetCallback() { System.Net.ServicePointManager.ServerCertificateValidationCallback = null; }
}
"@
} [TrustEverything]::SetCallback()
#
# prompt for an API key
#
if (-not $apikey) {$apikey = Get-Credential -Message "Enter your API key"}
#
# Run an API call to add a target account
#
ForEach ($line in Get-Content "C:\creds.txt")
{
$acctId = ''
write-host "Trying $line ...."
$newAcct = @{
accountName = "$line"
#aliasNames = ''
attributes = @{
verifyThroughOtherAccount = 'false'
otherAccount = $PAM_otheraccount
useOtherAccountToChangePassword = 'true'
passwordChangeMethod = 'USE_SUDO'
}
#cacheBehavior = 'noCache'
#cacheDuration = ''
#description1 = ''
#description2 = ''
password = '_generate_pass_'
passwordViewPolicyId = $PAM_viewPolicy
privileged = 't'
synchronize = 't'
useAliasNameParameter = 'f'}
$newAcct = ConvertTo-Json -InputObject $newAcct
$acctId = Invoke-RestMethod -Uri "https://$pamServer/api.php/v1/devices.json/$deviceId/targetApplications/$appId/targetAccounts" -Method Post -Body $newAcct -Credential $apikey -ContentType 'application/json'
If ($acctId -ne "") {write-host "Target Account id $acctId added"}
}
Original Message:
Sent: 03-20-2020 10:38 AM
From: Joseph Fry
Subject: PAM REST API - using synchronize = 't' and password ='_generate_pass_' together
Glad your figuring this stuff out Chris.
Just to expand on what Ralf was saying. You can use the API to generate a password for a stand alone account, but it's a two step process:
- Create the target account first with a known password.
- Update the target account with password = '_generate_pass_'
The two steps are necessary because the first one lets PAM know what the current password is, then the second says to use that password to change the password to the new randomized value.
This is exactly how you would do it in the UI as well.
Original Message:
Sent: 03-19-2020 09:44 PM
From: Chris Scott
Subject: PAM REST API - using synchronize = 't' and password ='_generate_pass_' together
Ralph,
It took some persistence - but I got it to work using separate account to set the password
$newAcct = @{
accountName = 'db2xxxxx
#aliasNames = ''
attributes = @{
verifyThroughOtherAccount = 'false'
otherAccount = '3001'
useOtherAccountToChangePassword = 'true'
passwordChangeMethod = 'USE_SUDO'
}
#cacheBehavior = 'noCache'
#cacheDuration = ''
description1 = 'API'
#description2 = ''
password = '_generate_pass_'
passwordViewPolicyId = '3001'
privileged = 't'
synchronize = 't'
useAliasNameParameter = 'f'
}
$newAcct = ConvertTo-Json -InputObject $newAcct
$acctId = Invoke-RestMethod -Uri "https://$pamServer/api.php/v1/devices.json/$deviceId/targetApplications/$appId/targetAccounts" -Method Post -Body $newAcct -Credential $apikey -ContentType 'application/json'
write-host "Target Account id $acctId added"
Original Message:
Sent: 03-19-2020 07:55 PM
From: Ralf Prigl
Subject: PAM REST API - using synchronize = 't' and password ='_generate_pass_' together
Hello Chris, This cannot possibly work for an account that manages its own password. For that you have to start by providing the current password. A newly generated password can work only when you use an existing account to update the new account's password.
Original Message:
Sent: 03-19-2020 07:16 PM
From: Chris Scott
Subject: PAM REST API - using synchronize = 't' and password ='_generate_pass_' together
$newAcct = @{
accountName = 'db2xxxxx'
#aliasNames = ''
#attributes = ''
cacheBehavior = 'noCache'
#cacheDuration = ''
description1 = 'API'
#description2 = ''
password ='_generate_pass_'
passwordViewPolicyId = '3001'
privileged = 't'
synchronize = 't'
useAliasNameParameter = 'f'
}
Using password ='_generate_pass_' and synchronize = 't' always generates an Error:
Invoke-RestMethod : {"error":{"code":400,"message":"Bad Request: PAM-CMN-0467: A Password Authority problem prevented completing the request.
Message: PAM-CM-1341: Failed to establish a communications channel to the remote host. AddTargetAccountCmd.invoke: Failed to verify password with target. Check log for details."}}