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

Improved P12 handling #255

Closed FISHMANPET closed 4 years ago

FISHMANPET commented 4 years ago

This isn't fully ready to be merged, but I wanted to open this PR to see how you feel about these changes.

I'm trying to migrate from a Google API module my team has written, UMN-Google, to this module. Our primary use case is running from within Azure Automation. Additionally, We're currently using a service account with a .p12 cert to do all our authentication, though our .p12 isn't a super admin, it's just a "regular" user in our domain. Additionally, when we first created our .p12 cert we re-exported it with a new more secure password, instead of notasecret.

So the first change I've made here is to create a P12KeyPassword config item. It can be specified with Set-PSGSuiteConfig. If it exists, New-GoogleService will use it instead of the default password. I've constructed it in the way I have such that, if someone doesn't use this parameter, they'll never see it in their config. This also makes it backwards compatible with existing configs, and doesn't require anything like setting the notasecret password in every config file.

The rest of the changes are because of our primary use case, Azure Automation. First I'll note that I wrote the rest of this before I saw the Import and Export Config commands. So it's entirely possible I could be using those, but at a first glance I don't think they'd fully work in my scenario.

Azure Automation has its own secrets management. It can store/retrieve strings. It can also store/retreive a few object types, like PSCredential and X509Certificate2. Because we do all our secrets management in Azure Automation directly, I don't want to have to do any work to store my configuration on the actual machine, and make the deployment of new HybridRunbookWorkers as simple and automated as possible.

So first, I've modified the Get-PSGsuiteConfig function, specifically the internal Decrypt function. Now it will "decrypt" one additional datatype, a ScriptBlock. It does this by actually executing the ScriptBlock, which makes the configuration incredibly versatile. I haven't modified the corresponding Set command for this, because I think it may be advanced enough that someone should have to edit their Configuration by hand if they want to do it.

In Azure Automation if I want to retrieve a string value, I would use the command Get-AutomationVariable -Name <name>. For example if I stored my App Email in a variable called gcert-email then Get-AutomationVariable -Name 'gcert-email' in a runbook would return the App Email. Then I can do something like this in my Configuration, making it fully portable:

AppEmail = (ScriptBlock "Get-AutomationVariable -Name 'gcert-email'")

The ScriptBlock construction here is a feature of the Configuration module, when it deseralizes this, the AppEmail property will be an actual ScriptBlock

To Decrypt this I added another case, if the $String being decrypted is of type [ScriptBlock] it will execute it and return whatever it returns. In my case it will return an actual string, so the end result is the AppEmail config item is being set and defined by my Azure Automation Variable.

Azure Automation can also produce exportable passwordless certificates, in the same format as your certificate construction code currently takes. So I've added another config that can be retreived with Get-PSGsuiteConfig, P12KeyObject. If P12KeyObject is defined, New-GoogleService will skip trying to write the bytes of the password protected cert, and skip creating the certificate object, and just use the value of P12KeyObject directly.

The end result of all this is I can write a config file that looks like this:

@{
  aaservice = @{
    ConfigPath = 'C:\ProgramData\powershell\SCRT HQ\PSGSuite\Configuration.psd1'
    AppEmail = (ScriptBlock "Get-AutomationVariable -Name 'gcert-email'")
    AdminEmail = (ScriptBlock "Get-AutomationVariable -Name 'gcert-email'")
    P12KeyObject = (ScriptBlock "Get-AutomationCertificate -Name 'gcert'")
  }
  DefaultConfig = 'aaservice'
}

I've been able to test this in my environment, but that's the extent of testing I've done. I'm opening this to see what you think about this, to determine if I'll put more work into making it merge ready.

scrthq commented 4 years ago

This is great @FISHMANPET !!! Thank you! I'll review it, but I don't see any issues with it so long as it doesn't introduce any bugs to existing users.

scrthq commented 4 years ago

@FISHMANPET - Loving this. The only feedback I have is that JSONServiceAccountKeyPath seems to me to be the same as ClientSecretsKeyPath (intended for the client_secrets.json file that you'd normally use when setting up other tools like GAM). Is there a different use case for that config value or is this a potential docs issue?

image

scrthq commented 4 years ago

Made some adjustments, getting this merged in for now :-)