PrepareTargetSubscriptionForCentralModeCA.md

January 28, 2021 ยท View on GitHub

IMPORTANT: DevOps Kit (AzSK) is being sunset by end of FY21. More details here


function PrepareTargetSubscriptionForCentralModeCA($SubscriptionId, $Location, $AADAppName, $LoggingOption)
{
 	#Do not change this rgName value unless you have your own AzSK org-specific policy setup
    $rgName = 'AzSKRG'  
 
    #region Step 1: Set context to target subscription
    Write-Host "Changing current subscription context to [$subscriptionId]..." -ForegroundColor Yellow
    Set-AzContext -Subscription $subscriptionId | Out-Null
    Write-Host "Completed changing subscription context to [$subscriptionId]." -ForegroundColor Green
    #endregion
 
    #region Step 2: Check if the AzSK resource group exists
    $isRGPresent = (Get-AzResourceGroup -Name $rgName -ErrorAction SilentlyContinue | Measure-Object).Count -ne 0
    #endregion

    #region Step 3: Check whether Storage Resource provider is registered
 
    $providerNamespace = "Microsoft.Storage";
    Write-Host "Checking if resource provider [$providerNamespace] is registered..." -ForegroundColor Yellow
    $isRegistered = (Get-AzResourceProvider -ProviderNamespace $providerNamespace | Where-Object { $_.RegistrationState -ne "Registered" } | Measure-Object).Count -eq 0
    #endregion

                 
    #region Step 4: Check whether AzSK storage account is present
    $storageAccountPreName = 'azsk';
    $storageResourceType = "Microsoft.Storage/storageAccounts"
    $storageType = 'Standard_LRS';
    $storageAccount = Get-AzResource -ResourceGroupName $rgName -Name "*$storageAccountPreName*" -ResourceType $storageResourceType -ErrorAction SilentlyContinue
    $isStoragePresent = (($storageAccount | Where-Object{$_.Name -match '^azsk\d{14}$'} | Measure-Object).Count -ne 0)
    #endregion

    #region Step 5: Grant required permissions on target sub and AzSK RG
    $ADApplication = Get-AzADApplication -DisplayNameStartWith $AADAppName | Where-Object -Property DisplayName -eq $AADAppName
    if(($ADApplication | Measure-Object).Count -le 0)
    {
       throw "AADApplication [$AADAppName] not found. You must specify an existing app name for which you are Owner."
    }
 
    $haveRGAccess = $false;
    $haveSubAccess = $false;
    $spPermissions = Get-AzRoleAssignment -ServicePrincipalName $ADApplication.ApplicationId
    #endregion
 

    if($LoggingOption -eq "IndividualSub")
    { 
        #region Step 2: Create the AzSK resource group
 
        #check if the resource group exists
        Write-Host "Checking if resource group [$rgName] exists in the target subscription..." -ForegroundColor Yellow
        if(-not $isRGPresent)
        {
            Write-Host "Creating new resource group [$rgName]..." -ForegroundColor Yellow
            $newRG = New-AzResourceGroup -Name $rgName -Location $Location -ErrorAction Stop
        }
        $azSKRG = $null;
 
        #wait  until resource group creation is completed
        $retryCount = 6
        $localTimeout = $baseTimeout;
        while($retryCount -gt 0 -and $null -eq $azSKRG)
        {
            $azSKRG = Get-AzResourceGroup -Name $rgName -ErrorAction SilentlyContinue;
            if($null -eq $azSKRG)
            {
                Write-Host "Waiting...sleep interval: [$localTimeout] RetryCount: [$retryCount]"
                Start-Sleep -Seconds $localTimeout
                $localTimeout += 10
                $retryCount--;
            }
        }
        Write-Host "Completed creating resource group [$rgName]" -ForegroundColor Green
        #endregion
 
        #region Step 3: Register for Storage Resource provider
        Write-Host "Checking if resource provider [$providerNamespace] is registered..." -ForegroundColor Yellow
 
        if($isRegistered)
        {
            Write-Host "Resource provider [$providerNamespace] is already registered" -ForegroundColor Green
        }
 
        else
        {
            Register-AzResourceProvider -ProviderNamespace $providerNamespace
            $retryCount = 10;
            $localTimeout = $baseTimeout;
            while($retryCount -ne 0 -and -not $isRegistered)
            {
                $isRegistered = ((Get-AzResourceProvider -ProviderNamespace $providerNamespace | Where-Object { $_.RegistrationState -ne "Registered" } | Measure-Object).Count -eq 0);
                if(-not $isRegistered)
                {
                    Write-Host "Waiting...Sleeping Interval: [$localTimeout] RetryCount: [$retryCount]"
                       Start-Sleep -Seconds $localTimeout
                       $retryCount--;     
                    $localTimeout += 5
                }    
            }
            Write-Host "Completed registering resource provider [$providerNamespace]" -ForegroundColor Green
        }
        #endregion
 
        #region Step 4: Create AzSK storage account
        if(-not $isStoragePresent)
        {
            $storageAccountName = ($storageAccountPreName + (Get-Date).ToUniversalTime().ToString("yyyyMMddHHmmss")); 
            $newStorage = New-AzStorageAccount -ResourceGroupName $rgName `
                            -Name $storageAccountName `
                            -SkuName $storageType `
                            -Location $Location `
                            -Kind BlobStorage `
                            -AccessTier Cool `
                            -EnableHttpsTrafficOnly $true `
                            -ErrorAction Stop
 
            $retryAccount = 6
            $localTimeout = $baseTimeout;
            while($null -eq $storageObject -and $retryAccount -gt 0)
            {
                $storageObject = Get-AzStorageAccount -ResourceGroupName 'AzSKRG' -Name $storageAccountName -ErrorAction SilentlyContinue
                if($null -eq $storageObject)
                {
                    Write-Host "Waiting...sleep interval: [$localTimeout] RetryCount: [$retryCount]"
                    Start-Sleep -seconds $localTimeout
                    $localTimeout += 5;
                    $retryAccount--;
                }
            }
 
            #the below settings are required to create compliant AzSK storage
            if ($storageObject) {
                $currentContext = $storageObject.Context
               $logging= Set-AzStorageServiceLoggingProperty -ServiceType Blob -LoggingOperations All -Context $currentContext -RetentionDays 365 -PassThru -ErrorAction Stop
               $metrics= Set-AzStorageServiceMetricsProperty -MetricsType Hour -ServiceType Blob -Context $currentContext -MetricsLevel ServiceAndApi -RetentionDays 365 -PassThru -ErrorAction Stop
            }
            Write-Host "Created a new AzSK storage account [$storageAccountName]" -ForegroundColor Green
        }
        else
        {
            Write-Host "AzSK storage account is already present" -ForegroundColor Green
        }
        #endregion
 
        #region Step 5: Grant required permissions on target sub and AzSK RG
        Write-Host "Setting up permissions for AzSK CA SPN [$AADAppName]..." -ForegroundColor Yellow
        if(($spPermissions|Measure-Object).count -gt 0)
        {
               $haveRGAccess = ($spPermissions | Where-Object {$_.scope -eq (Get-AzResourceGroup -Name $rgName).ResourceId -and $_.RoleDefinitionName -eq "Contributor" }|measure-object).count -gt 0
               $haveSubAccess = ($spPermissions | Where-Object {$_.scope -eq "/subscriptions/$subscriptionId" -and $_.RoleDefinitionName -eq "Reader"}|Measure-Object).count -gt 0
        }
 
        if(-not $haveRGAccess)
        {
            New-AzRoleAssignment -Scope $azSKRG.ResourceId -RoleDefinitionName Contributor -ServicePrincipalName $ADApplication.ApplicationId -ErrorAction SilentlyContinue | Out-Null
            Write-Host "Completed granting access to AzSK CA SPN on ResourceGroup [$rgName]" -ForegroundColor Green
        }
        else
        {
            Write-Host "AzSK CA SPN already have required access on ResourceGroup [$rgName]" -ForegroundColor Green
        }
        if(-not $haveSubAccess)
        {
            New-AzRoleAssignment -RoleDefinitionName Reader -ServicePrincipalName $ADApplication.ApplicationId -ErrorAction SilentlyContinue | Out-Null
            Write-Host "Completed granting access to AzSK CA SPN on Subscription" -ForegroundColor Green
        }
        else
        {
            Write-Host "AzSK CA SPN already have required access on Subscription" -ForegroundColor Green
        }
        #endregion    	     	
    }

    elseif($LoggingOption -eq "CentralSub")
    {
        #region Step 2: Check if the AzSK resource group exists
 
        Write-Host "Checking if resource group [$rgName] exists in the target subscription..." -ForegroundColor Yellow
        if($isRGPresent)
        {
            Write-Host "AzSK resource group is already present" -ForegroundColor Green
        }
        #endregion

        #region Step 3: Check whether Storage Resource provider is registered
 
        Write-Host "Checking if resource provider [$providerNamespace] is registered..." -ForegroundColor Yellow
        if($isRegistered)
        {
            Write-Host "Storage Resource Provider is already registered" -ForegroundColor Green
        }
        #endregion

                 
        #region Step 4: Check whether AzSK storage account is present
        Write-Host "Checking if AzSK storage account is present..." -ForegroundColor Yellow
        #check if storage account is present        
        if($isStoragePresent)
        {
            Write-Host "AzSK storage account is already present" -ForegroundColor Green
        }
        #endregion
 
        #region Step 5: Grant required permissions on target sub and AzSK RG
        Write-Host "Setting up permissions for AzSK CA SPN [$AADAppName]..." -ForegroundColor Yellow
        if(($spPermissions|Measure-Object).count -gt 0)
        {
            if($isRGPresent -and $isRegistered -and $isStoragePresent)
            {
               $haveRGAccess = ($spPermissions | Where-Object {$_.scope -eq (Get-AzResourceGroup -Name $rgName).ResourceId -and $_.RoleDefinitionName -eq "Contributor" }|measure-object).count -gt 0 
               if(-not $haveRGAccess)
               {
                    New-AzRoleAssignment -Scope $azSKRG.ResourceId -RoleDefinitionName Contributor -ServicePrincipalName $ADApplication.ApplicationId -ErrorAction SilentlyContinue | Out-Null
                    Write-Host "Completed granting access to AzSK CA SPN on ResourceGroup [$rgName]" -ForegroundColor Green
               }
               else
               {
                    Write-Host "AzSK CA SPN already have required access on ResourceGroup [$rgName]" -ForegroundColor Green
               }
            }
            $haveSubAccess = ($spPermissions | Where-Object {$_.scope -eq "/subscriptions/$subscriptionId" -and $_.RoleDefinitionName -eq "Reader"}|Measure-Object).count -gt 0
        }
         
        if(-not $haveSubAccess)
        {
            New-AzRoleAssignment -RoleDefinitionName Reader -ServicePrincipalName $ADApplication.ApplicationId -ErrorAction SilentlyContinue | Out-Null
            Write-Host "Completed granting access to AzSK CA SPN on Subscription" -ForegroundColor Green
        }
        else
        {
            Write-Host "AzSK CA SPN already have required access on Subscription" -ForegroundColor Green
        }
        #endregion    	     	
    }
 
}

#This is the SPN that got created when you setup CA in the central (host) 
#subscription in central scan mode. You can get it by calling 'Get-AzSKContinuousAssurance'
#for that subscription (or from the CA log).
$azskSPN = '<AzSK_CA_SPN_from_host_sub>' #'AzSK_CA_SPN_xxxx'

#The resource group and storage account will be created at this location.
#Choose the location where your host subscription's 'AzSKRG' is setup.
$loc = '<AzSKRG_location_from_host_sub>' #'eastus2'

#This is the target subscription. Each target sub should be similarly 'prepped' 
$subId = "<target_sub_id>"

#This is the logging option for which the target sub needs to be configured.
$loggingOption = "<CentralSub | IndividualSub>"
PrepareTargetSubscriptionForCentralModeCA -SubscriptionId $subId -Location $loc -AADAppName $azskSPN -LoggingOption $loggingOption