HBoPS #6: Handling Credentials

So if there is one thing that just annoys me, it’s when I have to handle credentials in PowerShell. Mind you, not the simple “call, use, discard” type of handling… Oh No… That’s easy! It’s when there’s a need to save credentials that things get tricky!

You see, I don’t like putting credentials anywhere. Because no matter what you do, you’re going to run in to issues. Which issue is acceptable, and how to make our code as secure as possible, is something we have to decide upon in a case-by-case basis.

Wait… What are you on about?

I just hear John’s voice (good old Irish buddy and former colleague of mine) whenever I utter these words.

The thing is that there are multiple ways of handling credentials when you’re writing PowerShell tools or controllers. Each of them have their limitations. Some you should never, ever do. And I do mean NEVER!

Well what are my options then?

I think we can summarize the options we have for handling credentials very simply:

  1. Store the credentials in the script itself (I will find you and hunt you down if you do this)
  2. Ask for credentials every time we perform an action that requires credentials
  3. Use Integrated Windows Authentication.
  4. Create an ACL protected file with our credentials
  5. Encrypt a file that contains our credentials

Obviously option 1 should be avoided at all cost… As I like to tell all my customers: “When listing your options, list all of them!”. Even doing nothing is an option. Not a good option, but an option none the less…

Using Integrated Windows Authentication

By far the most secure method of dealing with credentials is using IWA. Try to always use IWA where possibly. Also, I like the way IWA sounds….

The downside to using IWA is that it only is going to work if our resource is Active Directory aware, and in the same (or a trusting) Active Directory Domain. And it’s something that is more typically used with web services…

Creating password hash files

Storing credentials securely on disk is neat, and you can choose from 2 main methods when it comes to “encrypting” your credentials: AES and DPAPI

Now both AES and DPAPI have native suport in PowerShell, which means that it’s relatively easy to use both ways.

DPAPI

DPAPI encrypted data can only be decrypted by the same host (and same user profile) that encrypted it. This raises our confidentiality perspective, but lowers our usability since the data is not portable between machines. So any tasks that would require you to reuse the same set of credentials on multiple machines is going to require you to save the credentials before executing tasks.

How to do it

First of all we will need to retrieve our credentials:

$creds = get-credential

Our variable $Creds now contains a username (stored in clear text…) and a Password (stores as a Sytem.Security.SecureString).

Now you cannot go and export this Password to a file just yet. You have to convert the SecureString object to an Encrypted Standard String first!

$EncryptedString = $creds.Password | ConvertFrom-SecureString

And now you can export that $encryptedString:

$EncryptedString | Out-file <Path to file>

Or less lines:

$creds = get-credential 
$creds.Password | ConvertFrom-SecureString | Out-file <Path to file>

Returning it to a usable thing is fairly straightforward:

$User = "RandomUser@RandomCompany.com"
$Creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, (Get-Content | ConvertTo-SecureString)

Obviously this is not going to stop people who know what they’re doing in their tracks. It is better than storing your password in plain text, and that is something already…

Toolkits exist to decrypt DPAPI encrypted items, and they are freely available. Adding ACL to the file makes things a bit harder, but stil…

AES

AES on the other hand can be extremely portable, as you’ll be encrypting the password with a key you define. That does mean that it is also more vulnerable than DPAPI. You lose access to the key, you lose functionality. And even worse, someone gains access to the key, they can now decrypt your credentials! So properly secure this key and guard it with your life.

How to do it…

First we need a key:

$AESKey = New-Object Byte[] 32 [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESKey) 
$AESKey | out-file <Path to Key File>

Then we encrypt the password and write it to disk:

$creds.Password | ConvertFrom-SecureString -key $AESKey | Out-file <Path to file> 

Decrypting the key is as simple as 1,2,3:

$User = "RandomUser@RandomCompany.com"
$AESKey = Get-Content
$Creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, (Get-Content | ConvertTo-SecureString -key $AESKey)

Update:
On LinkedIn, Peter Rombouts pointed out we could also use Azure Key Vault for credential management. I will incorporate that in a future article.

https://docs.microsoft.com/en-us/azure/key-vault/

Index:
HBoPS #1: Use a proper editor!
HBoPS #2: Error handling and you!
HBoPS #3: Avoid using Write-Host (and save puppies!)
HBoPS #4: Variables, Parameters, and Battlestar Galactica
HBoPS #5: Reduce, Reuse, Recycle
HBoPS #6: Handling Credentials

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Close Menu
%d bloggers like this: