Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(arm): ensure ACR disables anonymous pulling of images (CKV_AZURE_138) #6373

Merged
38 changes: 38 additions & 0 deletions checkov/arm/checks/resource/ACRAnonymousPullDisabled.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from __future__ import annotations

from typing import Any

from checkov.common.models.enums import CheckResult, CheckCategories
from checkov.arm.base_resource_check import BaseResourceCheck


class ACRAnonymousPullDisabled(BaseResourceCheck):
ANONYMOUS_PULL_SKUS = {"Standard", "Premium"} # noqa: CCE003 # a static attribute

def __init__(self) -> None:
name = "Ensures that ACR disables anonymous pulling of images"
id = "CKV_AZURE_138"
supported_resources = ("Microsoft.ContainerRegistry/registries",)
categories = (CheckCategories.IAM,)
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)

def scan_resource_conf(self, conf: dict[str, Any]) -> CheckResult:
properties = conf.get("properties", {})

anonymousPullEnabled = properties.get("anonymousPullEnabled")

sku = conf.get("sku")

if (
sku is not None
and isinstance(sku.get("name"), str)
and sku.get("name") in ACRAnonymousPullDisabled.ANONYMOUS_PULL_SKUS
and properties
and anonymousPullEnabled
):
return CheckResult.FAILED

return CheckResult.PASSED


check = ACRAnonymousPullDisabled()
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.ContainerRegistry/registries",
"apiVersion": "2021-09-01",
"name": "fail",
"location": "eastus",
"sku": {
"name": "Standard"
},
"properties": {
"anonymousPullEnabled": true
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.ContainerRegistry/registries",
"apiVersion": "2021-09-01",
"name": "fail2",
"location": "eastus",
"sku": {
"name": "Premium"
},
"properties": {
"anonymousPullEnabled": true
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.ContainerRegistry/registries",
"apiVersion": "2021-09-01",
"name": "pass",
"location": "eastus",
"sku": {
"name": []
},
"properties": {
"anonymousPullEnabled": true
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.ContainerRegistry/registries",
"apiVersion": "2021-09-01",
"name": "pass2",
"location": "eastus",
"sku": {
"name": "Premium"
},
"properties": {
"anonymousPullEnabled": false
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.ContainerRegistry/registries",
"apiVersion": "2021-09-01",
"name": "pass3",
"location": "eastus",
"sku": {
"name": "Premium"
},
"properties": {
"zoneRedundancy": "Disabled"

}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.ContainerRegistry/registries",
"apiVersion": "2021-09-01",
"name": "pass4",
"location": "eastus",
"sku": {
"name": "Standard"
},
"properties": {
"zoneRedundancy": "Disabled"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.ContainerRegistry/registries",
"apiVersion": "2021-09-01",
"name": "pass5",
"location": "eastus",
"sku": {
"name": "Basic"
},
"properties": {
"anonymousPullEnabled": true
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.ContainerRegistry/registries",
"apiVersion": "2021-09-01",
"name": "pass6",
"location": "eastus",
"properties": {
"anonymousPullEnabled": true
}
}
]
}
46 changes: 46 additions & 0 deletions tests/arm/checks/resource/test_ACRAnonymousPullDisabled.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import unittest
from pathlib import Path

from checkov.arm.checks.resource.ACRAnonymousPullDisabled import check
from checkov.arm.runner import Runner
from checkov.runner_filter import RunnerFilter


class TestACRAnonymousPullDisabled(unittest.TestCase):
def test_summary(self):
# given
test_files_dir = Path(__file__).parent / "example_ACRAnonymousPullDisabled"

# when
report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id]))

# then
summary = report.get_summary()

passing_resources = {
"Microsoft.ContainerRegistry/registries.pass",
"Microsoft.ContainerRegistry/registries.pass2",
"Microsoft.ContainerRegistry/registries.pass3",
"Microsoft.ContainerRegistry/registries.pass4",
"Microsoft.ContainerRegistry/registries.pass5",
"Microsoft.ContainerRegistry/registries.pass6"
}
failing_resources = {
"Microsoft.ContainerRegistry/registries.fail",
"Microsoft.ContainerRegistry/registries.fail2"
}

passed_check_resources = {c.resource for c in report.passed_checks}
failed_check_resources = {c.resource for c in report.failed_checks}

self.assertEqual(summary["passed"], len(passing_resources))
self.assertEqual(summary["failed"], len(failing_resources))
self.assertEqual(summary["skipped"], 0)
self.assertEqual(summary["parsing_errors"], 0)

self.assertEqual(passing_resources, passed_check_resources)
self.assertEqual(failing_resources, failed_check_resources)


if __name__ == "__main__":
unittest.main()
Loading