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

fix(terraform): Ensure HTTPS in Azure Function App and App Slots #5766

Merged
merged 1 commit into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,17 +1,44 @@
from checkov.common.models.enums import CheckCategories
from checkov.terraform.checks.resource.base_resource_value_check import BaseResourceValueCheck
from __future__ import annotations

from typing import Any

class FunctionAppsAccessibleOverHttps(BaseResourceValueCheck):
def __init__(self):
from checkov.common.models.enums import CheckCategories, CheckResult
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck


class FunctionAppsAccessibleOverHttps(BaseResourceCheck):

def __init__(self) -> None:
name = "Ensure that Function apps is only accessible over HTTPS"
id = "CKV_AZURE_70"
supported_resources = ['azurerm_function_app']
supported_resources = ['azurerm_function_app', 'azurerm_linux_function_app', 'azurerm_windows_function_app',
'azurerm_function_app_slot', 'azurerm_linux_function_app_slot',
'azurerm_windows_function_app_slot']
categories = [CheckCategories.NETWORKING]
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)

def get_inspected_key(self):
return 'https_only'
def scan_resource_conf(self, conf: dict[str, list[Any]]) -> CheckResult:
# default=false for https_only
if 'https_only' not in conf.keys():
return CheckResult.FAILED

https_only = conf.get('https_only')[0]
if not https_only:
return CheckResult.FAILED

# relevant for linux/windows resources
if 'auth_settings_v2' in conf.keys():
auth_settings_v2 = conf['auth_settings_v2'][0]

# default=true for require_https
if 'require_https' not in auth_settings_v2.keys():
return CheckResult.PASSED

require_https = auth_settings_v2.get('require_https')[0]
if not require_https:
return CheckResult.FAILED

return CheckResult.PASSED


check = FunctionAppsAccessibleOverHttps()
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@

## app

resource "azurerm_function_app" "fail" {
name = "test-azure-functions"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
}
resource "azurerm_function_app" "fail2" {
name = "test-azure-functions"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
https_only = false
}
resource "azurerm_function_app" "pass" {
name = "test-azure-functions"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
https_only = true
}

## app_slot

resource "azurerm_function_app_slot" "fail" {
name = "test-azure-functions_slot"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
function_app_name = azurerm_function_app.example.name
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
}
resource "azurerm_function_app_slot" "fail2" {
name = "test-azure-functions_slot"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
function_app_name = azurerm_function_app.example.name
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
https_only = false
}
resource "azurerm_function_app_slot" "pass" {
name = "test-azure-functions_slot"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
function_app_name = azurerm_function_app.example.name
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
https_only = true
}

#### linux/windows

## app

resource "azurerm_linux_function_app" "fail" {
name = "example-linux-function-app"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
service_plan_id = azurerm_service_plan.example.id

site_config {}
}
resource "azurerm_linux_function_app" "fail2" {
name = "example-linux-function-app"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
service_plan_id = azurerm_service_plan.example.id

site_config {}
https_only = false
}
resource "azurerm_linux_function_app" "fail3" {
name = "example-linux-function-app"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
service_plan_id = azurerm_service_plan.example.id

site_config {}

https_only = true
auth_settings_v2 {
require_https = false
}
}
resource "azurerm_linux_function_app" "pass" {
name = "example-linux-function-app"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
service_plan_id = azurerm_service_plan.example.id

site_config {}
https_only = true
}
resource "azurerm_linux_function_app" "pass2" {
name = "example-linux-function-app"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
service_plan_id = azurerm_service_plan.example.id

site_config {}

https_only = true
auth_settings_v2 {
require_https = true
}
}

## app slot

