DEV Community

Discussion on: Automate password rotation with GitHub and Azure (Part 1)

Collapse
 
polar profile image
Info Comment hidden by post author - thread only visible in this permalink
Polar Humenn • Edited

Okay, that is all well and good policy from the top down 11,000ft view. I urge you to think of your approach and think critically about it, and think about its threats. Basically, write the argument against your approach. Here is one such threat, which can easily be demonstrated.

Get-Random -SetSeed 1234
([char[]]([char]33..[char]95) + ([char[]]([char]97..[char]126)) + 0..9 | sort-object {Get-Random})[0..15] -join ''
([char[]]([char]33..[char]95) + ([char[]]([char]97..[char]126)) + 0..9 | sort-object {Get-Random})[0..15] -join ''
([char[]]([char]33..[char]95) + ([char[]]([char]97..[char]126)) + 0..9 | sort-object {Get-Random})[0..15] -join ''
Enter fullscreen mode Exit fullscreen mode

Run it a few times and examine the results.
This attack is one of the most common.

Thread Thread
 
pwd9000 profile image
Info Comment hidden by post author - thread only visible in this permalink
Marcel.L • Edited

I'm not entirely sure why you are setting a seed on get-random in the above demonstration. Using SetSeed will result in non-random behaviour.
In the absence of -SetSeed parameter, Get-Random takes its seed from the cryptographic RandomNumberGenerator from the System.Security.Cryptography Namespace. So I am unclear on exactly what threat you mean? Perhaps you could go a bit more into detail?

Thread Thread
 
polar profile image
Info Comment hidden by post author - thread only visible in this permalink
Polar Humenn • Edited

Okay, I set the seed in Get-Random to make the specific point: to realize that once you have a seed for Get-Random then the results are repeatable, or predictable. That is why I said to run several times. I know you would not intentionally put the -SetSeed in the script, of course, except maybe for testing.

That being said, it is documented that Get-Random gets its initial seed from the system clock. Given that your script is scheduled at regular intervals, an attacker can guess the seed range and using a brute force attack can generate the passwords. With that approach, they may have the passwords before you do! Once they find the first one, they have all the others with this approach.

One of the common problems concerning encryption cracking, historically, has been with the use of a random number generator.

The thing is to think "outside the box". Sorry, I am an old professor. The hackers do not play by the rules, but exploit misconceptions or flaws in the system fundamentals that are applied without critical view.

Thread Thread
 
pwd9000 profile image
Info Comment hidden by post author - thread only visible in this permalink
Marcel.L • Edited

You have a great point there.

I have updated the code with a fix by adding an additional step using the system.web assembly to generate a random 64charset and using that set of which get-random can derive from.

- name: Generate Random Char Set using System.Web Assembly and set environment
      shell: powershell
      run: |
        [system.reflection.assembly]::LoadWithPartialName("System.Web")
        [String]$random = [System.Web.Security.Membership]::GeneratePassword(64, 32)
        echo "RANDOM_CHAR_SET=$random" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
Enter fullscreen mode Exit fullscreen mode

deriving the password from the random set:

$passwordGen = ("$${{ env.RANDOM_CHAR_SET }}" | sort {Get-Random})[0..15] -join ''
Enter fullscreen mode Exit fullscreen mode

This way even if an attacker could potentially guess the seed value there would be no way to be able to tell what charset or what positional chars were used to come to the concluded password as each of the password charsets would have been randomized each time the worflow ran.

You can also test this technique by running:

Get-Random -SetSeed 1234
[system.reflection.assembly]::LoadWithPartialName("System.Web")
[String]$random = [System.Web.Security.Membership]::GeneratePassword(64, 32)
($random | sort {Get-Random})[0..15] -join ''
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
polar profile image
Info Comment hidden by post author - thread only visible in this permalink
Polar Humenn • Edited

Better, but basically this is the same thing, only adding an extra level of obscurity/complexity. I do not have the time to do a full analysis, but cursory view says that GeneratePassword has its issues as well.

poshhelp.wordpress.com/2017/01/30/...

And then there are the possible vulnerabilities depending on how you operationally deploy this job. Think about how environment variables may be injected or monitored. You are writing the environment variable to a file, correct? Also, there are other things to think about. You have a "centralized" approach.

   "This solution adds an additional layer of protection to virtual machines, is centrally managed and cost effective."
Enter fullscreen mode Exit fullscreen mode

To us computer security geeks, this means "single point of failure" or "single point of attack". Think about what can happen if you could intercept or disrupt the connection to your Azure cred vault. It is a web service after all. Furthermore, this is how ransomware tasks are actually happening, getting the admin credentials using out-of-band methods such as social engineering/phishing, or phone attacks, etc. You get that password, and you have got everything. Think about how you might mitigate that attack.

Do not get me wrong, I do not practice what I preach, because personally I use a password manager, which bothers me to no end, but damn, I cannot remember a new password that I have not used for 4 decades. :P

The professor just wants me to tell you to not stop thinking about how you can attack your solution. Assume your attacker has the code (which at this point, they do). For example, I presented this issue, and you made your approach better. Keep going!
Good Luck Marcel!

Thread Thread
 
pwd9000 profile image
Info Comment hidden by post author - thread only visible in this permalink
Marcel.L • Edited

Thank you for the feedback and pointing out the risks with Get-Random seed value. :)

The workflow env variable in this case is short lived and only used for randomizing the charset at each run, (not the actual password). You could also even use a GitHub secret for the randomized charset instead of an environment variable if you chose to do so, but would need to be rotated manually. Or push the randomized charset to the key vault and pulling it back in as a key vault secret on the main step. There are a few alternatives here to pick from.
The Github actions runner also only exists for the time of the run of the workflow as we are using github-hosted runners and is then destroyed.

Another thing to also bear in mind is that the tutorial to demonstrate this automation is published on a public GitHub repository for reasons to share knowledge, in practise, if anyone adopts this sort of automation process they would likely use a private or internally hosted repo and not expose the source code or actions workflows publicly (unless they chose to) with only authorised users working on the repo source code.

Azure key vault is also pretty flexible as well in how you can deploy, use and configure secrets management centrally and securely. Especially from the operational side and also making use of private endpoints so that the key vault is not exposed to the public internet or using the firewall and networking features to limit what external services can connect to the vault.

There’s also the topic of permissions, allowing and managing access to the azure key vault only to authorised identities and users using role based access controls or Access Policies. Some of these topics are a bit out of scope for this tutorial but I would recommend reading up on some of the features and security of azure key vault if you’re interested: Azure Key Vault

Some comments have been hidden by the post's author - find out more