Framework/Configurations/Migration/PolicyMigration.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
Set-StrictMode -Version Latest

class PolicyMigrationHelper 
{
    static [string] $PolicyRGName
    static [string] $NewPolicyRGName
    static [void] StartMigration([SubscriptionContext] $subscriptionContext, [PSObject] $PolicyInstance, [PSObject] $OPolicyInstance)
    {
        [PSObject] $MigrationOutput = @{}
        [bool] $ErrorOccurred = $false;
        #Prepar Policy RG Name

        [PolicyMigrationHelper]::PolicyRGName = $OPolicyInstance.ResourceGroupName;
        [PolicyMigrationHelper]::NewPolicyRGName = $PolicyInstance.ResourceGroupName;

        #region Step 1: Validate if Policy Exists
        if(-not [PolicyMigrationHelper]::MigrationPrerequisiteCheck())
        {                
            return
        }
        #endregion

        #region Step 2: Get meta data for existing policy
        Write-Host ([Constants]::DoubleDashLine + "`r`nUpdating your current Org policy with latest AzSK resources...`r`n" + [Constants]::DoubleDashLine) -ForegroundColor Cyan;

        #region clear any existing locks
        try
        {
            Write-Host ("Checking if there are any resource locks on old Org policy resource group...") -ForegroundColor Yellow;

            $azskRGScope = "/subscriptions/$($subscriptionContext.SubscriptionId)/resourceGroups/$([PolicyMigrationHelper]::PolicyRGName)"
            $resourceLocks = @();
            $resourceLocks += Get-AzureRmResourceLock -Scope $azskRGScope -ErrorAction Stop
            if($resourceLocks.Count -gt 0)
            {
                $resourceLocks | ForEach-Object {
                    Remove-AzureRmResourceLock -LockId $_.LockId -Force
                }
                Write-Host ("Successfully removed the locks on old Org policy resource group.") -ForegroundColor Green;
            }
            else
            {
                Write-Host ("No locks found on old Org policy resource group.") -ForegroundColor Green;
            }
            $MigrationOutput.LockRemoval = "Success"
        }
        catch
        {
            Write-Host "An error occurred during removal of locks on old Org policy resource group: [$([PolicyMigrationHelper]::PolicyRGName)]" -ForegroundColor Red
            $MigrationOutput.LockRemoval = "Failed. Message[$_]"
            $ErrorOccurred = $true;
            throw;
        }
        #endregion
        #endregion

        #region capture the existing information
        $oldResourceGroupLocation = [ConfigurationManager]::GetAzSKConfigData().AzSKLocation;
        try
        {
            Write-Host ("Extracting policy files from old Org policy resources...") -ForegroundColor Yellow;

            $oldRg = Get-AzureRmResourceGroup -Name $([PolicyMigrationHelper]::PolicyRGName) -ErrorAction SilentlyContinue
            if($oldRg)
            {
                $oldResourceGroupLocation = $oldRg.Location;                    
            }
            
            #region extract storage policies
                $storageAccounts = @();
                $storageAccounts += Get-AzureRmStorageAccount -ResourceGroupName $([PolicyMigrationHelper]::PolicyRGName) -ErrorAction SilentlyContinue;
                $storageAccounts = $storageAccounts | Where-Object { $_.StorageAccountName -like "$([OldConstants]::StorageAccountPreName)*" } ;
                if(($storageAccounts | Measure-Object).Count -ne 1)
                {
                    return;
                }
                $context = $storageAccounts[0].Context;        

                $policyBlobs = Get-AzureStorageBlob -Container "policies" -Context $context -ErrorAction SilentlyContinue
                if(($policyBlobs | Measure-Object).Count -gt 0)
                {
                    if(-not (Test-Path "$($PolicyInstance.ConfigFolderPath)"))
                    {
                        mkdir -Path "$($PolicyInstance.ConfigFolderPath)" -ErrorAction Stop | Out-Null
                    }
                    else
                    {
                        Remove-Item -Path "$($PolicyInstance.ConfigFolderPath)\*" -Force -Recurse 
                    }
                     ForEach($blob in $policyBlobs ) {                
                        $splitNames = $blob.Name.Split("/")
                        $fileName = $splitNames[($splitNames.Count-1)]
                        if($fileName -eq "AzSDK.json")
                        {
                            $fileName = "AzSK.json"
                        }
                        if($fileName -eq "RunbookScanAgent.ps1")
                        {
                            continue
                        }
                        $filepath = "$($PolicyInstance.ConfigFolderPath)\$fileName"
                        Get-AzureStorageBlobContent -Blob $blob.Name -Container "policies" -Destination $filepath -Context $context -Force -ErrorAction SilentlyContinue
                    }
                }                    
                #endregion

            Write-Host ("Successfully completed extracting policy files from old Org policy resources.") -ForegroundColor Green;
            $MigrationOutput.CurrentDataExtraction = "Success"                
        }
        catch{
            Write-Host "An error while extracting current metadata and copying policy files from old Org policy resources" -ForegroundColor Red                
            $MigrationOutput.CurrentDataExtraction = "Failed. Message[$_]"
            $ErrorOccurred = $true;
            throw;
        }
        #endregion
            
        #region creating new resources
        try
        {
            #region copy subscription migration to policy
            Write-Host ("Copying subscription migration script to policy folder...") -ForegroundColor Yellow;    
            $migrationScriptContent = [ConfigurationHelper]::LoadOfflineConfigFile("Migration.ps1")                     
            Out-File -InputObject $migrationScriptContent -Force -FilePath "$($PolicyInstance.ConfigFolderPath)\Migration.ps1" -Encoding utf8
            Write-Host ("Successfully completed copying subscription migration script to policy folder.") -ForegroundColor Green;
            #endregion
            Write-Host ("Setting up Org policy using the *AzSK* module...`r`n"+[Constants]::GTLine) -ForegroundColor Yellow;    
            
            [PolicyMigrationHelper]::SetupPolicyResources($PolicyInstance)    
            
            Write-Host ([Constants]::GTLine+"`r`nSuccessfully completed setting up Org policy using the *AzSK* module.`r`n"+[Constants]::SingleDashLine) -ForegroundColor Green;
            
            $MigrationOutput.ResourceCreation = "Success"
        }
        catch{
            Write-Host "An error occurred during setting up Org policy with latest AzSK. See migration log for details." -ForegroundColor Red                
            $MigrationOutput.ResourceCreation = "Failed. Message[$_]"
            $ErrorOccurred = $true;
            throw;
        }
        #endregion
        Write-Host ("Performing last couple of steps...") -ForegroundColor Yellow;
        #Override existing IWR
        Write-Host ("Updating old Org-specific installer ('iwr')...") -ForegroundColor Yellow;    
        Set-AzureStorageBlobContent -File $PolicyInstance.InstallerFile -Container $($PolicyInstance.InstallerContainerName) -BlobType Block -Context $context -Force -ErrorAction Stop                        
        Write-Host ("Successfully updated installer.") -ForegroundColor Green;
        Write-Host ("Uploading Org policy migration log to storage [$($PolicyInstance.StorageAccountName)]...") -ForegroundColor Yellow;
        [PolicyMigrationHelper]::PersistMigrationOutput($subscriptionContext.SubscriptionId,[PolicyMigrationHelper]::NewPolicyRGName, $MigrationOutput);        
        Write-Host ("Successfully uploaded log.") -ForegroundColor Green;
        #region complete migration
        $MigrationOutput.ErrorOccurred = $ErrorOccurred
        if($MigrationOutput.ErrorOccurred -eq $false)
        {                
            [PolicyMigrationHelper]::CompleteMigration($subscriptionContext.SubscriptionId,[PolicyMigrationHelper]::NewPolicyRGName, $MigrationOutput)
            #endregion
            write-host ([Constants]::SingleDashLine + "`r`n Org policy migration completed successfully`r`n"+[Constants]::SingleDashLine) -ForegroundColor Green
            write-host ([Constants]::SingleDashLine + "`r`n Follow next steps at: https://aka.ms/devopskit/extmigration#org-policy") -ForegroundColor Green
            
        }
        else
        {
            [PolicyMigrationHelper]::PersistMigrationOutput($subscriptionContext.SubscriptionId, $MigrationOutput)                
            write-host ([Constants]::SingleDashLine + "`r`nAn error during policy migration, please retry again. If issue still continue please reach out to support team.`r`n"+[Constants]::SingleDashLine) -ForegroundColor Red
        }        
    }

