diff --git a/changes/unreleased/Added-20211209-162551.yaml b/changes/unreleased/Added-20211209-162551.yaml new file mode 100755 index 00000000..030d9d4c --- /dev/null +++ b/changes/unreleased/Added-20211209-162551.yaml @@ -0,0 +1,3 @@ +kind: Added +body: Azure Resource Manager (ARM) template support with 38 rules. This feature is + currently in preview. diff --git a/cmd/flags.go b/cmd/flags.go index abecea3d..f13ce8ac 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -52,6 +52,7 @@ Input types: cfn CloudFormation template in YAML or JSON format tf Terraform directory or file k8s Kubernetes manifest in YAML format + arm Azure Resource Manager (ARM) JSON templates (feature in preview) ` const formatDescriptions = ` Output formats: diff --git a/pkg/loader/arm.go b/pkg/loader/arm.go new file mode 100644 index 00000000..eb1769f6 --- /dev/null +++ b/pkg/loader/arm.go @@ -0,0 +1,110 @@ +// Copyright 2021 Fugue, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package loader + +import ( + "encoding/json" + "fmt" +) + +var validArmExts map[string]bool = map[string]bool{ + ".json": true, +} + +type ArmDetector struct{} + +func (c *ArmDetector) DetectFile(i InputFile, opts DetectOptions) (IACConfiguration, error) { + if !opts.IgnoreExt && !validArmExts[i.Ext()] { + return nil, fmt.Errorf("File does not have .json extension: %v", i.Path()) + } + contents, err := i.Contents() + if err != nil { + return nil, err + } + + template := &armTemplate{} + if err := json.Unmarshal(contents, &template.Contents); err != nil { + return nil, fmt.Errorf("Failed to parse file as JSON %v: %v", i.Path(), err) + } + _, hasSchema := template.Contents["$schema"] + _, hasResources := template.Contents["resources"] + + if !hasSchema && !hasResources { + return nil, fmt.Errorf("Input file is not an ARM template: %v", i.Path()) + } + path := i.Path() + + return &armConfiguration{ + path: path, + template: *template, + }, nil +} + +func (c *ArmDetector) DetectDirectory(i InputDirectory, opts DetectOptions) (IACConfiguration, error) { + return nil, nil +} + +type armConfiguration struct { + path string + template armTemplate + source *SourceInfoNode +} + +func (l *armConfiguration) RegulaInput() RegulaInput { + return RegulaInput{ + "filepath": l.path, + "content": l.template.Contents, + } +} + +func (l *armConfiguration) Location(path []string) (LocationStack, error) { + if l.source == nil || len(path) < 1 { + return nil, nil + } + + resourcePath := []string{"Resources"} + resourcePath = append(resourcePath, path[0]) + resource, err := l.source.GetPath(resourcePath) + if err != nil { + return nil, nil + } + resourceLine, resourceColumn := resource.Location() + resourceLocation := Location{ + Path: l.path, + Line: resourceLine, + Col: resourceColumn, + } + + properties, err := resource.GetKey("Properties") + if err != nil { + return []Location{resourceLocation}, nil + } + + attribute, err := properties.GetPath(path[1:]) + if attribute != nil { + return []Location{resourceLocation}, nil + } + + line, column := attribute.Location() + return []Location{{Path: l.path, Line: line, Col: column}}, nil +} + +func (l *armConfiguration) LoadedFiles() []string { + return []string{l.path} +} + +type armTemplate struct { + Contents map[string]interface{} +} diff --git a/pkg/loader/base.go b/pkg/loader/base.go index 38223518..98e4af45 100644 --- a/pkg/loader/base.go +++ b/pkg/loader/base.go @@ -47,6 +47,8 @@ const ( Tf // Kubernetes manifests will be loaded K8s + // Azure Resource Manager JSON + Arm ) // InputTypeIDs maps the InputType enums to string values that can be specified in @@ -57,6 +59,7 @@ var InputTypeIDs = map[InputType][]string{ Cfn: {"cfn"}, Tf: {"tf"}, K8s: {"k8s", "kubernetes"}, + Arm: {"arm"}, } var DefaultInputTypes = InputTypeIDs[Auto] diff --git a/pkg/loader/loadpaths.go b/pkg/loader/loadpaths.go index c74b2849..18a28618 100644 --- a/pkg/loader/loadpaths.go +++ b/pkg/loader/loadpaths.go @@ -256,6 +256,7 @@ func detectorByInputType(inputType InputType) (ConfigurationDetector, error) { &TfPlanDetector{}, &TfDetector{}, &KubernetesDetector{}, + &ArmDetector{}, ), nil case Cfn: return &CfnDetector{}, nil @@ -265,6 +266,8 @@ func detectorByInputType(inputType InputType) (ConfigurationDetector, error) { return &TfDetector{}, nil case K8s: return &KubernetesDetector{}, nil + case Arm: + return &ArmDetector{}, nil default: return nil, fmt.Errorf("Unsupported input type: %v", inputType) } diff --git a/rego/lib/arm/disk_encryption_library.rego b/rego/lib/arm/disk_encryption_library.rego new file mode 100644 index 00000000..7e62a2c0 --- /dev/null +++ b/rego/lib/arm/disk_encryption_library.rego @@ -0,0 +1,49 @@ +# Copyright 2020 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This helper rego code works for Azure "no ingress" rules. +# It is built on top of the terraform code that does the same, +# through a simple conversion (`rule_to_tf`). +package fugue.arm.disk_encryption_library + +import data.fugue + +disks := fugue.resources("Microsoft.Compute/disks") + +virtual_machines := fugue.resources("Microsoft.Compute/virtualMachines") + +data_disk_ids := {id | + disk := virtual_machines[_].properties.storageProfile.dataDisks[_] + id := disk.managedDisk.id +} + +os_disk_ids := {id | + id := virtual_machines[_].properties.storageProfile.osDisk.managedDisk.id +} + +unattached_disk_ids := {id | + _ := disks[id] + not data_disk_ids[id] + not os_disk_ids[id] +} + +disk_encrypted(disk) { + disk.properties.encryptionSettingsCollection.enabled == true +} + +disk_encrypted(disk) { + des_id := disk.properties.encryption.diskEncryptionSetId + is_string(des_id) + des_id != "" +} diff --git a/rego/lib/arm/network_security_group_library.rego b/rego/lib/arm/network_security_group_library.rego new file mode 100644 index 00000000..77a4b232 --- /dev/null +++ b/rego/lib/arm/network_security_group_library.rego @@ -0,0 +1,69 @@ +# Copyright 2020 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This helper rego code works for Azure "no ingress" rules. +# It is built on top of the terraform code that does the same, +# through a simple conversion (`rule_to_tf`). +package fugue.arm.network_security_group_library + +import data.fugue +import data.fugue.azure.network_security_group as tf + +rule_to_tf(arm_rule) = ret { + # We only pass in the attributes we actually use. + props = arm_rule.properties + ret := { + "access": props.access, + "direction": props.direction, + "destination_port_range": object.get(props, "destinationPortRange", null), + "destination_port_ranges": object.get(props, "destinationPortRanges", []), + "source_address_prefix": object.get(props, "sourceAddressPrefix", null), + "source_address_prefixes": object.get(props, "sourceAddressPrefixes", null), + } +} + +rule_allows_anywhere_to_port(rule, bad_port) { + tf.rule_allows_anywhere_to_port(rule_to_tf(rule), bad_port) +} + +group_allows_anywhere_to_port(group, bad_port) { + rule = group.properties.securityRules[_] + tf.rule_allows_anywhere_to_port(rule_to_tf(rule), bad_port) +} + +no_inbound_anywhere_to_port_policy(port) = ret { + security_groups := fugue.resources("Microsoft.Network/networkSecurityGroups") + security_groups_policy = {p | + security_group := security_groups[_] + group_allows_anywhere_to_port(security_group, port) + p := fugue.deny_resource(security_group) + } | {p | + security_group := security_groups[_] + not group_allows_anywhere_to_port(security_group, port) + p := fugue.allow_resource(security_group) + } + + security_rules := fugue.resources("Microsoft.Network/networkSecurityGroups/securityRules") + security_rules_policy = {p | + security_rule := security_rules[_] + rule_allows_anywhere_to_port(security_rule, port) + p := fugue.deny_resource(security_rule) + } | {p | + security_rule := security_rules[_] + not rule_allows_anywhere_to_port(security_rule, port) + p := fugue.allow_resource(security_rule) + } + + ret := security_groups_policy | security_rules_policy +} diff --git a/rego/lib/arm/postgresql_configuration_library.rego b/rego/lib/arm/postgresql_configuration_library.rego new file mode 100644 index 00000000..d4538471 --- /dev/null +++ b/rego/lib/arm/postgresql_configuration_library.rego @@ -0,0 +1,47 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package fugue.arm.postgresql_configuration_library + +import data.fugue + +servers = fugue.resources("Microsoft.DBforPostgreSQL/servers") + +configurations = fugue.resources("Microsoft.DBforPostgreSQL/servers/configurations") + +configuration_defaults := { + "connection_throttling": "on", + "log_checkpoints": "on", + "log_connections": "on", + "log_disconnections": "off", + "log_duration": "off", + "log_retention_days": "3", +} + +configuration_by_server_id := {server_id: configuration | + server := servers[server_id] + configuration := {name: value | + option := configurations[_] + option._parent_id == server_id + id_parts := split(option.id, "/") + name := id_parts[count(id_parts) - 1] + value := option.properties.value + } +} + +configuration_value(server, name) = ret { + ret := configuration_by_server_id[server.id][name] +} else = ret { + ret := configuration_defaults[name] +} diff --git a/rego/lib/fugue/input_type.rego b/rego/lib/fugue/input_type.rego index 0b07ce30..df8663ed 100644 --- a/rego/lib/fugue/input_type.rego +++ b/rego/lib/fugue/input_type.rego @@ -22,6 +22,7 @@ package fugue.input_type_internal # - "tf_runtime" # - "cfn" # - "k8s" +# - "arm" # # To check the current resource type, use `input_type`. # To check if a rule applies for this input type, use `compatibility`. @@ -40,6 +41,8 @@ input_type = "tf" { _ = input.AWSTemplateFormatVersion } else = "k8s" { _ = input.k8s_resource_view_version +} else = "arm" { + _ = input.contentVersion } else = "unknown" { true } @@ -58,6 +61,10 @@ kubernetes_input_type { input_type == "k8s" } +arm_input_type { + input_type == "arm" +} + rule_input_type(pkg) = ret { # This is a workaround for an issue in fregot, where the next line will fail # the typechecker when there isn't a single `input_type` defined, which is @@ -77,4 +84,5 @@ compatibility := { "cfn": {"cfn"}, "cloudformation": {"cfn"}, # Backwards-compatibility "k8s": {"k8s"}, + "arm": {"arm"}, } diff --git a/rego/lib/fugue/resource_view.rego b/rego/lib/fugue/resource_view.rego index 960cc31c..70a7e8a2 100644 --- a/rego/lib/fugue/resource_view.rego +++ b/rego/lib/fugue/resource_view.rego @@ -21,6 +21,7 @@ import data.fugue.input_type_internal import data.fugue.resource_view.cloudformation import data.fugue.resource_view.terraform import data.fugue.resource_view.kubernetes +import data.fugue.resource_view.arm resource_view = ret { # If we are already given a resource view, just pass it through. @@ -35,6 +36,9 @@ resource_view = ret { } else = ret { input_type_internal.kubernetes_input_type ret = kubernetes.resource_view +} else = ret { + input_type_internal.arm_input_type + ret = arm.resource_view } resource_view_input = ret { @@ -49,4 +53,7 @@ resource_view_input = ret { } else = ret { input_type_internal.kubernetes_input_type ret = {"resources": resource_view, "_template": input} +} else = ret { + input_type_internal.arm_input_type + ret = {"resources": resource_view, "_template": input} } diff --git a/rego/lib/fugue/resource_view/arm.rego b/rego/lib/fugue/resource_view/arm.rego new file mode 100644 index 00000000..e85276bf --- /dev/null +++ b/rego/lib/fugue/resource_view/arm.rego @@ -0,0 +1,137 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package fugue.resource_view.arm + +# Returns a list of all parent resources of the resource at the given path, +# ending with the resource itself. +parent_resources(top_level_resource, path) = ret { + indices := numbers.range(1, floor(count(path) / 2)) + ret := array.concat([top_level_resource], [resource | + i := indices[_] * 2 + parent_path := array.slice(path, 0, i) + resource := json.patch(top_level_resource, [{"op": "move", "path": [], "from": parent_path}]) + ]) +} + +# Construct a full name from the type name and names, e.g.: +# +# Microsoft.Network/virtualNetworks + VNet1 = +# -> Microsoft.Network/virtualNetworks/VNet1 +# +# Microsoft.Network/virtualNetworks/subnets + VNet1/Subnet1 = +# -> Microsoft.Network/virtualNetworks/VNet1/subnets/Subnet1 +make_typed_name(type, name) = ret { + # Azure supports up to 5 levels of nesting which we need to write out + # fully, unfortunately. + [service, t0] = split(type, "/") + [n0] = split(name, "/") + ret = concat("/", [service, t0, n0]) +} else = ret { + [service, t0, t1] = split(type, "/") + [n0, n1] = split(name, "/") + ret = concat("/", [service, t0, n0, t1, n1]) +} else = ret { + [service, t0, t1, t2] = split(type, "/") + [n0, n1, n2] = split(name, "/") + ret = concat("/", [service, t0, n0, t1, n1, t2, n2]) +} else = ret { + [service, t0, t1, t2, t3] = split(type, "/") + [n0, n1, n2, n3] = split(name, "/") + ret = concat("/", [service, t0, n0, t1, n1, t2, n2, t3, n3]) +} else = ret { + [service, t0, t1, t2, t3, t4] = split(type, "/") + [n0, n1, n2, n3, n4] = split(name, "/") + ret = concat("/", [service, t0, n0, t1, n1, t2, n2, t3, n3, t4, n4]) +} else = ret { + [service, t0, t1, t2, t3, t4, t5] = split(type, "/") + [n0, n1, n2, n3, n4, n5] = split(name, "/") + ret = concat("/", [service, t0, n0, t1, n1, t2, n2, t3, n3, t4, n4, t5, n5]) +} + +# Retrieve the parent name of a typed name, or null. +# E.g. +# +# Microsoft.Network/virtualNetworks/VNet1/subnets/Subnet1 +# -> Microsoft.Network/virtualNetworks/VNet1 +parent_typed_name(typed_name) = ret { + parts := split(typed_name, "/") + count(parts) > 3 + ret := concat("/", array.slice(parts, 0, count(parts) - 2)) +} else = ret { + ret := null +} + +# Extract all children resources (including the parent itself) from a resource. +extract_resources(top_level_resource) = ret { + ret := {id: resource | + # Walk over a top level resource to retrieve all children. + # The path will be of the shape ["resources", 0, "resources", 2]. + [path, value] = walk(top_level_resource) + count(path) % 2 == 0 + all([ok | k = path[i]; i % 2 == 0; ok := k == "resources"]) + + parents := parent_resources(top_level_resource, path) + name := concat("/", [r.name | r := parents[_]]) + type := concat("/", [r.type | r := parents[_]]) + typed_name := make_typed_name(type, name) + + id := typed_name + resource := json.patch(value, [ + {"op": "add", "path": ["id"], "value": typed_name}, + {"op": "add", "path": ["_type"], "value": type}, + {"op": "add", "path": ["_provider"], "value": "arm"}, + {"op": "add", "path": ["_parent_id"], "value": parent_typed_name(typed_name)}, + ]) + } +} + +resource_view := ret { + # First pass on resources. + resources_0 := {id: resource | + top_level_resource := input.resources[_] + resource := extract_resources(top_level_resource)[id] + } + + # Rewrite references. + resources_1 := {id: resource | + resource_0 := resources_0[id] + patches := [patch | + [path, val] := walk(resource_0) + is_string(val) + rewrite := rewrite_string_reference(val, resources_0) + patch := {"op": "add", "path": path, "value": rewrite} + ] + + resource := json.patch(resource_0, patches) + } + + ret := resources_1 +} + +# Rewrite resource IDs and other references. +rewrite_string_reference(string, resources) = ret { + startswith(string, "[") + tokens := [p | p := regex.split(`[\[\]()',[:space:]]+`, string)[_]; p != ""] + ret = rewrite_token_reference(tokens, resources) +} + +# Matches patterns that can be used to refer to resources. +rewrite_token_reference(tokens, resources) = ret { + tokens[0] == "resourceId" + type := tokens[1] + names := array.slice(tokens, 2, count(tokens)) + typed_name := make_typed_name(type, concat("/", names)) + _ := resources[typed_name] + ret := typed_name +} diff --git a/rego/rules/arm/app_service/auth_enabled.rego b/rego/rules/arm/app_service/auth_enabled.rego new file mode 100644 index 00000000..7fbb2d2c --- /dev/null +++ b/rego/rules/arm/app_service/auth_enabled.rego @@ -0,0 +1,70 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_app_service_auth_enabled + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00345", + "title": "App Service web app authentication should be enabled", + "description": "Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching the API app, or authenticate those that have tokens before they reach the API app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_9.1" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_9.1" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +sites := fugue.resources("Microsoft.Web/sites") +configs := fugue.resources("Microsoft.Web/sites/config") + +is_valid_authsettings(c) { + c.name == "authsettings" + c.properties.enabled == true +} + +is_valid_authsettings(c) { + c.name == "authsettingsv2" + c.properties.platform.enabled == true +} + +valid_sites := {id | + c := configs[_] + is_valid_authsettings(c) + id := c._parent_id + sites[id] +} + +policy[p] { + s := sites[id] + not valid_sites[id] + p = fugue.deny_resource(s) +} + +policy[p] { + s := sites[id] + valid_sites[id] + p = fugue.allow_resource(s) +} diff --git a/rego/rules/arm/app_service/client_certs.rego b/rego/rules/arm/app_service/client_certs.rego new file mode 100644 index 00000000..092f8c1b --- /dev/null +++ b/rego/rules/arm/app_service/client_certs.rego @@ -0,0 +1,44 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_app_service_client_certs + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00348", + "title": "App Service web apps should have 'Incoming client certificates' enabled", + "description": "Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_9.4" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_9.4" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Web/sites" + +default allow = false + +allow { + input.properties.clientCertEnabled == true +} diff --git a/rego/rules/arm/app_service/https_only.rego b/rego/rules/arm/app_service/https_only.rego new file mode 100644 index 00000000..af4b1cb6 --- /dev/null +++ b/rego/rules/arm/app_service/https_only.rego @@ -0,0 +1,44 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_app_service_https_only + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00346", + "title": "App Service web apps should have 'HTTPS only' enabled", + "description": "Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_9.2" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_9.2" + ] + }, + "severity": "High" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Web/sites" + +default allow = false + +allow { + input.properties.httpsOnly == true +} diff --git a/rego/rules/arm/app_service/min_tls_version.rego b/rego/rules/arm/app_service/min_tls_version.rego new file mode 100644 index 00000000..7f705118 --- /dev/null +++ b/rego/rules/arm/app_service/min_tls_version.rego @@ -0,0 +1,76 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_app_service_min_tls_version + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00347", + "title": "App Service web apps should have 'Minimum TLS Version' set to '1.2'", + "description": "The TLS (Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_9.3" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_9.3" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +sites := fugue.resources("Microsoft.Web/sites") +configs := fugue.resources("Microsoft.Web/sites/config") + +min_tls_version := parse_version("1.2") + +parse_version(str) = ret { + ret := [to_number(p) | p = regex.find_n(`[0-9]+`, str, -1)[_]] +} + +valid_via_config := {id | + c := configs[_] + c.name == "web" + parsed := parse_version(c.properties.minTlsVersion) + parsed >= min_tls_version + id := c._parent_id + sites[id] +} + +valid_via_property := {id | + s := sites[id] + parsed := parse_version(s.properties.siteConfig.minTlsVersion) + parsed >= min_tls_version +} + +valid_sites := valid_via_config | valid_via_property + +policy[p] { + s := sites[id] + valid_sites[id] + p = fugue.allow_resource(s) +} + +policy[p] { + s := sites[id] + not valid_sites[id] + p = fugue.deny_resource(s) +} diff --git a/rego/rules/arm/app_service/register_with_ad.rego b/rego/rules/arm/app_service/register_with_ad.rego new file mode 100644 index 00000000..3e2bd725 --- /dev/null +++ b/rego/rules/arm/app_service/register_with_ad.rego @@ -0,0 +1,39 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_app_service_register_with_ad + +__rego__metadoc__ := { + "id": "FG_R00452", + "title": "App Service web apps should use a system-assigned managed service identity", + "description": "A system-assigned managed service entity from Azure Active Directory enables the app to connect to other Azure services securely without the need for usernames and passwords. Eliminating credentials from the app is a more secure approach.", + "custom": { + "controls": { + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_9.5" + ] + }, + "severity": "Low" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Web/sites" + +default allow = false + +allow { + lower(input.identity.type) == "systemassigned" +} diff --git a/rego/rules/arm/authorization/custom_owner_role.rego b/rego/rules/arm/authorization/custom_owner_role.rego new file mode 100644 index 00000000..70b71a08 --- /dev/null +++ b/rego/rules/arm/authorization/custom_owner_role.rego @@ -0,0 +1,70 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_authorization_custom_owner_role + +import data.fugue +import data.fugue.utils + +__rego__metadoc__ := { + "id": "FG_R00288", + "title": "Active Directory custom subscription owner roles should not be created", + "description": "Subscription ownership should not include permission to create custom owner roles. The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_1.23" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_1.21" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Authorization/roledefinitions" + +is_subscription_scope(scope) { + scope == "/" +} + +# Examples: +# * "/subscriptions/479a226b-4153-48f7-8943-3e8e388a93cb" +# * "/subscriptions/479a226b-4153-48f7-8943-3e8e388a93cb/" +is_subscription_scope(scope) { + re_match(`^/subscriptions/[^/]+/?$`, lower(scope)) +} + +# Examples: +# * "[concat('/subscriptions/', subscription().subscriptionId)]" +# * "[concat('/subscriptions/', '479a226b-4153-48f7-8943-3e8e388a93cb')]" +# * "[concat('/subscriptions/', parameters('subscriptionId'))]" +is_subscription_scope(scope) { + re_match(`^\[concat\('/subscriptions/',[^,]+\]$`, replace(lower(scope), " ", "")) +} + +is_subscription_scope(scope) { + replace(lower(scope), " ", "") == "[subscription().id]" +} + +default deny = false + +deny { + actions := utils.as_array(input.properties.permissions[_].actions) + actions[_] == "*" + is_subscription_scope(input.properties.assignableScopes[_]) +} diff --git a/rego/rules/arm/key_vault/recoverable.rego b/rego/rules/arm/key_vault/recoverable.rego new file mode 100644 index 00000000..598de609 --- /dev/null +++ b/rego/rules/arm/key_vault/recoverable.rego @@ -0,0 +1,45 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_key_vault_recoverable + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00227", + "title": "Key Vault 'Enable Soft Delete' and 'Enable Purge Protection' should be enabled", + "description": "Enabling soft deletion ensures that even if the key vault is deleted, the key vault and its objects remain recoverable for next 90 days. In this span of 90 days, the key vault and its objects can be recovered or purged (permanent deletion). Enabling purge protection ensures that the key vault and its objects cannot be purged during the 90 day retention period.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_8.4" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_8.4" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.KeyVault/vaults" + +default allow = false + +allow { + input.properties.enablePurgeProtection == true + input.properties.enableSoftDelete == true +} diff --git a/rego/rules/arm/key_vault/secret_expiry.rego b/rego/rules/arm/key_vault/secret_expiry.rego new file mode 100644 index 00000000..ed121669 --- /dev/null +++ b/rego/rules/arm/key_vault/secret_expiry.rego @@ -0,0 +1,44 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_key_vault_secret_expiry + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00451", + "title": "Key Vault secrets should have an expiration date set", + "description": "By default, Key Vault secrets do not expire, which can be a security issue if secrets are compromised. As a best practice, an explicit expiration date should be set for secrets and secrets should be rotated.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_8.2" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_8.2" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.KeyVault/vaults/secrets" + +default allow = false + +allow { + is_number(input.properties.attributes.exp) +} diff --git a/rego/rules/arm/kubernetes/cluster_instances_rbac.rego b/rego/rules/arm/kubernetes/cluster_instances_rbac.rego new file mode 100644 index 00000000..0535f8b4 --- /dev/null +++ b/rego/rules/arm/kubernetes/cluster_instances_rbac.rego @@ -0,0 +1,44 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_kubernetes_cluster_instances_rbac + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00329", + "title": "Azure Kubernetes Service instances should have RBAC enabled", + "description": "Azure Kubernetes Services has the capability to integrate Azure Active Directory users and groups into Kubernetes RBAC controls within the AKS Kubernetes API Server. This should be utilized to enable granular access to Kubernetes resources within the AKS clusters supporting RBAC controls not just of the overarching AKS instance but also the individual resources managed within Kubernetes.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_8.5" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_8.5" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.ContainerService/managedClusters" + +default allow = false + +allow { + input.properties.enableRBAC == true +} diff --git a/rego/rules/arm/monitor/key_vault_logging.rego b/rego/rules/arm/monitor/key_vault_logging.rego new file mode 100644 index 00000000..0bc987f5 --- /dev/null +++ b/rego/rules/arm/monitor/key_vault_logging.rego @@ -0,0 +1,82 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_monitor_key_vault_logging + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00344", + "title": "Key Vault logging should be enabled", + "description": "Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_5.1.7" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_5.1.5" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +key_vaults := fugue.resources("Microsoft.KeyVault/vaults") +diagnostic_settings := fugue.resources("Microsoft.Insights/diagnosticSettings") + +tokenize(str) = ret { + ret = [p | p := regex.split(`[\[\]()',[:space:]]+`, str)[_]; p != ""] +} + +retention_is_valid(retention) { + retention.enabled == true + retention.days >= 180 +} + +retention_is_valid(retention) { + retention.enabled == true + retention.days == 0 +} + +valid_key_vault_diagnostics := {id: ds | + ds := diagnostic_settings[id] + contains(lower(ds.scope), "microsoft.keyvault/vaults") + log = ds.properties.logs[_] + lower(log.category) == "auditevent" + log.enabled == true + retention_is_valid(log.retentionPolicy) +} + +valid_key_vaults := {id | + kv := key_vaults[id] + ds := valid_key_vault_diagnostics[_] + tokenize(lower(ds.scope))[_] == lower(kv.name) +} + +policy[p] { + kv := key_vaults[id] + valid_key_vaults[id] + p := fugue.allow_resource(kv) +} + +policy[p] { + kv := key_vaults[id] + not valid_key_vaults[id] + p := fugue.deny_resource(kv) +} diff --git a/rego/rules/arm/monitor/log_profile_all_categories.rego b/rego/rules/arm/monitor/log_profile_all_categories.rego new file mode 100644 index 00000000..0119abe4 --- /dev/null +++ b/rego/rules/arm/monitor/log_profile_all_categories.rego @@ -0,0 +1,44 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_monitor_log_profile_all_categories + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00341", + "title": "Monitor audit profile should log all activities", + "description": "The log profile should be configured to export all activities from the control/management plane. A log profile controls how the activity log is exported. Configuring the log profile to collect logs for the categories \"write\", \"delete\" and \"action\" ensures that all the control/management plane activities performed on the subscription are exported.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_5.1.3" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Insights/logprofiles" + +required_categories := {"write", "delete", "action"} + +default allow = false + +allow { + categories := {lower(c) | c = input.properties.categories[_]} + count(required_categories - categories) == 0 +} diff --git a/rego/rules/arm/monitor/log_profile_global_locations.rego b/rego/rules/arm/monitor/log_profile_global_locations.rego new file mode 100644 index 00000000..5e051368 --- /dev/null +++ b/rego/rules/arm/monitor/log_profile_global_locations.rego @@ -0,0 +1,68 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_monitor_log_profile_global_locations + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00342", + "title": "Monitor log profile should have activity logs for global services and all regions", + "description": "Configure the log profile to export activities from all Azure supported regions/locations including global. This rule is evaluated against all resource locations that Fugue has permission to scan.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_5.1.4" + ], + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +log_profiles = fugue.resources("Microsoft.Insights/logprofiles") + +used_locations := {lower(l) | + fugue.resource_types_v0[ty] + r := fugue.resources(ty) + l := r[_].location +} + +required_locations := used_locations | {"global"} + +invalid_profiles := {id: msg | + profile := log_profiles[id] + locs := {lower(l) | l = profile.properties.locations[_]} + missing := required_locations - locs + count(missing) > 0 + msg := sprintf( + "The log profile is missing the following locations: %s", + [concat(", ", missing)] + ) +} + +policy[p] { + profile := log_profiles[id] + not invalid_profiles[id] + p := fugue.allow({"resource": profile}) +} + +policy[p] { + profile := log_profiles[id] + msg := invalid_profiles[id] + p := fugue.deny({"resource": profile, "message": msg}) +} diff --git a/rego/rules/arm/monitor/log_profile_retention.rego b/rego/rules/arm/monitor/log_profile_retention.rego new file mode 100644 index 00000000..69586464 --- /dev/null +++ b/rego/rules/arm/monitor/log_profile_retention.rego @@ -0,0 +1,48 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_monitor_log_profile_retention + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00340", + "title": "Monitor 'Activity Log Retention' should be 365 days or greater", + "description": "A log profile controls how the activity log is exported and retained. Since the average time to detect a breach is 210 days, the activity log should be retained for 365 days or more in order to have time to respond to any incidents.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_5.1.2" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Insights/logprofiles" + +default allow = false + +allow { + input.properties.retentionPolicy.enabled == true + input.properties.retentionPolicy.days >= 365 +} + +allow { + input.properties.retentionPolicy.enabled == true + # A value of 0 will retain the events indefinitely. + input.properties.retentionPolicy.days == 0 +} diff --git a/rego/rules/arm/mysql/enforce_ssl.rego b/rego/rules/arm/mysql/enforce_ssl.rego new file mode 100644 index 00000000..c4bf6459 --- /dev/null +++ b/rego/rules/arm/mysql/enforce_ssl.rego @@ -0,0 +1,41 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_mysql_enforce_ssl + +__rego__metadoc__ := { + "id": "FG_R00225", + "title": "MySQL Database server 'enforce SSL connection' should be enabled", + "description": "Enforcing SSL connections between your database server and your client applications helps protect against \"man in the middle\" attacks by encrypting the data stream between the server and your application.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_4.11" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_4.3.2" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.DBforMySQL/servers" + +default allow = false +allow { + lower(input.properties.sslEnforcement) == "enabled" +} diff --git a/rego/rules/arm/mysql/no_inbound_all.rego b/rego/rules/arm/mysql/no_inbound_all.rego new file mode 100644 index 00000000..f8975355 --- /dev/null +++ b/rego/rules/arm/mysql/no_inbound_all.rego @@ -0,0 +1,35 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_mysql_no_inbound_all + +__rego__metadoc__ := { + "id": "FG_R00222", + "title": "MySQL Database server firewall rules should not permit start and end IP addresses to be 0.0.0.0", + "description": "Adding a rule with range 0.0.0.0 to 0.0.0.0 is the same as enabling the \"Allow access to Azure services\" setting, which allows all connections from Azure, including from other subscriptions. Disabling this setting helps prevent malicious Azure users from connecting to your database and accessing sensitive data.", + "custom": { + "controls": {}, + "severity": "High" + } +} + +input_type = "arm" + +resource_type = "Microsoft.DBforMySQL/servers/firewallRules" + +default deny = false +deny { + input.properties.startIpAddress == "0.0.0.0" + input.properties.endIpAddress == "0.0.0.0" +} diff --git a/rego/rules/arm/network/app_gateway_waf_enabled.rego b/rego/rules/arm/network/app_gateway_waf_enabled.rego new file mode 100644 index 00000000..7f56ac83 --- /dev/null +++ b/rego/rules/arm/network/app_gateway_waf_enabled.rego @@ -0,0 +1,40 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_network_app_gateway_waf_enabled + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00224", + "title": "Ensure Azure Application Gateway Web application firewall (WAF) is enabled", + "description": "Azure Application Gateway offers a web application firewall (WAF) that provides centralized protection of your web applications from common exploits and vulnerabilities. Web applications are increasingly targeted by malicious attacks that exploit commonly known vulnerabilities.", + "custom": { + "controls": {}, + "severity": "Medium", + }, +} + +input_type = "arm" + +resource_type = "Microsoft.Network/applicationGateways" + +default allow = false + +allow { + waf_sku_tiers[input.properties.sku.tier] + input.properties.webApplicationFirewallConfiguration.enabled == true +} + +waf_sku_tiers = {"WAF", "WAF_v2"} diff --git a/rego/rules/arm/network/flow_log_retention.rego b/rego/rules/arm/network/flow_log_retention.rego new file mode 100644 index 00000000..626df6a7 --- /dev/null +++ b/rego/rules/arm/network/flow_log_retention.rego @@ -0,0 +1,69 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_network_flow_log_retention + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00286", + "title": "Virtual Network security group flow log retention period should be set to 90 days or greater", + "description": "Flow logs enable capturing information about IP traffic flowing in and out of network security groups. Logs can be used to check for anomalies and give insight into suspected breaches.", + "custom": { + "controls": {}, + "severity": "Medium", + }, +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +network_security_groups = fugue.resources("Microsoft.Network/networkSecurityGroups") + +flow_logs = fugue.resources("Microsoft.Network/networkWatchers/flowLogs") + +nsg_id_to_flow_logs := {nsg_id: nsg_flow_logs | + _ := network_security_groups[nsg_id] + nsg_flow_logs := [flow_log | + flow_log := flow_logs[_] + nsg_id == flow_log.properties.targetResourceId + ] +} + +flow_log_has_retention(flow_log) { + flow_log.properties.retentionPolicy.enabled == true + flow_log.properties.retentionPolicy.days >= 90 +} + +bad_nsg(nsg) = msg { + count(nsg_id_to_flow_logs[nsg.id]) < 1 + msg := "No associated flow logs found" +} else = msg { + flow_log := nsg_id_to_flow_logs[nsg.id][_] + not flow_log_has_retention(flow_log) + msg := "Retention policy needs to be set to 90 days or more" +} + +policy[p] { + nsg := network_security_groups[_] + msg := bad_nsg(nsg) + p := fugue.deny({"resource": nsg, "message": msg}) +} + +policy[p] { + nsg := network_security_groups[_] + not bad_nsg(nsg) + p := fugue.allow({"resource": nsg}) +} diff --git a/rego/rules/arm/network/security_group_no_inbound_22.rego b/rego/rules/arm/network/security_group_no_inbound_22.rego new file mode 100644 index 00000000..03d9569e --- /dev/null +++ b/rego/rules/arm/network/security_group_no_inbound_22.rego @@ -0,0 +1,33 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_network_security_group_no_inbound_22 + +import data.fugue.arm.network_security_group_library as lib + +__rego__metadoc__ := { + "id": "FG_R00191", + "title": "Virtual Network security groups should not permit ingress from '0.0.0.0/0' to TCP/UDP port 22 (SSH)", + "description": "The potential security problem with using SSH over the internet is that attackers can use various brute force techniques to gain access to Azure Virtual Machines. Once the attackers gain access, they can use a virtual machine as a launch point for compromising other machines on the Azure Virtual Network or even attack networked devices outside of Azure.", + "custom": { + "controls": {}, + "severity": "High", + }, +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +policy = lib.no_inbound_anywhere_to_port_policy(22) diff --git a/rego/rules/arm/network/security_group_no_inbound_3389.rego b/rego/rules/arm/network/security_group_no_inbound_3389.rego new file mode 100644 index 00000000..451e58fc --- /dev/null +++ b/rego/rules/arm/network/security_group_no_inbound_3389.rego @@ -0,0 +1,33 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_network_security_group_no_inbound_3389 + +import data.fugue.arm.network_security_group_library as lib + +__rego__metadoc__ := { + "id": "FG_R00190", + "title": "Virtual Network security groups should not permit ingress from '0.0.0.0/0' to TCP/UDP port 3389 (RDP)", + "description": "The potential security problem with using RDP over the Internet is that attackers can use various brute force techniques to gain access to Azure Virtual Machines. Once the attackers gain access, they can use a virtual machine as a launch point for compromising other machines on an Azure Virtual Network or even attack networked devices outside of Azure.", + "custom": { + "controls": {}, + "severity": "High", + }, +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +policy = lib.no_inbound_anywhere_to_port_policy(3389) diff --git a/rego/rules/arm/postgresql/connection_throttling.rego b/rego/rules/arm/postgresql/connection_throttling.rego new file mode 100644 index 00000000..7a721701 --- /dev/null +++ b/rego/rules/arm/postgresql/connection_throttling.rego @@ -0,0 +1,55 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_connection_throttling + +import data.fugue +import data.fugue.arm.postgresql_configuration_library as lib + +__rego__metadoc__ := { + "id": "FG_R00335", + "title": "PostgreSQL Database configuration 'connection_throttling' should be on", + "description": "Enabling connection_throttling helps the PostgreSQL Database to Set the verbosity of logged messages which in turn generates query and error logs with respect to concurrent connections, that could lead to a successful Denial of Service (DoS) attack by exhausting connection resources.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_4.17" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_4.3.6" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +is_valid(server) { + lower(lib.configuration_value(server, "connection_throttling")) == "on" +} + +policy[p] { + server = lib.servers[_] + is_valid(server) + p = fugue.allow_resource(server) +} + +policy[p] { + server = lib.servers[_] + not is_valid(server) + p = fugue.deny_resource(server) +} diff --git a/rego/rules/arm/postgresql/enforce_ssl.rego b/rego/rules/arm/postgresql/enforce_ssl.rego new file mode 100644 index 00000000..0ea3a791 --- /dev/null +++ b/rego/rules/arm/postgresql/enforce_ssl.rego @@ -0,0 +1,43 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_enforce_ssl + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00226", + "title": "PostgreSQL Database server 'enforce SSL connection' should be enabled", + "description": "Enforcing SSL connections between your database server and your client applications helps protect against \"man in the middle\" attacks by encrypting the data stream between the server and your application.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_4.13" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_4.3.1" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.DBforPostgreSQL/servers" + +default allow = false +allow { + lower(input.properties.sslEnforcement) == "enabled" +} diff --git a/rego/rules/arm/postgresql/log_checkpoints.rego b/rego/rules/arm/postgresql/log_checkpoints.rego new file mode 100644 index 00000000..65567fd0 --- /dev/null +++ b/rego/rules/arm/postgresql/log_checkpoints.rego @@ -0,0 +1,55 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_log_checkpoints + +import data.fugue +import data.fugue.arm.postgresql_configuration_library as lib + +__rego__metadoc__ := { + "id": "FG_R00317", + "title": "PostgreSQL Database configuration 'log_checkpoints' should be on", + "description": "Enabling log_checkpoints helps the PostgreSQL Database to Log each checkpoint in turn generates query and error logs. However, access to transaction logs is not supported. Query and error logs can be used to identify, troubleshoot, and repair configuration errors and sub-optimal performance.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_4.12" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_4.3.3" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +is_valid(server) { + lower(lib.configuration_value(server, "log_checkpoints")) == "on" +} + +policy[p] { + server = lib.servers[_] + is_valid(server) + p = fugue.allow_resource(server) +} + +policy[p] { + server = lib.servers[_] + not is_valid(server) + p = fugue.deny_resource(server) +} diff --git a/rego/rules/arm/postgresql/log_connections.rego b/rego/rules/arm/postgresql/log_connections.rego new file mode 100644 index 00000000..e3ffb7de --- /dev/null +++ b/rego/rules/arm/postgresql/log_connections.rego @@ -0,0 +1,55 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_log_connections + +import data.fugue +import data.fugue.arm.postgresql_configuration_library as lib + +__rego__metadoc__ := { + "id": "FG_R00318", + "title": "PostgreSQL Database configuration 'log_connections' should be on", + "description": "Enabling log_connections helps PostgreSQL Database to log attempted connection to the server, as well as successful completion of client authentication. Log data can be used to identify, troubleshoot, and repair configuration errors and suboptimal performance.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_4.14" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_4.3.4" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +is_valid(server) { + lower(lib.configuration_value(server, "log_connections")) == "on" +} + +policy[p] { + server = lib.servers[_] + is_valid(server) + p = fugue.allow_resource(server) +} + +policy[p] { + server = lib.servers[_] + not is_valid(server) + p = fugue.deny_resource(server) +} diff --git a/rego/rules/arm/postgresql/log_disconnections.rego b/rego/rules/arm/postgresql/log_disconnections.rego new file mode 100644 index 00000000..7e0bbbfd --- /dev/null +++ b/rego/rules/arm/postgresql/log_disconnections.rego @@ -0,0 +1,55 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_log_disconnections + +import data.fugue +import data.fugue.arm.postgresql_configuration_library as lib + +__rego__metadoc__ := { + "id": "FG_R00331", + "title": "PostgreSQL Database configuration 'log_disconnections' should be on", + "description": "Enabling log_disconnections helps PostgreSQL Database to Logs end of a session, including duration, which in turn generates query and error logs. Query and error logs can be used to identify, troubleshoot, and repair configuration errors and sub-optimal performance.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_4.15" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_4.3.5" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +is_valid(server) { + lower(lib.configuration_value(server, "log_disconnections")) == "on" +} + +policy[p] { + server = lib.servers[_] + is_valid(server) + p = fugue.allow_resource(server) +} + +policy[p] { + server = lib.servers[_] + not is_valid(server) + p = fugue.deny_resource(server) +} diff --git a/rego/rules/arm/postgresql/log_duration.rego b/rego/rules/arm/postgresql/log_duration.rego new file mode 100644 index 00000000..0c4a6ad7 --- /dev/null +++ b/rego/rules/arm/postgresql/log_duration.rego @@ -0,0 +1,52 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_log_duration + +import data.fugue +import data.fugue.arm.postgresql_configuration_library as lib + +__rego__metadoc__ := { + "id": "FG_R00333", + "title": "PostgreSQL Database configuration 'log_duration' should be on", + "description": "Enabling log_duration helps the PostgreSQL Database to Logs the duration of each completed SQL statement which in turn generates query and error logs. Query and error logs can be used to identify, troubleshoot, and repair configuration errors and sub-optimal performance.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_4.16" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +is_valid(server) { + lower(lib.configuration_value(server, "log_duration")) == "on" +} + +policy[p] { + server = lib.servers[_] + is_valid(server) + p = fugue.allow_resource(server) +} + +policy[p] { + server = lib.servers[_] + not is_valid(server) + p = fugue.deny_resource(server) +} diff --git a/rego/rules/arm/postgresql/log_retention.rego b/rego/rules/arm/postgresql/log_retention.rego new file mode 100644 index 00000000..1ef9ba97 --- /dev/null +++ b/rego/rules/arm/postgresql/log_retention.rego @@ -0,0 +1,56 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_log_retention + +import data.fugue +import data.fugue.arm.postgresql_configuration_library as lib + +__rego__metadoc__ := { + "id": "FG_R00337", + "title": "PostgreSQL Database configuration 'log_retention days' should be greater than 3", + "description": "Enabling log_retention_days helps PostgreSQL Database to Sets number of days a log file is retained which in turn generates query and error logs. Query and error logs can be used to identify, troubleshoot, and repair configuration errors and sub-optimal performance.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_4.18" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_4.3.7" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +is_valid(server) { + days = lib.configuration_value(server, "log_retention_days") + to_number(days) > 3 +} + +policy[p] { + server = lib.servers[_] + is_valid(server) + p = fugue.allow_resource(server) +} + +policy[p] { + server = lib.servers[_] + not is_valid(server) + p = fugue.deny_resource(server) +} diff --git a/rego/rules/arm/postgresql/no_inbound_all.rego b/rego/rules/arm/postgresql/no_inbound_all.rego new file mode 100644 index 00000000..7e00c174 --- /dev/null +++ b/rego/rules/arm/postgresql/no_inbound_all.rego @@ -0,0 +1,39 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_no_inbound_all + +__rego__metadoc__ := { + "id": "FG_R00223", + "title": "PostgreSQL Database server firewall rules should not permit start and end IP addresses to be 0.0.0.0", + "description": "Adding a rule with range 0.0.0.0 to 0.0.0.0 is the same as enabling the \"Allow access to Azure services\" setting, which allows all connections from Azure, including from other subscriptions. Disabling this setting helps prevent malicious Azure users from connecting to your database and accessing sensitive data.", + "custom": { + "controls": { + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_4.3.8" + ] + }, + "severity": "High" + } +} + +input_type = "arm" + +resource_type = "Microsoft.DBforPostgreSQL/servers/firewallRules" + +default deny = false +deny { + input.properties.startIpAddress == "0.0.0.0" + input.properties.endIpAddress == "0.0.0.0" +} diff --git a/rego/rules/arm/security/contact_notifications_enabled.rego b/rego/rules/arm/security/contact_notifications_enabled.rego new file mode 100644 index 00000000..e261ee75 --- /dev/null +++ b/rego/rules/arm/security/contact_notifications_enabled.rego @@ -0,0 +1,39 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_security_contact_notifications_enabled + +__rego__metadoc__ := { + "id": "FG_R00468", + "title": "Security Center 'Send email notification for high severity alerts' should be enabled", + "description": "Security Center email notifications ensure that the appropriate individuals in an organization are notified when issues occur, speeding up time to remediation. If using the Azure CLI or API, notifications are sent for \"high\" or greater severity alerts. If using the Azure Portal, users have the additional option of configuring the severity level.", + "custom": { + "controls": { + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_2.14" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Security/securityContacts" + +default allow = false + +allow { + lower(input.properties.alertNotifications) == "on" +} diff --git a/rego/rules/arm/sql/auditing.rego b/rego/rules/arm/sql/auditing.rego new file mode 100644 index 00000000..a5ea6618 --- /dev/null +++ b/rego/rules/arm/sql/auditing.rego @@ -0,0 +1,59 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_sql_auditing + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00282", + "title": "SQL Server auditing should be enabled", + "description": "The Azure platform allows a SQL server to be created as a service. Enabling auditing at the server level ensures that all existing and newly created databases on the SQL server instance are audited. Auditing policy applied on the SQL database does not override auditing policy and settings applied on the particular SQL server where the database is hosted.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_4.1" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_4.1.1" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +servers = fugue.resources("Microsoft.Sql/servers") +auditing_settings = fugue.resources("Microsoft.Sql/servers/auditingSettings") + +valid_server_ids[id] { + settings := auditing_settings[_] + lower(settings.properties.state) == "enabled" + id := settings._parent_id +} + +policy[p] { + server := servers[_] + not valid_server_ids[server.id] + p := fugue.deny_resource(server) +} + +policy[p] { + server := servers[_] + valid_server_ids[server.id] + p := fugue.allow_resource(server) +} diff --git a/rego/rules/arm/sql/auditing_retention.rego b/rego/rules/arm/sql/auditing_retention.rego new file mode 100644 index 00000000..ba206c84 --- /dev/null +++ b/rego/rules/arm/sql/auditing_retention.rego @@ -0,0 +1,59 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_sql_auditing_retention + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00283", + "title": "SQL Server auditing retention should be 90 days or greater", + "description": "Audit Logs can be used to check for anomalies and give insight into suspected breaches or misuse of information and access.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_4.3" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_4.1.3" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +servers = fugue.resources("Microsoft.Sql/servers") +auditing_settings = fugue.resources("Microsoft.Sql/servers/auditingSettings") + +valid_server_ids[id] { + settings := auditing_settings[_] + settings.properties.retentionDays >= 90 + id := settings._parent_id +} + +policy[p] { + server := servers[_] + not valid_server_ids[server.id] + p := fugue.deny_resource(server) +} + +policy[p] { + server := servers[_] + valid_server_ids[server.id] + p := fugue.allow_resource(server) +} diff --git a/rego/rules/arm/sql/no_inbound_all.rego b/rego/rules/arm/sql/no_inbound_all.rego new file mode 100644 index 00000000..8920fc56 --- /dev/null +++ b/rego/rules/arm/sql/no_inbound_all.rego @@ -0,0 +1,35 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_sql_no_inbound_all + +__rego__metadoc__ := { + "id": "FG_R00221", + "title": "SQL Server firewall rules should not permit start and end IP addresses to be 0.0.0.0", + "description": "Adding a rule with range 0.0.0.0 to 0.0.0.0 is the same as enabling the \"Allow access to Azure services\" setting, which allows all connections from Azure, including from other subscriptions. Disabling this setting helps prevent malicious Azure users from connecting to your database and accessing sensitive data.", + "custom": { + "controls": {}, + "severity": "High" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Sql/servers/firewallRules" + +default deny = false +deny { + input.properties.startIpAddress == "0.0.0.0" + input.properties.endIpAddress == "0.0.0.0" +} diff --git a/rego/rules/arm/storage/account_default_deny_access.rego b/rego/rules/arm/storage/account_default_deny_access.rego new file mode 100644 index 00000000..4bcca386 --- /dev/null +++ b/rego/rules/arm/storage/account_default_deny_access.rego @@ -0,0 +1,41 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_storage_account_default_deny_access + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00154", + "title": "Storage Account default network access rules should deny all traffic", + "description": "Storage accounts should be configured to deny access to traffic from all networks. Access can be granted to traffic from specific Azure Virtual networks, allowing a secure network boundary for specific applications to be built. Access can also be granted to public internet IP address ranges, to enable connections from specific internet or on-premises clients. When network rules are configured, only applications from allowed networks can access a storage account. When calling from an allowed network, applications continue to require proper authorization (a valid access key or SAS token) to access the storage account.", + "custom": { + "controls": { + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_3.6" + ] + }, + "severity": "High" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Storage/storageAccounts" + +default allow = false + +allow { + lower(input.properties.networkAcls.defaultAction) == "deny" +} diff --git a/rego/rules/arm/storage/account_queue_logging.rego b/rego/rules/arm/storage/account_queue_logging.rego new file mode 100644 index 00000000..91c0ab68 --- /dev/null +++ b/rego/rules/arm/storage/account_queue_logging.rego @@ -0,0 +1,48 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_storage_account_queue_logging + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00440", + "title": "Storage Queue logging should be enabled for read, write, and delete requests", + "description": "Storage account read, write, and delete logging for Storage Queues is not enabled by default. Logging should be enabled so that users can monitor queues for security and performance issues.", + "custom": { + "controls": { + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_3.3" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Storage/storageAccounts/queueServices/providers/diagnosticsettings" + +default allow = false + +allow { + enabled_log_categories := {lower(log.category) | + log := input.properties.logs[_] + log.enabled == true + } + + enabled_log_categories["storageread"] + enabled_log_categories["storagewrite"] + enabled_log_categories["storagedelete"] +} diff --git a/rego/rules/arm/storage/account_secure_transfer.rego b/rego/rules/arm/storage/account_secure_transfer.rego new file mode 100644 index 00000000..88ebf35b --- /dev/null +++ b/rego/rules/arm/storage/account_secure_transfer.rego @@ -0,0 +1,48 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_storage_account_secure_transfer + +__rego__metadoc__ := { + "id": "FG_R00152", + "title": "Storage Accounts 'Secure transfer required' should be enabled", + "description": "The secure transfer option enhances the security of a storage account by only allowing requests to the storage account by a secure connection. This control does not apply for custom domain names since Azure storage does not support HTTPS for custom domain names.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_3.1" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_3.1" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Storage/storageAccounts" + +default deny = false + +deny { + # supportsHttpsTrafficOnly defaults to true starting with api version 2019-04-01 + input.apiVersion < "2019-04-01" + not input.properties.supportsHttpsTrafficOnly +} + +deny { + input.properties.supportsHttpsTrafficOnly == false +} diff --git a/rego/rules/arm/storage/account_trusted_ms_services.rego b/rego/rules/arm/storage/account_trusted_ms_services.rego new file mode 100644 index 00000000..202dcbc7 --- /dev/null +++ b/rego/rules/arm/storage/account_trusted_ms_services.rego @@ -0,0 +1,41 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_storage_account_trusted_ms_services + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00208", + "title": "Storage Accounts should have 'Trusted Microsoft Services' enabled", + "description": "Some Microsoft services that interact with storage accounts operate from networks that can't be granted access through network rules. Enabling \"Trusted Microsoft Services\" allows Azure Backup, Azure Site Recovery, Azure Networking, Azure Monitor, and other Azure services to access your storage account and bypass any firewall rules.", + "custom": { + "controls": { + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.3.0_3.7" + ] + }, + "severity": "Medium" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Storage/storageAccounts" + +default allow = false + +allow { + contains(input.properties.networkAcls.bypass, "AzureServices") +} diff --git a/rego/rules/arm/storage/disable_public_access.rego b/rego/rules/arm/storage/disable_public_access.rego new file mode 100644 index 00000000..82d4b675 --- /dev/null +++ b/rego/rules/arm/storage/disable_public_access.rego @@ -0,0 +1,46 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_storage_disable_public_access + +import data.fugue + +__rego__metadoc__ := { + "id": "FG_R00207", + "title": "Blob Storage containers should have public access disabled", + "description": "Anonymous, public read access to a container and its blobs can be enabled in Azure Blob storage. It grants read-only access to these resources without sharing the account key, and without requiring a shared access signature. It is recommended not to provide anonymous access to blob containers until, and unless, it is strongly desired. A shared access signature token should be used for providing controlled and timed access to blob containers.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_3.6" + ], + "CIS-Azure_v1.3.0": [ + "CIS-Azure_v1.1.0_3.5" + ] + }, + "severity": "Critical" + } +} + +input_type = "arm" + +resource_type = "Microsoft.Storage/storageAccounts/blobServices/containers" + +public_options := {"blob", "container"} + +default deny = false + +deny { + public_options[lower(input.properties.publicAccess)] +} diff --git a/rego/rules/arm/vm/data_disk_encryption.rego b/rego/rules/arm/vm/data_disk_encryption.rego new file mode 100644 index 00000000..8e6acfef --- /dev/null +++ b/rego/rules/arm/vm/data_disk_encryption.rego @@ -0,0 +1,72 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_vm_data_disk_encryption + +import data.fugue +import data.fugue.arm.disk_encryption_library as lib + +__rego__metadoc__ := { + "id": "FG_R00196", + "title": "Virtual Machines data disks (non-boot volumes) should be encrypted", + "description": "Encrypting the IaaS VM's Data disks ensures that its entire content is fully unrecoverable without a key and thus protects the volume from unwarranted reads.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_7.2" + ] + }, + "severity": "High" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +disks[id] = disk { + disk := lib.disks[id] + lib.data_disk_ids[id] +} + +policy[p] { + disk := disks[_] + not lib.disk_encrypted(disk) + p := fugue.deny_resource(disk) +} + +policy[p] { + disk := disks[_] + lib.disk_encrypted(disk) + p := fugue.allow_resource(disk) +} + + +# Data disks inlined in virtual machine definitions do not have encryption +# settings, so mark these as invalid. + +managed_disk(disk) { + _ := disk.managedDisk.id +} + +has_unmanaged_disk(virtual_machine) { + disk := virtual_machine.properties.storageProfile.dataDisks[_] + not managed_disk(disk) +} + +policy[p] { + virtual_machine := lib.virtual_machines[_] + has_unmanaged_disk(virtual_machine) + p := fugue.deny_resource(virtual_machine) +} diff --git a/rego/rules/arm/vm/unattached_disk_encryption.rego b/rego/rules/arm/vm/unattached_disk_encryption.rego new file mode 100644 index 00000000..584a60f4 --- /dev/null +++ b/rego/rules/arm/vm/unattached_disk_encryption.rego @@ -0,0 +1,53 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_vm_unattached_disk_encryption + +import data.fugue +import data.fugue.arm.disk_encryption_library as lib + +__rego__metadoc__ := { + "id": "FG_R00197", + "title": "Virtual Machines unattached disks should be encrypted", + "description": "Encrypting the IaaS VM's disks ensures that its entire content is fully unrecoverable without a key and thus protects the volume from unwarranted reads.", + "custom": { + "controls": { + "CIS-Azure_v1.1.0": [ + "CIS-Azure_v1.1.0_7.3" + ] + }, + "severity": "High" + } +} + +input_type = "arm" + +resource_type = "MULTIPLE" + +disks[id] = disk { + disk := lib.disks[id] + lib.unattached_disk_ids[id] +} + +policy[p] { + disk = disks[_] + not lib.disk_encrypted(disk) + p = fugue.deny_resource(disk) +} + +policy[p] { + disk = disks[_] + lib.disk_encrypted(disk) + p = fugue.allow_resource(disk) +} diff --git a/rego/rules/tf/azurerm/sql/auditing_retention_90days.rego b/rego/rules/tf/azurerm/sql/auditing_retention_90days.rego index a605fd90..3863c42b 100644 --- a/rego/rules/tf/azurerm/sql/auditing_retention_90days.rego +++ b/rego/rules/tf/azurerm/sql/auditing_retention_90days.rego @@ -29,9 +29,9 @@ __rego__metadoc__ := { }, "severity": "Medium" }, - "description": "SQL Server auditing retention should be greater than 90 days. Audit Logs can be used to check for anomalies and give insight into suspected breaches or misuse of information and access.", + "description": "Audit Logs can be used to check for anomalies and give insight into suspected breaches or misuse of information and access.", "id": "FG_R00283", - "title": "SQL Server auditing retention should be greater than 90 days" + "title": "SQL Server auditing retention should be 90 days or greater" } servers = fugue.resources("azurerm_sql_server") diff --git a/rego/tests/lib/fugue_resource_view_arm_test.rego b/rego/tests/lib/fugue_resource_view_arm_test.rego new file mode 100644 index 00000000..c7f5e4c2 --- /dev/null +++ b/rego/tests/lib/fugue_resource_view_arm_test.rego @@ -0,0 +1,63 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package fugue.resource_view + +import data.tests.lib.inputs.arm_resource_view_01 + +test_resource_view_arm { + arm_resource_view_01.mock_resources == expected +} + +expected = { + "Microsoft.Network/virtualNetworks/VNet1": { + "_type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2018-10-01", + "location": "switzerlandnorth", + "resources": [{ + "apiVersion": "2018-10-01", + "dependsOn": ["VNet1"], + "name": "Subnet1", + "type": "subnets", + "properties": {"addressPrefix": "10.0.0.0/24"}, + }], + "_parent_id": null, + "name": "VNet1", + "id": "Microsoft.Network/virtualNetworks/VNet1", + "type": "Microsoft.Network/virtualNetworks", + "_provider": "arm", + "properties": {"addressSpace": {"addressPrefixes": ["10.0.0.0/16"]}}, + }, + "Microsoft.Network/virtualNetworks/VNet1/subnets/Subnet2": { + "_type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2018-10-01", + "_parent_id": "Microsoft.Network/virtualNetworks/VNet1", + "dependsOn": ["VNet1"], + "name": "VNet1/Subnet2", + "id": "Microsoft.Network/virtualNetworks/VNet1/subnets/Subnet2", + "type": "Microsoft.Network/virtualNetworks/subnets", + "_provider": "arm", + "properties": {"addressPrefix": "10.0.1.0/24"}, + }, + "Microsoft.Network/virtualNetworks/VNet1/subnets/Subnet1": { + "_type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2018-10-01", + "_parent_id": "Microsoft.Network/virtualNetworks/VNet1", + "dependsOn": ["VNet1"], + "name": "Subnet1", + "id": "Microsoft.Network/virtualNetworks/VNet1/subnets/Subnet1", + "type": "subnets", + "_provider": "arm", + "properties": {"addressPrefix": "10.0.0.0/24"}, + }, +} diff --git a/rego/tests/lib/inputs/arm_resource_view_01.rego b/rego/tests/lib/inputs/arm_resource_view_01.rego new file mode 100644 index 00000000..f51a44e6 --- /dev/null +++ b/rego/tests/lib/inputs/arm_resource_view_01.rego @@ -0,0 +1,64 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.lib.inputs.arm_resource_view_01 + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2018-10-01", + "name": "VNet1", + "location": "switzerlandnorth", + "properties": { + "addressSpace": { + "addressPrefixes": [ + "10.0.0.0/16" + ] + } + }, + "resources": [ + { + "type": "subnets", + "apiVersion": "2018-10-01", + "name": "Subnet1", + "dependsOn": [ + "VNet1" + ], + "properties": { + "addressPrefix": "10.0.0.0/24" + } + } + ] + }, + { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2018-10-01", + "name": "VNet1/Subnet2", + "dependsOn": [ + "VNet1" + ], + "properties": { + "addressPrefix": "10.0.1.0/24" + } + } + ] +} diff --git a/rego/tests/rules/arm/app_service/auth_enabled_test.rego b/rego/tests/rules/arm/app_service/auth_enabled_test.rego new file mode 100644 index 00000000..0e10de44 --- /dev/null +++ b/rego/tests/rules/arm/app_service/auth_enabled_test.rego @@ -0,0 +1,25 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_app_service_auth_enabled + +import data.tests.rules.arm.app_service.inputs.auth_enabled_infra_json as infra + +test_auth_enabled { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + by_resource_id["Microsoft.Web/sites/withAuth"] == true + by_resource_id["Microsoft.Web/sites/withAuthV2"] == true + by_resource_id["Microsoft.Web/sites/withoutAuth"] == false +} diff --git a/rego/tests/rules/arm/app_service/client_certs_test.rego b/rego/tests/rules/arm/app_service/client_certs_test.rego new file mode 100644 index 00000000..4f2c692a --- /dev/null +++ b/rego/tests/rules/arm/app_service/client_certs_test.rego @@ -0,0 +1,23 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_app_service_client_certs + +import data.tests.rules.arm.app_service.inputs.client_certs_infra_json as infra + +test_client_certs { + allow with input as infra.mock_resources["Microsoft.Web/sites/enabled"] + not allow with input as infra.mock_resources["Microsoft.Web/sites/disabled"] + not allow with input as infra.mock_resources["Microsoft.Web/sites/default"] +} diff --git a/rego/tests/rules/arm/app_service/https_only_test.rego b/rego/tests/rules/arm/app_service/https_only_test.rego new file mode 100644 index 00000000..6dad9226 --- /dev/null +++ b/rego/tests/rules/arm/app_service/https_only_test.rego @@ -0,0 +1,23 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_app_service_https_only + +import data.tests.rules.arm.app_service.inputs.https_only_infra_json as infra + +test_https_only { + allow with input as infra.mock_resources["Microsoft.Web/sites/enabled"] + not allow with input as infra.mock_resources["Microsoft.Web/sites/disabled"] + not allow with input as infra.mock_resources["Microsoft.Web/sites/default"] +} diff --git a/rego/tests/rules/arm/app_service/inputs/auth_enabled_infra.json b/rego/tests/rules/arm/app_service/inputs/auth_enabled_infra.json new file mode 100644 index 00000000..a472e2e7 --- /dev/null +++ b/rego/tests/rules/arm/app_service/inputs/auth_enabled_infra.json @@ -0,0 +1,81 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Web/serverfarms", + "apiVersion": "2021-02-01", + "name": "appServicePlanPortal", + "location": "[resourceGroup().location]", + "sku": { + "name": "B1", + "tier": "Basic", + "size": "B1" + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "withAuth", + "location": "[resourceGroup().location]", + "resources": [ + { + "type": "config", + "apiVersion": "2021-02-01", + "name": "authsettings", + "dependsOn": [ + "[resourceId('Microsoft.Web/Sites', 'withAuth')]" + ], + "properties": { + "enabled": true + } + } + ], + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "withAuthV2", + "location": "[resourceGroup().location]", + "resources": [ + { + "type": "config", + "apiVersion": "2021-02-01", + "name": "authsettingsv2", + "dependsOn": [ + "[resourceId('Microsoft.Web/Sites', 'withAuthV2')]" + ], + "properties": { + "platform": { + "enabled": true + } + } + } + ], + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "withoutAuth", + "location": "[resourceGroup().location]", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + } + } + ] +} diff --git a/rego/tests/rules/arm/app_service/inputs/auth_enabled_infra_json.rego b/rego/tests/rules/arm/app_service/inputs/auth_enabled_infra_json.rego new file mode 100644 index 00000000..415eaa41 --- /dev/null +++ b/rego/tests/rules/arm/app_service/inputs/auth_enabled_infra_json.rego @@ -0,0 +1,103 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.app_service.inputs.auth_enabled_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "apiVersion": "2021-02-01", + "location": "[resourceGroup().location]", + "name": "appServicePlanPortal", + "sku": { + "name": "B1", + "size": "B1", + "tier": "Basic" + }, + "type": "Microsoft.Web/serverfarms" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "withAuth", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "resources": [ + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/Sites', 'withAuth')]" + ], + "name": "authsettings", + "properties": { + "enabled": true + }, + "type": "config" + } + ], + "type": "Microsoft.Web/sites" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "withAuthV2", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "resources": [ + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/Sites', 'withAuthV2')]" + ], + "name": "authsettingsv2", + "properties": { + "platform": { + "enabled": true + } + }, + "type": "config" + } + ], + "type": "Microsoft.Web/sites" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "withoutAuth", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "type": "Microsoft.Web/sites" + } + ] +} + diff --git a/rego/tests/rules/arm/app_service/inputs/client_certs_infra.json b/rego/tests/rules/arm/app_service/inputs/client_certs_infra.json new file mode 100644 index 00000000..e147a48e --- /dev/null +++ b/rego/tests/rules/arm/app_service/inputs/client_certs_infra.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Web/serverfarms", + "apiVersion": "2021-02-01", + "name": "appServicePlanPortal", + "location": "[resourceGroup().location]", + "sku": { + "name": "B1", + "tier": "Basic", + "size": "B1" + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "enabled", + "location": "[resourceGroup().location]", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]", + "clientCertEnabled": true + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "disabled", + "location": "[resourceGroup().location]", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]", + "clientCertEnabled": false + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "default", + "location": "[resourceGroup().location]", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + } + } + ] +} diff --git a/rego/tests/rules/arm/app_service/inputs/client_certs_infra_json.rego b/rego/tests/rules/arm/app_service/inputs/client_certs_infra_json.rego new file mode 100644 index 00000000..c7aabc20 --- /dev/null +++ b/rego/tests/rules/arm/app_service/inputs/client_certs_infra_json.rego @@ -0,0 +1,78 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.app_service.inputs.client_certs_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-02-01", + "location": "[resourceGroup().location]", + "name": "appServicePlanPortal", + "sku": { + "name": "B1", + "size": "B1", + "tier": "Basic" + }, + "type": "Microsoft.Web/serverfarms" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "enabled", + "properties": { + "clientCertEnabled": true, + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "type": "Microsoft.Web/sites" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "disabled", + "properties": { + "clientCertEnabled": false, + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "type": "Microsoft.Web/sites" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "default", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "type": "Microsoft.Web/sites" + } + ] +} + diff --git a/rego/tests/rules/arm/app_service/inputs/https_only_infra.json b/rego/tests/rules/arm/app_service/inputs/https_only_infra.json new file mode 100644 index 00000000..9e7bb8ca --- /dev/null +++ b/rego/tests/rules/arm/app_service/inputs/https_only_infra.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Web/serverfarms", + "apiVersion": "2021-02-01", + "name": "appServicePlanPortal", + "location": "[resourceGroup().location]", + "sku": { + "name": "B1", + "tier": "Basic", + "size": "B1" + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "enabled", + "location": "[resourceGroup().location]", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]", + "httpsOnly": true + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "disabled", + "location": "[resourceGroup().location]", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]", + "httpsOnly": false + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "default", + "location": "[resourceGroup().location]", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + } + } + ] +} diff --git a/rego/tests/rules/arm/app_service/inputs/https_only_infra_json.rego b/rego/tests/rules/arm/app_service/inputs/https_only_infra_json.rego new file mode 100644 index 00000000..76f65f4f --- /dev/null +++ b/rego/tests/rules/arm/app_service/inputs/https_only_infra_json.rego @@ -0,0 +1,78 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.app_service.inputs.https_only_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-02-01", + "location": "[resourceGroup().location]", + "name": "appServicePlanPortal", + "sku": { + "name": "B1", + "size": "B1", + "tier": "Basic" + }, + "type": "Microsoft.Web/serverfarms" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "enabled", + "properties": { + "httpsOnly": true, + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "type": "Microsoft.Web/sites" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "disabled", + "properties": { + "httpsOnly": false, + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "type": "Microsoft.Web/sites" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "default", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "type": "Microsoft.Web/sites" + } + ] +} + diff --git a/rego/tests/rules/arm/app_service/inputs/min_tls_version_infra.json b/rego/tests/rules/arm/app_service/inputs/min_tls_version_infra.json new file mode 100644 index 00000000..bcb0fea9 --- /dev/null +++ b/rego/tests/rules/arm/app_service/inputs/min_tls_version_infra.json @@ -0,0 +1,110 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Web/serverfarms", + "apiVersion": "2021-02-01", + "name": "appServicePlanPortal", + "location": "[resourceGroup().location]", + "sku": { + "name": "B1", + "tier": "Basic", + "size": "B1" + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "validViaProperty", + "location": "[resourceGroup().location]", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]", + "siteConfig": { + "minTlsVersion": "1.2" + } + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "validViaConfig", + "location": "[resourceGroup().location]", + "resources": [ + { + "type": "config", + "apiVersion": "2021-02-01", + "name": "web", + "dependsOn": [ + "[resourceId('Microsoft.Web/Sites', 'validViaConfig')]" + ], + "properties": { + "minTlsVersion": "1.2" + } + } + ], + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "invalidViaConfig", + "location": "[resourceGroup().location]", + "resources": [ + { + "type": "config", + "apiVersion": "2021-02-01", + "name": "web", + "dependsOn": [ + "[resourceId('Microsoft.Web/Sites', 'invalidViaConfig')]" + ], + "properties": { + "minTlsVersion": "1.1" + } + } + ], + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "invalidViaProperty", + "location": "[resourceGroup().location]", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]", + "siteConfig": { + "minTlsVersion": "1.1" + } + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "invalidUnset", + "location": "[resourceGroup().location]", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + } + } + ] +} diff --git a/rego/tests/rules/arm/app_service/inputs/min_tls_version_infra_json.rego b/rego/tests/rules/arm/app_service/inputs/min_tls_version_infra_json.rego new file mode 100644 index 00000000..1329024b --- /dev/null +++ b/rego/tests/rules/arm/app_service/inputs/min_tls_version_infra_json.rego @@ -0,0 +1,132 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.app_service.inputs.min_tls_version_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-02-01", + "location": "[resourceGroup().location]", + "name": "appServicePlanPortal", + "sku": { + "name": "B1", + "size": "B1", + "tier": "Basic" + }, + "type": "Microsoft.Web/serverfarms" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "validViaProperty", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]", + "siteConfig": { + "minTlsVersion": "1.2" + } + }, + "type": "Microsoft.Web/sites" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "validViaConfig", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "resources": [ + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/Sites', 'validViaConfig')]" + ], + "name": "web", + "properties": { + "minTlsVersion": "1.2" + }, + "type": "config" + } + ], + "type": "Microsoft.Web/sites" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "invalidViaConfig", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "resources": [ + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/Sites', 'invalidViaConfig')]" + ], + "name": "web", + "properties": { + "minTlsVersion": "1.1" + }, + "type": "config" + } + ], + "type": "Microsoft.Web/sites" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "invalidViaProperty", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]", + "siteConfig": { + "minTlsVersion": "1.1" + } + }, + "type": "Microsoft.Web/sites" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "invalidUnset", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "type": "Microsoft.Web/sites" + } + ] +} + diff --git a/rego/tests/rules/arm/app_service/inputs/register_with_ad_infra.json b/rego/tests/rules/arm/app_service/inputs/register_with_ad_infra.json new file mode 100644 index 00000000..17e9c0b1 --- /dev/null +++ b/rego/tests/rules/arm/app_service/inputs/register_with_ad_infra.json @@ -0,0 +1,59 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Web/serverfarms", + "apiVersion": "2021-02-01", + "name": "appServicePlanPortal", + "location": "[resourceGroup().location]", + "sku": { + "name": "B1", + "tier": "Basic", + "size": "B1" + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "valid", + "location": "[resourceGroup().location]", + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "invalidType", + "location": "[resourceGroup().location]", + "identity": { + "type": "None" + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-02-01", + "name": "invalidUnset", + "location": "[resourceGroup().location]", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + } + } + ] +} diff --git a/rego/tests/rules/arm/app_service/inputs/register_with_ad_infra_json.rego b/rego/tests/rules/arm/app_service/inputs/register_with_ad_infra_json.rego new file mode 100644 index 00000000..d8949c2c --- /dev/null +++ b/rego/tests/rules/arm/app_service/inputs/register_with_ad_infra_json.rego @@ -0,0 +1,81 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.app_service.inputs.register_with_ad_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "apiVersion": "2021-02-01", + "location": "[resourceGroup().location]", + "name": "appServicePlanPortal", + "sku": { + "name": "B1", + "size": "B1", + "tier": "Basic" + }, + "type": "Microsoft.Web/serverfarms" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "identity": { + "type": "SystemAssigned" + }, + "location": "[resourceGroup().location]", + "name": "valid", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "type": "Microsoft.Web/sites" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "identity": { + "type": "None" + }, + "location": "[resourceGroup().location]", + "name": "invalidType", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "type": "Microsoft.Web/sites" + }, + { + "apiVersion": "2021-02-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + ], + "location": "[resourceGroup().location]", + "name": "invalidUnset", + "properties": { + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlanPortal')]" + }, + "type": "Microsoft.Web/sites" + } + ] +} + diff --git a/rego/tests/rules/arm/app_service/min_tls_version_test.rego b/rego/tests/rules/arm/app_service/min_tls_version_test.rego new file mode 100644 index 00000000..764cdea1 --- /dev/null +++ b/rego/tests/rules/arm/app_service/min_tls_version_test.rego @@ -0,0 +1,27 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_app_service_min_tls_version + +import data.tests.rules.arm.app_service.inputs.min_tls_version_infra_json as infra + +test_min_tls_version { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + by_resource_id["Microsoft.Web/sites/validViaProperty"] == true + by_resource_id["Microsoft.Web/sites/validViaConfig"] == true + by_resource_id["Microsoft.Web/sites/invalidViaConfig"] == false + by_resource_id["Microsoft.Web/sites/invalidViaProperty"] == false + by_resource_id["Microsoft.Web/sites/invalidUnset"] == false +} diff --git a/rego/tests/rules/arm/app_service/register_with_ad_test.rego b/rego/tests/rules/arm/app_service/register_with_ad_test.rego new file mode 100644 index 00000000..d433cbf3 --- /dev/null +++ b/rego/tests/rules/arm/app_service/register_with_ad_test.rego @@ -0,0 +1,23 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_app_service_register_with_ad + +import data.tests.rules.arm.app_service.inputs.register_with_ad_infra_json as infra + +test_register_with_ad { + allow with input as infra.mock_resources["Microsoft.Web/sites/valid"] + not allow with input as infra.mock_resources["Microsoft.Web/sites/invalidType"] + not allow with input as infra.mock_resources["Microsoft.Web/sites/invalidUnset"] +} diff --git a/rego/tests/rules/arm/authorization/custom_owner_role_test.rego b/rego/tests/rules/arm/authorization/custom_owner_role_test.rego new file mode 100644 index 00000000..dec8cb19 --- /dev/null +++ b/rego/tests/rules/arm/authorization/custom_owner_role_test.rego @@ -0,0 +1,40 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_authorization_custom_owner_role + +import data.tests.rules.arm.authorization.inputs.custom_owner_role_infra_json as infra + +test_is_subscription_scope { + is_subscription_scope("/") + is_subscription_scope("/subscriptions/479a226b-4153-48f7-8943-3e8e388a93cb") + is_subscription_scope("/subscriptions/479a226b-4153-48f7-8943-3e8e388a93cb/") + is_subscription_scope("[concat('/subscriptions/', subscription().subscriptionId)]") + is_subscription_scope("[concat('/subscriptions/', '479a226b-4153-48f7-8943-3e8e388a93cb')]") + is_subscription_scope("[concat('/subscriptions/', parameters('subscriptionId'))]") + is_subscription_scope("[subscription().id]") + + not is_subscription_scope("/subscriptions/479a226b-4153-48f7-8943-3e8e388a93cb/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635") + not is_subscription_scope("[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]") +} + +test_custom_owner_role { + deny with input as infra.mock_resources["Microsoft.Authorization/roleDefinitions/invalidTopLevel"] + deny with input as infra.mock_resources["Microsoft.Authorization/roleDefinitions/invalidActionsArr"] + deny with input as infra.mock_resources["Microsoft.Authorization/roleDefinitions/invalidHardcodedId"] + deny with input as infra.mock_resources["Microsoft.Authorization/roleDefinitions/invalidConcat"] + deny with input as infra.mock_resources["Microsoft.Authorization/roleDefinitions/invalidSubscriptionId"] + not deny with input as infra.mock_resources["Microsoft.Authorization/roleDefinitions/validAction"] + not deny with input as infra.mock_resources["Microsoft.Authorization/roleDefinitions/validScope"] +} diff --git a/rego/tests/rules/arm/authorization/inputs/custom_owner_role_infra.json b/rego/tests/rules/arm/authorization/inputs/custom_owner_role_infra.json new file mode 100644 index 00000000..21dcb4ef --- /dev/null +++ b/rego/tests/rules/arm/authorization/inputs/custom_owner_role_infra.json @@ -0,0 +1,117 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "storageName": { + "type": "string", + "defaultValue": "[concat('storage', uniqueString(resourceGroup().id))]" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleDefinitions", + "apiVersion": "2021-02-01", + "name": "invalidTopLevel", + "properties": { + "permissions": [ + { + "actions": "*" + } + ], + "assignableScopes": [ + "/" + ] + } + }, + { + "type": "Microsoft.Authorization/roleDefinitions", + "apiVersion": "2021-02-01", + "name": "invalidActionsArr", + "properties": { + "permissions": [ + { + "actions": "*" + } + ], + "assignableScopes": [ + "/" + ] + } + }, + { + "type": "Microsoft.Authorization/roleDefinitions", + "apiVersion": "2021-02-01", + "name": "invalidHardcodedId", + "properties": { + "permissions": [ + { + "actions": "*" + } + ], + "assignableScopes": [ + "/subscriptions/479a226b-4153-48f7-8943-3e8e388a93cb" + ] + } + }, + { + "type": "Microsoft.Authorization/roleDefinitions", + "apiVersion": "2021-02-01", + "name": "invalidConcat", + "properties": { + "permissions": [ + { + "actions": "*" + } + ], + "assignableScopes": [ + "[concat('/subscriptions/', subscription().subscriptionId)]" + ] + } + }, + { + "type": "Microsoft.Authorization/roleDefinitions", + "apiVersion": "2021-02-01", + "name": "invalidSubscriptionId", + "properties": { + "permissions": [ + { + "actions": "*" + } + ], + "assignableScopes": [ + "[subscription().id]" + ] + } + }, + { + "type": "Microsoft.Authorization/roleDefinitions", + "apiVersion": "2021-02-01", + "name": "validAction", + "properties": { + "permissions": [ + { + "actions": "Microsoft.Resources/subscriptions/read" + } + ], + "assignableScopes": [ + "[subscription().id]" + ] + } + }, + { + "type": "Microsoft.Authorization/roleDefinitions", + "apiVersion": "2021-02-01", + "name": "validScope", + "properties": { + "permissions": [ + { + "actions": "*" + } + ], + "assignableScopes": [ + "[concat('Microsoft.Storage/storageAccounts', '/', parameters('storageName'))]" + ] + } + } + ] +} diff --git a/rego/tests/rules/arm/authorization/inputs/custom_owner_role_infra_json.rego b/rego/tests/rules/arm/authorization/inputs/custom_owner_role_infra_json.rego new file mode 100644 index 00000000..525de520 --- /dev/null +++ b/rego/tests/rules/arm/authorization/inputs/custom_owner_role_infra_json.rego @@ -0,0 +1,139 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.authorization.inputs.custom_owner_role_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "storageName": { + "defaultValue": "[concat('storage', uniqueString(resourceGroup().id))]", + "type": "string" + } + }, + "resources": [ + { + "apiVersion": "2021-02-01", + "name": "invalidTopLevel", + "properties": { + "assignableScopes": [ + "/" + ], + "permissions": [ + { + "actions": "*" + } + ] + }, + "type": "Microsoft.Authorization/roleDefinitions" + }, + { + "apiVersion": "2021-02-01", + "name": "invalidActionsArr", + "properties": { + "assignableScopes": [ + "/" + ], + "permissions": [ + { + "actions": "*" + } + ] + }, + "type": "Microsoft.Authorization/roleDefinitions" + }, + { + "apiVersion": "2021-02-01", + "name": "invalidHardcodedId", + "properties": { + "assignableScopes": [ + "/subscriptions/479a226b-4153-48f7-8943-3e8e388a93cb" + ], + "permissions": [ + { + "actions": "*" + } + ] + }, + "type": "Microsoft.Authorization/roleDefinitions" + }, + { + "apiVersion": "2021-02-01", + "name": "invalidConcat", + "properties": { + "assignableScopes": [ + "[concat('/subscriptions/', subscription().subscriptionId)]" + ], + "permissions": [ + { + "actions": "*" + } + ] + }, + "type": "Microsoft.Authorization/roleDefinitions" + }, + { + "apiVersion": "2021-02-01", + "name": "invalidSubscriptionId", + "properties": { + "assignableScopes": [ + "[subscription().id]" + ], + "permissions": [ + { + "actions": "*" + } + ] + }, + "type": "Microsoft.Authorization/roleDefinitions" + }, + { + "apiVersion": "2021-02-01", + "name": "validAction", + "properties": { + "assignableScopes": [ + "[subscription().id]" + ], + "permissions": [ + { + "actions": "Microsoft.Resources/subscriptions/read" + } + ] + }, + "type": "Microsoft.Authorization/roleDefinitions" + }, + { + "apiVersion": "2021-02-01", + "name": "validScope", + "properties": { + "assignableScopes": [ + "[concat('Microsoft.Storage/storageAccounts', '/', parameters('storageName'))]" + ], + "permissions": [ + { + "actions": "*" + } + ] + }, + "type": "Microsoft.Authorization/roleDefinitions" + } + ] +} + diff --git a/rego/tests/rules/arm/key_vault/inputs/recoverable_infra.json b/rego/tests/rules/arm/key_vault/inputs/recoverable_infra.json new file mode 100644 index 00000000..77976e27 --- /dev/null +++ b/rego/tests/rules/arm/key_vault/inputs/recoverable_infra.json @@ -0,0 +1,116 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "vmName": { + "type": "string", + "metadata": { + "description": "Name of the virtual machine." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-04-01", + "name": "valid", + "location": "[resourceGroup().location]", + "properties": { + "tenantId": "[subscription().tenantId]", + "sku": { + "family": "A", + "name": "Standard" + }, + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ], + "enablePurgeProtection": true, + "enableSoftDelete": true + } + }, + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-04-01", + "name": "invalidUnset", + "location": "[resourceGroup().location]", + "properties": { + "tenantId": "[subscription().tenantId]", + "sku": { + "family": "A", + "name": "Standard" + }, + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ] + } + }, + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-04-01", + "name": "invalidEnablePurgeProtection", + "location": "[resourceGroup().location]", + "properties": { + "tenantId": "[subscription().tenantId]", + "sku": { + "family": "A", + "name": "Standard" + }, + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ], + "enablePurgeProtection": false, + "enableSoftDelete": true + } + }, + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-04-01", + "name": "invalidEnableSoftDelete", + "location": "[resourceGroup().location]", + "properties": { + "tenantId": "[subscription().tenantId]", + "sku": { + "family": "A", + "name": "Standard" + }, + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ], + "enablePurgeProtection": true, + "enableSoftDelete": false + } + } + ] +} diff --git a/rego/tests/rules/arm/key_vault/inputs/recoverable_infra_json.rego b/rego/tests/rules/arm/key_vault/inputs/recoverable_infra_json.rego new file mode 100644 index 00000000..50486cda --- /dev/null +++ b/rego/tests/rules/arm/key_vault/inputs/recoverable_infra_json.rego @@ -0,0 +1,138 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.key_vault.inputs.recoverable_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "vmName": { + "metadata": { + "description": "Name of the virtual machine." + }, + "type": "string" + } + }, + "resources": [ + { + "apiVersion": "2021-04-01", + "location": "[resourceGroup().location]", + "name": "valid", + "properties": { + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ], + "enablePurgeProtection": true, + "enableSoftDelete": true, + "sku": { + "family": "A", + "name": "Standard" + }, + "tenantId": "[subscription().tenantId]" + }, + "type": "Microsoft.KeyVault/vaults" + }, + { + "apiVersion": "2021-04-01", + "location": "[resourceGroup().location]", + "name": "invalidUnset", + "properties": { + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ], + "sku": { + "family": "A", + "name": "Standard" + }, + "tenantId": "[subscription().tenantId]" + }, + "type": "Microsoft.KeyVault/vaults" + }, + { + "apiVersion": "2021-04-01", + "location": "[resourceGroup().location]", + "name": "invalidEnablePurgeProtection", + "properties": { + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ], + "enablePurgeProtection": false, + "enableSoftDelete": true, + "sku": { + "family": "A", + "name": "Standard" + }, + "tenantId": "[subscription().tenantId]" + }, + "type": "Microsoft.KeyVault/vaults" + }, + { + "apiVersion": "2021-04-01", + "location": "[resourceGroup().location]", + "name": "invalidEnableSoftDelete", + "properties": { + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ], + "enablePurgeProtection": true, + "enableSoftDelete": false, + "sku": { + "family": "A", + "name": "Standard" + }, + "tenantId": "[subscription().tenantId]" + }, + "type": "Microsoft.KeyVault/vaults" + } + ] +} + diff --git a/rego/tests/rules/arm/key_vault/inputs/secret_expiry_infra.json b/rego/tests/rules/arm/key_vault/inputs/secret_expiry_infra.json new file mode 100644 index 00000000..ccb4c6cc --- /dev/null +++ b/rego/tests/rules/arm/key_vault/inputs/secret_expiry_infra.json @@ -0,0 +1,63 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-06-01-preview", + "name": "regulasecretvault1", + "location": "[resourceGroup().location]", + "properties": { + "enablePurgeProtection": true, + "enabledForDiskEncryption": true, + "accessPolicies": [ + { + "tenantId": "[subscription().tenantId]", + "objectId": "[subscription().subscriptionId]", + "permissions": { + "keys": [], + "secrets": [ + "Get", + "List" + ], + "certificates": [] + } + } + ], + "sku": { + "family": "A", + "name": "Standard" + }, + "tenantId": "[subscription().tenantId]" + }, + "resources": [ + { + "type": "secrets", + "apiVersion": "2021-06-01-preview", + "name": "secret1", + "properties": { + "value": "hunter2" + }, + "dependsOn": [ + "Microsoft.KeyVault/vaults/regulasecretvault1" + ] + }, + { + "type": "secrets", + "apiVersion": "2021-06-01-preview", + "name": "secret2", + "properties": { + "value": "hunter2", + "attributes": { + "exp": 1700000000 + } + }, + "dependsOn": [ + "Microsoft.KeyVault/vaults/regulasecretvault1" + ] + } + ] + } + ] +} diff --git a/rego/tests/rules/arm/key_vault/inputs/secret_expiry_infra_json.rego b/rego/tests/rules/arm/key_vault/inputs/secret_expiry_infra_json.rego new file mode 100644 index 00000000..369dcba4 --- /dev/null +++ b/rego/tests/rules/arm/key_vault/inputs/secret_expiry_infra_json.rego @@ -0,0 +1,85 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.key_vault.inputs.secret_expiry_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-06-01-preview", + "location": "[resourceGroup().location]", + "name": "regulasecretvault1", + "properties": { + "accessPolicies": [ + { + "objectId": "[subscription().subscriptionId]", + "permissions": { + "certificates": [], + "keys": [], + "secrets": [ + "Get", + "List" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ], + "enablePurgeProtection": true, + "enabledForDiskEncryption": true, + "sku": { + "family": "A", + "name": "Standard" + }, + "tenantId": "[subscription().tenantId]" + }, + "resources": [ + { + "apiVersion": "2021-06-01-preview", + "dependsOn": [ + "Microsoft.KeyVault/vaults/regulasecretvault1" + ], + "name": "secret1", + "properties": { + "value": "hunter2" + }, + "type": "secrets" + }, + { + "apiVersion": "2021-06-01-preview", + "dependsOn": [ + "Microsoft.KeyVault/vaults/regulasecretvault1" + ], + "name": "secret2", + "properties": { + "attributes": { + "exp": 1700000000 + }, + "value": "hunter2" + }, + "type": "secrets" + } + ], + "type": "Microsoft.KeyVault/vaults" + } + ] +} + diff --git a/rego/tests/rules/arm/key_vault/recoverable_test.rego b/rego/tests/rules/arm/key_vault/recoverable_test.rego new file mode 100644 index 00000000..5dc9c60f --- /dev/null +++ b/rego/tests/rules/arm/key_vault/recoverable_test.rego @@ -0,0 +1,24 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_key_vault_recoverable + +import data.tests.rules.arm.key_vault.inputs.recoverable_infra_json as infra + +test_key_vault_recoverable { + allow with input as infra.mock_resources["Microsoft.KeyVault/vaults/valid"] + not allow with input as infra.mock_resources["Microsoft.KeyVault/vaults/invalidUnset"] + not allow with input as infra.mock_resources["Microsoft.KeyVault/vaults/invalidEnablePurgeProtection"] + not allow with input as infra.mock_resources["Microsoft.KeyVault/vaults/invalidEnableSoftDelete"] +} diff --git a/rego/tests/rules/arm/key_vault/secret_expiry_test.rego b/rego/tests/rules/arm/key_vault/secret_expiry_test.rego new file mode 100644 index 00000000..a5fe3824 --- /dev/null +++ b/rego/tests/rules/arm/key_vault/secret_expiry_test.rego @@ -0,0 +1,22 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_key_vault_secret_expiry + +import data.tests.rules.arm.key_vault.inputs.secret_expiry_infra_json as infra + +test_key_vault_secret_expiry { + not allow with input as infra.mock_resources["Microsoft.KeyVault/vaults/regulasecretvault1/secrets/secret1"] + allow with input as infra.mock_resources["Microsoft.KeyVault/vaults/regulasecretvault1/secrets/secret2"] +} diff --git a/rego/tests/rules/arm/kubernetes/cluster_instances_rbac_test.rego b/rego/tests/rules/arm/kubernetes/cluster_instances_rbac_test.rego new file mode 100644 index 00000000..83e55ec2 --- /dev/null +++ b/rego/tests/rules/arm/kubernetes/cluster_instances_rbac_test.rego @@ -0,0 +1,23 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_kubernetes_cluster_instances_rbac + +import data.tests.rules.arm.kubernetes.inputs.cluster_instances_rbac_infra_json as infra + +test_cluster_instances_rbac { + allow with input as infra.mock_resources["Microsoft.ContainerService/managedClusters/valid"] + not allow with input as infra.mock_resources["Microsoft.ContainerService/managedClusters/invalid"] + not allow with input as infra.mock_resources["Microsoft.ContainerService/managedClusters/invalidUnset"] +} diff --git a/rego/tests/rules/arm/kubernetes/inputs/cluster_instances_rbac_infra.json b/rego/tests/rules/arm/kubernetes/inputs/cluster_instances_rbac_infra.json new file mode 100644 index 00000000..f3bd4c0b --- /dev/null +++ b/rego/tests/rules/arm/kubernetes/inputs/cluster_instances_rbac_infra.json @@ -0,0 +1,81 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2021-10-01", + "name": "valid", + "location": "[resourceGroup().location]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "enableRBAC": true, + "dnsPrefix": "valid", + "agentPoolProfiles": [ + { + "name": "agentpool", + "osDiskSizeGB": 0, + "count": 1, + "vmSize": "Standard_D2s_v3", + "osType": "Linux", + "storageProfile": "ManagedDisks", + "type": "VirtualMachineScaleSets", + "mode": "System" + } + ] + } + }, + { + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2021-10-01", + "name": "invalid", + "location": "[resourceGroup().location]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "dnsPrefix": "invalid", + "enableRBAC": false, + "agentPoolProfiles": [ + { + "name": "agentpool", + "osDiskSizeGB": 0, + "count": 1, + "vmSize": "Standard_D2s_v3", + "osType": "Linux", + "storageProfile": "ManagedDisks", + "type": "VirtualMachineScaleSets", + "mode": "System" + } + ] + } + }, + { + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2021-10-01", + "name": "invalidUnset", + "location": "[resourceGroup().location]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "dnsPrefix": "invalid-unset", + "agentPoolProfiles": [ + { + "name": "agentpool", + "osDiskSizeGB": 0, + "count": 1, + "vmSize": "Standard_D2s_v3", + "osType": "Linux", + "storageProfile": "ManagedDisks", + "type": "VirtualMachineScaleSets", + "mode": "System" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/rego/tests/rules/arm/kubernetes/inputs/cluster_instances_rbac_infra_json.rego b/rego/tests/rules/arm/kubernetes/inputs/cluster_instances_rbac_infra_json.rego new file mode 100644 index 00000000..bec8ecd8 --- /dev/null +++ b/rego/tests/rules/arm/kubernetes/inputs/cluster_instances_rbac_infra_json.rego @@ -0,0 +1,103 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.kubernetes.inputs.cluster_instances_rbac_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-10-01", + "identity": { + "type": "SystemAssigned" + }, + "location": "[resourceGroup().location]", + "name": "valid", + "properties": { + "agentPoolProfiles": [ + { + "count": 1, + "mode": "System", + "name": "agentpool", + "osDiskSizeGB": 0, + "osType": "Linux", + "storageProfile": "ManagedDisks", + "type": "VirtualMachineScaleSets", + "vmSize": "Standard_D2s_v3" + } + ], + "dnsPrefix": "valid", + "enableRBAC": true + }, + "type": "Microsoft.ContainerService/managedClusters" + }, + { + "apiVersion": "2021-10-01", + "identity": { + "type": "SystemAssigned" + }, + "location": "[resourceGroup().location]", + "name": "invalid", + "properties": { + "agentPoolProfiles": [ + { + "count": 1, + "mode": "System", + "name": "agentpool", + "osDiskSizeGB": 0, + "osType": "Linux", + "storageProfile": "ManagedDisks", + "type": "VirtualMachineScaleSets", + "vmSize": "Standard_D2s_v3" + } + ], + "dnsPrefix": "invalid", + "enableRBAC": false + }, + "type": "Microsoft.ContainerService/managedClusters" + }, + { + "apiVersion": "2021-10-01", + "identity": { + "type": "SystemAssigned" + }, + "location": "[resourceGroup().location]", + "name": "invalidUnset", + "properties": { + "agentPoolProfiles": [ + { + "count": 1, + "mode": "System", + "name": "agentpool", + "osDiskSizeGB": 0, + "osType": "Linux", + "storageProfile": "ManagedDisks", + "type": "VirtualMachineScaleSets", + "vmSize": "Standard_D2s_v3" + } + ], + "dnsPrefix": "invalid-unset" + }, + "type": "Microsoft.ContainerService/managedClusters" + } + ] +} + diff --git a/rego/tests/rules/arm/monitor/inputs/key_vault_logging_infra.json b/rego/tests/rules/arm/monitor/inputs/key_vault_logging_infra.json new file mode 100644 index 00000000..0d8b1030 --- /dev/null +++ b/rego/tests/rules/arm/monitor/inputs/key_vault_logging_infra.json @@ -0,0 +1,144 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "vmName": { + "type": "string", + "metadata": { + "description": "Name of the virtual machine." + } + } + }, + "variables": { + "storageAccountName": "[concat('regula', uniqueString(resourceGroup().id))]" + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-06-01", + "name": "[variables('storageAccountName')]", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "StorageV2" + }, + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-04-01-preview", + "name": "valid", + "location": "[resourceGroup().location]", + "properties": { + "sku": { + "name": "standard", + "family": "A" + }, + "tenantId": "[subscription().tenantId]", + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ] + } + }, + { + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', 'valid')]", + "name": "valid", + "properties": { + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "logs": [ + { + "category": "AuditEvent", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": 180 + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', 'valid')]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ] + }, + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-04-01-preview", + "name": "invalidNoRetention", + "location": "[resourceGroup().location]", + "properties": { + "sku": { + "name": "standard", + "family": "A" + }, + "tenantId": "[subscription().tenantId]", + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ] + } + }, + { + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', 'invalidNoRetention')]", + "name": "invalidNoRetention", + "properties": { + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "logs": [ + { + "category": "AuditEvent", + "enabled": true, + "retentionPolicy": { + "enabled": false + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', 'invalidNoRetention')]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ] + }, + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-04-01-preview", + "name": "invalidNoDiagnostics", + "location": "[resourceGroup().location]", + "properties": { + "sku": { + "name": "standard", + "family": "A" + }, + "tenantId": "[subscription().tenantId]", + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ] + } + } + ] +} diff --git a/rego/tests/rules/arm/monitor/inputs/key_vault_logging_infra_json.rego b/rego/tests/rules/arm/monitor/inputs/key_vault_logging_infra_json.rego new file mode 100644 index 00000000..bda638b9 --- /dev/null +++ b/rego/tests/rules/arm/monitor/inputs/key_vault_logging_infra_json.rego @@ -0,0 +1,166 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.monitor.inputs.key_vault_logging_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "vmName": { + "metadata": { + "description": "Name of the virtual machine." + }, + "type": "string" + } + }, + "resources": [ + { + "apiVersion": "2021-06-01", + "kind": "StorageV2", + "location": "[resourceGroup().location]", + "name": "[variables('storageAccountName')]", + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2021-04-01-preview", + "location": "[parameters('location')]", + "name": "valid", + "properties": { + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ], + "sku": { + "family": "A", + "name": "standard" + }, + "tenantId": "[subscription().tenantId]" + }, + "type": "Microsoft.KeyVault/vaults" + }, + { + "apiVersion": "2021-05-01-preview", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ], + "name": "valid", + "properties": { + "logs": [ + { + "category": "AuditEvent", + "enabled": true, + "retentionPolicy": { + "days": 180, + "enabled": true + } + } + ], + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + }, + "scope": "[format('Microsoft.KeyVault/vaults/{0}', 'valid')]", + "type": "Microsoft.Insights/diagnosticSettings" + }, + { + "apiVersion": "2021-04-01-preview", + "location": "[parameters('location')]", + "name": "invalidNoRetention", + "properties": { + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ], + "sku": { + "family": "A", + "name": "standard" + }, + "tenantId": "[subscription().tenantId]" + }, + "type": "Microsoft.KeyVault/vaults" + }, + { + "apiVersion": "2021-05-01-preview", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ], + "name": "invalidNoRetention", + "properties": { + "logs": [ + { + "category": "AuditEvent", + "enabled": true, + "retentionPolicy": { + "enabled": false + } + } + ], + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + }, + "scope": "[format('Microsoft.KeyVault/vaults/{0}', 'invalidNoRetention')]", + "type": "Microsoft.Insights/diagnosticSettings" + }, + { + "apiVersion": "2021-04-01-preview", + "location": "[parameters('location')]", + "name": "invalidNoDiagnostics", + "properties": { + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines/', parameters('vmName')), '2020-12-01', 'full').identity.principalId]", + "permissions": { + "secrets": [ + "get" + ] + }, + "tenantId": "[subscription().tenantId]" + } + ], + "sku": { + "family": "A", + "name": "standard" + }, + "tenantId": "[subscription().tenantId]" + }, + "type": "Microsoft.KeyVault/vaults" + } + ], + "variables": { + "storageAccountName": "[concat('regula', uniqueString(resourceGroup().id))]" + } +} + diff --git a/rego/tests/rules/arm/monitor/inputs/log_profile_all_categories_infra.json b/rego/tests/rules/arm/monitor/inputs/log_profile_all_categories_infra.json new file mode 100644 index 00000000..afe8dafc --- /dev/null +++ b/rego/tests/rules/arm/monitor/inputs/log_profile_all_categories_infra.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "storageAccountId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Insights/logprofiles", + "apiVersion": "2016-03-01", + "name": "valid", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + } + }, + { + "type": "Microsoft.Insights/logprofiles", + "apiVersion": "2016-03-01", + "name": "invalid1", + "properties": { + "categories": [ + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + } + }, + { + "type": "Microsoft.Insights/logprofiles", + "apiVersion": "2016-03-01", + "name": "invalid2", + "properties": { + "categories": [ + "Action", + "Delete" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + } + } + ] +} diff --git a/rego/tests/rules/arm/monitor/inputs/log_profile_all_categories_infra_json.rego b/rego/tests/rules/arm/monitor/inputs/log_profile_all_categories_infra_json.rego new file mode 100644 index 00000000..76cc0ca4 --- /dev/null +++ b/rego/tests/rules/arm/monitor/inputs/log_profile_all_categories_infra_json.rego @@ -0,0 +1,88 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.monitor.inputs.log_profile_all_categories_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "storageAccountId": { + "type": "string" + } + }, + "resources": [ + { + "apiVersion": "2016-03-01", + "name": "valid", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + }, + "type": "Microsoft.Insights/logprofiles" + }, + { + "apiVersion": "2016-03-01", + "name": "invalid1", + "properties": { + "categories": [ + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + }, + "type": "Microsoft.Insights/logprofiles" + }, + { + "apiVersion": "2016-03-01", + "name": "invalid2", + "properties": { + "categories": [ + "Action", + "Delete" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + }, + "type": "Microsoft.Insights/logprofiles" + } + ] +} + diff --git a/rego/tests/rules/arm/monitor/inputs/log_profile_global_locations_infra.json b/rego/tests/rules/arm/monitor/inputs/log_profile_global_locations_infra.json new file mode 100644 index 00000000..296b5240 --- /dev/null +++ b/rego/tests/rules/arm/monitor/inputs/log_profile_global_locations_infra.json @@ -0,0 +1,62 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Insights/logprofiles", + "apiVersion": "2016-03-01", + "name": "valid", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + } + }, + { + "type": "Microsoft.Insights/logprofiles", + "apiVersion": "2016-03-01", + "name": "invalidEmpty", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [], + "retentionPolicy": { + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + } + }, + { + "type": "Microsoft.Insights/logprofiles", + "apiVersion": "2016-03-01", + "name": "invalidMissing", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "East US" + ], + "retentionPolicy": { + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + } + } + ] +} diff --git a/rego/tests/rules/arm/monitor/inputs/log_profile_global_locations_infra_json.rego b/rego/tests/rules/arm/monitor/inputs/log_profile_global_locations_infra_json.rego new file mode 100644 index 00000000..aed238d6 --- /dev/null +++ b/rego/tests/rules/arm/monitor/inputs/log_profile_global_locations_infra_json.rego @@ -0,0 +1,84 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.monitor.inputs.log_profile_global_locations_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2016-03-01", + "name": "valid", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + }, + "type": "Microsoft.Insights/logprofiles" + }, + { + "apiVersion": "2016-03-01", + "name": "invalidEmpty", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [], + "retentionPolicy": { + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + }, + "type": "Microsoft.Insights/logprofiles" + }, + { + "apiVersion": "2016-03-01", + "name": "invalidMissing", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "East US" + ], + "retentionPolicy": { + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + }, + "type": "Microsoft.Insights/logprofiles" + } + ] +} + diff --git a/rego/tests/rules/arm/monitor/inputs/log_profile_retention_infra.json b/rego/tests/rules/arm/monitor/inputs/log_profile_retention_infra.json new file mode 100644 index 00000000..d305ff9b --- /dev/null +++ b/rego/tests/rules/arm/monitor/inputs/log_profile_retention_infra.json @@ -0,0 +1,91 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "storageAccountId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Insights/logprofiles", + "apiVersion": "2016-03-01", + "name": "validYear", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "enabled": true, + "days": 365 + }, + "storageAccountId": "[parameters('storageAccountId')]" + } + }, + { + "type": "Microsoft.Insights/logprofiles", + "apiVersion": "2016-03-01", + "name": "validIndefinite", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "enabled": true, + "days": 0 + }, + "storageAccountId": "[parameters('storageAccountId')]" + } + }, + { + "type": "Microsoft.Insights/logprofiles", + "apiVersion": "2016-03-01", + "name": "invalidDisabled", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "enabled": false, + "days": 0 + }, + "storageAccountId": "[parameters('storageAccountId')]" + } + }, + { + "type": "Microsoft.Insights/logprofiles", + "apiVersion": "2016-03-01", + "name": "invalidShortRetention", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "enabled": true, + "days": 90 + }, + "storageAccountId": "[parameters('storageAccountId')]" + } + } + ] +} diff --git a/rego/tests/rules/arm/monitor/inputs/log_profile_retention_infra_json.rego b/rego/tests/rules/arm/monitor/inputs/log_profile_retention_infra_json.rego new file mode 100644 index 00000000..d9805b12 --- /dev/null +++ b/rego/tests/rules/arm/monitor/inputs/log_profile_retention_infra_json.rego @@ -0,0 +1,113 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.monitor.inputs.log_profile_retention_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "storageAccountId": { + "type": "string" + } + }, + "resources": [ + { + "apiVersion": "2016-03-01", + "name": "validYear", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "days": 365, + "enabled": true + }, + "storageAccountId": "[parameters('storageAccountId')]" + }, + "type": "Microsoft.Insights/logprofiles" + }, + { + "apiVersion": "2016-03-01", + "name": "validIndefinite", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "days": 0, + "enabled": true + }, + "storageAccountId": "[parameters('storageAccountId')]" + }, + "type": "Microsoft.Insights/logprofiles" + }, + { + "apiVersion": "2016-03-01", + "name": "invalidDisabled", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "days": 0, + "enabled": false + }, + "storageAccountId": "[parameters('storageAccountId')]" + }, + "type": "Microsoft.Insights/logprofiles" + }, + { + "apiVersion": "2016-03-01", + "name": "invalidShortRetention", + "properties": { + "categories": [ + "Action", + "Delete", + "Write" + ], + "locations": [ + "global" + ], + "retentionPolicy": { + "days": 90, + "enabled": true + }, + "storageAccountId": "[parameters('storageAccountId')]" + }, + "type": "Microsoft.Insights/logprofiles" + } + ] +} + diff --git a/rego/tests/rules/arm/monitor/key_vault_logging_test.rego b/rego/tests/rules/arm/monitor/key_vault_logging_test.rego new file mode 100644 index 00000000..809239a1 --- /dev/null +++ b/rego/tests/rules/arm/monitor/key_vault_logging_test.rego @@ -0,0 +1,25 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_monitor_key_vault_logging + +import data.tests.rules.arm.monitor.inputs.key_vault_logging_infra_json as infra + +test_key_vault_logging { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + by_resource_id["Microsoft.KeyVault/vaults/valid"] == true + by_resource_id["Microsoft.KeyVault/vaults/invalidNoRetention"] == false + by_resource_id["Microsoft.KeyVault/vaults/invalidNoDiagnostics"] == false +} diff --git a/rego/tests/rules/arm/monitor/log_profile_all_categories_test.rego b/rego/tests/rules/arm/monitor/log_profile_all_categories_test.rego new file mode 100644 index 00000000..a8205c33 --- /dev/null +++ b/rego/tests/rules/arm/monitor/log_profile_all_categories_test.rego @@ -0,0 +1,23 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_monitor_log_profile_all_categories + +import data.tests.rules.arm.monitor.inputs.log_profile_all_categories_infra_json as infra + +test_log_profile_all_categories { + allow with input as infra.mock_resources["Microsoft.Insights/logprofiles/valid"] + not allow with input as infra.mock_resources["Microsoft.Insights/logprofiles/invalid1"] + not allow with input as infra.mock_resources["Microsoft.Insights/logprofiles/invalid2"] +} diff --git a/rego/tests/rules/arm/monitor/log_profile_global_locations_test.rego b/rego/tests/rules/arm/monitor/log_profile_global_locations_test.rego new file mode 100644 index 00000000..c9825e67 --- /dev/null +++ b/rego/tests/rules/arm/monitor/log_profile_global_locations_test.rego @@ -0,0 +1,25 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_monitor_log_profile_global_locations + +import data.tests.rules.arm.monitor.inputs.log_profile_global_locations_infra_json as infra + +test_log_profile_global_locations { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + by_resource_id["Microsoft.Insights/logprofiles/valid"] == true + by_resource_id["Microsoft.Insights/logprofiles/invalidEmpty"] == false + by_resource_id["Microsoft.Insights/logprofiles/invalidMissing"] == false +} diff --git a/rego/tests/rules/arm/monitor/log_profile_retention_test.rego b/rego/tests/rules/arm/monitor/log_profile_retention_test.rego new file mode 100644 index 00000000..72ec639b --- /dev/null +++ b/rego/tests/rules/arm/monitor/log_profile_retention_test.rego @@ -0,0 +1,24 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_monitor_log_profile_retention + +import data.tests.rules.arm.monitor.inputs.log_profile_retention_infra_json as infra + +test_log_profile_retention { + allow with input as infra.mock_resources["Microsoft.Insights/logprofiles/validYear"] + allow with input as infra.mock_resources["Microsoft.Insights/logprofiles/validIndefinite"] + not allow with input as infra.mock_resources["Microsoft.Insights/logprofiles/invalidDisabled"] + not allow with input as infra.mock_resources["Microsoft.Insights/logprofiles/invalidShortRetention"] +} diff --git a/rego/tests/rules/arm/mysql/enforce_ssl_test.rego b/rego/tests/rules/arm/mysql/enforce_ssl_test.rego new file mode 100644 index 00000000..035738df --- /dev/null +++ b/rego/tests/rules/arm/mysql/enforce_ssl_test.rego @@ -0,0 +1,22 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_mysql_enforce_ssl + +import data.tests.rules.arm.mysql.inputs.enforce_ssl_infra_json as infra + +test_rule { + not allow with input as infra.mock_resources["Microsoft.DBforMySQL/servers/RegulaServer1"] + allow with input as infra.mock_resources["Microsoft.DBforMySQL/servers/RegulaServer2"] +} diff --git a/rego/tests/rules/arm/mysql/inputs/enforce_ssl_infra.json b/rego/tests/rules/arm/mysql/inputs/enforce_ssl_infra.json new file mode 100644 index 00000000..696aefc1 --- /dev/null +++ b/rego/tests/rules/arm/mysql/inputs/enforce_ssl_infra.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2017-12-01", + "type": "Microsoft.DBforMySQL/servers", + "name": "RegulaServer1", + "location": "switzerlandnorth", + "properties": { + "version": "5.7", + "sslEnforcement": "Disabled", + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!", + "storageProfile": { + "storageMB": "5120", + "backupRetentionDays": "7", + "geoRedundantBackup": "Disabled" + } + }, + "sku": { + "name": "B_Gen5_2", + "tier": "Basic", + "capacity": "2", + "family": "Gen5" + } + }, + { + "apiVersion": "2017-12-01", + "type": "Microsoft.DBforMySQL/servers", + "name": "RegulaServer2", + "location": "switzerlandnorth", + "properties": { + "version": "5.7", + "sslEnforcement": "Enabled", + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!", + "storageProfile": { + "storageMB": "5120", + "backupRetentionDays": "7", + "geoRedundantBackup": "Disabled" + } + }, + "sku": { + "name": "B_Gen5_2", + "tier": "Basic", + "capacity": "2", + "family": "Gen5" + } + } + ] +} diff --git a/rego/tests/rules/arm/mysql/inputs/enforce_ssl_infra_json.rego b/rego/tests/rules/arm/mysql/inputs/enforce_ssl_infra_json.rego new file mode 100644 index 00000000..8200f903 --- /dev/null +++ b/rego/tests/rules/arm/mysql/inputs/enforce_ssl_infra_json.rego @@ -0,0 +1,75 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.mysql.inputs.enforce_ssl_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2017-12-01", + "location": "switzerlandnorth", + "name": "RegulaServer1", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!", + "sslEnforcement": "Disabled", + "storageProfile": { + "backupRetentionDays": "7", + "geoRedundantBackup": "Disabled", + "storageMB": "5120" + }, + "version": "5.7" + }, + "sku": { + "capacity": "2", + "family": "Gen5", + "name": "B_Gen5_2", + "tier": "Basic" + }, + "type": "Microsoft.DBforMySQL/servers" + }, + { + "apiVersion": "2017-12-01", + "location": "switzerlandnorth", + "name": "RegulaServer2", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!", + "sslEnforcement": "Enabled", + "storageProfile": { + "backupRetentionDays": "7", + "geoRedundantBackup": "Disabled", + "storageMB": "5120" + }, + "version": "5.7" + }, + "sku": { + "capacity": "2", + "family": "Gen5", + "name": "B_Gen5_2", + "tier": "Basic" + }, + "type": "Microsoft.DBforMySQL/servers" + } + ] +} + diff --git a/rego/tests/rules/arm/mysql/inputs/no_inbound_all_infra.json b/rego/tests/rules/arm/mysql/inputs/no_inbound_all_infra.json new file mode 100644 index 00000000..f7eb227b --- /dev/null +++ b/rego/tests/rules/arm/mysql/inputs/no_inbound_all_infra.json @@ -0,0 +1,55 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2017-12-01", + "type": "Microsoft.DBforMySQL/servers", + "name": "RegulaServer1", + "location": "switzerlandnorth", + "properties": { + "version": "5.7", + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!", + "storageProfile": { + "storageMB": "5120", + "backupRetentionDays": "7", + "geoRedundantBackup": "Disabled" + } + }, + "sku": { + "name": "B_Gen5_2", + "tier": "Basic", + "capacity": "2", + "family": "Gen5" + }, + "resources": [ + { + "apiVersion": "2017-12-01", + "name": "Rule1", + "type": "firewallRules", + "properties": { + "startIpAddress": "0.0.0.0", + "endIpAddress": "0.0.0.0" + }, + "dependsOn": [ + "Microsoft.DBforMySQL/servers/RegulaServer1" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "Rule2", + "type": "firewallRules", + "properties": { + "startIpAddress": "10.0.0.0", + "endIpAddress": "10.0.255.0" + }, + "dependsOn": [ + "Microsoft.DBforMySQL/servers/RegulaServer1" + ] + } + ] + } + ] +} diff --git a/rego/tests/rules/arm/mysql/inputs/no_inbound_all_infra_json.rego b/rego/tests/rules/arm/mysql/inputs/no_inbound_all_infra_json.rego new file mode 100644 index 00000000..071bf37e --- /dev/null +++ b/rego/tests/rules/arm/mysql/inputs/no_inbound_all_infra_json.rego @@ -0,0 +1,77 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.mysql.inputs.no_inbound_all_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2017-12-01", + "location": "switzerlandnorth", + "name": "RegulaServer1", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!", + "storageProfile": { + "backupRetentionDays": "7", + "geoRedundantBackup": "Disabled", + "storageMB": "5120" + }, + "version": "5.7" + }, + "resources": [ + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforMySQL/servers/RegulaServer1" + ], + "name": "Rule1", + "properties": { + "endIpAddress": "0.0.0.0", + "startIpAddress": "0.0.0.0" + }, + "type": "firewallRules" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforMySQL/servers/RegulaServer1" + ], + "name": "Rule2", + "properties": { + "endIpAddress": "10.0.255.0", + "startIpAddress": "10.0.0.0" + }, + "type": "firewallRules" + } + ], + "sku": { + "capacity": "2", + "family": "Gen5", + "name": "B_Gen5_2", + "tier": "Basic" + }, + "type": "Microsoft.DBforMySQL/servers" + } + ] +} + diff --git a/rego/tests/rules/arm/mysql/no_inbound_all_test.rego b/rego/tests/rules/arm/mysql/no_inbound_all_test.rego new file mode 100644 index 00000000..2462cf51 --- /dev/null +++ b/rego/tests/rules/arm/mysql/no_inbound_all_test.rego @@ -0,0 +1,22 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_mysql_no_inbound_all + +import data.tests.rules.arm.mysql.inputs.no_inbound_all_infra_json as infra + +test_rule { + deny with input as infra.mock_resources["Microsoft.DBforMySQL/servers/RegulaServer1/firewallRules/Rule1"] + not deny with input as infra.mock_resources["Microsoft.DBforMySQL/servers/RegulaServer1/firewallRules/Rule2"] +} diff --git a/rego/tests/rules/arm/network/app_gateway_waf_enabled_test.rego b/rego/tests/rules/arm/network/app_gateway_waf_enabled_test.rego new file mode 100644 index 00000000..bbba665c --- /dev/null +++ b/rego/tests/rules/arm/network/app_gateway_waf_enabled_test.rego @@ -0,0 +1,22 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_network_app_gateway_waf_enabled + +import data.tests.rules.arm.network.inputs.app_gateway_waf_enabled_infra_json as infra + +test_rule { + not allow with input as infra.mock_resources["Microsoft.Network/applicationGateways/RegulaAG1"] + allow with input as infra.mock_resources["Microsoft.Network/applicationGateways/RegulaAG2"] +} diff --git a/rego/tests/rules/arm/network/flow_log_retention_test.rego b/rego/tests/rules/arm/network/flow_log_retention_test.rego new file mode 100644 index 00000000..5a734dca --- /dev/null +++ b/rego/tests/rules/arm/network/flow_log_retention_test.rego @@ -0,0 +1,26 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_network_flow_log_retention + +import data.tests.rules.arm.network.inputs.flow_log_retention_infra_json as infra + +test_rule { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + count(by_resource_id) == 3 + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaNSG1"] == true + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaNSG2"] == false + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaNSG3"] == false +} diff --git a/rego/tests/rules/arm/network/inputs/app_gateway_waf_enabled_infra.json b/rego/tests/rules/arm/network/inputs/app_gateway_waf_enabled_infra.json new file mode 100644 index 00000000..8b318933 --- /dev/null +++ b/rego/tests/rules/arm/network/inputs/app_gateway_waf_enabled_infra.json @@ -0,0 +1,210 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2018-10-01", + "name": "RegulaNet1", + "location": "switzerlandnorth", + "properties": { + "addressSpace": { + "addressPrefixes": [ + "10.0.0.0/16" + ] + } + }, + "resources": [ + { + "type": "subnets", + "apiVersion": "2018-10-01", + "name": "Subnet1", + "dependsOn": [ + "RegulaNet1" + ], + "properties": { + "addressPrefix": "10.0.0.0/24" + } + } + ] + }, + { + "type": "Microsoft.Network/applicationGateways", + "apiVersion": "2021-03-01", + "name": "RegulaAG1", + "location": "switzerlandnorth", + "properties": { + "backendAddressPools": [ + { + "name": "BAP1" + } + ], + "backendHttpSettingsCollection": [ + { + "name": "BHSC1", + "properties": { + "hostName": "example.com", + "port": 80 + } + } + ], + "frontendIPConfigurations": [ + { + "name": "FIPC1", + "properties": { + "subnet": { + "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', 'RegulaNet1'), '/subnets/Subnet1')]" + } + } + } + ], + "frontendPorts": [ + { + "name": "FP1", + "properties": { + "port": 80 + } + } + ], + "httpListeners": [ + { + "name": "HL1", + "properties": { + "frontendIPConfiguration": { + "id": "[resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', 'RegulaAG1', 'FIPC1')]" + }, + "frontendPort": { + "id": "[resourceId('Microsoft.Network/applicationGateways/frontendPorts', 'RegulaAG1', 'FP1')]" + } + } + } + ], + "gatewayIPConfigurations": [ + { + "name": "IPC1", + "properties": { + "subnet": { + "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', 'RegulaNet1'), '/subnets/Subnet1')]" + } + } + } + ], + "requestRoutingRules": [ + { + "name": "RRR1", + "properties": { + "backendAddressPool": { + "id": "[resourceId('Microsoft.Network/applicationGateways/backendAddressPools', 'RegulaAG1', 'BAP1')]" + }, + "backendHttpSettings": { + "id": "[resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', 'RegulaAG1', 'BHSC1')]" + }, + "httpListener": { + "id": "[resourceId('Microsoft.Network/applicationGateways/httpListeners', 'RegulaAG1', 'HL1')]" + } + } + } + ], + "sku": { + "capacity": 1, + "name": "WAF_Medium", + "tier": "WAF" + } + }, + "dependsOn": [ + "Microsoft.Network/virtualNetworks/RegulaNet1" + ] + }, + { + "type": "Microsoft.Network/applicationGateways", + "apiVersion": "2021-03-01", + "name": "RegulaAG2", + "location": "switzerlandnorth", + "properties": { + "backendAddressPools": [ + { + "name": "BAP1" + } + ], + "backendHttpSettingsCollection": [ + { + "name": "BHSC1", + "properties": { + "hostName": "example.com", + "port": 80 + } + } + ], + "frontendIPConfigurations": [ + { + "name": "FIPC1", + "properties": { + "subnet": { + "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', 'RegulaNet1'), '/subnets/Subnet1')]" + } + } + } + ], + "frontendPorts": [ + { + "name": "FP1", + "properties": { + "port": 80 + } + } + ], + "httpListeners": [ + { + "name": "HL1", + "properties": { + "frontendIPConfiguration": { + "id": "[resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', 'RegulaAG2', 'FIPC1')]" + }, + "frontendPort": { + "id": "[resourceId('Microsoft.Network/applicationGateways/frontendPorts', 'RegulaAG2', 'FP1')]" + } + } + } + ], + "gatewayIPConfigurations": [ + { + "name": "IPC1", + "properties": { + "subnet": { + "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', 'RegulaNet1'), '/subnets/Subnet1')]" + } + } + } + ], + "requestRoutingRules": [ + { + "name": "RRR1", + "properties": { + "backendAddressPool": { + "id": "[resourceId('Microsoft.Network/applicationGateways/backendAddressPools', 'RegulaAG2', 'BAP1')]" + }, + "backendHttpSettings": { + "id": "[resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', 'RegulaAG2', 'BHSC1')]" + }, + "httpListener": { + "id": "[resourceId('Microsoft.Network/applicationGateways/httpListeners', 'RegulaAG2', 'HL1')]" + } + } + } + ], + "webApplicationFirewallConfiguration": { + "enabled": true + }, + "sku": { + "capacity": 1, + "name": "WAF_Medium", + "tier": "WAF" + } + }, + "dependsOn": [ + "Microsoft.Network/virtualNetworks/RegulaNet1" + ] + } + ] +} diff --git a/rego/tests/rules/arm/network/inputs/app_gateway_waf_enabled_infra_json.rego b/rego/tests/rules/arm/network/inputs/app_gateway_waf_enabled_infra_json.rego new file mode 100644 index 00000000..0b0575cd --- /dev/null +++ b/rego/tests/rules/arm/network/inputs/app_gateway_waf_enabled_infra_json.rego @@ -0,0 +1,232 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.network.inputs.app_gateway_waf_enabled_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2018-10-01", + "location": "switzerlandnorth", + "name": "RegulaNet1", + "properties": { + "addressSpace": { + "addressPrefixes": [ + "10.0.0.0/16" + ] + } + }, + "resources": [ + { + "apiVersion": "2018-10-01", + "dependsOn": [ + "RegulaNet1" + ], + "name": "Subnet1", + "properties": { + "addressPrefix": "10.0.0.0/24" + }, + "type": "subnets" + } + ], + "type": "Microsoft.Network/virtualNetworks" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "Microsoft.Network/virtualNetworks/RegulaNet1" + ], + "location": "switzerlandnorth", + "name": "RegulaAG1", + "properties": { + "backendAddressPools": [ + { + "name": "BAP1" + } + ], + "backendHttpSettingsCollection": [ + { + "name": "BHSC1", + "properties": { + "hostName": "example.com", + "port": 80 + } + } + ], + "frontendIPConfigurations": [ + { + "name": "FIPC1", + "properties": { + "subnet": { + "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', 'RegulaNet1'), '/subnets/Subnet1')]" + } + } + } + ], + "frontendPorts": [ + { + "name": "FP1", + "properties": { + "port": 80 + } + } + ], + "gatewayIPConfigurations": [ + { + "name": "IPC1", + "properties": { + "subnet": { + "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', 'RegulaNet1'), '/subnets/Subnet1')]" + } + } + } + ], + "httpListeners": [ + { + "name": "HL1", + "properties": { + "frontendIPConfiguration": { + "id": "[resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', 'RegulaAG1', 'FIPC1')]" + }, + "frontendPort": { + "id": "[resourceId('Microsoft.Network/applicationGateways/frontendPorts', 'RegulaAG1', 'FP1')]" + } + } + } + ], + "requestRoutingRules": [ + { + "name": "RRR1", + "properties": { + "backendAddressPool": { + "id": "[resourceId('Microsoft.Network/applicationGateways/backendAddressPools', 'RegulaAG1', 'BAP1')]" + }, + "backendHttpSettings": { + "id": "[resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', 'RegulaAG1', 'BHSC1')]" + }, + "httpListener": { + "id": "[resourceId('Microsoft.Network/applicationGateways/httpListeners', 'RegulaAG1', 'HL1')]" + } + } + } + ], + "sku": { + "capacity": 1, + "name": "WAF_Medium", + "tier": "WAF" + } + }, + "type": "Microsoft.Network/applicationGateways" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "Microsoft.Network/virtualNetworks/RegulaNet1" + ], + "location": "switzerlandnorth", + "name": "RegulaAG2", + "properties": { + "backendAddressPools": [ + { + "name": "BAP1" + } + ], + "backendHttpSettingsCollection": [ + { + "name": "BHSC1", + "properties": { + "hostName": "example.com", + "port": 80 + } + } + ], + "frontendIPConfigurations": [ + { + "name": "FIPC1", + "properties": { + "subnet": { + "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', 'RegulaNet1'), '/subnets/Subnet1')]" + } + } + } + ], + "frontendPorts": [ + { + "name": "FP1", + "properties": { + "port": 80 + } + } + ], + "gatewayIPConfigurations": [ + { + "name": "IPC1", + "properties": { + "subnet": { + "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', 'RegulaNet1'), '/subnets/Subnet1')]" + } + } + } + ], + "httpListeners": [ + { + "name": "HL1", + "properties": { + "frontendIPConfiguration": { + "id": "[resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', 'RegulaAG2', 'FIPC1')]" + }, + "frontendPort": { + "id": "[resourceId('Microsoft.Network/applicationGateways/frontendPorts', 'RegulaAG2', 'FP1')]" + } + } + } + ], + "requestRoutingRules": [ + { + "name": "RRR1", + "properties": { + "backendAddressPool": { + "id": "[resourceId('Microsoft.Network/applicationGateways/backendAddressPools', 'RegulaAG2', 'BAP1')]" + }, + "backendHttpSettings": { + "id": "[resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', 'RegulaAG2', 'BHSC1')]" + }, + "httpListener": { + "id": "[resourceId('Microsoft.Network/applicationGateways/httpListeners', 'RegulaAG2', 'HL1')]" + } + } + } + ], + "sku": { + "capacity": 1, + "name": "WAF_Medium", + "tier": "WAF" + }, + "webApplicationFirewallConfiguration": { + "enabled": true + } + }, + "type": "Microsoft.Network/applicationGateways" + } + ] +} + diff --git a/rego/tests/rules/arm/network/inputs/flow_log_retention_infra.json b/rego/tests/rules/arm/network/inputs/flow_log_retention_infra.json new file mode 100644 index 00000000..da57c0c5 --- /dev/null +++ b/rego/tests/rules/arm/network/inputs/flow_log_retention_infra.json @@ -0,0 +1,79 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2021-03-01", + "name": "RegulaNSG1", + "location": "switzerlandnorth" + }, + { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2021-03-01", + "name": "RegulaNSG2", + "location": "switzerlandnorth" + }, + { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2021-03-01", + "name": "RegulaNSG3", + "location": "switzerlandnorth" + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "regulasa01", + "location": "switzerlandnorth", + "sku": { + "name": "Standard_LRS" + }, + "kind": "StorageV2" + }, + { + "type": "Microsoft.Network/networkWatchers", + "apiVersion": "2021-04-01", + "name": "RegulaWatcher1", + "location": "switzerlandnorth", + "resources": [ + { + "type": "flowLogs", + "apiVersion": "2021-04-01", + "name": "FL1", + "location": "switzerlandnorth", + "properties": { + "targetResourceId": "[resourceId('Microsoft.Network/networkSecurityGroups', 'RegulaNSG1')]", + "storageId": "[resourceId('Microsoft.Storage/storageAccounts', 'regulasa01')]", + "retentionPolicy": { + "days": 90, + "enabled": true + } + }, + "dependsOn": [ + "Microsoft.Network/networkWatchers/RegulaWatcher1", + "Microsoft.Storage/storageAccounts/regulasa01" + ] + }, + { + "type": "flowLogs", + "apiVersion": "2021-04-01", + "name": "FL2", + "location": "switzerlandnorth", + "properties": { + "targetResourceId": "[resourceId('Microsoft.Network/networkSecurityGroups', 'RegulaNSG2')]", + "storageId": "[resourceId('Microsoft.Storage/storageAccounts', 'regulasa01')]", + "retentionPolicy": { + "days": 70, + "enabled": true + } + }, + "dependsOn": [ + "Microsoft.Network/networkWatchers/RegulaWatcher1", + "Microsoft.Storage/storageAccounts/regulasa01" + ] + } + ] + } + ] +} diff --git a/rego/tests/rules/arm/network/inputs/flow_log_retention_infra_json.rego b/rego/tests/rules/arm/network/inputs/flow_log_retention_infra_json.rego new file mode 100644 index 00000000..0e7af9ab --- /dev/null +++ b/rego/tests/rules/arm/network/inputs/flow_log_retention_infra_json.rego @@ -0,0 +1,101 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.network.inputs.flow_log_retention_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-03-01", + "location": "switzerlandnorth", + "name": "RegulaNSG1", + "type": "Microsoft.Network/networkSecurityGroups" + }, + { + "apiVersion": "2021-03-01", + "location": "switzerlandnorth", + "name": "RegulaNSG2", + "type": "Microsoft.Network/networkSecurityGroups" + }, + { + "apiVersion": "2021-03-01", + "location": "switzerlandnorth", + "name": "RegulaNSG3", + "type": "Microsoft.Network/networkSecurityGroups" + }, + { + "apiVersion": "2021-04-01", + "kind": "StorageV2", + "location": "switzerlandnorth", + "name": "regulasa01", + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2021-04-01", + "location": "switzerlandnorth", + "name": "RegulaWatcher1", + "resources": [ + { + "apiVersion": "2021-04-01", + "dependsOn": [ + "Microsoft.Network/networkWatchers/RegulaWatcher1", + "Microsoft.Storage/storageAccounts/regulasa01" + ], + "location": "switzerlandnorth", + "name": "FL1", + "properties": { + "retentionPolicy": { + "days": 90, + "enabled": true + }, + "storageId": "[resourceId('Microsoft.Storage/storageAccounts', 'regulasa01')]", + "targetResourceId": "[resourceId('Microsoft.Network/networkSecurityGroups', 'RegulaNSG1')]" + }, + "type": "flowLogs" + }, + { + "apiVersion": "2021-04-01", + "dependsOn": [ + "Microsoft.Network/networkWatchers/RegulaWatcher1", + "Microsoft.Storage/storageAccounts/regulasa01" + ], + "location": "switzerlandnorth", + "name": "FL2", + "properties": { + "retentionPolicy": { + "days": 70, + "enabled": true + }, + "storageId": "[resourceId('Microsoft.Storage/storageAccounts', 'regulasa01')]", + "targetResourceId": "[resourceId('Microsoft.Network/networkSecurityGroups', 'RegulaNSG2')]" + }, + "type": "flowLogs" + } + ], + "type": "Microsoft.Network/networkWatchers" + } + ] +} + diff --git a/rego/tests/rules/arm/network/inputs/security_group_no_inbound_22_infra.json b/rego/tests/rules/arm/network/inputs/security_group_no_inbound_22_infra.json new file mode 100644 index 00000000..093cb07b --- /dev/null +++ b/rego/tests/rules/arm/network/inputs/security_group_no_inbound_22_infra.json @@ -0,0 +1,125 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2021-03-01", + "name": "RegulaSG1", + "location": "switzerlandnorth", + "properties": { + "securityRules": [ + { + "name": "Rule1", + "properties": { + "priority": 110, + "access": "Allow", + "direction": "Inbound", + "destinationPortRange": "*", + "sourcePortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "protocol": "*" + } + } + ] + } + }, + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2021-03-01", + "name": "RegulaSG1/Rule2", + "location": "switzerlandnorth", + "properties": { + "priority": 120, + "access": "Deny", + "direction": "Inbound", + "destinationPortRange": "*", + "sourcePortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "protocol": "*" + }, + "dependsOn": [ + "RegulaSG1" + ] + }, + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2021-03-01", + "name": "RegulaSG1/Rule3", + "location": "switzerlandnorth", + "properties": { + "priority": 130, + "access": "Allow", + "direction": "Inbound", + "destinationPortRange": "22", + "sourcePortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "protocol": "*" + }, + "dependsOn": [ + "RegulaSG1" + ] + }, + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2021-03-01", + "name": "RegulaSG1/Rule4", + "location": "switzerlandnorth", + "properties": { + "priority": 140, + "access": "Allow", + "direction": "Inbound", + "destinationPortRanges": ["9-10", "21-23"], + "sourcePortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "protocol": "*" + }, + "dependsOn": [ + "RegulaSG1" + ] + }, + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2021-03-01", + "name": "RegulaSG1/Rule5", + "location": "switzerlandnorth", + "properties": { + "priority": 150, + "access": "Allow", + "direction": "Inbound", + "destinationPortRanges": ["9-10", "23-25"], + "sourcePortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "protocol": "*" + }, + "dependsOn": [ + "RegulaSG1" + ] + }, + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2021-03-01", + "name": "RegulaSG1/Rule6", + "location": "switzerlandnorth", + "properties": { + "priority": 160, + "access": "Allow", + "direction": "Inbound", + "destinationPortRanges": ["9-10", "21-22"], + "sourcePortRange": "*", + "sourceAddressPrefix": "10.0.0.0/24", + "destinationAddressPrefix": "*", + "protocol": "*" + }, + "dependsOn": [ + "RegulaSG1" + ] + } + ] +} diff --git a/rego/tests/rules/arm/network/inputs/security_group_no_inbound_22_infra_json.rego b/rego/tests/rules/arm/network/inputs/security_group_no_inbound_22_infra_json.rego new file mode 100644 index 00000000..1278e4fc --- /dev/null +++ b/rego/tests/rules/arm/network/inputs/security_group_no_inbound_22_infra_json.rego @@ -0,0 +1,156 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.network.inputs.security_group_no_inbound_22_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-03-01", + "location": "switzerlandnorth", + "name": "RegulaSG1", + "properties": { + "securityRules": [ + { + "name": "Rule1", + "properties": { + "access": "Allow", + "destinationAddressPrefix": "*", + "destinationPortRange": "*", + "direction": "Inbound", + "priority": 110, + "protocol": "*", + "sourceAddressPrefix": "*", + "sourcePortRange": "*" + } + } + ] + }, + "type": "Microsoft.Network/networkSecurityGroups" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "RegulaSG1" + ], + "location": "switzerlandnorth", + "name": "RegulaSG1/Rule2", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRange": "*", + "direction": "Inbound", + "priority": 120, + "protocol": "*", + "sourceAddressPrefix": "*", + "sourcePortRange": "*" + }, + "type": "Microsoft.Network/networkSecurityGroups/securityRules" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "RegulaSG1" + ], + "location": "switzerlandnorth", + "name": "RegulaSG1/Rule3", + "properties": { + "access": "Allow", + "destinationAddressPrefix": "*", + "destinationPortRange": "22", + "direction": "Inbound", + "priority": 130, + "protocol": "*", + "sourceAddressPrefix": "*", + "sourcePortRange": "*" + }, + "type": "Microsoft.Network/networkSecurityGroups/securityRules" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "RegulaSG1" + ], + "location": "switzerlandnorth", + "name": "RegulaSG1/Rule4", + "properties": { + "access": "Allow", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "9-10", + "21-23" + ], + "direction": "Inbound", + "priority": 140, + "protocol": "*", + "sourceAddressPrefix": "*", + "sourcePortRange": "*" + }, + "type": "Microsoft.Network/networkSecurityGroups/securityRules" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "RegulaSG1" + ], + "location": "switzerlandnorth", + "name": "RegulaSG1/Rule5", + "properties": { + "access": "Allow", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "9-10", + "23-25" + ], + "direction": "Inbound", + "priority": 150, + "protocol": "*", + "sourceAddressPrefix": "*", + "sourcePortRange": "*" + }, + "type": "Microsoft.Network/networkSecurityGroups/securityRules" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "RegulaSG1" + ], + "location": "switzerlandnorth", + "name": "RegulaSG1/Rule6", + "properties": { + "access": "Allow", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "9-10", + "21-22" + ], + "direction": "Inbound", + "priority": 160, + "protocol": "*", + "sourceAddressPrefix": "10.0.0.0/24", + "sourcePortRange": "*" + }, + "type": "Microsoft.Network/networkSecurityGroups/securityRules" + } + ] +} + diff --git a/rego/tests/rules/arm/network/inputs/security_group_no_inbound_3389_infra.json b/rego/tests/rules/arm/network/inputs/security_group_no_inbound_3389_infra.json new file mode 100644 index 00000000..253b5c7d --- /dev/null +++ b/rego/tests/rules/arm/network/inputs/security_group_no_inbound_3389_infra.json @@ -0,0 +1,125 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2021-03-01", + "name": "RegulaSG1", + "location": "switzerlandnorth", + "properties": { + "securityRules": [ + { + "name": "Rule1", + "properties": { + "priority": 110, + "access": "Allow", + "direction": "Inbound", + "destinationPortRange": "*", + "sourcePortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "protocol": "*" + } + } + ] + } + }, + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2021-03-01", + "name": "RegulaSG1/Rule2", + "location": "switzerlandnorth", + "properties": { + "priority": 120, + "access": "Deny", + "direction": "Inbound", + "destinationPortRange": "*", + "sourcePortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "protocol": "*" + }, + "dependsOn": [ + "RegulaSG1" + ] + }, + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2021-03-01", + "name": "RegulaSG1/Rule3", + "location": "switzerlandnorth", + "properties": { + "priority": 130, + "access": "Allow", + "direction": "Inbound", + "destinationPortRange": "3389", + "sourcePortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "protocol": "*" + }, + "dependsOn": [ + "RegulaSG1" + ] + }, + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2021-03-01", + "name": "RegulaSG1/Rule4", + "location": "switzerlandnorth", + "properties": { + "priority": 140, + "access": "Allow", + "direction": "Inbound", + "destinationPortRanges": ["9-10", "3388-3390"], + "sourcePortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "protocol": "*" + }, + "dependsOn": [ + "RegulaSG1" + ] + }, + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2021-03-01", + "name": "RegulaSG1/Rule5", + "location": "switzerlandnorth", + "properties": { + "priority": 150, + "access": "Allow", + "direction": "Inbound", + "destinationPortRanges": ["9-10", "3390-3395"], + "sourcePortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "protocol": "*" + }, + "dependsOn": [ + "RegulaSG1" + ] + }, + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2021-03-01", + "name": "RegulaSG1/Rule6", + "location": "switzerlandnorth", + "properties": { + "priority": 160, + "access": "Allow", + "direction": "Inbound", + "destinationPortRanges": ["9-10", "3388-3389"], + "sourcePortRange": "*", + "sourceAddressPrefix": "10.0.0.0/24", + "destinationAddressPrefix": "*", + "protocol": "*" + }, + "dependsOn": [ + "RegulaSG1" + ] + } + ] +} diff --git a/rego/tests/rules/arm/network/inputs/security_group_no_inbound_3389_infra_json.rego b/rego/tests/rules/arm/network/inputs/security_group_no_inbound_3389_infra_json.rego new file mode 100644 index 00000000..d251c76c --- /dev/null +++ b/rego/tests/rules/arm/network/inputs/security_group_no_inbound_3389_infra_json.rego @@ -0,0 +1,156 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.network.inputs.security_group_no_inbound_3389_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-03-01", + "location": "switzerlandnorth", + "name": "RegulaSG1", + "properties": { + "securityRules": [ + { + "name": "Rule1", + "properties": { + "access": "Allow", + "destinationAddressPrefix": "*", + "destinationPortRange": "*", + "direction": "Inbound", + "priority": 110, + "protocol": "*", + "sourceAddressPrefix": "*", + "sourcePortRange": "*" + } + } + ] + }, + "type": "Microsoft.Network/networkSecurityGroups" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "RegulaSG1" + ], + "location": "switzerlandnorth", + "name": "RegulaSG1/Rule2", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRange": "*", + "direction": "Inbound", + "priority": 120, + "protocol": "*", + "sourceAddressPrefix": "*", + "sourcePortRange": "*" + }, + "type": "Microsoft.Network/networkSecurityGroups/securityRules" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "RegulaSG1" + ], + "location": "switzerlandnorth", + "name": "RegulaSG1/Rule3", + "properties": { + "access": "Allow", + "destinationAddressPrefix": "*", + "destinationPortRange": "3389", + "direction": "Inbound", + "priority": 130, + "protocol": "*", + "sourceAddressPrefix": "*", + "sourcePortRange": "*" + }, + "type": "Microsoft.Network/networkSecurityGroups/securityRules" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "RegulaSG1" + ], + "location": "switzerlandnorth", + "name": "RegulaSG1/Rule4", + "properties": { + "access": "Allow", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "9-10", + "3388-3390" + ], + "direction": "Inbound", + "priority": 140, + "protocol": "*", + "sourceAddressPrefix": "*", + "sourcePortRange": "*" + }, + "type": "Microsoft.Network/networkSecurityGroups/securityRules" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "RegulaSG1" + ], + "location": "switzerlandnorth", + "name": "RegulaSG1/Rule5", + "properties": { + "access": "Allow", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "9-10", + "3390-3395" + ], + "direction": "Inbound", + "priority": 150, + "protocol": "*", + "sourceAddressPrefix": "*", + "sourcePortRange": "*" + }, + "type": "Microsoft.Network/networkSecurityGroups/securityRules" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "RegulaSG1" + ], + "location": "switzerlandnorth", + "name": "RegulaSG1/Rule6", + "properties": { + "access": "Allow", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "9-10", + "3388-3389" + ], + "direction": "Inbound", + "priority": 160, + "protocol": "*", + "sourceAddressPrefix": "10.0.0.0/24", + "sourcePortRange": "*" + }, + "type": "Microsoft.Network/networkSecurityGroups/securityRules" + } + ] +} + diff --git a/rego/tests/rules/arm/network/security_group_no_inbound_22_test.rego b/rego/tests/rules/arm/network/security_group_no_inbound_22_test.rego new file mode 100644 index 00000000..dff40036 --- /dev/null +++ b/rego/tests/rules/arm/network/security_group_no_inbound_22_test.rego @@ -0,0 +1,28 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_network_security_group_no_inbound_22 + +import data.tests.rules.arm.network.inputs.security_group_no_inbound_22_infra_json as infra + +test_rule { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaSG1"] == false + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaSG1/securityRules/Rule2"] == true + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaSG1/securityRules/Rule3"] == false + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaSG1/securityRules/Rule4"] == false + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaSG1/securityRules/Rule5"] == true + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaSG1/securityRules/Rule6"] == true +} diff --git a/rego/tests/rules/arm/network/security_group_no_inbound_3389_test.rego b/rego/tests/rules/arm/network/security_group_no_inbound_3389_test.rego new file mode 100644 index 00000000..f30da02f --- /dev/null +++ b/rego/tests/rules/arm/network/security_group_no_inbound_3389_test.rego @@ -0,0 +1,28 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_network_security_group_no_inbound_3389 + +import data.tests.rules.arm.network.inputs.security_group_no_inbound_3389_infra_json as infra + +test_rule { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaSG1"] == false + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaSG1/securityRules/Rule2"] == true + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaSG1/securityRules/Rule3"] == false + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaSG1/securityRules/Rule4"] == false + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaSG1/securityRules/Rule5"] == true + by_resource_id["Microsoft.Network/networkSecurityGroups/RegulaSG1/securityRules/Rule6"] == true +} diff --git a/rego/tests/rules/arm/postgresql/connection_throttling_test.rego b/rego/tests/rules/arm/postgresql/connection_throttling_test.rego new file mode 100644 index 00000000..6d80c483 --- /dev/null +++ b/rego/tests/rules/arm/postgresql/connection_throttling_test.rego @@ -0,0 +1,26 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_connection_throttling + +import data.tests.rules.arm.postgresql.inputs.configuration_infra_json as infra + +test_rule { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + count(by_resource_id) == 3 + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid"] == true + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid"] == false + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigDefault"] == true +} diff --git a/rego/tests/rules/arm/postgresql/enforce_ssl_test.rego b/rego/tests/rules/arm/postgresql/enforce_ssl_test.rego new file mode 100644 index 00000000..92de34a6 --- /dev/null +++ b/rego/tests/rules/arm/postgresql/enforce_ssl_test.rego @@ -0,0 +1,22 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_enforce_ssl + +import data.tests.rules.arm.postgresql.inputs.enforce_ssl_infra_json as infra + +test_rule { + not allow with input as infra.mock_resources["Microsoft.DBforPostgreSQL/servers/RegulaServer1"] + allow with input as infra.mock_resources["Microsoft.DBforPostgreSQL/servers/RegulaServer2"] +} diff --git a/rego/tests/rules/arm/postgresql/inputs/configuration_infra.json b/rego/tests/rules/arm/postgresql/inputs/configuration_infra.json new file mode 100644 index 00000000..36885cce --- /dev/null +++ b/rego/tests/rules/arm/postgresql/inputs/configuration_infra.json @@ -0,0 +1,173 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2017-12-01", + "type": "Microsoft.DBforPostgreSQL/servers", + "name": "RegulaServerConfigValid", + "location": "switzerlandnorth", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!" + }, + "resources": [ + { + "apiVersion": "2017-12-01", + "name": "log_checkpoints", + "type": "configurations", + "properties": { + "value": "on" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "log_connections", + "type": "configurations", + "properties": { + "value": "on" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "log_disconnections", + "type": "configurations", + "properties": { + "value": "on" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "log_duration", + "type": "configurations", + "properties": { + "value": "on" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "connection_throttling", + "type": "configurations", + "properties": { + "value": "on" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "log_retention_days", + "type": "configurations", + "properties": { + "value": "7" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid" + ] + } + ] + }, + { + "apiVersion": "2017-12-01", + "type": "Microsoft.DBforPostgreSQL/servers", + "name": "RegulaServerConfigInvalid", + "location": "switzerlandnorth", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!" + }, + "resources": [ + { + "apiVersion": "2017-12-01", + "name": "log_checkpoints", + "type": "configurations", + "properties": { + "value": "off" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "log_connections", + "type": "configurations", + "properties": { + "value": "off" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "log_disconnections", + "type": "configurations", + "properties": { + "value": "off" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "log_duration", + "type": "configurations", + "properties": { + "value": "off" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "connection_throttling", + "type": "configurations", + "properties": { + "value": "off" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "log_retention_days", + "type": "configurations", + "properties": { + "value": "1" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid" + ] + } + ] + }, + { + "apiVersion": "2017-12-01", + "type": "Microsoft.DBforPostgreSQL/servers", + "name": "RegulaServerConfigDefault", + "location": "switzerlandnorth", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!" + } + } + ] +} diff --git a/rego/tests/rules/arm/postgresql/inputs/configuration_infra_json.rego b/rego/tests/rules/arm/postgresql/inputs/configuration_infra_json.rego new file mode 100644 index 00000000..bfc47865 --- /dev/null +++ b/rego/tests/rules/arm/postgresql/inputs/configuration_infra_json.rego @@ -0,0 +1,195 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.postgresql.inputs.configuration_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2017-12-01", + "location": "switzerlandnorth", + "name": "RegulaServerConfigValid", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!" + }, + "resources": [ + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid" + ], + "name": "log_checkpoints", + "properties": { + "value": "on" + }, + "type": "configurations" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid" + ], + "name": "log_connections", + "properties": { + "value": "on" + }, + "type": "configurations" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid" + ], + "name": "log_disconnections", + "properties": { + "value": "on" + }, + "type": "configurations" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid" + ], + "name": "log_duration", + "properties": { + "value": "on" + }, + "type": "configurations" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid" + ], + "name": "connection_throttling", + "properties": { + "value": "on" + }, + "type": "configurations" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid" + ], + "name": "log_retention_days", + "properties": { + "value": "7" + }, + "type": "configurations" + } + ], + "type": "Microsoft.DBforPostgreSQL/servers" + }, + { + "apiVersion": "2017-12-01", + "location": "switzerlandnorth", + "name": "RegulaServerConfigInvalid", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!" + }, + "resources": [ + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid" + ], + "name": "log_checkpoints", + "properties": { + "value": "off" + }, + "type": "configurations" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid" + ], + "name": "log_connections", + "properties": { + "value": "off" + }, + "type": "configurations" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid" + ], + "name": "log_disconnections", + "properties": { + "value": "off" + }, + "type": "configurations" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid" + ], + "name": "log_duration", + "properties": { + "value": "off" + }, + "type": "configurations" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid" + ], + "name": "connection_throttling", + "properties": { + "value": "off" + }, + "type": "configurations" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid" + ], + "name": "log_retention_days", + "properties": { + "value": "1" + }, + "type": "configurations" + } + ], + "type": "Microsoft.DBforPostgreSQL/servers" + }, + { + "apiVersion": "2017-12-01", + "location": "switzerlandnorth", + "name": "RegulaServerConfigDefault", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!" + }, + "type": "Microsoft.DBforPostgreSQL/servers" + } + ] +} + diff --git a/rego/tests/rules/arm/postgresql/inputs/enforce_ssl_infra.json b/rego/tests/rules/arm/postgresql/inputs/enforce_ssl_infra.json new file mode 100644 index 00000000..a6aed792 --- /dev/null +++ b/rego/tests/rules/arm/postgresql/inputs/enforce_ssl_infra.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2017-12-01", + "type": "Microsoft.DBforPostgreSQL/servers", + "name": "RegulaServer1", + "location": "switzerlandnorth", + "properties": { + "sslEnforcement": "Disabled", + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!" + } + }, + { + "apiVersion": "2017-12-01", + "type": "Microsoft.DBforPostgreSQL/servers", + "name": "RegulaServer2", + "location": "switzerlandnorth", + "properties": { + "sslEnforcement": "Enabled", + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!" + } + } + ] +} diff --git a/rego/tests/rules/arm/postgresql/inputs/enforce_ssl_infra_json.rego b/rego/tests/rules/arm/postgresql/inputs/enforce_ssl_infra_json.rego new file mode 100644 index 00000000..55681623 --- /dev/null +++ b/rego/tests/rules/arm/postgresql/inputs/enforce_ssl_infra_json.rego @@ -0,0 +1,51 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.postgresql.inputs.enforce_ssl_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2017-12-01", + "location": "switzerlandnorth", + "name": "RegulaServer1", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!", + "sslEnforcement": "Disabled" + }, + "type": "Microsoft.DBforPostgreSQL/servers" + }, + { + "apiVersion": "2017-12-01", + "location": "switzerlandnorth", + "name": "RegulaServer2", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!", + "sslEnforcement": "Enabled" + }, + "type": "Microsoft.DBforPostgreSQL/servers" + } + ] +} + diff --git a/rego/tests/rules/arm/postgresql/inputs/no_inbound_all_infra.json b/rego/tests/rules/arm/postgresql/inputs/no_inbound_all_infra.json new file mode 100644 index 00000000..245549f5 --- /dev/null +++ b/rego/tests/rules/arm/postgresql/inputs/no_inbound_all_infra.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2017-12-01", + "type": "Microsoft.DBforPostgreSQL/servers", + "name": "RegulaServer1", + "location": "switzerlandnorth", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!" + }, + "resources": [ + { + "apiVersion": "2017-12-01", + "name": "Rule1", + "type": "firewallRules", + "properties": { + "startIpAddress": "0.0.0.0", + "endIpAddress": "0.0.0.0" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServer1" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "Rule2", + "type": "firewallRules", + "properties": { + "startIpAddress": "10.0.0.0", + "endIpAddress": "10.0.255.0" + }, + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServer1" + ] + } + ] + } + ] +} diff --git a/rego/tests/rules/arm/postgresql/inputs/no_inbound_all_infra_json.rego b/rego/tests/rules/arm/postgresql/inputs/no_inbound_all_infra_json.rego new file mode 100644 index 00000000..9d43cec1 --- /dev/null +++ b/rego/tests/rules/arm/postgresql/inputs/no_inbound_all_infra_json.rego @@ -0,0 +1,65 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.postgresql.inputs.no_inbound_all_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2017-12-01", + "location": "switzerlandnorth", + "name": "RegulaServer1", + "properties": { + "administratorLogin": "foo", + "administratorLoginPassword": "abcd1234!" + }, + "resources": [ + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServer1" + ], + "name": "Rule1", + "properties": { + "endIpAddress": "0.0.0.0", + "startIpAddress": "0.0.0.0" + }, + "type": "firewallRules" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.DBforPostgreSQL/servers/RegulaServer1" + ], + "name": "Rule2", + "properties": { + "endIpAddress": "10.0.255.0", + "startIpAddress": "10.0.0.0" + }, + "type": "firewallRules" + } + ], + "type": "Microsoft.DBforPostgreSQL/servers" + } + ] +} + diff --git a/rego/tests/rules/arm/postgresql/log_checkpoints_test.rego b/rego/tests/rules/arm/postgresql/log_checkpoints_test.rego new file mode 100644 index 00000000..e0d9c779 --- /dev/null +++ b/rego/tests/rules/arm/postgresql/log_checkpoints_test.rego @@ -0,0 +1,26 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_log_checkpoints + +import data.tests.rules.arm.postgresql.inputs.configuration_infra_json as infra + +test_rule { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + count(by_resource_id) == 3 + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid"] == true + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid"] == false + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigDefault"] == true +} diff --git a/rego/tests/rules/arm/postgresql/log_connections_test.rego b/rego/tests/rules/arm/postgresql/log_connections_test.rego new file mode 100644 index 00000000..928b7292 --- /dev/null +++ b/rego/tests/rules/arm/postgresql/log_connections_test.rego @@ -0,0 +1,26 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_log_connections + +import data.tests.rules.arm.postgresql.inputs.configuration_infra_json as infra + +test_rule { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + count(by_resource_id) == 3 + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid"] == true + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid"] == false + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigDefault"] == true +} diff --git a/rego/tests/rules/arm/postgresql/log_disconnections_test.rego b/rego/tests/rules/arm/postgresql/log_disconnections_test.rego new file mode 100644 index 00000000..137eef73 --- /dev/null +++ b/rego/tests/rules/arm/postgresql/log_disconnections_test.rego @@ -0,0 +1,26 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_log_disconnections + +import data.tests.rules.arm.postgresql.inputs.configuration_infra_json as infra + +test_rule { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + count(by_resource_id) == 3 + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid"] == true + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid"] == false + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigDefault"] == false +} diff --git a/rego/tests/rules/arm/postgresql/log_duration_test.rego b/rego/tests/rules/arm/postgresql/log_duration_test.rego new file mode 100644 index 00000000..4c3ddcce --- /dev/null +++ b/rego/tests/rules/arm/postgresql/log_duration_test.rego @@ -0,0 +1,26 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_log_duration + +import data.tests.rules.arm.postgresql.inputs.configuration_infra_json as infra + +test_rule { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + count(by_resource_id) == 3 + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid"] == true + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid"] == false + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigDefault"] == false +} diff --git a/rego/tests/rules/arm/postgresql/log_retention_test.rego b/rego/tests/rules/arm/postgresql/log_retention_test.rego new file mode 100644 index 00000000..0ba8364a --- /dev/null +++ b/rego/tests/rules/arm/postgresql/log_retention_test.rego @@ -0,0 +1,26 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_log_retention + +import data.tests.rules.arm.postgresql.inputs.configuration_infra_json as infra + +test_rule { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + count(by_resource_id) == 3 + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigValid"] == true + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigInvalid"] == false + by_resource_id["Microsoft.DBforPostgreSQL/servers/RegulaServerConfigDefault"] == false +} diff --git a/rego/tests/rules/arm/postgresql/no_inbound_all_test.rego b/rego/tests/rules/arm/postgresql/no_inbound_all_test.rego new file mode 100644 index 00000000..f9dd07f5 --- /dev/null +++ b/rego/tests/rules/arm/postgresql/no_inbound_all_test.rego @@ -0,0 +1,22 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_postgresql_no_inbound_all + +import data.tests.rules.arm.postgresql.inputs.no_inbound_all_infra_json as infra + +test_rule { + deny with input as infra.mock_resources["Microsoft.DBforPostgreSQL/servers/RegulaServer1/firewallRules/Rule1"] + not deny with input as infra.mock_resources["Microsoft.DBforPostgreSQL/servers/RegulaServer1/firewallRules/Rule2"] +} diff --git a/rego/tests/rules/arm/security/contact_notifications_enabled_test.rego b/rego/tests/rules/arm/security/contact_notifications_enabled_test.rego new file mode 100644 index 00000000..f3e4b494 --- /dev/null +++ b/rego/tests/rules/arm/security/contact_notifications_enabled_test.rego @@ -0,0 +1,22 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_security_contact_notifications_enabled + +import data.tests.rules.arm.security.inputs.contact_notifications_enabled_infra_json as infra + +test_contact_notifications_enabled { + allow with input as infra.mock_resources["Microsoft.Security/securityContacts/valid"] + not allow with input as infra.mock_resources["Microsoft.Security/securityContacts/invalid"] +} diff --git a/rego/tests/rules/arm/security/inputs/contact_notifications_enabled_infra.json b/rego/tests/rules/arm/security/inputs/contact_notifications_enabled_infra.json new file mode 100644 index 00000000..c9df26f1 --- /dev/null +++ b/rego/tests/rules/arm/security/inputs/contact_notifications_enabled_infra.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Security/securityContacts", + "apiVersion": "2017-08-01-preview", + "name": "valid", + "properties": { + "alertNotifications": "On", + "alertsToAdmins": "Off", + "email": "regula.valid@example.com" + } + }, + { + "type": "Microsoft.Security/securityContacts", + "apiVersion": "2017-08-01-preview", + "name": "invalid", + "properties": { + "alertNotifications": "Off", + "alertsToAdmins": "Off", + "email": "regula.invalid@example.com" + } + } + ] +} diff --git a/rego/tests/rules/arm/security/inputs/contact_notifications_enabled_infra_json.rego b/rego/tests/rules/arm/security/inputs/contact_notifications_enabled_infra_json.rego new file mode 100644 index 00000000..eac38ba3 --- /dev/null +++ b/rego/tests/rules/arm/security/inputs/contact_notifications_enabled_infra_json.rego @@ -0,0 +1,48 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.security.inputs.contact_notifications_enabled_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "apiVersion": "2017-08-01-preview", + "name": "valid", + "properties": { + "alertNotifications": "On", + "alertsToAdmins": "Off", + "email": "regula.valid@example.com" + }, + "type": "Microsoft.Security/securityContacts" + }, + { + "apiVersion": "2017-08-01-preview", + "name": "invalid", + "properties": { + "alertNotifications": "Off", + "alertsToAdmins": "Off", + "email": "regula.invalid@example.com" + }, + "type": "Microsoft.Security/securityContacts" + } + ] +} + diff --git a/rego/tests/rules/arm/sql/auditing_retention_test.rego b/rego/tests/rules/arm/sql/auditing_retention_test.rego new file mode 100644 index 00000000..7992201b --- /dev/null +++ b/rego/tests/rules/arm/sql/auditing_retention_test.rego @@ -0,0 +1,26 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_sql_auditing_retention + +import data.tests.rules.arm.sql.inputs.auditing_infra_json as infra + +test_rule { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + count(by_resource_id) == 3 + by_resource_id["Microsoft.Sql/servers/regulaserver1"] == true + by_resource_id["Microsoft.Sql/servers/regulaserver2"] == false + by_resource_id["Microsoft.Sql/servers/regulaserver3"] == false +} diff --git a/rego/tests/rules/arm/sql/auditing_test.rego b/rego/tests/rules/arm/sql/auditing_test.rego new file mode 100644 index 00000000..f948569c --- /dev/null +++ b/rego/tests/rules/arm/sql/auditing_test.rego @@ -0,0 +1,26 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_sql_auditing + +import data.tests.rules.arm.sql.inputs.auditing_infra_json as infra + +test_rule { + pol = policy with input as infra.mock_input + by_resource_id = {p.id: p.valid | pol[p]} + count(by_resource_id) == 3 + by_resource_id["Microsoft.Sql/servers/regulaserver1"] == true + by_resource_id["Microsoft.Sql/servers/regulaserver2"] == false + by_resource_id["Microsoft.Sql/servers/regulaserver3"] == true +} diff --git a/rego/tests/rules/arm/sql/inputs/auditing_infra.json b/rego/tests/rules/arm/sql/inputs/auditing_infra.json new file mode 100644 index 00000000..99a09b9f --- /dev/null +++ b/rego/tests/rules/arm/sql/inputs/auditing_infra.json @@ -0,0 +1,67 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Sql/servers", + "apiVersion": "2014-04-01", + "name": "regulaserver1", + "location": "[resourceGroup().location]", + "properties": { + "administratorLogin": "sysadmin", + "administratorLoginPassword": "abcd1234!" + }, + "resources": [ + { + "type": "auditingSettings", + "apiVersion": "2021-05-01-preview", + "name": "as1", + "properties": { + "state": "Enabled", + "retentionDays": 90, + "isAzureMonitorTargetEnabled": true + }, + "dependsOn": [ + "Microsoft.Sql/servers/regulaserver1" + ] + } + ] + }, + { + "type": "Microsoft.Sql/servers", + "apiVersion": "2014-04-01", + "name": "regulaserver2", + "location": "[resourceGroup().location]", + "properties": { + "administratorLogin": "sysadmin", + "administratorLoginPassword": "abcd1234!" + } + }, + { + "type": "Microsoft.Sql/servers", + "apiVersion": "2014-04-01", + "name": "regulaserver3", + "location": "[resourceGroup().location]", + "properties": { + "administratorLogin": "sysadmin", + "administratorLoginPassword": "abcd1234!" + }, + "resources": [ + { + "type": "auditingSettings", + "apiVersion": "2021-05-01-preview", + "name": "as1", + "properties": { + "state": "Enabled", + "retentionDays": 3, + "isAzureMonitorTargetEnabled": true + }, + "dependsOn": [ + "Microsoft.Sql/servers/regulaserver3" + ] + } + ] + } + ] +} diff --git a/rego/tests/rules/arm/sql/inputs/auditing_infra_json.rego b/rego/tests/rules/arm/sql/inputs/auditing_infra_json.rego new file mode 100644 index 00000000..305f9545 --- /dev/null +++ b/rego/tests/rules/arm/sql/inputs/auditing_infra_json.rego @@ -0,0 +1,89 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.sql.inputs.auditing_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2014-04-01", + "location": "[resourceGroup().location]", + "name": "regulaserver1", + "properties": { + "administratorLogin": "sysadmin", + "administratorLoginPassword": "abcd1234!" + }, + "resources": [ + { + "apiVersion": "2021-05-01-preview", + "dependsOn": [ + "Microsoft.Sql/servers/regulaserver1" + ], + "name": "as1", + "properties": { + "isAzureMonitorTargetEnabled": true, + "retentionDays": 90, + "state": "Enabled" + }, + "type": "auditingSettings" + } + ], + "type": "Microsoft.Sql/servers" + }, + { + "apiVersion": "2014-04-01", + "location": "[resourceGroup().location]", + "name": "regulaserver2", + "properties": { + "administratorLogin": "sysadmin", + "administratorLoginPassword": "abcd1234!" + }, + "type": "Microsoft.Sql/servers" + }, + { + "apiVersion": "2014-04-01", + "location": "[resourceGroup().location]", + "name": "regulaserver3", + "properties": { + "administratorLogin": "sysadmin", + "administratorLoginPassword": "abcd1234!" + }, + "resources": [ + { + "apiVersion": "2021-05-01-preview", + "dependsOn": [ + "Microsoft.Sql/servers/regulaserver3" + ], + "name": "as1", + "properties": { + "isAzureMonitorTargetEnabled": true, + "retentionDays": 3, + "state": "Enabled" + }, + "type": "auditingSettings" + } + ], + "type": "Microsoft.Sql/servers" + } + ] +} + diff --git a/rego/tests/rules/arm/sql/inputs/no_inbound_all_infra.json b/rego/tests/rules/arm/sql/inputs/no_inbound_all_infra.json new file mode 100644 index 00000000..de2e6cc2 --- /dev/null +++ b/rego/tests/rules/arm/sql/inputs/no_inbound_all_infra.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2017-12-01", + "type": "Microsoft.Sql/servers", + "name": "Server1", + "location": "switzerlandnorth", + "properties": { + "administratorLogin": "admin", + "administratorLoginPassword": "hunter2" + }, + "resources": [ + { + "apiVersion": "2017-12-01", + "name": "Rule1", + "type": "firewallRules", + "properties": { + "startIpAddress": "0.0.0.0", + "endIpAddress": "0.0.0.0" + }, + "dependsOn": [ + "Microsoft.Sql/servers/Server1" + ] + }, + { + "apiVersion": "2017-12-01", + "name": "Rule2", + "type": "firewallRules", + "properties": { + "startIpAddress": "10.0.0.0", + "endIpAddress": "10.0.255.0" + }, + "dependsOn": [ + "Microsoft.Sql/servers/Server1" + ] + } + ] + } + ] +} diff --git a/rego/tests/rules/arm/sql/inputs/no_inbound_all_infra_json.rego b/rego/tests/rules/arm/sql/inputs/no_inbound_all_infra_json.rego new file mode 100644 index 00000000..d502257a --- /dev/null +++ b/rego/tests/rules/arm/sql/inputs/no_inbound_all_infra_json.rego @@ -0,0 +1,65 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.sql.inputs.no_inbound_all_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2017-12-01", + "location": "switzerlandnorth", + "name": "Server1", + "properties": { + "administratorLogin": "admin", + "administratorLoginPassword": "hunter2" + }, + "resources": [ + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.Sql/servers/Server1" + ], + "name": "Rule1", + "properties": { + "endIpAddress": "0.0.0.0", + "startIpAddress": "0.0.0.0" + }, + "type": "firewallRules" + }, + { + "apiVersion": "2017-12-01", + "dependsOn": [ + "Microsoft.Sql/servers/Server1" + ], + "name": "Rule2", + "properties": { + "endIpAddress": "10.0.255.0", + "startIpAddress": "10.0.0.0" + }, + "type": "firewallRules" + } + ], + "type": "Microsoft.Sql/servers" + } + ] +} + diff --git a/rego/tests/rules/arm/sql/no_inbound_all_test.rego b/rego/tests/rules/arm/sql/no_inbound_all_test.rego new file mode 100644 index 00000000..d038f12e --- /dev/null +++ b/rego/tests/rules/arm/sql/no_inbound_all_test.rego @@ -0,0 +1,22 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_sql_no_inbound_all + +import data.tests.rules.arm.sql.inputs.no_inbound_all_infra_json as infra + +test_rule { + deny with input as infra.mock_resources["Microsoft.Sql/servers/Server1/firewallRules/Rule1"] + not deny with input as infra.mock_resources["Microsoft.Sql/servers/Server1/firewallRules/Rule2"] +} diff --git a/rego/tests/rules/arm/storage/account_default_deny_access_test.rego b/rego/tests/rules/arm/storage/account_default_deny_access_test.rego new file mode 100644 index 00000000..ef270275 --- /dev/null +++ b/rego/tests/rules/arm/storage/account_default_deny_access_test.rego @@ -0,0 +1,23 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_storage_account_default_deny_access + +import data.tests.rules.arm.storage.inputs.account_default_deny_access_infra_json as infra + +test_account_default_deny_access { + allow with input as infra.mock_resources["Microsoft.Storage/storageAccounts/valid"] + not allow with input as infra.mock_resources["Microsoft.Storage/storageAccounts/invalidallow"] + not allow with input as infra.mock_resources["Microsoft.Storage/storageAccounts/invalidunset"] +} diff --git a/rego/tests/rules/arm/storage/account_queue_logging_test.rego b/rego/tests/rules/arm/storage/account_queue_logging_test.rego new file mode 100644 index 00000000..3869b9d5 --- /dev/null +++ b/rego/tests/rules/arm/storage/account_queue_logging_test.rego @@ -0,0 +1,22 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_storage_account_queue_logging + +import data.tests.rules.arm.storage.inputs.account_queue_logging_infra_json as infra + +test_storage_account_queue_logging { + not allow with input as infra.mock_resources["Microsoft.Storage/storageAccounts/regulastorage1/queueServices/default/providers/Microsoft.Insights/diagnosticSettings/setting1"] + allow with input as infra.mock_resources["Microsoft.Storage/storageAccounts/regulastorage2/queueServices/default/providers/Microsoft.Insights/diagnosticSettings/setting2"] +} diff --git a/rego/tests/rules/arm/storage/account_secure_transfer_test.rego b/rego/tests/rules/arm/storage/account_secure_transfer_test.rego new file mode 100644 index 00000000..538f0f9a --- /dev/null +++ b/rego/tests/rules/arm/storage/account_secure_transfer_test.rego @@ -0,0 +1,25 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_storage_account_secure_transfer + +import data.tests.rules.arm.storage.inputs.account_secure_transfer_infra_json as infra + +test_storage_account_secure_transfer { + deny with input as infra.mock_resources["Microsoft.Storage/storageAccounts/invalid"] + deny with input as infra.mock_resources["Microsoft.Storage/storageAccounts/invaliddefault"] + not deny with input as infra.mock_resources["Microsoft.Storage/storageAccounts/valid"] + not deny with input as infra.mock_resources["Microsoft.Storage/storageAccounts/validdefault"] + not deny with input as infra.mock_resources["Microsoft.Storage/storageAccounts/validolder"] +} diff --git a/rego/tests/rules/arm/storage/account_trusted_ms_services_test.rego b/rego/tests/rules/arm/storage/account_trusted_ms_services_test.rego new file mode 100644 index 00000000..7aee6d13 --- /dev/null +++ b/rego/tests/rules/arm/storage/account_trusted_ms_services_test.rego @@ -0,0 +1,25 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_storage_account_trusted_ms_services + +import data.tests.rules.arm.storage.inputs.account_trusted_ms_services_infra_json as infra + +test_storage_account_trusted_ms_services { + allow with input as infra.mock_resources["Microsoft.Storage/storageAccounts/valid"] + allow with input as infra.mock_resources["Microsoft.Storage/storageAccounts/validmulti"] + allow with input as infra.mock_resources["Microsoft.Storage/storageAccounts/validmulti2"] + not allow with input as infra.mock_resources["Microsoft.Storage/storageAccounts/invalid"] + not allow with input as infra.mock_resources["Microsoft.Storage/storageAccounts/invalidunset"] +} diff --git a/rego/tests/rules/arm/storage/disable_public_access_test.rego b/rego/tests/rules/arm/storage/disable_public_access_test.rego new file mode 100644 index 00000000..15acb617 --- /dev/null +++ b/rego/tests/rules/arm/storage/disable_public_access_test.rego @@ -0,0 +1,23 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_storage_disable_public_access + +import data.tests.rules.arm.storage.inputs.disable_public_access_infra_json as infra + +test_disable_public_access { + not deny with input as infra.mock_resources["Microsoft.Storage/storageAccounts/storage/blobServices/default/containers/valid"] + not deny with input as infra.mock_resources["Microsoft.Storage/storageAccounts/storage/blobServices/default/containers/validUnset"] + deny with input as infra.mock_resources["Microsoft.Storage/storageAccounts/storage/blobServices/default/containers/invalid"] +} diff --git a/rego/tests/rules/arm/storage/inputs/account_default_deny_access_infra.json b/rego/tests/rules/arm/storage/inputs/account_default_deny_access_infra.json new file mode 100644 index 00000000..cffae582 --- /dev/null +++ b/rego/tests/rules/arm/storage/inputs/account_default_deny_access_infra.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "valid", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": { + "networkAcls": { + "defaultAction": "Deny" + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "invalidallow", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": { + "networkAcls": { + "defaultAction": "Allow" + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "invalidunset", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": {} + } + ] +} diff --git a/rego/tests/rules/arm/storage/inputs/account_default_deny_access_infra_json.rego b/rego/tests/rules/arm/storage/inputs/account_default_deny_access_infra_json.rego new file mode 100644 index 00000000..376542ee --- /dev/null +++ b/rego/tests/rules/arm/storage/inputs/account_default_deny_access_infra_json.rego @@ -0,0 +1,70 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.storage.inputs.account_default_deny_access_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-04-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "valid", + "properties": { + "networkAcls": { + "defaultAction": "Deny" + } + }, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2021-04-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "invalidallow", + "properties": { + "networkAcls": { + "defaultAction": "Allow" + } + }, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2021-04-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "invalidunset", + "properties": {}, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + } + ] +} + diff --git a/rego/tests/rules/arm/storage/inputs/account_queue_logging_infra.json b/rego/tests/rules/arm/storage/inputs/account_queue_logging_infra.json new file mode 100644 index 00000000..fef3e519 --- /dev/null +++ b/rego/tests/rules/arm/storage/inputs/account_queue_logging_infra.json @@ -0,0 +1,125 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "regulalogstorage1", + "location": "switzerlandnorth", + "sku": { + "name": "Standard_LRS" + }, + "kind": "StorageV2" + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "regulastorage1", + "location": "switzerlandnorth", + "sku": { + "name": "Standard_LRS" + }, + "kind": "StorageV2" + }, + { + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2017-05-01-preview", + "name": "setting1", + "properties": { + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', 'regulalogstorage1')]" + }, + "scope": "Microsoft.Storage/storageAccounts/regulastorage1", + "dependsOn": [ + "Microsoft.Storage/storageAccounts/regulalogstorage1", + "Microsoft.Storage/storageAccounts/regulastorage1" + ] + }, + { + "type": "Microsoft.Storage/storageAccounts/queueServices/providers/diagnosticSettings", + "apiVersion": "2017-05-01-preview", + "name": "regulastorage1/default/Microsoft.Insights/setting1", + "properties": { + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', 'regulalogstorage1')]", + "logs": [ + { + "category": "StorageRead", + "enabled": true + }, + { + "category": "StorageWrite", + "enabled": true + }, + { + "category": "StorageDelete", + "enabled": false + } + ] + }, + "dependsOn": [ + "Microsoft.Storage/storageAccounts/regulalogstorage1", + "Microsoft.Storage/storageAccounts/regulastorage1" + ] + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "regulalogstorage2", + "location": "switzerlandnorth", + "sku": { + "name": "Standard_LRS" + }, + "kind": "StorageV2" + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "regulastorage2", + "location": "switzerlandnorth", + "sku": { + "name": "Standard_LRS" + }, + "kind": "StorageV2" + }, + { + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2017-05-01-preview", + "name": "setting2", + "properties": { + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', 'regulalogstorage2')]" + }, + "scope": "Microsoft.Storage/storageAccounts/regulastorage2", + "dependsOn": [ + "Microsoft.Storage/storageAccounts/regulalogstorage2", + "Microsoft.Storage/storageAccounts/regulastorage2" + ] + }, + { + "type": "Microsoft.Storage/storageAccounts/queueServices/providers/diagnosticSettings", + "apiVersion": "2017-05-01-preview", + "name": "regulastorage2/default/Microsoft.Insights/setting2", + "properties": { + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', 'regulalogstorage2')]", + "logs": [ + { + "category": "StorageRead", + "enabled": true + }, + { + "category": "StorageWrite", + "enabled": true + }, + { + "category": "StorageDelete", + "enabled": true + } + ] + }, + "dependsOn": [ + "Microsoft.Storage/storageAccounts/regulalogstorage2", + "Microsoft.Storage/storageAccounts/regulastorage2" + ] + } + ] +} diff --git a/rego/tests/rules/arm/storage/inputs/account_queue_logging_infra_json.rego b/rego/tests/rules/arm/storage/inputs/account_queue_logging_infra_json.rego new file mode 100644 index 00000000..202f9256 --- /dev/null +++ b/rego/tests/rules/arm/storage/inputs/account_queue_logging_infra_json.rego @@ -0,0 +1,147 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.storage.inputs.account_queue_logging_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-04-01", + "kind": "StorageV2", + "location": "switzerlandnorth", + "name": "regulalogstorage1", + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2021-04-01", + "kind": "StorageV2", + "location": "switzerlandnorth", + "name": "regulastorage1", + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2017-05-01-preview", + "dependsOn": [ + "Microsoft.Storage/storageAccounts/regulalogstorage1", + "Microsoft.Storage/storageAccounts/regulastorage1" + ], + "name": "setting1", + "properties": { + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', 'regulalogstorage1')]" + }, + "scope": "Microsoft.Storage/storageAccounts/regulastorage1", + "type": "Microsoft.Insights/diagnosticSettings" + }, + { + "apiVersion": "2017-05-01-preview", + "dependsOn": [ + "Microsoft.Storage/storageAccounts/regulalogstorage1", + "Microsoft.Storage/storageAccounts/regulastorage1" + ], + "name": "regulastorage1/default/Microsoft.Insights/setting1", + "properties": { + "logs": [ + { + "category": "StorageRead", + "enabled": true + }, + { + "category": "StorageWrite", + "enabled": true + }, + { + "category": "StorageDelete", + "enabled": false + } + ], + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', 'regulalogstorage1')]" + }, + "type": "Microsoft.Storage/storageAccounts/queueServices/providers/diagnosticSettings" + }, + { + "apiVersion": "2021-04-01", + "kind": "StorageV2", + "location": "switzerlandnorth", + "name": "regulalogstorage2", + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2021-04-01", + "kind": "StorageV2", + "location": "switzerlandnorth", + "name": "regulastorage2", + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2017-05-01-preview", + "dependsOn": [ + "Microsoft.Storage/storageAccounts/regulalogstorage2", + "Microsoft.Storage/storageAccounts/regulastorage2" + ], + "name": "setting2", + "properties": { + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', 'regulalogstorage2')]" + }, + "scope": "Microsoft.Storage/storageAccounts/regulastorage2", + "type": "Microsoft.Insights/diagnosticSettings" + }, + { + "apiVersion": "2017-05-01-preview", + "dependsOn": [ + "Microsoft.Storage/storageAccounts/regulalogstorage2", + "Microsoft.Storage/storageAccounts/regulastorage2" + ], + "name": "regulastorage2/default/Microsoft.Insights/setting2", + "properties": { + "logs": [ + { + "category": "StorageRead", + "enabled": true + }, + { + "category": "StorageWrite", + "enabled": true + }, + { + "category": "StorageDelete", + "enabled": true + } + ], + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', 'regulalogstorage2')]" + }, + "type": "Microsoft.Storage/storageAccounts/queueServices/providers/diagnosticSettings" + } + ] +} + diff --git a/rego/tests/rules/arm/storage/inputs/account_secure_transfer_infra.json b/rego/tests/rules/arm/storage/inputs/account_secure_transfer_infra.json new file mode 100644 index 00000000..cf70cd92 --- /dev/null +++ b/rego/tests/rules/arm/storage/inputs/account_secure_transfer_infra.json @@ -0,0 +1,68 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "valid", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": { + "supportsHttpsTrafficOnly": true + } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "invalid", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": { + "supportsHttpsTrafficOnly": false + } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "validdefault", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": {} + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2018-11-01", + "name": "validolder", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": { + "supportsHttpsTrafficOnly": true + } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2018-11-01", + "name": "invaliddefault", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": {} + } + ] +} diff --git a/rego/tests/rules/arm/storage/inputs/account_secure_transfer_infra_json.rego b/rego/tests/rules/arm/storage/inputs/account_secure_transfer_infra_json.rego new file mode 100644 index 00000000..95686a12 --- /dev/null +++ b/rego/tests/rules/arm/storage/inputs/account_secure_transfer_infra_json.rego @@ -0,0 +1,90 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.storage.inputs.account_secure_transfer_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-04-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "valid", + "properties": { + "supportsHttpsTrafficOnly": true + }, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2021-04-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "invalid", + "properties": { + "supportsHttpsTrafficOnly": false + }, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2021-04-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "validdefault", + "properties": {}, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2018-11-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "validolder", + "properties": { + "supportsHttpsTrafficOnly": true + }, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2018-11-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "invaliddefault", + "properties": {}, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + } + ] +} + diff --git a/rego/tests/rules/arm/storage/inputs/account_trusted_ms_services_infra.json b/rego/tests/rules/arm/storage/inputs/account_trusted_ms_services_infra.json new file mode 100644 index 00000000..222dc3a3 --- /dev/null +++ b/rego/tests/rules/arm/storage/inputs/account_trusted_ms_services_infra.json @@ -0,0 +1,86 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "valid", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": { + "networkAcls": { + "defaultAction": "Deny", + "bypass": "AzureServices" + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "validmulti", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": { + "networkAcls": { + "defaultAction": "Deny", + "bypass": "AzureServices,Logging" + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "validmulti2", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": { + "networkAcls": { + "defaultAction": "Deny", + "bypass": "Logging, AzureServices" + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "invalid", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": { + "networkAcls": { + "defaultAction": "Deny", + "bypass": "Logging" + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "invalidunset", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": { + "networkAcls": { + "defaultAction": "Deny" + } + } + } + ] +} diff --git a/rego/tests/rules/arm/storage/inputs/account_trusted_ms_services_infra_json.rego b/rego/tests/rules/arm/storage/inputs/account_trusted_ms_services_infra_json.rego new file mode 100644 index 00000000..42cd2b68 --- /dev/null +++ b/rego/tests/rules/arm/storage/inputs/account_trusted_ms_services_infra_json.rego @@ -0,0 +1,108 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.storage.inputs.account_trusted_ms_services_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-04-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "valid", + "properties": { + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "Deny" + } + }, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2021-04-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "validmulti", + "properties": { + "networkAcls": { + "bypass": "AzureServices,Logging", + "defaultAction": "Deny" + } + }, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2021-04-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "validmulti2", + "properties": { + "networkAcls": { + "bypass": "Logging, AzureServices", + "defaultAction": "Deny" + } + }, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2021-04-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "invalid", + "properties": { + "networkAcls": { + "bypass": "Logging", + "defaultAction": "Deny" + } + }, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + }, + { + "apiVersion": "2021-04-01", + "kind": "Storage", + "location": "[resourceGroup().location]", + "name": "invalidunset", + "properties": { + "networkAcls": { + "defaultAction": "Deny" + } + }, + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + } + ] +} + diff --git a/rego/tests/rules/arm/storage/inputs/disable_public_access_infra.json b/rego/tests/rules/arm/storage/inputs/disable_public_access_infra.json new file mode 100644 index 00000000..a778576a --- /dev/null +++ b/rego/tests/rules/arm/storage/inputs/disable_public_access_infra.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "name": "storage", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "StorageV2", + "properties": { + "accessTier": "Hot" + }, + "resources": [ + { + "type": "blobServices/containers", + "apiVersion": "2021-04-01", + "name": "default/valid", + "dependsOn": [ + "storage" + ], + "properties": { + "publicAccess": "None" + } + }, + { + "type": "blobServices/containers", + "apiVersion": "2021-04-01", + "name": "default/validUnset", + "dependsOn": [ + "storage" + ], + "properties": {} + }, + { + "type": "blobServices/containers", + "apiVersion": "2021-04-01", + "name": "default/invalid", + "dependsOn": [ + "storage" + ], + "properties": { + "publicAccess": "Blob" + } + } + ] + } + ] +} diff --git a/rego/tests/rules/arm/storage/inputs/disable_public_access_infra_json.rego b/rego/tests/rules/arm/storage/inputs/disable_public_access_infra_json.rego new file mode 100644 index 00000000..56e88119 --- /dev/null +++ b/rego/tests/rules/arm/storage/inputs/disable_public_access_infra_json.rego @@ -0,0 +1,75 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.storage.inputs.disable_public_access_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-04-01", + "kind": "StorageV2", + "location": "[resourceGroup().location]", + "name": "storage", + "properties": { + "accessTier": "Hot" + }, + "resources": [ + { + "apiVersion": "2021-04-01", + "dependsOn": [ + "storage" + ], + "name": "default/valid", + "properties": { + "publicAccess": "None" + }, + "type": "blobServices/containers" + }, + { + "apiVersion": "2021-04-01", + "dependsOn": [ + "storage" + ], + "name": "default/validUnset", + "properties": {}, + "type": "blobServices/containers" + }, + { + "apiVersion": "2021-04-01", + "dependsOn": [ + "storage" + ], + "name": "default/invalid", + "properties": { + "publicAccess": "Blob" + }, + "type": "blobServices/containers" + } + ], + "sku": { + "name": "Standard_LRS" + }, + "type": "Microsoft.Storage/storageAccounts" + } + ] +} + diff --git a/rego/tests/rules/arm/vm/data_disk_encryption_test.rego b/rego/tests/rules/arm/vm/data_disk_encryption_test.rego new file mode 100644 index 00000000..76f5ab08 --- /dev/null +++ b/rego/tests/rules/arm/vm/data_disk_encryption_test.rego @@ -0,0 +1,26 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_vm_data_disk_encryption + +import data.tests.rules.arm.vm.inputs.disk_encryption_infra_json as infra + +test_rule { + pol := policy with input as infra.mock_input + by_resource_id := {p.id: p.valid | pol[p]} + count(by_resource_id) == 3 + by_resource_id["Microsoft.Compute/disks/reguladisk2"] == true + by_resource_id["Microsoft.Compute/disks/reguladisk4"] == false + by_resource_id["Microsoft.Compute/virtualMachines/regulavm3"] == false +} diff --git a/rego/tests/rules/arm/vm/inputs/disk_encryption_infra.json b/rego/tests/rules/arm/vm/inputs/disk_encryption_infra.json new file mode 100644 index 00000000..8ba1b129 --- /dev/null +++ b/rego/tests/rules/arm/vm/inputs/disk_encryption_infra.json @@ -0,0 +1,422 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-06-01-preview", + "name": "regulavault3", + "location": "[resourceGroup().location]", + "properties": { + "enablePurgeProtection": true, + "enabledForDiskEncryption": true, + "accessPolicies": [ + { + "tenantId": "[subscription().tenantId]", + "objectId": "[subscription().subscriptionId]", + "permissions": { + "keys": [ + "Get", + "WrapKey", + "UnwrapKey" + ], + "secrets": [], + "certificates": [] + } + } + ], + "sku": { + "family": "A", + "name": "Standard" + }, + "tenantId": "[subscription().tenantId]" + }, + "resources": [ + { + "type": "keys", + "apiVersion": "2021-06-01-preview", + "name": "key1", + "properties": { + "kty": "RSA", + "keySize": 4096 + }, + "dependsOn": [ + "Microsoft.KeyVault/vaults/regulavault3" + ] + }, + { + "type": "secrets", + "apiVersion": "2021-06-01-preview", + "name": "secret1", + "properties": { + "value": "hunter2" + }, + "dependsOn": [ + "Microsoft.KeyVault/vaults/regulavault3" + ] + } + ] + }, + { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2021-06-01-preview", + "name": "regulavault3/add", + "properties": { + "accessPolicies": [ + { + "tenantId": "[subscription().tenantId]", + "objectId": "[reference(resourceId('Microsoft.Compute/diskEncryptionSets', 'regulades1'), '2021-04-01', 'Full').identity.PrincipalId]", + "permissions": { + "keys": [ + "Get", + "WrapKey", + "UnwrapKey" + ], + "secrets": [], + "certificates": [] + } + } + ] + }, + "dependsOn": [ + "Microsoft.Compute/diskEncryptionSets/regulades1", + "Microsoft.KeyVault/vaults/regulavault3" + ] + }, + { + "type": "Microsoft.Compute/diskEncryptionSets", + "apiVersion": "2021-04-01", + "name": "regulades1", + "location": "[resourceGroup().location]", + "properties": { + "activeKey": { + "keyUrl": "[reference(resourceId('Microsoft.KeyVault/vaults/keys', 'regulavault3', 'key1'), '2021-06-01-preview', 'Full').properties.keyUriWithVersion]", + "sourceVault": { + "id": "[resourceId('Microsoft.KeyVault/vaults', 'regulavault3')]" + } + } + }, + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "Microsoft.KeyVault/vaults/regulavault3/keys/key1" + ] + }, + { + "type": "Microsoft.Compute/disks", + "apiVersion": "2021-04-01", + "name": "reguladisk1", + "comments": "Encrypted inline, unattached", + "location": "[resourceGroup().location]", + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2, + "encryptionSettingsCollection": { + "enabled": true, + "encryptionSettings": [ + { + "diskEncryptionKey": { + "secretUrl": "[reference(resourceId('Microsoft.KeyVault/vaults/secrets', 'regulavault3', 'secret1'), '2021-06-01-preview', 'Full').properties.secretUriWithVersion]", + "sourceVault": { + "id": "[resourceId('Microsoft.KeyVault/vaults', 'regulavault3')]" + } + } + } + ] + } + }, + "dependsOn": [ + "Microsoft.KeyVault/vaults/regulavault3/secrets/secret1" + ] + }, + { + "type": "Microsoft.Compute/disks", + "apiVersion": "2021-04-01", + "name": "reguladisk2", + "comments": "Encrypted using DES, attached as data disk", + "location": "[resourceGroup().location]", + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2, + "encryption": { + "diskEncryptionSetId": "[resourceId('Microsoft.Compute/diskEncryptionSets', 'regulades1')]" + } + }, + "dependsOn": [ + "Microsoft.Compute/diskEncryptionSets/regulades1", + "Microsoft.KeyVault/vaults/regulavault3/accessPolicies/add" + ] + }, + { + "type": "Microsoft.Compute/disks", + "apiVersion": "2021-04-01", + "name": "reguladisk3", + "comments": "Unencrypted, attached as OS disk", + "location": "[resourceGroup().location]", + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2 + } + }, + { + "type": "Microsoft.Compute/disks", + "apiVersion": "2021-04-01", + "name": "reguladisk4", + "comments": "Unencrypted, attached as data disk", + "location": "[resourceGroup().location]", + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2 + } + }, + { + "type": "Microsoft.Compute/disks", + "apiVersion": "2021-04-01", + "name": "reguladisk5", + "comments": "Unencrypted, unattached", + "location": "[resourceGroup().location]", + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2 + } + }, + { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2018-10-01", + "name": "regulanet1", + "location": "switzerlandnorth", + "properties": { + "addressSpace": { + "addressPrefixes": [ + "10.0.0.0/16" + ] + }, + "subnets": [ + { + "name": "subnet1", + "properties": { + "addressPrefix": "10.0.0.0/24" + } + } + ] + } + }, + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2021-03-01", + "name": "regulanic1", + "location": "[resourceGroup().location]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "subnet": { + "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'regulanet1', 'subnet1')]" + }, + "privateIPAllocationMethod": "Dynamic" + } + } + ] + }, + "dependsOn": [ + "Microsoft.Network/virtualNetworks/regulanet1" + ] + }, + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2021-03-01", + "name": "regulanic2", + "location": "[resourceGroup().location]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "subnet": { + "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'regulanet1', 'subnet1')]" + }, + "privateIPAllocationMethod": "Dynamic" + } + } + ] + }, + "dependsOn": [ + "Microsoft.Network/virtualNetworks/regulanet1" + ] + }, + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2021-03-01", + "name": "regulanic3", + "location": "[resourceGroup().location]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "subnet": { + "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'regulanet1', 'subnet1')]" + }, + "privateIPAllocationMethod": "Dynamic" + } + } + ] + }, + "dependsOn": [ + "Microsoft.Network/virtualNetworks/regulanet1" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2021-07-01", + "name": "regulavm1", + "location": "[resourceGroup().location]", + "properties": { + "storageProfile": { + "dataDisks": [ + { + "createOption": "Attach", + "lun": 0, + "managedDisk": { + "id": "[resourceId('Microsoft.Compute/disks', 'reguladisk2')]", + "diskEncryptionSet": { + "id": "[resourceId('Microsoft.Compute/diskEncryptionSets', 'regulades1')]" + } + } + }, + { + "createOption": "Attach", + "lun": 1, + "managedDisk": { + "id": "[resourceId('Microsoft.Compute/disks', 'reguladisk4')]" + } + } + ], + "imageReference": { + "publisher": "canonical", + "offer": "0001-com-ubuntu-server-focal", + "sku": "20_04-lts-gen2", + "version": "latest" + } + }, + "osProfile": { + "computerName": "vm", + "adminUsername": "azureuser", + "adminPassword": "abcd1234!" + }, + "hardwareProfile": { + "vmSize": "Standard_B1s" + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', 'regulanic1')]", + "properties": { + "deleteOption": "Detach" + } + } + ] + } + }, + "dependsOn": [ + "Microsoft.Network/networkInterfaces/regulanic1", + "Microsoft.Compute/disks/reguladisk2", + "Microsoft.Compute/disks/reguladisk4", + "Microsoft.Compute/diskEncryptionSets/regulades1", + "Microsoft.KeyVault/vaults/regulavault3/accessPolicies/add" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2021-07-01", + "name": "regulavm2", + "location": "[resourceGroup().location]", + "properties": { + "storageProfile": { + "dataDisks": [], + "osDisk": { + "createOption": "Attach", + "osType": "Linux", + "managedDisk": { + "id": "[resourceId('Microsoft.Compute/disks', 'reguladisk3')]" + } + } + }, + "hardwareProfile": { + "vmSize": "Standard_B1s" + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', 'regulanic2')]", + "properties": { + "deleteOption": "Detach" + } + } + ] + } + }, + "dependsOn": [ + "Microsoft.Network/networkInterfaces/regulanic2", + "Microsoft.Compute/disks/reguladisk3" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2021-07-01", + "name": "regulavm3", + "location": "[resourceGroup().location]", + "properties": { + "storageProfile": { + "dataDisks": [ + { + "createOption": "Empty", + "diskSizeGB": 2, + "lun": 0 + } + ], + "imageReference": { + "publisher": "canonical", + "offer": "0001-com-ubuntu-server-focal", + "sku": "20_04-lts-gen2", + "version": "latest" + } + }, + "osProfile": { + "computerName": "vm", + "adminUsername": "azureuser", + "adminPassword": "abcd1234!" + }, + "hardwareProfile": { + "vmSize": "Standard_B1s" + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', 'regulanic3')]", + "properties": { + "deleteOption": "Detach" + } + } + ] + } + }, + "dependsOn": [ + "Microsoft.Network/networkInterfaces/regulanic3" + ] + } + ] +} diff --git a/rego/tests/rules/arm/vm/inputs/disk_encryption_infra_json.rego b/rego/tests/rules/arm/vm/inputs/disk_encryption_infra_json.rego new file mode 100644 index 00000000..5e8aee01 --- /dev/null +++ b/rego/tests/rules/arm/vm/inputs/disk_encryption_infra_json.rego @@ -0,0 +1,444 @@ +# Copyright 2020-2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package tests.rules.arm.vm.inputs.disk_encryption_infra_json + +import data.fugue.resource_view.resource_view_input + +mock_input := ret { + ret = resource_view_input with input as mock_config +} +mock_resources := mock_input.resources +mock_config := { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "apiVersion": "2021-06-01-preview", + "location": "[resourceGroup().location]", + "name": "regulavault3", + "properties": { + "accessPolicies": [ + { + "objectId": "[subscription().subscriptionId]", + "permissions": { + "certificates": [], + "keys": [ + "Get", + "WrapKey", + "UnwrapKey" + ], + "secrets": [] + }, + "tenantId": "[subscription().tenantId]" + } + ], + "enablePurgeProtection": true, + "enabledForDiskEncryption": true, + "sku": { + "family": "A", + "name": "Standard" + }, + "tenantId": "[subscription().tenantId]" + }, + "resources": [ + { + "apiVersion": "2021-06-01-preview", + "dependsOn": [ + "Microsoft.KeyVault/vaults/regulavault3" + ], + "name": "key1", + "properties": { + "keySize": 4096, + "kty": "RSA" + }, + "type": "keys" + }, + { + "apiVersion": "2021-06-01-preview", + "dependsOn": [ + "Microsoft.KeyVault/vaults/regulavault3" + ], + "name": "secret1", + "properties": { + "value": "hunter2" + }, + "type": "secrets" + } + ], + "type": "Microsoft.KeyVault/vaults" + }, + { + "apiVersion": "2021-06-01-preview", + "dependsOn": [ + "Microsoft.Compute/diskEncryptionSets/regulades1", + "Microsoft.KeyVault/vaults/regulavault3" + ], + "name": "regulavault3/add", + "properties": { + "accessPolicies": [ + { + "objectId": "[reference(resourceId('Microsoft.Compute/diskEncryptionSets', 'regulades1'), '2021-04-01', 'Full').identity.PrincipalId]", + "permissions": { + "certificates": [], + "keys": [ + "Get", + "WrapKey", + "UnwrapKey" + ], + "secrets": [] + }, + "tenantId": "[subscription().tenantId]" + } + ] + }, + "type": "Microsoft.KeyVault/vaults/accessPolicies" + }, + { + "apiVersion": "2021-04-01", + "dependsOn": [ + "Microsoft.KeyVault/vaults/regulavault3/keys/key1" + ], + "identity": { + "type": "SystemAssigned" + }, + "location": "[resourceGroup().location]", + "name": "regulades1", + "properties": { + "activeKey": { + "keyUrl": "[reference(resourceId('Microsoft.KeyVault/vaults/keys', 'regulavault3', 'key1'), '2021-06-01-preview', 'Full').properties.keyUriWithVersion]", + "sourceVault": { + "id": "[resourceId('Microsoft.KeyVault/vaults', 'regulavault3')]" + } + } + }, + "type": "Microsoft.Compute/diskEncryptionSets" + }, + { + "apiVersion": "2021-04-01", + "comments": "Encrypted inline, unattached", + "dependsOn": [ + "Microsoft.KeyVault/vaults/regulavault3/secrets/secret1" + ], + "location": "[resourceGroup().location]", + "name": "reguladisk1", + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2, + "encryptionSettingsCollection": { + "enabled": true, + "encryptionSettings": [ + { + "diskEncryptionKey": { + "secretUrl": "[reference(resourceId('Microsoft.KeyVault/vaults/secrets', 'regulavault3', 'secret1'), '2021-06-01-preview', 'Full').properties.secretUriWithVersion]", + "sourceVault": { + "id": "[resourceId('Microsoft.KeyVault/vaults', 'regulavault3')]" + } + } + } + ] + } + }, + "type": "Microsoft.Compute/disks" + }, + { + "apiVersion": "2021-04-01", + "comments": "Encrypted using DES, attached as data disk", + "dependsOn": [ + "Microsoft.Compute/diskEncryptionSets/regulades1", + "Microsoft.KeyVault/vaults/regulavault3/accessPolicies/add" + ], + "location": "[resourceGroup().location]", + "name": "reguladisk2", + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2, + "encryption": { + "diskEncryptionSetId": "[resourceId('Microsoft.Compute/diskEncryptionSets', 'regulades1')]" + } + }, + "type": "Microsoft.Compute/disks" + }, + { + "apiVersion": "2021-04-01", + "comments": "Unencrypted, attached as OS disk", + "location": "[resourceGroup().location]", + "name": "reguladisk3", + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2 + }, + "type": "Microsoft.Compute/disks" + }, + { + "apiVersion": "2021-04-01", + "comments": "Unencrypted, attached as data disk", + "location": "[resourceGroup().location]", + "name": "reguladisk4", + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2 + }, + "type": "Microsoft.Compute/disks" + }, + { + "apiVersion": "2021-04-01", + "comments": "Unencrypted, unattached", + "location": "[resourceGroup().location]", + "name": "reguladisk5", + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2 + }, + "type": "Microsoft.Compute/disks" + }, + { + "apiVersion": "2018-10-01", + "location": "switzerlandnorth", + "name": "regulanet1", + "properties": { + "addressSpace": { + "addressPrefixes": [ + "10.0.0.0/16" + ] + }, + "subnets": [ + { + "name": "subnet1", + "properties": { + "addressPrefix": "10.0.0.0/24" + } + } + ] + }, + "type": "Microsoft.Network/virtualNetworks" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "Microsoft.Network/virtualNetworks/regulanet1" + ], + "location": "[resourceGroup().location]", + "name": "regulanic1", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'regulanet1', 'subnet1')]" + } + } + } + ] + }, + "type": "Microsoft.Network/networkInterfaces" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "Microsoft.Network/virtualNetworks/regulanet1" + ], + "location": "[resourceGroup().location]", + "name": "regulanic2", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'regulanet1', 'subnet1')]" + } + } + } + ] + }, + "type": "Microsoft.Network/networkInterfaces" + }, + { + "apiVersion": "2021-03-01", + "dependsOn": [ + "Microsoft.Network/virtualNetworks/regulanet1" + ], + "location": "[resourceGroup().location]", + "name": "regulanic3", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'regulanet1', 'subnet1')]" + } + } + } + ] + }, + "type": "Microsoft.Network/networkInterfaces" + }, + { + "apiVersion": "2021-07-01", + "dependsOn": [ + "Microsoft.Network/networkInterfaces/regulanic1", + "Microsoft.Compute/disks/reguladisk2", + "Microsoft.Compute/disks/reguladisk4", + "Microsoft.Compute/diskEncryptionSets/regulades1", + "Microsoft.KeyVault/vaults/regulavault3/accessPolicies/add" + ], + "location": "[resourceGroup().location]", + "name": "regulavm1", + "properties": { + "hardwareProfile": { + "vmSize": "Standard_B1s" + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', 'regulanic1')]", + "properties": { + "deleteOption": "Detach" + } + } + ] + }, + "osProfile": { + "adminPassword": "abcd1234!", + "adminUsername": "azureuser", + "computerName": "vm" + }, + "storageProfile": { + "dataDisks": [ + { + "createOption": "Attach", + "lun": 0, + "managedDisk": { + "diskEncryptionSet": { + "id": "[resourceId('Microsoft.Compute/diskEncryptionSets', 'regulades1')]" + }, + "id": "[resourceId('Microsoft.Compute/disks', 'reguladisk2')]" + } + }, + { + "createOption": "Attach", + "lun": 1, + "managedDisk": { + "id": "[resourceId('Microsoft.Compute/disks', 'reguladisk4')]" + } + } + ], + "imageReference": { + "offer": "0001-com-ubuntu-server-focal", + "publisher": "canonical", + "sku": "20_04-lts-gen2", + "version": "latest" + } + } + }, + "type": "Microsoft.Compute/virtualMachines" + }, + { + "apiVersion": "2021-07-01", + "dependsOn": [ + "Microsoft.Network/networkInterfaces/regulanic2", + "Microsoft.Compute/disks/reguladisk3" + ], + "location": "[resourceGroup().location]", + "name": "regulavm2", + "properties": { + "hardwareProfile": { + "vmSize": "Standard_B1s" + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', 'regulanic2')]", + "properties": { + "deleteOption": "Detach" + } + } + ] + }, + "storageProfile": { + "dataDisks": [], + "osDisk": { + "createOption": "Attach", + "managedDisk": { + "id": "[resourceId('Microsoft.Compute/disks', 'reguladisk3')]" + }, + "osType": "Linux" + } + } + }, + "type": "Microsoft.Compute/virtualMachines" + }, + { + "apiVersion": "2021-07-01", + "dependsOn": [ + "Microsoft.Network/networkInterfaces/regulanic3" + ], + "location": "[resourceGroup().location]", + "name": "regulavm3", + "properties": { + "hardwareProfile": { + "vmSize": "Standard_B1s" + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', 'regulanic3')]", + "properties": { + "deleteOption": "Detach" + } + } + ] + }, + "osProfile": { + "adminPassword": "abcd1234!", + "adminUsername": "azureuser", + "computerName": "vm" + }, + "storageProfile": { + "dataDisks": [ + { + "createOption": "Empty", + "diskSizeGB": 2, + "lun": 0 + } + ], + "imageReference": { + "offer": "0001-com-ubuntu-server-focal", + "publisher": "canonical", + "sku": "20_04-lts-gen2", + "version": "latest" + } + } + }, + "type": "Microsoft.Compute/virtualMachines" + } + ] +} + diff --git a/rego/tests/rules/arm/vm/unattached_disk_encryption_test.rego b/rego/tests/rules/arm/vm/unattached_disk_encryption_test.rego new file mode 100644 index 00000000..b9c77692 --- /dev/null +++ b/rego/tests/rules/arm/vm/unattached_disk_encryption_test.rego @@ -0,0 +1,25 @@ +# Copyright 2021 Fugue, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package rules.arm_vm_unattached_disk_encryption + +import data.tests.rules.arm.vm.inputs.disk_encryption_infra_json as infra + +test_rule { + pol := policy with input as infra.mock_input + by_resource_id := {p.id: p.valid | pol[p]} + count(by_resource_id) == 2 + by_resource_id["Microsoft.Compute/disks/reguladisk1"] == true + by_resource_id["Microsoft.Compute/disks/reguladisk5"] == false +}