modules/Definitions/Google.Entro.psm1
|
Set-StrictMode -Version Latest function Import-EntroGcpWizardModules { $wizardRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent $modRoot = Join-Path $wizardRoot 'modules' # -Global: the step Run blocks call these from a different scope, and ISC.EntroGcp # resolves Invoke-GCloud (exported by ISC.GoogleWorkspaceConnector) via Get-Command. # Every step calls this, so a loaded module is kept: re-importing would replace an Invoke-GCloud the caller already set up. if (-not (Get-Command Invoke-GCloud -ErrorAction SilentlyContinue)) { Import-Module (Join-Path $modRoot 'ISC.GoogleWorkspaceConnector.psm1') -Force -Global -WarningAction SilentlyContinue Initialize-GoogleWorkspaceConnectorData } if (-not (Get-Module -Name 'ISC.EntroGcp')) { Import-Module (Join-Path $modRoot 'ISC.EntroGcp.psm1') -Force -Global -WarningAction SilentlyContinue } } function Get-EntroGcpWizardReportPath { param([hashtable]$Context) $base = if ($Context['OutputDirectory']) { $Context['OutputDirectory'] } else { Get-Location } Join-Path $base 'entro-gcp-report.md' } function Get-EntroGcpServiceAccountName { param([hashtable]$Context) if ($Context['ServiceAccountName']) { return [string]$Context['ServiceAccountName'] } 'entro-automatic-onboard' } function Get-EntroGcpWizardStateDirectory { param([hashtable]$Context) if ($Context['IntegrationFolderPath']) { return [string]$Context['IntegrationFolderPath'] } if ($Context['OutputDirectory']) { return [string]$Context['OutputDirectory'] } return (Get-Location).Path } function Get-EntroGcpServiceAccountKeyPath { param([hashtable]$Context) Join-Path (Get-EntroGcpWizardStateDirectory -Context $Context) 'entro-reader-key.json' } function Get-EntroGcpServiceAccountKeyStep { @{ Id = 'key' Title = 'Service account key' Kind = 'Ensure' Probe = { param($c) Import-EntroGcpWizardModules $name = Get-EntroGcpServiceAccountName -Context $c $path = Get-EntroGcpServiceAccountKeyPath -Context $c $email = "$name@$($c['ProjectId']).iam.gserviceaccount.com" if (Test-EntroGcpServiceAccountKeyFile -Path $path -Email $email) { Invoke-EntroGcpEnsureServiceAccountKey -ProjectId $c['ProjectId'] -ServiceAccountName $name -KeyPath $path -Context $c 'Skip' } else { 'Create' } } Run = { param($c) Import-EntroGcpWizardModules $name = Get-EntroGcpServiceAccountName -Context $c return Invoke-EntroGcpEnsureServiceAccountKey -ProjectId $c['ProjectId'] -ServiceAccountName $name ` -KeyPath (Get-EntroGcpServiceAccountKeyPath -Context $c) -Context $c } BuildScript = { param($c) $sa = Get-EntroGcpServiceAccountName -Context $c $keyPath = (Get-EntroGcpServiceAccountKeyPath -Context $c) -replace "'", "''" @" Import-Module (Join-Path `$PSScriptRoot 'modules/ISC.GoogleWorkspaceConnector.psm1') -Force Import-Module (Join-Path `$PSScriptRoot 'modules/ISC.EntroGcp.psm1') -Force Initialize-GoogleWorkspaceConnectorData Invoke-EntroGcpEnsureServiceAccountKey -ProjectId '$($c['ProjectId'])' -ServiceAccountName '$sa' -KeyPath '$keyPath' "@ } } } function Get-EntroGcpOperatorHandoffStep { param([hashtable]$Context) $sa = Get-EntroGcpServiceAccountName -Context $Context $project = [string]$Context['ProjectId'] $account = "$sa@$project.iam.gserviceaccount.com" if ($Context['Method'] -eq 'WorkloadIdentity') { return @{ Id = 'wif' Title = 'Workload Identity handoff' Kind = 'Manual' Manual = "Create the Workload Identity pool and provider Entro documents, then upload the WIF JSON and the organization domain in Entro GCP onboarding. This run does not create a private key for $account." } } $keyPath = Get-EntroGcpServiceAccountKeyPath -Context $Context return @{ Id = 'entro-upload' Title = 'Upload the key in Entro' Kind = 'Manual' Manual = "Upload '$keyPath' and the organization domain in Entro GCP onboarding." When = { param($c) if (-not (Get-Command Get-EntroGcpRunRecord -ErrorAction SilentlyContinue)) { return $true } $record = Get-EntroGcpRunRecord -Context $c return [string]$record.KeyResult -ne 'Blocked by organization policy' } } } function Register-GoogleEntroDefinitions { Register-IntegrationWizardDefinition @{ Id = 'google-gcp-entro' Platform = 'GoogleCloud' Product = 'Entro' CoreSwitch = 'GcpEntro' CliName = 'gcloud' Title = 'Entro Google GCP organization integration' FolderName = 'Entro-GCP' AccessLevels = @() AdminRoles = @('Organization admin') OutputsHelp = 'Upload private key JSON or WIF JSON and organization domain in Entro GCP onboarding.' Inputs = @( @{ Name = 'OrganizationId'; Source = 'Discover'; Prompt = 'Organization ID'; Purpose = 'Google Cloud organization'; Required = $true } @{ Name = 'ProjectId'; Source = 'Discover'; Prompt = 'Host project ID'; Purpose = 'Host project'; Required = $true } @{ Name = 'Method'; Source = 'Supply'; Prompt = 'Auth method'; Purpose = 'PrivateKey or WorkloadIdentity'; Required = $true; ValidateSet = @('PrivateKey', 'WorkloadIdentity'); Default = 'PrivateKey' } @{ Name = 'ServiceAccountName'; Source = 'Supply'; Prompt = 'Service account name'; Purpose = 'Entro SA id'; Required = $false; Default = 'entro-automatic-onboard' } ) Steps = { param($ctx) $keyStep = if ($ctx['Method'] -eq 'WorkloadIdentity') { $null } else { Get-EntroGcpServiceAccountKeyStep } $all = @( @{ Id = 'precheck' Title = 'Pre-onboarding check' Kind = 'Ensure' Run = { param($c) Import-EntroGcpWizardModules Invoke-EntroGcpPreOnboardingCheck -ReportPath (Get-EntroGcpWizardReportPath -Context $c) -Context $c } BuildScript = { param($c) $report = Get-EntroGcpWizardReportPath -Context $c @" Import-Module (Join-Path `$PSScriptRoot 'modules/ISC.GoogleWorkspaceConnector.psm1') -Force Import-Module (Join-Path `$PSScriptRoot 'modules/ISC.EntroGcp.psm1') -Force Initialize-GoogleWorkspaceConnectorData Invoke-EntroGcpPreOnboardingCheck -ReportPath '$($report -replace "'", "''")' "@ } } @{ Id = 'apis' Title = 'Enable APIs' Kind = 'Ensure' Run = { param($c) Import-EntroGcpWizardModules Invoke-EntroGcpEnableApis -OrganizationId $c['OrganizationId'] -ProjectId $c['ProjectId'] -Mode 'apply' -Context $c Invoke-EntroGcpEnableApis -OrganizationId $c['OrganizationId'] -ProjectId $c['ProjectId'] -Mode 'verify' -Context $c } BuildScript = { param($c) @" Import-Module (Join-Path `$PSScriptRoot 'modules/ISC.GoogleWorkspaceConnector.psm1') -Force Import-Module (Join-Path `$PSScriptRoot 'modules/ISC.EntroGcp.psm1') -Force Initialize-GoogleWorkspaceConnectorData Invoke-EntroGcpEnableApis -OrganizationId '$($c['OrganizationId'])' -ProjectId '$($c['ProjectId'])' -Mode apply Invoke-EntroGcpEnableApis -OrganizationId '$($c['OrganizationId'])' -ProjectId '$($c['ProjectId'])' -Mode verify "@ } } @{ Id = 'sa-create' Title = 'Create Entro reader service account' Kind = 'Ensure' Probe = { param($c) Import-EntroGcpWizardModules $name = Get-EntroGcpServiceAccountName -Context $c if (Test-EntroGcpServiceAccountExists -ProjectId $c['ProjectId'] -ServiceAccountName $name) { Invoke-EntroGcpEnsureServiceAccount -ProjectId $c['ProjectId'] -ServiceAccountName $name -Context $c 'Skip' } else { 'Create' } } Run = { param($c) Import-EntroGcpWizardModules Invoke-EntroGcpEnsureServiceAccount -ProjectId $c['ProjectId'] -ServiceAccountName (Get-EntroGcpServiceAccountName -Context $c) ` -StateDirectory (Get-EntroGcpWizardStateDirectory -Context $c) -Context $c } BuildScript = { param($c) $sa = Get-EntroGcpServiceAccountName -Context $c @" Import-Module (Join-Path `$PSScriptRoot 'modules/ISC.GoogleWorkspaceConnector.psm1') -Force Import-Module (Join-Path `$PSScriptRoot 'modules/ISC.EntroGcp.psm1') -Force Initialize-GoogleWorkspaceConnectorData Invoke-EntroGcpEnsureServiceAccount -ProjectId '$($c['ProjectId'])' -ServiceAccountName '$sa' "@ } } @{ Id = 'iam' Title = 'IAM grants' Kind = 'Ensure' Probe = { param($c) Import-EntroGcpWizardModules $sa = Get-EntroGcpServiceAccountName -Context $c if (Test-EntroGcpIamGrantsComplete -OrganizationId $c['OrganizationId'] -ProjectId $c['ProjectId'] -ServiceAccountName $sa) { Sync-EntroGcpIamReport -OrganizationId $c['OrganizationId'] -ProjectId $c['ProjectId'] ` -ServiceAccountName $sa -StateDirectory (Get-EntroGcpWizardStateDirectory -Context $c) -Context $c 'Skip' } else { 'Apply' } } Run = { param($c) Import-EntroGcpWizardModules $sa = Get-EntroGcpServiceAccountName -Context $c Invoke-EntroGcpIamGrants -OrganizationId $c['OrganizationId'] -ProjectId $c['ProjectId'] ` -ServiceAccountName $sa -StateDirectory (Get-EntroGcpWizardStateDirectory -Context $c) -Context $c -Mode 'apply' } BuildScript = { param($c) $sa = Get-EntroGcpServiceAccountName -Context $c $stateDir = (Get-EntroGcpWizardStateDirectory -Context $c) -replace "'", "''" @" Import-Module (Join-Path `$PSScriptRoot 'modules/ISC.GoogleWorkspaceConnector.psm1') -Force Import-Module (Join-Path `$PSScriptRoot 'modules/ISC.EntroGcp.psm1') -Force Initialize-GoogleWorkspaceConnectorData Invoke-EntroGcpIamGrants -OrganizationId '$($c['OrganizationId'])' -ProjectId '$($c['ProjectId'])' -ServiceAccountName '$sa' -StateDirectory '$stateDir' -Mode apply "@ } } $keyStep (Get-EntroGcpOperatorHandoffStep -Context $ctx) @{ Id = 'audit' Title = 'Org audit logs' Kind = 'Ensure' Probe = { param($c) Import-EntroGcpWizardModules if (Test-EntroGcpAuditConfigsComplete -OrganizationId $c['OrganizationId']) { $record = Get-EntroGcpRunRecord -Context $c if ($record) { $record.AuditResult = 'Already in place' } 'Skip' } else { 'Apply' } } Run = { param($c) Import-EntroGcpWizardModules Invoke-EntroGcpAuditConfigs -OrganizationId $c['OrganizationId'] -Context $c } BuildScript = { param($c) @" Import-Module (Join-Path `$PSScriptRoot 'modules/ISC.GoogleWorkspaceConnector.psm1') -Force Import-Module (Join-Path `$PSScriptRoot 'modules/ISC.EntroGcp.psm1') -Force Initialize-GoogleWorkspaceConnectorData Invoke-EntroGcpAuditConfigs -OrganizationId '$($c['OrganizationId'])' "@ } } ) $kept = [System.Collections.Generic.List[object]]::new() foreach ($item in $all) { if ($null -ne $item) { $kept.Add($item) } } return @($kept) } OnRunComplete = { param($ctx) Import-EntroGcpWizardModules $record = Get-EntroGcpRunRecord -Context $ctx $record.Finished = $true if ($ctx['Method']) { $record.Method = [string]$ctx['Method'] } if (-not $record.OrganizationId -and $ctx['OrganizationId']) { $record.OrganizationId = [string]$ctx['OrganizationId'] } if (-not $record.ProjectId -and $ctx['ProjectId']) { $record.ProjectId = [string]$ctx['ProjectId'] } $sa = Get-EntroGcpServiceAccountName -Context $ctx if (-not $record.ServiceAccountEmail -and $ctx['ProjectId']) { $record.ServiceAccountEmail = "$sa@$($ctx['ProjectId']).iam.gserviceaccount.com" } $pending = @() $platform = if ($ctx['IntegrationPlatformTitle']) { [string]$ctx['IntegrationPlatformTitle'] } else { 'Google Cloud' } $section = "$platform / Entro GCP" if (-not (Get-Command Save-IntegrationProjectOperatorAction -ErrorAction SilentlyContinue)) { Import-Module (Join-Path (Split-Path $PSScriptRoot -Parent) 'IW.Project.psm1') -WarningAction SilentlyContinue } $blockedActions = [System.Collections.Generic.List[hashtable]]::new() if ($record.KeyGuidance) { $blockedActions.Add(@{ Section = $section Id = 'key-policy' Title = 'Allow the service account key' Detail = 'Google returned FAILED_PRECONDITION. Follow "How to clear this precondition" in entro-gcp-report.md, rerun the wizard, then upload the key file and the organization domain in Entro.' Done = $false }) } foreach ($item in @($record.Blocked)) { $blockedActions.Add(@{ Section = $section; Id = [string]$item.Id; Title = [string]$item.Title; Detail = [string]$item.Detail; Done = $false }) } if ($ctx['IntegrationProjectName'] -and (Get-Command Save-IntegrationProjectOperatorAction -ErrorAction SilentlyContinue)) { foreach ($action in $blockedActions) { Save-IntegrationProjectOperatorAction -ProjectName ([string]$ctx['IntegrationProjectName']) -Action $action } } if ($ctx['IntegrationProjectName'] -and (Get-Command Read-IntegrationProjectOperatorActions -ErrorAction SilentlyContinue)) { $pending = @(Read-IntegrationProjectOperatorActions -ProjectName ([string]$ctx['IntegrationProjectName']) | Where-Object { $_.Section -eq $section }) } if ($pending.Count -eq 0) { $pending = @($blockedActions) if (-not $record.KeyGuidance) { $handoff = Get-EntroGcpOperatorHandoffStep -Context $ctx $pending = @(@{ Title = $handoff.Title; Detail = $handoff.Manual; Done = $false }) + $pending } } Write-EntroGcpRunReport -Context $ctx -Path (Get-EntroGcpWizardReportPath -Context $ctx) -Pending $pending } } Register-IntegrationWizardDefinition @{ Id = 'google-workspace-entro' Platform = 'GoogleCloud' Product = 'Entro' CoreSwitch = 'WorkspaceEntro' CliName = 'gcloud' Title = 'Entro Google Workspace integration' FolderName = 'Entro-Workspace' AccessLevels = @() AdminRoles = @('Google Workspace super admin for domain-wide delegation') OutputsHelp = 'Paste Client ID and service account key JSON in Entro Workspace onboarding.' Inputs = @( @{ Name = 'ClientId'; Source = 'Supply'; Prompt = 'OAuth client ID'; Purpose = 'Workspace admin console'; Required = $true } ) Steps = { param($ctx) @( @{ Id = 'dwd' Title = 'Domain-wide delegation' Kind = 'Manual' Manual = 'In Google Workspace Admin → Security → API controls, authorize the service account Client ID with Drive scopes documented by Entro.' } ) } } } Export-ModuleMember -Function Register-GoogleEntroDefinitions |