    static [bool] MigrationPrerequisiteCheck()
    {
        $PrerequisiteCheckResult = $true
        
        $PolicyRG= Get-AzureRmResourceGroup -Name $([PolicyMigrationHelper]::PolicyRGName) -ErrorAction SilentlyContinue
        if(-not $PolicyRG)
        {
            $PrerequisiteCheckResult = $false
            Write-Host ("WARNING: No policy setup found for Org in the subscription. Migration does not apply. You can use the AzSK module directly to setup new policy.") -ForegroundColor Yellow;
            return $PrerequisiteCheckResult
        }
        $tagName = [Constants]::PolicyMigrationTagName
        $OrgRGName = [PolicyMigrationHelper]::NewPolicyRGName
        $resourceGroupTags = [Helpers]::GetResourceGroupTags($OrgRGName)
        $migrationTag = $resourceGroupTags.GetEnumerator() | Where-Object { $_.Name -eq $tagName }
        if(($migrationTag | Measure-Object).Count -gt 0)
        {
            $PrerequisiteCheckResult = $false
            Write-Host ("WARNING: Policy is already migrated.") -ForegroundColor Yellow;
            return $PrerequisiteCheckResult
        }        
        return $PrerequisiteCheckResult
    }

    static SetupPolicyResources([PSObject] $PolicyInstance)
    {
        # Install Policy
        $PolicyInstance.InstallPolicy([Constants]::NewModuleName)        
    }
    static [void] CompleteMigration([string] $subscriptionId,[string] $OrgRGName, [PSObject] $MigrationOutput)
    {
        #apply tag
        $tagName = [Constants]::PolicyMigrationTagName
        $resourceGroupTags = [Helpers]::GetResourceGroupTags($OrgRGName)
        $resourceGroupTags.Add($tagName,[DateTime]::UtcNow.ToString("yyyyMMdd_HHmmss"));
        [Helpers]::SetResourceGroupTags($OrgRGName,$resourceGroupTags,$false,$false)        ;            
    }

