Framework/Core/SVT/Services/ContainerRegistry.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
Set-StrictMode -Version Latest 
class ContainerRegistry: SVTBase
{       
    hidden [PSObject] $ResourceObject;
    hidden [PSObject] $AccessList;

    ContainerRegistry([string] $subscriptionId, [string] $resourceGroupName, [string] $resourceName): 
        Base($subscriptionId, $resourceGroupName, $resourceName) 
    { 
        $this.GetResourceObject();
    }

    ContainerRegistry([string] $subscriptionId, [SVTResource] $svtResource): 
        Base($subscriptionId, $svtResource) 
    { 
        $this.GetResourceObject();
    }

    hidden [PSObject] GetResourceObject()
    {
        if (-not $this.ResourceObject) 
        {
            $this.ResourceObject = Get-AzContainerRegistry -Name $this.ResourceContext.ResourceName -ResourceGroupName $this.ResourceContext.ResourceGroupName

            if(-not $this.ResourceObject)
            {
                throw ([SuppressedException]::new(("Resource '{0}' not found under Resource Group '{1}'" -f ($this.ResourceContext.ResourceName), ($this.ResourceContext.ResourceGroupName)), [SuppressedExceptionType]::InvalidOperation))
            }

            # Get RBAC data to avoid multiple calls
            $this.AccessList = [RoleAssignmentHelper]::GetAzSKRoleAssignmentByScope($this.GetResourceId(), $false, $true);
        }
        return $this.ResourceObject;
    }

    hidden [ControlResult] CheckAdminUserStatus([ControlResult] $controlResult)
    {
        $isAdminUserEnabled = $this.ResourceObject.AdminUserEnabled
        
        if($isAdminUserEnabled)
        {
            $controlResult.EnableFixControl = $true;
            $controlResult.VerificationResult = [VerificationResult]::Failed
        }
        else
        {
            $controlResult.VerificationResult = [VerificationResult]::Passed
        }
    
        return $controlResult;
    }

    hidden [ControlResult] CheckResourceRBACAccess([ControlResult] $controlResult)
    {
        return $this.CheckRBACAccess($controlResult, $this.AccessList)
    }

    hidden [ControlResult] CheckResourceAccess([ControlResult] $controlResult)
    {
        $nonSPIdentities = $this.AccessList | Where-Object { $_.Scope -eq $this.GetResourceId() -and $_.ObjectType -ne 'ServicePrincipal' };
        
        if(($nonSPIdentities | Measure-Object).Count -ne 0)
        {
            $controlResult.SetStateData("Non Service Principal identities having RBAC access at resource level", ($nonSPIdentities | Select-Object -Property ObjectId,RoleDefinitionId,RoleDefinitionName,Scope));
            
            $controlResult.AddMessage([VerificationResult]::Failed, 
                            [MessageData]::new("Validate that the following non Service Principal identities have explicitly provided with RBAC access to resource - ["+ $this.ResourceContext.ResourceName +"]"));

            $controlResult.AddMessage([MessageData]::new($nonSPIdentities));
        }
        else 
        {
            $controlResult.AddMessage([VerificationResult]::Verify, 
                            [MessageData]::new("Validate that the inherited non Service Principal identities should not be used to access the resource - ["+ $this.ResourceContext.ResourceName +"]"));
        }
  
        return $controlResult;
    }

    hidden [ControlResult] CheckContainerWebhooks([ControlResult] $controlResult)
    {

        $webhooks = Get-AzContainerRegistryWebhook -RegistryName $this.ResourceContext.ResourceName -ResourceGroupName $this.ResourceContext.ResourceGroupName -ErrorAction SilentlyContinue

        if(($webhooks | Measure-Object).Count -gt 0)
        {
            $controlResult.VerificationResult = [VerificationResult]::Verify; 
            $controlResult.SetStateData("Webhook configured to the Container Registry", ($webhooks | Select-Object -Property Actions, Config, Id, Scope, Status));
            $controlResult.AddMessage([MessageData]::new("Review that image vulnerability scan is configured for all the repositories through following webhook(s) to the Container Registry - ["+ $this.ResourceContext.ResourceName +"]", 
                                                $webhooks));
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Failed, 
                            [MessageData]::new("Webhooks for image vulnerability scan is not configured for the Container Registry - ["+ $this.ResourceContext.ResourceName +"]"));
        }
  
        return $controlResult;
    }

    hidden [ControlResult] CheckContentTrust([ControlResult] $controlResult)
    {
        $result = $null;
        $ResourceAppIdURI = [WebRequestHelper]::GetResourceManagerUrl()
        $uri = [System.String]::Format("{0}subscriptions/{1}/resourceGroups/{2}/providers/Microsoft.ContainerRegistry/registries/{3}/listPolicies?api-version=2017-10-01", $ResourceAppIdURI, $this.SubscriptionContext.SubscriptionId, $this.ResourceContext.ResourceGroupName, $this.ResourceContext.ResourceName)
            
        try 
        {     
            $result = [WebRequestHelper]::InvokeGetWebRequest($uri) 
        } 
        catch
        { 
            return $controlResult;
        }
  
        $isPolicyEnabled = $false
        if($null -ne $result)
        {
            if([Helpers]::CheckMember($result,"trustPolicy.status"))
            {
                if($result.trustPolicy.status -eq "enabled")
                {
                    $isPolicyEnabled = $true
                }
            }
        }

        if($isPolicyEnabled -eq $true)
        {
            $controlResult.AddMessage([VerificationResult]::Verify, 
                            [MessageData]::new("Verify that all the images in the repository must be signed."));
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Failed, 
                            [MessageData]::new("Content Trust is not enabled for the Container Registry - ["+ $this.ResourceContext.ResourceName +"]"));
        }
        
        return $controlResult;
    }
}