In this post I plan to continue on from my earlier post on Secure Authentication of Azure Resource Management Deployments to show how to control access to Azure KeyVault from a PowerShell script. A lot of this set up can be done from the Azure Portal and using tools like makecert.exe as was done in that earlier post, but to really have full, stand-alone automation we will want to replace tools like makecert.exe with some techniques that do not pop up password dialogs or require similar blocking user interaction. There are a lot of details to consider so I’ll break this up into a few simpler parts and try to tie it all together at the end.
1. Automating Secure Password Generation
If you are just wanting to generate secure passwords, a great tool is PWGen for Windows. But as mentioned already, in the case of automation we don’t want to block the process with a UI requiring direct user interaction. To do this with PowerShell — or any other .Net language — we might be tempted to try the built-in Random Class. In many cases this is good enough, but to secure your authentication with Azure — or especially with KeyVault where you will be store secrets and keys — you want to be as secure as possible. So let’s consider some general good rules of thumb to apply:
- Use a password that is long enough. With the increasing speed of processors and greater availability of distributed computing, we will need a password long enough so a brute-force attack won’t figure out your password in a reasonably short amount of time. There are many tools online that can easily analyse and show the approximate amount of computing power needed to break your password. I find this one is simple and gives you quick and clear results. Common techniques like character substitutions do not add much security. What we quickly see with these analyzers is that length is often a more significant factor in making your password hard to break. As of April, 2016 I generally consider a 16 character password to be long enough, but this may have to increase again in a year or two. Also note that if you are just protecting a short-lived resource like a certificate (e.g. as in the previous article) you may easily get away with a shorter password.
- Avoid Dictionary Words. Even with long passwords, using plain dictionary word or words altered with character substitution is still not optimal. The online password analyzers do not highlight the fact that use of dictionary words and character substitutions can very greatly reduce the search space that a brute-force attack must cover.
- Store your password securely. Some people will go to great lengths to create secure passwords and then, because it is hard to remember, write it down on a sticky note (or a close electronic, plain-text equivalent). Or worse still, they will keep it secure but then share it with a co-worker over unencrypted email or similar communication. There are simple solutions to these issues. Use a password manager. There are too many to list, but I’ll mention a free/open-source, cross-platform password manager that I often use called KeePass. Password managers require you to memorize just one secure password (the one for the password manager db) that will give you access to the rest. Similarly, if you have to share a password or any other secure information with a co-worker, then you should encrypt your email or other communications: GPG and OpenPGP supply simple tools to encrypt files, emails, and other data using (asymmetric) Public-Key Cryptography.
- Maximize Entropy. Information Theory introduces a concept called Shannon Entropy which is analogous to the entropy many people learned about in physics and thermodynamics. Though this is a very interesting topic I won’t waste any time here except to say that for a given set of data there is a measurable (calculable) amount of entropy associated with it. By maximizing the entropy in a set of information your are effectively optimizing the randomness and making it harder for brute-force attacks to extract the underlying information.
So how do we maximize entropy? Various OS’es (and hardware) try to capture entropy from sources of randomness atached to them. Linux, BSD, and many other *nix Os’es have a kernel entropy pool, often attached to /dev/random. These entropy pools gather randomness or entropy from several sources in the system. Even tools like PWGen will gather entropy from random mouse movements. For Windows and .Net we have the RNGCryptoServiceProvider which does a much better job of maximizing entropy (i.e. randomness) compared to the simpler .Net Random Class. RNGCryptoServiceProvider is even secure enough to comply with the U.S. Government FIP-140 standard.
So how do we use this?
Here is a simple PowerShell function that takes a single parameter, the password character length (defaulting to 16) and returns a secure password from the RNGCryptoServiceProvider:
function New-SecurePassword { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $false)] [Int]$PasswordLength = 16 ) $lowerCase = [Char[]]([Char]'a'..[Char]'z') $upperCase = [Char[]]([Char]'A'..[Char]'Z') $digits = [Char[]]([Char]'0'..[Char]'9') $validPunctuation = [Char[]]'!.-+*^_' $validCharacters = $lowerCase + $upperCase + $digits + $validPunctuation $bytes = New-Object -TypeName 'System.Byte[]' -ArgumentList $PasswordLength $cryptoRNG = New-Object -TypeName 'System.Security.Cryptography.RNGCryptoServiceProvider' $cryptoRNG.GetBytes($bytes) $newPassword = '' foreach ($rndByte in $bytes) { $newPassword += $validCharacters[($rndByte % $validCharacters.Length)] } $newPassword }
Note that here I am breaking up which characters are allowed in your password into upper and lower case (Latin alphabet) characters, decimal digits 0-9, and a collection of permitted punctuation characters. There are some punctuation characters that I’ve deliberately left out by personal preference because they may cause difficulty if you store passwords in XML or similar markup. Feel free to add or remove punctuation characters, but keep in mind that the more permitted characters used may effectively increase the search space required for a brute-force attack. You may even be able to add some extra, non-ASCII characters in there, but in many cases the system you are authenticating against may not permit them (I haven’t tried this so I don’t know what Azure allows, or other tools used later on in this series).
I’ll use this function in my next post in which I’ll demonstrate the next step: automating certificate generation. To facilitate this I’ll typically put commonly used PowerShell functions like this in a module so it can be easily reused for different purposes.