    static [void] PersistMigrationOutput([string] $subscriptionId,[string] $OrgRGName, [PSObject] $MigrationOutput)
    {
        if($null -ne $MigrationOutput)
        {
            $temp = ($env:temp + "\AzSKTemp\");
            $fileName =  "MigrationOutput_"+ (Get-Date).ToUniversalTime().ToString("yyyyMMddHHmmss")+ ".json"
            if(-not (Test-Path -Path $temp))
            {
                mkdir -Path $temp -Force
            }
            [Helpers]::ConvertToJsonCustom($MigrationOutput) | Out-File "$temp\$fileName" -Force;

            try{
                $newStorageRGName = $OrgRGName
                $newStorageAccount = Get-AzureRmResource -ResourceGroupName $newStorageRGName -ResourceType 'Microsoft.Storage/storageAccounts'
                if($newStorageAccount)
                {
                    $storageHelper = [StorageHelper]::new($subscriptionId,$newStorageRGName,$newStorageAccount.Location, $newStorageAccount.Name);
                    $fileInfos = @();
                    $fileInfos += [System.IO.FileInfo]::new("$temp\$fileName");
                    $storageHelper.UploadFilesToBlob("migration", "", $fileInfos, $true);
                }
            }
            catch
            {
                #Kept blank to avoid issue with posting migration logs to new storage
            }
        }
    }
}

[PolicyMigrationHelper]::StartMigration($subscriptionContext,$PolicyInstance, $OPolicyInstance)