SCRT-HQ / PSGSuite

Powershell module for Google / G Suite API calls wrapped in handy functions. Authentication is established using a service account via P12 key to negate the consent popup and allow for greater handsoff automation capabilities
https://psgsuite.io/
Apache License 2.0
234 stars 66 forks source link

P12 cert password #286

Closed FISHMANPET closed 4 years ago

FISHMANPET commented 4 years ago

OK, this would close #273

First of all, I did a bit of using the VSCode auto-formatting in EncryptionHelpers.ps1, as well as restyling it slightly to remove the backtick, and removing the (in my mind, unnecessary) commas. I can easily revert that if you'd like, or you can look at the diff with ignore whitespace option to see the actual code changes I made.

I added support for the JSONServiceAccountKey as I described in #273.

Set-PSGSuiteConfig will take a JSONServiceAccountKeyPath or just a JSONServiceAccountKey when creating a configuration, basically the same way that ClientSecrets can be used. While I was here I also modified the P12KeyPassword slightly. I in fact removed it from the switch statement entirely, because as written it wouldn't encrypt the password if a text string was passed in. It doesn't need any special handling, it just needs to be encrypted, so it can fall through to the Default action.

EncryptionHelpers now supports the JSONServiceAccountKey and Path. Additionally, it will try and pull some default values out of the JSONServiceAccount key if not specified, namely AppEmail and ClientID. I also fixed retrieving the ClientID from a ClientSecrets file, the client_id is inside the installed key in the clientsecrets JSON, so it wasn't actually grabbing that before. Finally I was thinking about I use a service account at work, where we've created a service account that isn't a super admin but essentially a user, just one that doesn't need to create and store a refresh token via web auth. So in our case the AppEmail read from the JSON file is identical to the AdminEmail. So if you specify a JSONServiceAccountKey, and don't specify an AdminEmail, it will default to the client_email/AppEmail. Like wise for ClientSecret accounts, there doesn't appear to be a case where AppEmail and AdminEmail would be different, or at the very least it's rare. So when you create a config with ClientSecrets you only need to include AdminEmail, then when the config is read, AppEmail will automatically be populated (the code was trying to read this from the client_secrets file, but there's no client_email in that file.

I also alluded to just bypassing all of this and just allowing the importing of a config as an Object (because the P12Object can't be serialized via JSON). So I modified Import-PSGSuiteConfig to accept a PSObject, as in the example I put there in the comment based help.

I also added some tests! My head was spinning trying to make sure I was setting the right values based on other values, so I wrote some tests to verify the implicit config values.

I'm opening this as a "draft" because as I was typing this up it occurred to me to try and run the results of Import-PSGSuiteConfig through Get-GSDecryptedConfig, so I want to play around with that a bit before I fully submit this.

FISHMANPET commented 4 years ago

"Decrypting" the imported configs was easy, so I did that and added some tests that will verify that the imported configs are being decrypted properly. This is now complete and ready for review

FISHMANPET commented 4 years ago

The impetus for this change, as well as the original efforts in this area, was to take advantage of secrets management within our automation platform (for us Azure Automation) without needing to rely on storing secrets locally on a machine or even depending on anything existing locally. There was already an example of doing that in the help file, so I don't think I've strayed too far from the "intent" of this cmdlet.

Also looking closely now at the Description of Import-PSGSuiteConfig and it talks about "unencrypted" though I am running the configs through Get-GSDecryptedConfig. In this case, I'm using it to take advantage of the value interpolation I've added to Get-GSDecryptedConfig, knowing that copying a Secure String from one machine to another won't actually be decryptable, but an unencrypted plaintext string passed through Get-GSDecryptedConfig will just filter through. So I've really overloaded Get-GSDecryptedConfig, maybe there's a way to pull apart the decryption and the interpolation to make it clearer what's happening. Is it even clear what's happening now? I have a tendency to accidentally write functional but "clever" code that can be hard to understand/maintain, so if you think this needs to be refactored to make it clearer, or even just documented more clearly, I'm open to that.