Framework/Core/SubscriptionSecurity/SubscriptionSecurity.ps1

using namespace System.Management.Automation
Set-StrictMode -Version Latest 

# The class serves as an intermediate class to call multiple subscription security module classes

class SubscriptionSecurity: CommandBase
{    
    [string] $Tags
    SubscriptionSecurity([string] $subscriptionId, [InvocationInfo] $invocationContext, [string] $tags): 
        Base($subscriptionId, $invocationContext)
    { 
        $this.Tags = $tags;
    }
    SubscriptionSecurity([string] $subscriptionId, [InvocationInfo] $invocationContext): 
        Base($subscriptionId, $invocationContext)
    {}
    [MessageData[]] SetSubscriptionSecurity(
        # Inputs for Security Center
        [string] $securityContactEmails, [string] $securityPhoneNumber, 
        # Inputs for Alerts
        [string] $targetResourceGroup, [string] $alertResourceGroupLocation
    )
    {    
        [MessageData[]] $messages = @();

        #Create all the required AzSDK Resources if missing
        try
        {
            $this.SetupAzSDKResources();
        }
        catch
        {
            $this.CommandError($_);
        }
        
        # Set up Security Center
        try 
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nConfiguring Security Center`r`n" + [Constants]::DoubleDashLine);
            $secCenter = [SecurityCenter]::new($this.SubscriptionContext.SubscriptionId,$this.Force);
            if ($secCenter) 
            {
                $messages += $secCenter.SetPolicies($securityContactEmails, $securityPhoneNumber);
                $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted Security Center configuration`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update);
            } 
        }
        catch 
        {
            $this.CommandError($_);
        }  
        
        # Set up RBAC
        try 
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nSetting up subscription RBAC`r`n" + [Constants]::DoubleDashLine);
            $rbac = [RBAC]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext, $this.Tags);
            if ($rbac) 
            {
                $messages += $rbac.SetRBACAccounts();
                $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted subscription RBAC configuration`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update);
            } 
        }
        catch 
        {
            $this.CommandError($_);
        }  

        # Set up ARM policies
        try 
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nSetting up ARM policies`r`n" + [Constants]::DoubleDashLine);
            $armPolicy = [ARMPolicy]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext, $this.Tags);
            if ($armPolicy) 
            {
                $messages += $armPolicy.SetARMPolicies();
                $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted ARM policy configuration`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update);
            } 
        }
        catch 
        {
            $this.CommandError($_);
        }  

        # Set up Alerts
        try 
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nSetting up Alerts`r`n" + [Constants]::DoubleDashLine);
            $alert = [Alerts]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext, $this.Tags);
            if ($alert) 
            {
                $messages += $alert.SetAlerts($targetResourceGroup, $securityContactEmails,$alertResourceGroupLocation);
                $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted Alerts configuration`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update);
            } 
        }
        catch 
        {
            $this.CommandError($_);
        }  

        return $messages;
    }
    
    [MessageData[]] RemoveSubscriptionSecurity([bool] $deleteResourceGroup, [string] $alertNames)
    {    
        [MessageData[]] $messages = @();

        # Remove ARM policies
        try 
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nRemoving ARM policies`r`n" + [Constants]::DoubleDashLine);
            $armPolicy = [ARMPolicy]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext, $this.Tags);
            if ($armPolicy) 
            {
                $messages += $armPolicy.RemoveARMPolicies();
                $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nRemoved ARM policies`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update);
            } 
        }
        catch 
        {
            $this.CommandError($_);
        }  

        # Remove Alerts
        try 
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nRemoving Alerts`r`n" + [Constants]::DoubleDashLine);
            $alert = [Alerts]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext, $this.Tags);
            if ($alert) 
            {
                $messages += $alert.RemoveAlerts($deleteResourceGroup, $alertNames);
                $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nRemoved Alerts`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update);
            } 
        }
        catch 
        {
            $this.CommandError($_);
        }  

        return $messages;
    }

    [MessageData[]] UpdateSubscriptionSecurity()
    {    
        [MessageData[]] $messages = @();

        #Adding all mandatory tags
        $mandatoryTags = [string]::Join(",", [ConfigurationManager]::GetAzSdkConfigData().SubscriptionMandatoryTags);

        #Create all the required AzSDK Resources if missing
        try
        {
            $this.SetupAzSDKResources();
        }
        catch
        {
            $this.CommandError($_);
        }

        # Set up Alerts
        try 
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nUpdating Alerts...`r`n" + [Constants]::DoubleDashLine);
            $alert = [Alerts]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext, $mandatoryTags);
            if ($alert) 
            {
                #calling alert method with default params i.e. without security contanct email and phone number
                $messages += $alert.SetAlerts();
                $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted updates for Alerts configuration`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update);
            } 
        }
        catch 
        {
            $this.CommandError($_);
        }
        
        # Set up Security Center
        try 
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nUpdating Security Center configuration...`r`n" + [Constants]::DoubleDashLine);
            $secCenter = [SecurityCenter]::new($this.SubscriptionContext.SubscriptionId,$this.Force);
            if ($secCenter) 
            {
                #calling the ASC policy method with default params i.e. without ASC security poc email and phone number
                $messages += $secCenter.SetPolicies();
                $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted updates for Security Center configuration`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update);
            } 
        }
        catch 
        {
            $this.CommandError($_);
        }  
        
        # Set up RBAC
        try 
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nUpdating subscription RBAC with required central accounts...`r`n" + [Constants]::DoubleDashLine);
            $rbac = [RBAC]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext, $mandatoryTags);
            if ($rbac) 
            {
                #calling the rbac command to set the subscription with all the required approved accounts
                $messages += $rbac.SetRBACAccounts();
                $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted updates for subscription RBAC configuration for central mandatory accounts`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update);
            } 
        }
        catch 
        {
            $this.CommandError($_);
        }  

        # Remove RBAC
        try 
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nUpdating subscription RBAC to remove any deprecated accounts...`r`n" + [Constants]::DoubleDashLine);
            $rbac = [RBAC]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext, $null);
            if ($rbac) 
            {
                #calling the rbac command to set the subscription with all the required approved accounts
                $messages += $rbac.RemoveRBACAccounts();
                $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted updates for subscription RBAC configuration`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update);
            } 
        }
        catch 
        {
            $this.CommandError($_);
        }  

        # Set up ARM policies
        try 
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nUpdating ARM policies...`r`n" + [Constants]::DoubleDashLine);
            $armPolicy = [ARMPolicy]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext, $mandatoryTags);
            if ($armPolicy) 
            {
                $messages += $armPolicy.SetARMPolicies();
                $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted updates for ARM policy configuration`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update);
            } 
        }
        catch 
        {
            $this.CommandError($_);
        }  
          

        #Update CA
        $caAccount = [CCAutomation]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext);
        if ($caAccount) 
        {
            # TODO: sending the fixruntime and fixmodule as false by default
            $messages += $caAccount.UpdateAzSDKContinuousAssurance($false, $false, $false);
        }
        return $messages;
    }

    [MessageData[]] SetupAzSDKResources()
    {
        [MessageData[]] $messages = @();

        $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nValidating the required resources for AzSDK...`r`n" + [Constants]::DoubleDashLine);
        #Check for the presence of AzSDK RG
        $azsdkRGName = [ConfigurationManager]::GetAzSdkConfigData().AzSDKRGName;
        try 
        {
            if((Get-AzureRmResourceGroup -Name $azsdkRGName -ErrorAction SilentlyContinue | Measure-Object).Count -eq 0)
            {
                $this.PublishCustomMessage("Creating AzSDK resource group...");
                [Helpers]::NewAzSDKResourceGroup($azsdkRGName ,[Constants]::AzSDKRGLocation ,$this.GetCurrentModuleVersion())
                $this.PublishCustomMessage("Completed creating AzSDK resource group.", [MessageType]::Update);                
            }
            else
            {
                $this.PublishCustomMessage("Found AzSDK resource group: [$azsdkRGName]", [MessageType]::Update);
            }
        }
        catch 
        {
            $this.CommandError($_);
        }
        $this.PublishCustomMessage([Constants]::SingleDashLine);

        #Check the presence of AzSDK StorageAccount
        try
        {
            $azsdkStorage = [Helpers]::GetAzSDKStorage($azsdkRGName);

            if($null -ne $azsdkStorage )
            {
                $this.PublishCustomMessage("Found AzSDK storage account: [$($azsdkStorage.Name)]", [MessageType]::Update);
            }
            else
            {
                $azsdkStorageAccountName = ("azsdk" + (Get-Date).ToUniversalTime().ToString("yyyyMMddHHmmss"))
                $this.PublishCustomMessage("Creating AzSDK storage account: [$azsdkStorageAccountName]...");
                [Helpers]::NewAzsdkCompliantStorage($azsdkStorageAccountName , $azsdkRGName, [Constants]::AzSDKRGLocation)
                $azsdkStorage = [Helpers]::GetAzSDKStorage($azsdkRGName);
                if(!$azsdkStorage)
                {
                    throw "Failed to create storage account."
                }  
                $this.PublishCustomMessage("Completed creating AzSDK storage account: [$azsdkStorageAccountName].", [MessageType]::Update);    
            }
            $this.PublishCustomMessage([Constants]::SingleDashLine);

            #Create the storage containers
        
            $keys = Get-AzureRmStorageAccountKey -ResourceGroupName $azsdkRGName  -Name $azsdkStorage.Name
            $currentContext = New-AzureStorageContext -StorageAccountName $azsdkStorage.Name -StorageAccountKey $keys[0].Value -Protocol Https

            #checking for state container
            try {
                Get-AzureStorageContainer -Name $([Constants]::StateContainerName) -Context $currentContext -ErrorAction Stop | Out-Null
                $this.PublishCustomMessage("Found AzSDK attestation container: [$([Constants]::StateContainerName)]", [MessageType]::Update);    
            }
            catch {
                $this.PublishCustomMessage("Creating AzSDK attestation container: [$([Constants]::StateContainerName)]");    
                New-AzureStorageContainer -Name $([Constants]::StateContainerName) -Context $currentContext | Out-Null
                $this.PublishCustomMessage("Completed creating AzSDK attestation container: [$([Constants]::StateContainerName)]", [MessageType]::Update);    
            }
            $this.PublishCustomMessage([Constants]::SingleDashLine);

            #checking for CA contianer logs
            try {
                Get-AzureStorageContainer -Name $([Constants]::CALogsContainerName) -Context $currentContext -ErrorAction Stop | Out-Null
                $this.PublishCustomMessage("Found AzSDK CA logs container: [$([Constants]::CALogsContainerName)]", [MessageType]::Update);    
            }
            catch {
                $this.PublishCustomMessage("Creating AzSDK CA logs container: [$([Constants]::CALogsContainerName)]");    
                New-AzureStorageContainer -Name $([Constants]::CALogsContainerName) -Context $currentContext | Out-Null
                $this.PublishCustomMessage("Completed creating AzSDK CA logs container: [$([Constants]::CALogsContainerName)]", [MessageType]::Update);    
            }
            $this.PublishCustomMessage([Constants]::SingleDashLine);

            #checking for CA scaling container
            try {
                Get-AzureStorageContainer -Name $([Constants]::CentralScanContainerName) -Context $currentContext -ErrorAction Stop | Out-Null
                $this.PublishCustomMessage("Found AzSDK CA scaling container: [$([Constants]::CentralScanContainerName)]", [MessageType]::Update);    
            }
            catch {
                $this.PublishCustomMessage("Creating AzSDK CA scaling container: [$([Constants]::CentralScanContainerName)]");    
                New-AzureStorageContainer -Name $([Constants]::CentralScanContainerName) -Context $currentContext | Out-Null
                $this.PublishCustomMessage("Completed creating AzSDK CA scaling container: [$([Constants]::CentralScanContainerName)]", [MessageType]::Update);    
            }
            $this.PublishCustomMessage([Constants]::SingleDashLine);

            #checking for control persistence container
            try {
                Get-AzureStorageContainer -Name $([Constants]::BaselineContainerName) -Context $currentContext -ErrorAction Stop | Out-Null
                $this.PublishCustomMessage("Found AzSDK persistence container: [$([Constants]::BaselineContainerName)]", [MessageType]::Update);    
            }
            catch {
                $this.PublishCustomMessage("Creating AzSDK persistence container: [$([Constants]::BaselineContainerName)]");    
                New-AzureStorageContainer -Name $([Constants]::BaselineContainerName) -Context $currentContext | Out-Null
                $this.PublishCustomMessage("Completed creating AzSDK persistence container: [$([Constants]::BaselineContainerName)]", [MessageType]::Update);    
            }            

        }
        catch
        {
            $this.CommandError($_);
        }        
        $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted validating all the required resources for AzSDK.`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update);

        return $messages;
    }
}