resource "azurerm_linux_function_app_slot" "fail" {
name = "example-linux-function-app-slot"
function_app_id = azurerm_linux_function_app.example.id
storage_account_name = azurerm_storage_account.example.name

site_config {}
}
resource "azurerm_linux_function_app_slot" "fail2" {
name = "example-linux-function-app-slot"
function_app_id = azurerm_linux_function_app.example.id
storage_account_name = azurerm_storage_account.example.name

site_config {}
https_only = false
}
resource "azurerm_linux_function_app_slot" "fail3" {
name = "example-linux-function-app-slot"
function_app_id = azurerm_linux_function_app.example.id
storage_account_name = azurerm_storage_account.example.name

site_config {}
auth_settings_v2 {
require_https = false
}
https_only = true
}
resource "azurerm_linux_function_app_slot" "pass" {
name = "example-linux-function-app-slot"
function_app_id = azurerm_linux_function_app.example.id
storage_account_name = azurerm_storage_account.example.name

site_config {}
auth_settings_v2 {}
https_only = true
}
resource "azurerm_linux_function_app_slot" "pass2" {
name = "example-linux-function-app-slot"
function_app_id = azurerm_linux_function_app.example.id
storage_account_name = azurerm_storage_account.example.name

site_config {}
auth_settings_v2 {
require_https = true
}
https_only = true
}
Original file line number Diff line number Diff line change
@@ -1,53 +1,50 @@
import unittest
from pathlib import Path

import hcl2

from checkov.runner_filter import RunnerFilter
from checkov.terraform.checks.resource.azure.FunctionAppsAccessibleOverHttps import check
from checkov.common.models.enums import CheckResult
from checkov.terraform.runner import Runner


class TestFunctionAppsAccessibleOverHttps(unittest.TestCase):
def test(self):
test_files_dir = Path(__file__).parent / "example_FunctionAppAccessibleOverHttps"

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

passing_resources = {
"azurerm_function_app.pass",
"azurerm_function_app_slot.pass",
"azurerm_linux_function_app.pass",
"azurerm_linux_function_app.pass2",
"azurerm_linux_function_app_slot.pass",
"azurerm_linux_function_app_slot.pass2",
}
failing_resources = {
"azurerm_function_app.fail",
"azurerm_function_app.fail2",
"azurerm_function_app_slot.fail",
"azurerm_function_app_slot.fail2",
"azurerm_linux_function_app.fail",
"azurerm_linux_function_app.fail2",
"azurerm_linux_function_app.fail3",
"azurerm_linux_function_app_slot.fail",
"azurerm_linux_function_app_slot.fail2",
"azurerm_linux_function_app_slot.fail3",
}

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)

def test_failure1(self):
hcl_res = hcl2.loads("""
resource "azurerm_app_service" "example" {
name = "example-app-service"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
https_only = false
}
""")
resource_conf = hcl_res['resource'][0]['azurerm_app_service']['example']
scan_result = check.scan_resource_conf(conf=resource_conf)
self.assertEqual(CheckResult.FAILED, scan_result)

def test_failure2(self):
hcl_res = hcl2.loads("""
resource "azurerm_app_service" "example" {
name = "example-app-service"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
}
""")
resource_conf = hcl_res['resource'][0]['azurerm_app_service']['example']
scan_result = check.scan_resource_conf(conf=resource_conf)
self.assertEqual(CheckResult.FAILED, scan_result)

def test_success(self):
hcl_res = hcl2.loads("""
resource "azurerm_app_service" "example" {
name = "example-app-service"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
https_only = true
}
""")
resource_conf = hcl_res['resource'][0]['azurerm_app_service']['example']
scan_result = check.scan_resource_conf(conf=resource_conf)
self.assertEqual(CheckResult.PASSED, scan_result)


if __name__ == '__main__':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def test_app_service_linux_function_resources(mocker: MockerFixture, graph_frame

assert len(tf_report.resources) == 2
assert len(tf_report.passed_checks) == 2
assert len(tf_report.failed_checks) == 2
assert len(tf_report.failed_checks) == 4
assert len(tf_report.skipped_checks) == 0
assert len(tf_report.parsing_errors) == 0

Expand Down
Loading