Skip to main content

Insecure Access Control

Fixing Insecure Access Control

About Insecure Access Control

What is improper access control?

Improper access control is a vulnerability that occurs when a system does not properly restrict or enforce access to resources, such as files, directories, network resources, or application functions.

Examples of improper access control vulnerabilities include:

  • Weak access controls: When access controls are weak or easily bypassed, attackers can gain access to sensitive resources or data by exploiting security weaknesses.
  • Insufficient authorization checks: When authorization checks are insufficient, it can allow unauthorized users to access sensitive data or resources, or to perform actions that they are not authorized to do.
  • Overly permissive access: When access controls are overly permissive, they can allow users to access resources or data that they do not need, increasing the risk of data breaches or other security incidents.

Check out these videos for a high-level explanation:

  • Missing function level access control

  • Missing object level access control

What is the impact of improper access control?

Improper access control can lead to various security threats, such as:

  • Data breaches: Improper access control can allow attackers to access sensitive data, leading to data breaches, data loss, or unauthorized access to confidential information.
  • Unauthorized access to resources: Attackers can exploit improper access control to gain unauthorized access to resources, such as servers, databases, and applications.
  • Account takeover: Attackers can use improper access control to take over user accounts and gain access to sensitive data or resources.

How to prevent improper access control?

Here are some measures that can help ensure proper access control:

  • Strong access controls: Implement strong access controls that restrict access to sensitive resources or data based on user roles and permissions.
  • Proper user authentication and authorization: Implement proper user authentication and authorization mechanisms to ensure that only authorized users can access sensitive data and resources.
  • Input validation and sanitization: Validate and sanitize user input before using it to access internal objects or data. Use regular expressions or input filters to remove or encode any special characters that could be used to access sensitive data or resources.
  • Least privilege: Use the principle of least privilege to restrict access to resources to only what is necessary for each user role. This can help prevent attackers from gaining access to resources that they do not need to access.
  • Regular security audits: Regularly audit your system for security vulnerabilities, including improper access control vulnerabilities. Use automated tools and manual testing to identify potential issues and fix them before they can be exploited.

References

Taxonomies

Explanation & Prevention

Training

In the context of Terraform, this vulnerability class identifies resources/roles with too many permissions.

Lambda Function With Privileged role

AWS Lambda Functions shouldn't have privileged permissions.

Rule-specific references:

Option A: Make sure that privileged permissions do not exist for Lambda Functions

  • aws_lambda_function.role should not have any privileged permissions through attached inline policy
  • aws_lambda_function.role should not have any privileged permissions through attached managed policy
  • aws_lambda_function.role should not have any privileged permissions
  1. Locate the following vulnerable patterns:

    resource "aws_lambda_function" "positivefunction1" {
    filename = "lambda_function_payload.zip"
    function_name = "lambda_function_name"
    role = aws_iam_role.positiverole1.arn
    handler = "exports.test"
    source_code_hash = filebase64sha256("lambda_function_payload.zip")
    runtime = "nodejs12.x"

    tags = {
    Name = "lambda"
    }

    environment = {
    variables = {
    foo = "bar"
    }
    }
    }

    resource "aws_lambda_function" "positivefunction2" {
    filename = "lambda_function_payload.zip"
    function_name = "lambda_function_name"
    role = aws_iam_role.positiverole2.arn
    handler = "exports.test"
    source_code_hash = filebase64sha256("lambda_function_payload.zip")
    runtime = "nodejs12.x"

    tags = {
    Name = "lambda"
    }

    environment = {
    variables = {
    foo = "bar"
    }
    }
    }

    resource "aws_iam_role" "positiverole1" {
    name = "positiverole1"

    assume_role_policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": ["some:action"],
    "Principal": {
    "Service": "lambda.amazonaws.com"
    },
    "Effect": "Allow",
    "Resource": "*",
    "Sid": ""
    }
    ]
    }
    EOF
    tags = {
    tag-key = "tag-value"
    }
    }

    resource "aws_iam_role" "positiverole2" {
    name = "positiverole2"

    assume_role_policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": ["some:action"],
    "Principal": {
    "Service": "lambda.amazonaws.com"
    },
    "Effect": "Allow",
    "Resource": "*",
    "Sid": ""
    }
    ]
    }
    EOF
    tags = {
    tag-key = "tag-value"
    }
    }

    resource "aws_iam_role_policy" "positiveinlinepolicy1" {
    name = "positiveinlinepolicy1"
    role = aws_iam_role.positiverole1.id

    # Terraform's "jsonencode" function converts a
    # Terraform expression result to valid JSON syntax.
    policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
    {
    Action = [
    "ec2:Describe*",
    "iam:*"
    ]
    Effect = "Allow"
    Resource = "*"
    },
    ]
    })
    }

    resource "aws_iam_policy" "positivecustomermanagedpolicy1" {
    name = "positivecustomermanagedpolicy1"

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": [
    "ec2:Describe*",
    "sts:AssumeRole"
    ],
    "Effect": "Allow",
    "Resource": "*"
    }
    ]
    }
    EOF
    }

    resource "aws_iam_policy" "positivecustomermanagedpolicy2" {
    name = "positivecustomermanagedpolicy2"

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": [
    "ec2:Describe*",
    "sts:AssumeRole"
    ],
    "Effect": "Allow",
    "Resource": "*"
    }
    ]
    }
    EOF
    }

    # Mapping of customer managed policy defined in this template set
    resource "aws_iam_role_policy_attachment" "positiverolepolicyattachment1" {
    role = aws_iam_role.positiverole1.name
    policy_arn = aws_iam_policy.positivecustomermanagedpolicy1.arn
    }

    resource "aws_iam_policy_attachment" "positivedirectpolicyattachment1" {
    roles = [aws_iam_role.positiverole1.name]
    policy_arn = aws_iam_policy.positivecustomermanagedpolicy2.arn
    }

    # Mapping of pre-existing policy arns
    resource "aws_iam_role_policy_attachment" "positiverolepolicyattachment2" {
    role = aws_iam_role.positiverole2.name
    policy_arn = "arn:aws:iam::policy/positivepreexistingpolicyarn1"
    }

    resource "aws_iam_policy_attachment" "positivedirectpolicyattachment2" {
    roles = [aws_iam_role.positiverole2.name]
    policy_arn = "arn:aws:iam::policy/AmazonPersonalizeFullAccess"
    }
  2. Modify the config to something like the following:

    resource "aws_lambda_function" "negativefunction1" {
    filename = "lambda_function_payload.zip"
    function_name = "lambda_function_name"
    role = aws_iam_role.negativerole1.arn
    handler = "exports.test"
    source_code_hash = filebase64sha256("lambda_function_payload.zip")
    runtime = "nodejs12.x"

    tags = {
    Name = "lambda"
    }

    environment = {
    variables = {
    foo = "bar"
    }
    }
    }

    resource "aws_lambda_function" "negativefunction2" {
    filename = "lambda_function_payload.zip"
    function_name = "lambda_function_name"
    role = aws_iam_role.negativerole2.arn
    handler = "exports.test"
    source_code_hash = filebase64sha256("lambda_function_payload.zip")
    runtime = "nodejs12.x"

    tags = {
    Name = "lambda"
    }

    environment = {
    variables = {
    foo = "bar"
    }
    }
    }

    resource "aws_iam_role" "negativerole1" {
    name = "negativerole1"

    assume_role_policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": ["some:action"],
    "Principal": {
    "Service": "lambda.amazonaws.com"
    },
    "Effect": "Allow",
    "Resource": "*",
    "Sid": ""
    }
    ]
    }
    EOF
    tags = {
    tag-key = "tag-value"
    }
    }

    resource "aws_iam_role" "negativerole2" {
    name = "negativerole2"

    assume_role_policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": ["some:action"],
    "Principal": {
    "Service": "lambda.amazonaws.com"
    },
    "Effect": "Allow",
    "Resource": "*",
    "Sid": ""
    }
    ]
    }
    EOF
    tags = {
    tag-key = "tag-value"
    }
    }

    resource "aws_iam_role_policy" "negativeinlinepolicy1" {
    name = "negativeinlinepolicy1"
    role = aws_iam_role.negativerole1.id

    # Terraform's "jsonencode" function converts a
    # Terraform expression result to valid JSON syntax.
    policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
    {
    Action = [
    "ec2:Describe*",
    "s3:GetObject"
    ]
    Effect = "Allow"
    Resource = "*"
    },
    ]
    })
    }

    resource "aws_iam_policy" "negativecustomermanagedpolicy1" {
    name = "negativecustomermanagedpolicy1"

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": [
    "ec2:Describe*"
    ],
    "Effect": "Allow",
    "Resource": "*"
    }
    ]
    }
    EOF
    }

    resource "aws_iam_policy" "negativecustomermanagedpolicy2" {
    name = "negativecustomermanagedpolicy2"

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": [
    "lambda:CreateFunction"
    ],
    "Effect": "Allow",
    "Resource": "*"
    }
    ]
    }
    EOF
    }

    # Mapping of customer managed policy defined in this template set
    resource "aws_iam_role_policy_attachment" "negativerolepolicyattachment1" {
    role = aws_iam_role.negativerole1.name
    policy_arn = aws_iam_policy.negativecustomermanagedpolicy1.arn
    }

    resource "aws_iam_policy_attachment" "negativedirectpolicyattachment1" {
    roles = [aws_iam_role.negativerole1.name]
    policy_arn = aws_iam_policy.negativecustomermanagedpolicy2.arn
    }

    # Mapping of pre-existing policy arns
    resource "aws_iam_role_policy_attachment" "negativerolepolicyattachment2" {
    role = aws_iam_role.negativerole2.name
    policy_arn = "arn:aws:iam::policy/negativepreexistingpolicyarn1"
    }

    resource "aws_iam_policy_attachment" "negativedirectpolicyattachment2" {
    roles = [aws_iam_role.negativerole2.name]
    policy_arn = "arn:aws:iam::policy/DenyAll"
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Legacy ABAC permissions

Option A: Enable RBAC

  1. Go through the issues that GuardRails identified
  2. Locate either the enable_legacy_abac argument in the google_container_cluster resource
  3. Set enable_legacy_abac to false, or remove the argument entirely

PSP With Added Capabilities

Kubernetes Pod Security Policy should not have added capabilities.

Rule-specific references:

Option A: Allowed Capabilities should not be included

resource kubernetes_pod_security_policy spec should not have the optional allowed_capabilities list.

  1. Locate the following vulnerable pattern:

    resource "kubernetes_pod_security_policy" "example" {
    metadata {
    name = "terraform-example"
    }
    spec {
    allowed_capabilities = ["NET_BIND_SERVICE"]
    privileged = false
    allow_privilege_escalation = false

    volumes = [
    "configMap",
    "emptyDir",
    "projected",
    "secret",
    "downwardAPI",
    "persistentVolumeClaim",
    ]

    run_as_user {
    rule = "MustRunAsNonRoot"
    }

    se_linux {
    rule = "RunAsAny"
    }

    supplemental_groups {
    rule = "MustRunAs"
    range {
    min = 1
    max = 65535
    }
    }

    fs_group {
    rule = "MustRunAs"
    range {
    min = 1
    max = 65535
    }
    }

    read_only_root_filesystem = true
    }
    }
  2. Modify the config to something like the following:

    resource "kubernetes_pod_security_policy" "example2" {
    metadata {
    name = "terraform-example"
    }
    spec {
    privileged = false
    allow_privilege_escalation = false

    volumes = [
    "configMap",
    "emptyDir",
    "projected",
    "secret",
    "downwardAPI",
    "persistentVolumeClaim",
    ]

    run_as_user {
    rule = "MustRunAsNonRoot"
    }

    se_linux {
    rule = "RunAsAny"
    }

    supplemental_groups {
    rule = "MustRunAs"
    range {
    min = 1
    max = 65535
    }
    }

    fs_group {
    rule = "MustRunAs"
    range {
    min = 1
    max = 65535
    }
    }

    read_only_root_filesystem = true
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Service Account with Improper Privileges

Service accounts should not have improper privileges like admin, editor, owner, or write roles.

This rule is violated if any of the following conditions are true:

  • google_iam_policy binding.role should not have admin, editor, owner, or write privileges for "serviceAccount" member
  • google_project_iam_binding role does not have admin, editor, owner, or write privileges for "serviceAccount" member
  • google_project_iam_member role does not have admin, editor, owner, or write privileges for "serviceAccount" member

Rule-specific references:

Option A: Make sure none of the above conditions are true

From the following vulnerable patterns, replace them with the matching non-vulnerable pattern.

  1. Locate one of the following vulnerable patterns:

    Vulnerable google_iam_policy pattern:

    data "google_iam_policy" "admin" {
    binding {
    role = "roles/editor"

    members = [
    "serviceAccount:[email protected]",
    ]
    }
    }

    Vulnerable google_project_iam_binding pattern:

    resource "google_project_iam_binding" "project1" {
    project = "your-project-id"
    role = "roles/container.admin"

    members = [
    "serviceAccount:[email protected]",
    ]

    condition {
    title = "expires_after_2019_12_31"
    description = "Expiring at midnight of 2019-12-31"
    expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")"
    }
    }

    Vulnerable google_project_iam_member pattern:

    resource "google_project_iam_member" "project2" {
    project = "your-project-id"
    role = "roles/editor"
    member = "serviceAccount:[email protected]"
    }
  2. Modify the config to one of the following non-vulnerable patterns:

    Replacement google_iam_policy pattern:

    data "google_iam_policy" "policy5" {
    binding {
    role = "roles/apigee.runtimeAgent"

    members = [
    "user:[email protected]",
    ]
    }
    }

    Replacement google_project_iam_binding pattern:

    resource "google_project_iam_binding" "project3" {
    project = "your-project-id"
    role = "roles/apigee.runtimeAgent"

    members = [
    "user:[email protected]",
    ]

    condition {
    title = "expires_after_2019_12_31"
    description = "Expiring at midnight of 2019-12-31"
    expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")"
    }
    }

    Replacement google_project_iam_member pattern:

    resource "google_project_iam_member" "project4" {
    project = "your-project-id"
    role = "roles/apigee.runtimeAgent"
    member = "user:[email protected]"
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

AWS ECS Task Definition (aws_ecs_task_definition) Network_Mode (network_mode) should be "awsvpc" for all Task Definitions. AWS VPCs provide the controls to facilitate a formal process for approving and testing all network connections and changes to the firewall and router configurations.

Rule-specific references:

Option A: Consider changing the Network Mode to AWS VPC

If the aws_ecs_task_definition.network_mode value is not already set to "awsvpc" then consider changing it to the superior mode. AWS VPC Network Mode can simplify many things and add a lot of security.

  1. Locate the following vulnerable pattern:

    resource "aws_ecs_task_definition" "positive1" {
    family = "service"
    network_mode = "none"

    volume {
    name = "service-storage"
    host_path = "/ecs/service-storage"
    }

    placement_constraints {
    type = "memberOf"
    expression = "attribute:ecs.availability-zone in [us-west-2a, us-west-2b]"
    }
    }
  2. Modify the config to something like the following:

    resource "aws_ecs_task_definition" "negative1" {
    family = "service"
    network_mode = "awsvpc"

    volume {
    name = "service-storage"
    host_path = "/ecs/service-storage"
    }

    placement_constraints {
    type = "memberOf"
    expression = "attribute:ecs.availability-zone in [us-west-2a, us-west-2b]"
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

EKS node group remote access disabled

EKS node group remote access is disabled when Source Security Groups are missing.

Rule-specific references:

Option A: AWS EKS node group remote access source security groups ids should be defined and not null

resource aws_eks_node_group remote_access.source_security_groups_ids should be defined and not null.

  1. Locate the following vulnerable pattern:

    resource "aws_eks_node_group" "positive" {
    cluster_name = aws_eks_cluster.example.name
    node_group_name = "example"
    node_role_arn = aws_iam_role.example.arn
    subnet_ids = aws_subnet.example[*].id

    scaling_config {
    desired_size = 1
    max_size = 1
    min_size = 1
    }

    remote_access {
    ec2_ssh_key = "my-rsa-key"
    }

    # Ensure that IAM Role permissions are created before and deleted after EKS Node Group handling.
    # Otherwise, EKS will not be able to properly delete EC2 Instances and Elastic Network Interfaces.
    depends_on = [
    aws_iam_role_policy_attachment.example-AmazonEKSWorkerNodePolicy,
    aws_iam_role_policy_attachment.example-AmazonEKS_CNI_Policy,
    aws_iam_role_policy_attachment.example-AmazonEC2ContainerRegistryReadOnly,
    ]
    }
  2. Modify the config to something like the following:

    resource "aws_eks_node_group" "negative" {
    cluster_name = aws_eks_cluster.example.name
    node_group_name = "example"
    node_role_arn = aws_iam_role.example.arn
    subnet_ids = aws_subnet.example[*].id

    scaling_config {
    desired_size = 1
    max_size = 1
    min_size = 1
    }

    remote_access {
    ec2_ssh_key = "my-rsa-key"
    source_security_groups_ids = "sg-213120ASNE"
    }

    # Ensure that IAM Role permissions are created before and deleted after EKS Node Group handling.
    # Otherwise, EKS will not be able to properly delete EC2 Instances and Elastic Network Interfaces.
    depends_on = [
    aws_iam_role_policy_attachment.example-AmazonEKSWorkerNodePolicy,
    aws_iam_role_policy_attachment.example-AmazonEKS_CNI_Policy,
    aws_iam_role_policy_attachment.example-AmazonEC2ContainerRegistryReadOnly,
    ]
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Container Runs Unmasked

Check if a container has full access (unmasked) to the host’s /proc command, which would allow to retrieve sensitive information and possibly change the kernel parameters in runtime.

Rule-specific references:

Option A: Make sure that Allowed Proc Mount Types contains the value "Default"

If resource kubernetes_pod_security_policy.spec.allowed_proc_mount_types contains the value "Unmasked", change it to "Default".

  1. Locate the following vulnerable pattern:

    resource "kubernetes_pod_security_policy" "example" {
    metadata {
    name = "terraform-example"
    }
    spec {
    privileged = false
    allow_privilege_escalation = false
    allowed_proc_mount_types = ["Unmasked"]

    volumes = [
    "configMap",
    "emptyDir",
    "projected",
    "secret",
    "downwardAPI",
    "persistentVolumeClaim",
    ]

    run_as_user {
    rule = "MustRunAsNonRoot"
    }

    se_linux {
    rule = "RunAsAny"
    }

    supplemental_groups {
    rule = "MustRunAs"
    range {
    min = 1
    max = 65535
    }
    }

    fs_group {
    rule = "MustRunAs"
    range {
    min = 1
    max = 65535
    }
    }

    read_only_root_filesystem = true
    }
    }
  2. Modify the config to something like the following:

    resource "kubernetes_pod_security_policy" "example" {
    metadata {
    name = "terraform-example"
    }
    spec {
    privileged = false
    allow_privilege_escalation = false
    allowed_proc_mount_types = ["Default"]

    volumes = [
    "configMap",
    "emptyDir",
    "projected",
    "secret",
    "downwardAPI",
    "persistentVolumeClaim",
    ]

    run_as_user {
    rule = "MustRunAsNonRoot"
    }

    se_linux {
    rule = "RunAsAny"
    }

    supplemental_groups {
    rule = "MustRunAs"
    range {
    min = 1
    max = 65535
    }
    }

    fs_group {
    rule = "MustRunAs"
    range {
    min = 1
    max = 65535
    }
    }

    read_only_root_filesystem = true
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Containers With Added Capabilities

Kubernetes Pod should not have extra capabilities allowed.

Rule-specific references:

Option A: Security Context Capabilities Add should not be defined

Remove any security_context.capabilities.add values from resource kubernetes_pod.spec.

  1. Locate the following vulnerable pattern:

    resource "kubernetes_pod" "positive" {
    metadata {
    name = "terraform-example"
    }

    spec {
    container {
    image = "nginx:1.7.9"
    name = "example"

    security_context {
    capabilities {
    add = ["NET_BIND_SERVICE"]
    }
    }

    env {
    name = "environment"
    value = "test"
    }

    port {
    container_port = 8080
    }

    liveness_probe {
    http_get {
    path = "/nginx_status"
    port = 80

    http_header {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }

    initial_delay_seconds = 3
    period_seconds = 3
    }
    }
    dns_config {
    nameservers = ["1.1.1.1", "8.8.8.8", "9.9.9.9"]
    searches = ["example.com"]

    option {
    name = "ndots"
    value = 1
    }

    option {
    name = "use-vc"
    }
    }

    dns_policy = "None"
    }
    }
  2. Modify the config to something like the following:

    resource "kubernetes_pod" "negative" {
    metadata {
    name = "terraform-example"
    }

    spec {
    container {
    image = "nginx:1.7.9"
    name = "example"

    env {
    name = "environment"
    value = "test"
    }

    port {
    container_port = 8080
    }

    liveness_probe {
    http_get {
    path = "/nginx_status"
    port = 80

    http_header {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }

    initial_delay_seconds = 3
    period_seconds = 3
    }
    }

    dns_config {
    nameservers = ["1.1.1.1", "8.8.8.8", "9.9.9.9"]
    searches = ["example.com"]

    option {
    name = "ndots"
    value = 1
    }

    option {
    name = "use-vc"
    }
    }

    dns_policy = "None"
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

VM With Full Cloud Access

A Google VM instance is configured to use the default service account with full access to all Cloud APIs.

Rule-specific references:

Option A: Remove Cloud Platform from Service Account Scopes for Google Cloud Platform (GCP) VMs

service_accounts.scopes should not contain cloud-platform.

  1. Locate the following vulnerable pattern:

    resource "google_compute_instance" "positive1" {
    name = "test"
    machine_type = "e2-medium"
    zone = "us-central1-a"

    boot_disk {
    initialize_params {
    image = "debian-cloud/debian-9"
    }
    }

    network_interface {
    network = "default"
    access_config {
    // Ephemeral IP
    }
    }

    service_account {
    scopes = ["userinfo-email", "compute-ro", "storage-ro", "cloud-platform"]
    }
    }
  2. Modify the config to something like the following:

    resource "google_compute_instance" "negative1" {
    name = "test"
    machine_type = "e2-medium"
    zone = "us-central1-a"

    boot_disk {
    initialize_params {
    image = "debian-cloud/debian-9"
    }
    }

    network_interface {
    network = "default"
    access_config {
    // Ephemeral IP
    }
    }

    service_account {
    scopes = ["userinfo-email", "compute-ro", "storage-ro"]
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Unlimited Capabilities For Pod Security Policy

Limit capabilities for a Pod Security Policy.

Rule-specific references:

Option A: Limit the capabilities available to Kubernetes Pods

Provide a list of required_drop_capabilities to the spec of kubernetes_pod_security_policy.

  1. Locate the following vulnerable pattern:

    resource "kubernetes_pod_security_policy" "example" {
    metadata {
    name = "terraform-example"
    }
    spec {
    privileged = false
    allow_privilege_escalation = false

    volumes = [
    "configMap",
    "emptyDir",
    "projected",
    "secret",
    "downwardAPI",
    "persistentVolumeClaim",
    ]

    run_as_user {
    rule = "MustRunAsNonRoot"
    }

    se_linux {
    rule = "RunAsAny"
    }

    supplemental_groups {
    rule = "MustRunAs"
    range {
    min = 1
    max = 65535
    }
    }

    fs_group {
    rule = "MustRunAs"
    range {
    min = 1
    max = 65535
    }
    }

    read_only_root_filesystem = true
    }
    }
  2. Modify the config to something like the following:

    resource "kubernetes_pod_security_policy" "example2" {
    metadata {
    name = "terraform-example"
    }
    spec {
    privileged = false
    allow_privilege_escalation = false
    required_drop_capabilities = ["ALL"]

    volumes = [
    "configMap",
    "emptyDir",
    "projected",
    "secret",
    "downwardAPI",
    "persistentVolumeClaim",
    ]

    run_as_user {
    rule = "MustRunAsNonRoot"
    }

    se_linux {
    rule = "RunAsAny"
    }

    supplemental_groups {
    rule = "MustRunAs"
    range {
    min = 1
    max = 65535
    }
    }

    fs_group {
    rule = "MustRunAs"
    range {
    min = 1
    max = 65535
    }
    }

    read_only_root_filesystem = true
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket With All Permissions

S3 Buckets must not have all permissions, as to prevent leaking private information to the entire internet or allow unauthorized data tampering/deletion.

Rule-specific references:

Option A: Remove the Action All from a Policy Statement Where Effect is Allow

Where the Effect is "Allow" the Action should not be or contain All ("*").

  1. Remove or replace any S3 bucket policy.Statement.Action specifying all ('*') where effect is "Allow"

  2. Locate one of the following vulnerable patterns:

    Vulnerable pattern via resource:

    resource "aws_s3_bucket" "positive1" {
    bucket = "S3B_181355"
    acl = "private"

    policy = <<EOF
    {
    "Id": "id113",
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": [
    "s3:*"
    ],
    "Effect": "Allow",
    "Resource": "arn:aws:s3:::S3B_181355/*",
    "Principal": "*"
    }
    ]
    }
    EOF
    }

    Vulnerable pattern via module:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }

    policy = <<EOF
    {
    "Id": "id113",
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": [
    "s3:*"
    ],
    "Effect": "Allow",
    "Resource": "arn:aws:s3:::S3B_181355/*",
    "Principal": "*"
    }
    ]
    }
    EOF
    }
  3. Modify the config to something like the following:

    Replacement pattern via resource:

    resource "aws_s3_bucket" "negative1" {
    bucket = "S3B_181355"
    acl = "private"

    policy = <<EOF
    {
    "Id": "id113",
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": [
    "s3:putObject"
    ],
    "Effect": "Allow",
    "Resource": "arn:aws:s3:::S3B_181355/*",
    "Principal": "*"
    }
    ]
    }
    EOF
    }

    Replacement pattern via module:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }

    policy = <<EOF
    {
    "Id": "id113",
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": [
    "s3:putObject"
    ],
    "Effect": "Allow",
    "Resource": "arn:aws:s3:::S3B_181355/*",
    "Principal": "*"
    }
    ]
    }
    EOF
    }
  4. Test it

  5. Ship it 🚢 and relax 🌴

S3 Bucket Access to Any Principal

S3 Buckets must not allow Actions From All Principals, as to prevent leaking private information to the entire internet or allow unauthorized data tampering/deletion. This means the 'Effect' must not be 'Allow' when there are All Principals.

Rule-specific references:

Option A: Change Effect to Deny when all Principals exist

policy.Statement should not contain a map with Effect of "Allow" where there are all ("*") Principals.

  1. Locate the following vulnerable pattern:

    resource "aws_s3_bucket_policy" "positive1" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": {
    "AWS": "*"
    },
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  2. Modify the config to something like the following:

    resource "aws_s3_bucket_policy" "negative1" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    The policy could also be expressed in other forms

  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket Allows Delete Action From All Principals

S3 Buckets must not allow Delete Action From All Principals, as to prevent leaking private information to the entire internet or allow unauthorized data tampering/deletion. This means the Effect must not be "Allow" when the Action is "Delete", for all Principals.

Rule-specific references:

Option A: Make sure to not Allow Delete Action for All Principals

policy.Statement should not contain a map with Effect of "Allow" where there are all ("*") Principals when an Action property with value "s3:DeleteObject" exists.

  1. Locate the following vulnerable patterns:

    Vulnerable Pattern 1:

    resource "aws_s3_bucket_policy" "positive1" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:DeleteObject",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Vulnerable Pattern 2:

    resource "aws_s3_bucket_policy" "positive2" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": {
    "AWS": "*"
    },
    "Action": "s3:DeleteObject",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Another Vulnerable Pattern:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:DeleteObject",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  2. Modify the config to something like the following:

    Replacement Pattern 1:

    resource "aws_s3_bucket_policy" "negative1" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Replacement Pattern 2:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket Allows Get Action From All Principals

S3 Buckets must not allow Get Action From All Principals, as to prevent leaking private information to the entire internet or allow unauthorized data tampering/deletion. This means the Effect must not be "Allow" when the Action is "Get", for all Principals.

Rule-specific references:

Option A: Make sure to not Allow Get Action for All Principals

policy.Statement should not contain a map with Effect of "Allow" where there are all ("*") Principals when an Action property with value "s3:GetObject" exists.

  1. Locate the following vulnerable pattern:

    Vulnerable Pattern 1:

    resource "aws_s3_bucket" "positive1" {
    bucket = "my_tf_test_bucket"
    }

    resource "aws_s3_bucket_policy" "positive2" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    resource "aws_s3_bucket_policy" "positive3" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": {
    "AWS": "*"
    },
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Vulnerable Pattern 2:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": {
    "AWS": "*"
    },
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  2. Modify the config to something like the following:

    Replacement Pattern 1:

    resource "aws_s3_bucket" "negative1" {
    bucket = "my_tf_test_bucket"
    }

    resource "aws_s3_bucket_policy" "negative2" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Replacement Pattern 2:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket Allows Put Action From All Principals

S3 Buckets must not allow Put Action From All Principals, as to prevent leaking private information to the entire internet or allow unauthorized data tampering/deletion. This means the Effect must not be "Allow" when the Action is "Put", for all Principals.

Rule-specific references:

Option A: Make sure to not Allow Put Action for All Principals

policy.Statement should not contain a map with Effect of "Allow" where there are all ("*") Principals when an Action property with the value "s3:PutObject" exists.

  1. Locate the following vulnerable patterns:

    Vulnerable Pattern 1:

    resource "aws_s3_bucket_policy" "positive1" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:PutObject",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Vulnerable Pattern 2:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": {
    "AWS": "*"
    },
    "Action": "s3:PutObject",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  2. Modify the config to something like the following:

    Replacement Pattern 1:

    resource "aws_s3_bucket_policy" "negative1" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Replacement Pattern 2:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket ACL Allows Read Or Write to All Users

S3 bucket with public READ/WRITE access.

Rule-specific references:

Option A: Make sure not to have ACL set to Public Read/Write

  • aws_s3_bucket.acl property should not have value "public-read" or "public-read-write"
  • module "s3_bucket" should not have property acl value "public-read" or "public-read-write"
  1. Locate the following vulnerable patterns:

    Vulnerable pattern resource "public-read":

    resource "aws_s3_bucket" "positive1" {
    bucket = "my-tf-test-bucket"
    acl = "public-read"

    tags = {
    Name = "My bucket"
    Environment = "Dev"
    }

    versioning {
    enabled = true
    }
    }

    Vulnerable pattern resource "public-read-write":

    resource "aws_s3_bucket" "positive2" {
    bucket = "my-tf-test-bucket"
    acl = "public-read-write"

    tags = {
    Name = "My bucket"
    Environment = "Dev"
    }

    versioning {
    enabled = true
    }
    }

    Vulnerable pattern module "public-read":

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "public-read"

    versioning = {
    enabled = true
    }
    }

    Vulnerable pattern module "public-read-write":

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "public-read-write"

    versioning = {
    enabled = true
    }
    }
  2. Modify the config to something like the following:

    Replacement pattern resource "private":

    resource "aws_s3_bucket" "negative1" {
    bucket = "my-tf-test-bucket"
    acl = "private"

    tags = {
    Name = "My bucket"
    Environment = "Dev"
    }

    versioning {
    enabled = true
    }
    }

    Replacement pattern module "private":

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket ACL Allows Read to Any Authenticated User

Misconfigured S3 buckets can leak private information to the entire internet or allow unauthorized data tampering/deletion.

Rule-specific references:

Option A: An S3 Bucket Should Not Have a Permission of Authenticated Read

Neither resource aws_s3_bucket.acl or module s3_bucket.acl should have a value of "authenticated-read".

Remove or replace the value "authenticated-read" from any resource aws_s3_bucket.acl or module s3_bucket.acl configuration with a less permissive permission, such as "private".

  1. Locate one of the following vulnerable patterns:

    Vulnerable pattern resource:

    resource "aws_s3_bucket" "positive1" {
    bucket = "my-tf-test-bucket"
    acl = "authenticated-read"

    tags = {
    Name = "My bucket"
    Environment = "Dev"
    }
    }

    Vulnerable pattern module:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "authenticated-read"

    versioning = {
    enabled = true
    }
    }
  2. Modify the config to something like the following:

    Replacement pattern resource:

    resource "aws_s3_bucket" "negative1" {
    bucket = "my-tf-test-bucket"
    acl = "private"

    tags = {
    Name = "My bucket"
    Environment = "Dev"
    }
    }

    Replacement pattern module:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket Allows All Actions From All Principals

S3 Buckets must not allow All Actions (containing "") From All Principals, as to prevent leaking private information to the entire internet or allow unauthorized data tampering/deletion. This means the Effect must not be "Allow" when the Action contains "", for all Principals.

Rule-specific references:

Option A: Make sure that S3 Bucket does not allow all actions from all Principals

If an aws_s3_bucket_policy has a Statement with the value of Effect being "Allow" and a Principal and Action that contains "*" take the following action.

  1. Locate one of the following vulnerable patterns:

    Vulnerable pattern resource:

    resource "aws_s3_bucket_policy" "positive1" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Vulnerable pattern module:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": {
    "AWS": "*"
    },
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Vulnerable pattern resource:

    resource "aws_s3_bucket_policy" "positive2" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": {
    "AWS": "*"
    },
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  2. Modify the config to something like the following:

    Replacement pattern resource:

    resource "aws_s3_bucket_policy" "negative2" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:PutObject",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Replacement pattern module:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:PutObject",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket Allows List Action From All Principals

S3 Buckets must not allow List ("s3:ListObjects") Action From All Principals, as to prevent leaking private information to the entire internet or allow unauthorized data tampering/deletion. This means the Effect must not be "Allow" when the Action is List ("s3:ListObjects"), for all Principals.

Rule-specific references:

Option A: Remove the List Action from a Principal specifying All

If an AWS S3 bucket policy has a Statement with value of Effect being "Allow" and a Principal that contains "*" and Action with value "s3:ListObjects" take the following action.

  1. Remove any S3 bucket policy.statement.action specifying "s3:ListObjects" where S3 bucket policy.Statement.Principal contains a value of '*'

  2. Locate one of the following vulnerable patterns:

    Vulnerable pattern resource:

    resource "aws_s3_bucket_policy" "positive1" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:ListObjects",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Vulnerable pattern module:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": {
    "AWS": "*"
    },
    "Action": "s3:ListObjects",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Vulnerable pattern resource:

    resource "aws_s3_bucket_policy" "positive2" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Allow",
    "Principal": {
    "AWS": "*"
    },
    "Action": "s3:ListObjects",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  3. Modify the config to something like the following:

    Replacement pattern resource:

    resource "aws_s3_bucket_policy" "negative1" {
    bucket = aws_s3_bucket.b.id

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }

    Replacement pattern module:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  4. Test it

  5. Ship it 🚢 and relax 🌴

Google Project IAM Member Service Account Has Admin Role

Verifies that Google Project IAM Member Service Account doesn't have an Admin Role associated.

Rule-specific references:

Option A: Remove Service Account Admin

The value of google_project_iam_member.member must not start with "serviceAccount:" or any given value in the google_project_iam_member.members list must not start with "serviceAccount:" and the value of google_project_iam_member.role must not contain "roles/iam.serviceAccountAdmin".

  1. Locate the following vulnerable pattern:

    resource "google_project_iam_member" "positive1" {
    project = "your-project-id"
    role = "roles/iam.serviceAccountAdmin"
    member = "serviceAccount:[email protected]"
    }

    resource "google_project_iam_member" "positive2" {
    project = "your-project-id"
    role = "roles/iam.serviceAccountAdmin"
    members = ["user:[email protected]", "serviceAccount:[email protected]"]
    }
  2. Modify the config to something like the following:

    resource "google_project_iam_member" "negative1" {
    project = "your-project-id"
    role = "roles/editor"
    members = "user:[email protected]"
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

IAM Policies With Full Privileges

IAM policies should not allow full administrative privileges (for all resources).

Rule-specific references:

Option A: Remove All actions from Policy Statements with Resource All

If policy.Statement.Resource has a value of "*" (All) policy.Statement.Action must not have a value of "*" (All).

  1. Locate the following vulnerable pattern:

    resource "aws_iam_role_policy" "positive1" {
    name = "apigateway-cloudwatch-logging"
    role = aws_iam_role.apigateway_cloudwatch_logging.id

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Action": ["*"],
    "Resource": "*"
    }
    ]
    }
    EOF
    }
  2. Modify the config to something like the following where a single specific action is specified:

    resource "aws_iam_role_policy" "negative1" {
    name = "apigateway-cloudwatch-logging"
    role = aws_iam_role.apigateway_cloudwatch_logging.id

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Action": ["some:action"],
    "Resource": "*"
    }
    ]
    }
    EOF
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

IAM Policy Grants AssumeRole Permission Across All Services

IAM role should not allow All ("*") services or Principals to assume it.

Rule-specific references:

Option A: Remove the All Specifier from the Principal

assume_rule_policy.Statement.Principal.AWS should not have a value of "*" (All).

  1. Locate the following vulnerable pattern:

    //  Create a role which OpenShift instances will assume.
    // This role has a policy saying it can be assumed by ec2
    // instances.
    resource "aws_iam_role" "positive1" {
    name = "${var.name_tag_prefix}-openshift-instance-role"

    assume_role_policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": "sts:AssumeRole",
    "Principal": {
    "Service": "ec2.amazonaws.com",
    "AWS": "*"
    },
    "Effect": "Allow",
    "Sid": ""
    }
    ]
    }
    EOF
    }

    // This policy allows an instance to forward logs to CloudWatch, and
    // create the Log Stream or Log Group if it doesn't exist.
    resource "aws_iam_policy" "positive3" {
    name = "${var.name_tag_prefix}-openshift-instance-forward-logs"
    path = "/"
    description = "Allows an instance to forward logs to CloudWatch"

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Action": [
    "logs:CreateLogGroup",
    "logs:CreateLogStream",
    "logs:PutLogEvents",
    "logs:DescribeLogStreams"
    ],
    "Resource": [
    "arn:aws:logs:*:*:*"
    ]
    }
    ]
    }
    EOF
    }

    // Attach the policies to the role.
    resource "aws_iam_policy_attachment" "positive4" {
    name = "${var.name_tag_prefix}-openshift-attachment-forward-logs"
    roles = ["${aws_iam_role.openshift-instance-role.name}"]
    policy_arn = "${aws_iam_policy.openshift-policy-forward-logs.arn}"
    }

    // Create a instance profile for the role.
    resource "aws_iam_instance_profile" "positive5" {
    name = "${var.name_tag_prefix}-openshift-instance-profile"
    role = "${aws_iam_role.openshift-instance-role.name}"
    }
  2. Modify the config to something like the following:

    //  Create a role which OpenShift instances will assume.
    // This role has a policy saying it can be assumed by ec2
    // instances.
    resource "aws_iam_role" "negative1" {
    name = "${var.name_tag_prefix}-openshift-instance-role"

    assume_role_policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": "sts:AssumeRole",
    "Principal": {
    "Service": "ec2.amazonaws.com"
    },
    "Effect": "Allow",
    "Sid": ""
    }
    ]
    }
    EOF
    }

    // This policy allows an instance to forward logs to CloudWatch, and
    // create the Log Stream or Log Group if it doesn't exist.
    resource "aws_iam_policy" "negative2" {
    name = "${var.name_tag_prefix}-openshift-instance-forward-logs"
    path = "/"
    description = "Allows an instance to forward logs to CloudWatch"

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Action": [
    "logs:CreateLogGroup",
    "logs:CreateLogStream",
    "logs:PutLogEvents",
    "logs:DescribeLogStreams"
    ],
    "Resource": [
    "arn:aws:logs:*:*:*"
    ]
    }
    ]
    }
    EOF
    }

    // Attach the policies to the role.
    resource "aws_iam_policy_attachment" "negative3" {
    name = "${var.name_tag_prefix}-openshift-attachment-forward-logs"
    roles = ["${aws_iam_role.openshift-instance-role.name}"]
    policy_arn = "${aws_iam_policy.openshift-policy-forward-logs.arn}"
    }

    // Create a instance profile for the role.
    resource "aws_iam_instance_profile" "negative4" {
    name = "${var.name_tag_prefix}-openshift-instance-profile"
    role = "${aws_iam_role.openshift-instance-role.name}"
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

IAM Policy Grants Full Permissions

IAM policies should not allow All ('*') in a statement action.

Rule-specific references:

Option A: Remove the All Specifier from the Resource Statement of the Policy

aws_iam_role_policy.policy.Statement.Resource should not have a value of "*" (All).

  1. Locate the following vulnerable pattern:

    resource "aws_iam_user" "positive1" {
    name = "${local.resource_prefix.value}-user"
    force_destroy = true

    tags = {
    Name = "${local.resource_prefix.value}-user"
    Environment = local.resource_prefix.value
    }

    }

    resource "aws_iam_access_key" "positive2" {
    user = aws_iam_user.user.name
    }

    resource "aws_iam_user_policy" "positive3" {
    name = "excess_policy"
    user = aws_iam_user.user.name

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": [
    "ec2:*",
    "s3:*",
    "lambda:*",
    "cloudwatch:*"
    ],
    "Effect": "Allow",
    "Resource": "*"
    }
    ]
    }
    EOF
    }

    output "username" {
    value = aws_iam_user.user.name
    }

    output "secret" {
    value = aws_iam_access_key.user.encrypted_secret
    }

  2. Modify the config to something like the following:

    resource "aws_iam_user" "negative1" {
    name = "${local.resource_prefix.value}-user"
    force_destroy = true

    tags = {
    Name = "${local.resource_prefix.value}-user"
    Environment = local.resource_prefix.value
    }

    }

    resource "aws_iam_access_key" "negative2" {
    user = aws_iam_user.user.name
    }

    resource "aws_iam_user_policy" "negative3" {
    name = "excess_policy"
    user = aws_iam_user.user.name

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": [
    "ec2:*",
    "s3:*",
    "lambda:*",
    "cloudwatch:*"
    ],
    "Effect": "Allow",
    "Resource": "SomeResource"
    }
    ]
    }
    EOF
    }

    output "username" {
    value = aws_iam_user.user.name
    }

    output "secret" {
    value = aws_iam_access_key.user.encrypted_secret
    }

  3. Test it

  4. Ship it 🚢 and relax 🌴

OSLogin Disabled

Verifies that the OSLogin is enabled. Setting enable-oslogin in project-wide metadata makes sure that all of the instances in your project are conforming to the specific value (true or false).

After you enable OS Login on one or more instances in your project, those VMs accept connections only from user accounts that have the necessary IAM roles in your project or organization.

Enabling Compute Engine OS Login for a project ensures that SSH keys used to access instances are mapped to IAM users. If access is revoked for an IAM user, associated SSH keys are revoked as well. This streamlines handling compromised SSH key pairs and the process for revoking access.

Rule-specific references:

Option A: Make sure Google Compute Project Metadata Enable OSLogin is not false or undefined

Locate google_compute_project_metadata.metadata and set the enable-oslogin property value to true.

  1. Locate the following vulnerable pattern:

    resource "google_compute_project_metadata" "positive1" {
    metadata = {
    enable-oslogin = false
    }
    }

    resource "google_compute_project_metadata" "positive2" {
    metadata = {
    foo = "bar"
    }
    }
  2. Modify the config to something like the following:

    resource "google_compute_project_metadata" "negative1" {
    metadata = {
    enable-oslogin = true
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

No Drop Capabilities for Containers

Sees if Kubernetes Drop Capabilities exist to ensure the container's security context.

Rule-specific references:

Option A: Security Context Capabilities Drop must be set

The security_context.capabilities.drop must have its value set, thus overriding the default of not dropping any capabilities.

  1. Locate one of the following vulnerable patterns:

    Adding but not dropping capabilities:

    resource "kubernetes_pod" "test1" {
    metadata {
    name = "terraform-example"
    }

    spec {

    container = [
    {
    image = "nginx:1.7.9"
    name = "example"

    security_context = {
    capabilities = {
    add = ["NET_BIND_SERVICE"]
    }
    }

    env = {
    name = "environment"
    value = "test"
    }

    port = {
    container_port = 8080
    }

    liveness_probe = {
    http_get = {
    path = "/nginx_status"
    port = 80

    http_header = {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }

    initial_delay_seconds = 3
    period_seconds = 3
    }
    },

    {
    image = "nginx:1.7.9"
    name = "example2"

    security_context = {
    capabilities = {
    drop = ["ALL"]
    }
    }

    env = {
    name = "environment"
    value = "test"
    }

    port = {
    container_port = 8080
    }

    liveness_probe = {
    http_get = {
    path = "/nginx_status"
    port = 80

    http_header = {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }

    initial_delay_seconds = 3
    period_seconds = 3
    }
    }
    ]

    dns_config {
    nameservers = ["1.1.1.1", "8.8.8.8", "9.9.9.9"]
    searches = ["example.com"]

    option {
    name = "ndots"
    value = 1
    }

    option {
    name = "use-vc"
    }
    }

    dns_policy = "None"
    }
    }

    No security_context.capabilities.drop:

    resource "kubernetes_pod" "test2" {
    metadata {
    name = "terraform-example"
    }
    spec {
    container = [
    {
    image = "nginx:1.7.9"
    name = "example"
    security_context = {
    allow_privilege_escalation = false
    }
    env = {
    name = "environment"
    value = "test"
    }
    port = {
    container_port = 8080
    }
    liveness_probe = {
    http_get = {
    path = "/nginx_status"
    port = 80

    http_header = {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }

    initial_delay_seconds = 3
    period_seconds = 3
    }
    },
    {
    image = "nginx:1.7.9"
    name = "example2"

    security_context = {
    capabilities = {
    drop = ["ALL"]
    }
    }

    env = {
    name = "environment"
    value = "test"
    }

    port = {
    container_port = 8080
    }

    liveness_probe = {
    http_get = {
    path = "/nginx_status"
    port = 80

    http_header = {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }

    initial_delay_seconds = 3
    period_seconds = 3
    }
    }
    ]

    dns_config {
    nameservers = ["1.1.1.1", "8.8.8.8", "9.9.9.9"]
    searches = ["example.com"]

    option {
    name = "ndots"
    value = 1
    }

    option {
    name = "use-vc"
    }
    }

    dns_policy = "None"
    }
    }

    No security_context at all:

    resource "kubernetes_pod" "test3" {
    metadata {
    name = "terraform-example"
    }
    spec {
    container = [
    {
    image = "nginx:1.7.9"
    name = "example"
    env = {
    name = "environment"
    value = "test"
    }
    port = {
    container_port = 8080
    }

    liveness_probe = {
    http_get = {
    path = "/nginx_status"
    port = 80

    http_header = {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }

    initial_delay_seconds = 3
    period_seconds = 3
    }
    },

    {
    image = "nginx:1.7.9"
    name = "example2"

    security_context = {
    capabilities = {
    drop = ["ALL"]
    }
    }

    env = {
    name = "environment"
    value = "test"
    }

    port = {
    container_port = 8080
    }

    liveness_probe = {
    http_get = {
    path = "/nginx_status"
    port = 80

    http_header = {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }

    initial_delay_seconds = 3
    period_seconds = 3
    }
    }
    ]

    dns_config {
    nameservers = ["1.1.1.1", "8.8.8.8", "9.9.9.9"]
    searches = ["example.com"]

    option {
    name = "ndots"
    value = 1
    }

    option {
    name = "use-vc"
    }
    }

    dns_policy = "None"
    }
    }
  2. Modify the config to something like the following, thus dropping capabilities:

    resource "kubernetes_pod" "negative4" {
    metadata {
    name = "terraform-example"
    }

    spec {

    container = [
    {
    image = "nginx:1.7.9"
    name = "example"

    security_context = {
    capabilities = {
    drop = ["ALL"]
    }
    }

    env = {
    name = "environment"
    value = "test"
    }

    port = {
    container_port = 8080
    }

    liveness_probe = {
    http_get = {
    path = "/nginx_status"
    port = 80

    http_header = {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }

    initial_delay_seconds = 3
    period_seconds = 3
    }
    },

    {
    image = "nginx:1.7.9"
    name = "example2"

    security_context = {
    capabilities = {
    drop = ["ALL"]
    }
    }

    env = {
    name = "environment"
    value = "test"
    }

    port = {
    container_port = 8080
    }

    liveness_probe = {
    http_get = {
    path = "/nginx_status"
    port = 80

    http_header = {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }

    initial_delay_seconds = 3
    period_seconds = 3
    }
    }
    ]

    dns_config {
    nameservers = ["1.1.1.1", "8.8.8.8", "9.9.9.9"]
    searches = ["example.com"]

    option {
    name = "ndots"
    value = 1
    }

    option {
    name = "use-vc"
    }
    }

    dns_policy = "None"
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Containers With Sys Admin Capabilities

Containers should not have CAP_SYS_ADMIN Linux capability.

Rule-specific references:

Option A: Security Context Capabilities should not add Sys Admin

kubernetes_pod spec.containers[n].security_context.capabilities.add should not include "SYS_ADMIN".

  1. Locate the following vulnerable pattern:

    resource "kubernetes_pod" "positive1" {
    metadata {
    name = "terraform-example"
    }

    spec {
    container = [
    {
    image = "nginx:1.7.9"
    name = "example"

    security_context = {
    capabilities = {
    add = ["SYS_ADMIN"]
    }
    }

    env = {
    name = "environment"
    value = "test"
    }

    port = {
    container_port = 8080
    }

    liveness_probe = {
    http_get = {
    path = "/nginx_status"
    port = 80

    http_header = {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }
    initial_delay_seconds = 3
    period_seconds = 3
    }
    },
    {
    image = "nginx:1.7.9"
    name = "example22222"

    security_context = {
    capabilities = {
    add = ["SYS_ADMIN"]
    }
    }

    env = {
    name = "environment"
    value = "test"
    }

    port = {
    container_port = 8080
    }

    liveness_probe = {
    http_get = {
    path = "/nginx_status"
    port = 80

    http_header = {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }
    initial_delay_seconds = 3
    period_seconds = 3
    }
    }
    ]
    // ...
    }
    }

    resource "kubernetes_pod" "positive2" {
    metadata {
    name = "terraform-example"
    }

    spec {
    container {
    image = "nginx:1.7.9"
    name = "example"

    security_context {
    capabilities {
    add = ["SYS_ADMIN"]
    }
    }

    env {
    name = "environment"
    value = "test"
    }

    port {
    container_port = 8080
    }

    liveness_probe {
    http_get {
    path = "/nginx_status"
    port = 80

    http_header {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }

    initial_delay_seconds = 3
    period_seconds = 3
    }
    }
    // ...
    }
    }
  2. Modify the config to something like the following:

    resource "kubernetes_pod" "negative3" {
    metadata {
    name = "terraform-example"
    }

    spec {
    container = [
    {
    image = "nginx:1.7.9"
    name = "example"

    env = {
    name = "environment"
    value = "test"
    }

    port = {
    container_port = 8080
    }

    liveness_probe = {
    http_get = {
    path = "/nginx_status"
    port = 80

    http_header = {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }
    initial_delay_seconds = 3
    period_seconds = 3
    }
    },
    {
    image = "nginx:1.7.9"
    name = "example2"

    env = {
    name = "environment"
    value = "test"
    }

    port = {
    container_port = 8080
    }

    liveness_probe = {
    http_get = {
    path = "/nginx_status"
    port = 80

    http_header = {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }
    initial_delay_seconds = 3
    period_seconds = 3
    }
    }
    ]
    // ...
    }
    }

    resource "kubernetes_pod" "negative4" {
    metadata {
    name = "terraform-example"
    }

    spec {
    container {
    image = "nginx:1.7.9"
    name = "example"

    env {
    name = "environment"
    value = "test"
    }

    port {
    container_port = 8080
    }

    liveness_probe {
    http_get {
    path = "/nginx_status"
    port = 80

    http_header {
    name = "X-Custom-Header"
    value = "Awesome"
    }
    }

    initial_delay_seconds = 3
    period_seconds = 3
    }
    }
    // ...
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Fixing Insecure Network Access

About Insecure Network Access

What is improper access control?

Improper access control is a vulnerability that occurs when a system does not properly restrict or enforce access to resources, such as files, directories, network resources, or application functions.

Examples of improper access control vulnerabilities include:

  • Weak access controls: When access controls are weak or easily bypassed, attackers can gain access to sensitive resources or data by exploiting security weaknesses.
  • Insufficient authorization checks: When authorization checks are insufficient, it can allow unauthorized users to access sensitive data or resources, or to perform actions that they are not authorized to do.
  • Overly permissive access: When access controls are overly permissive, they can allow users to access resources or data that they do not need, increasing the risk of data breaches or other security incidents.

Check out these videos for a high-level explanation:

  • Missing function level access control

  • Missing object level access control

What is the impact of improper access control?

Improper access control can lead to various security threats, such as:

  • Data breaches: Improper access control can allow attackers to access sensitive data, leading to data breaches, data loss, or unauthorized access to confidential information.
  • Unauthorized access to resources: Attackers can exploit improper access control to gain unauthorized access to resources, such as servers, databases, and applications.
  • Account takeover: Attackers can use improper access control to take over user accounts and gain access to sensitive data or resources.

How to prevent improper access control?

Here are some measures that can help ensure proper access control:

  • Strong access controls: Implement strong access controls that restrict access to sensitive resources or data based on user roles and permissions.
  • Proper user authentication and authorization: Implement proper user authentication and authorization mechanisms to ensure that only authorized users can access sensitive data and resources.
  • Input validation and sanitization: Validate and sanitize user input before using it to access internal objects or data. Use regular expressions or input filters to remove or encode any special characters that could be used to access sensitive data or resources.
  • Least privilege: Use the principle of least privilege to restrict access to resources to only what is necessary for each user role. This can help prevent attackers from gaining access to resources that they do not need to access.
  • Regular security audits: Regularly audit your system for security vulnerabilities, including improper access control vulnerabilities. Use automated tools and manual testing to identify potential issues and fix them before they can be exploited.

References

Taxonomies

Explanation & Prevention

Training

In the context of Terraform, this vulnerability class identifies vulnerabilities related to services being exposed publicly.

BigQuery Dataset Is Public

BigQuery dataset is anonymously or publicly accessible.

Rule-specific references:

Option A: Replace Access Special Group AllAuthenticatedUsers with a more restrictive option

access.special_group should not have "allAuthenticatedUsers" assigned.

  1. Locate the following vulnerable pattern:

    resource "google_bigquery_dataset" "vulnerable" {
    dataset_id = "example_dataset"
    friendly_name = "test"
    description = "This is a test description"
    location = "EU"
    default_table_expiration_ms = 3600000

    labels = {
    env = "default"
    }

    access {
    role = "OWNER"
    special_group = "allAuthenticatedUsers"
    }
    }
  2. Modify the config to something like the following:

    resource "google_bigquery_dataset" "not_vulnerable" {
    dataset_id = "example_dataset"
    friendly_name = "test"
    description = "This is a test description"
    location = "EU"
    default_table_expiration_ms = 3600000

    labels = {
    env = "default"
    }

    access {
    role = "OWNER"
    user_by_email = google_service_account.bqowner.email
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Cloud Storage Bucket Is Publicly Accessible

Cloud Storage Bucket is anonymously or publicly accessible.

Rule-specific references:

Option A: Remove All members

None of the member/members should have a value containing "allUsers" or "allAuthenticatedUsers".

  1. Locate the following vulnerable pattern:

    resource "google_storage_bucket_iam_member" "positive1" {
    bucket = google_storage_bucket.default.name
    role = "roles/storage.admin"
    member = "allUsers"
    }

    resource "google_storage_bucket_iam_member" "positive2" {
    bucket = google_storage_bucket.default.name
    role = "roles/storage.admin"
    members = ["user:[email protected]","allAuthenticatedUsers"]
    }
  2. Modify the config to something like the following:

    resource "google_storage_bucket_iam_member" "negative1" {
    bucket = google_storage_bucket.default.name
    role = "roles/storage.admin"
    member = "user:[email protected]"
    }

    resource "google_storage_bucket_iam_member" "negative2" {
    bucket = google_storage_bucket.default.name
    role = "roles/storage.admin"
    members = ["user:[email protected]","user:[email protected]"]
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

EC2 Instance Using Default Security Group

EC2 instances should not use default security group(s) (Security Group(s) with a name of "default").

Rule-specific references:

Option A: Remove any Default Security Groups

Remove any default security groups from the configuration. Add non-default security groups if needed.

  1. Locate the following vulnerable pattern:

    resource "aws_instance" "positive1" {
    ami = "ami-003634241a8fcdec0"
    instance_type = "t3.micro"
    // ...
    security_groups = [aws_security_group.default.id]
    }

    Or:

    resource "aws_instance" "positive2" {
    ami = "ami-003634241a8fcdec0"
    instance_type = "t2.micro"
    // ...
    vpc_security_group_ids = [aws_security_group.default.id]
    }
  2. Modify the config to something like the following:

    resource "aws_instance" "negative1" {
    ami = "ami-003634241a8fcdec0"
    instance_type = "t3.micro"
    // ...
    security_groups = [aws_security_group.sg.id]
    }

    Or:

    resource "aws_instance" "negative2" {
    ami = "ami-003634241a8fcdec0"
    instance_type = "t2.micro"
    // ...
    vpc_security_group_ids = [aws_security_group.sg.id]
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Limit Access to AWS Resources

Option A: Ensure sensitive resources are not public

In the context of Terraform, when a specific resource is marked as publicly accessible, it means that attackers may be able to interact with it. Resources that are identified include the following types:

  • aws_db_instance
  • aws_dms_replication_instance
  • aws_rds_cluster_instance
  • aws_redshift_cluster

Follow the steps below:

  1. Go through the issues that GuardRails identified in the PR/MR

  2. Review the affected resources to determine whether they can be public

    resource "aws_db_instance" "insecure" {
    # ... other configuration ...
    publicly_accessible = true
    }
  3. If not, then either remove the publicly_accessible argument or change it to publicly_accessible = false

  4. Test the changes and ensure that everything is working as expected

  5. Ship it 🚢 and relax 🌴

Option B: Ensure inbound traffic on AWS is restricted

AWS Security Groups can be configured to allow all incoming traffic, which is in violation of the security best practices.

  1. Go through the issues that GuardRails identified in the PR/MR

  2. Review the aws_security_group or aws_security_group_rule resources where cidr_blocks contain /0

    resource "aws_security_group" "allow_tls" {
    name = "allow_tls"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 443
    to_port = 443
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    }
    }
  3. Ensure that the cidr_blocks are limited to required ports and IP address ranges

Option C: Ensure inbound traffic on Azure is restricted

Azure Network Security Groups can be configured to allow all incoming traffic, which is in violation of the security best practices.

  1. Go through the issues that GuardRails identified in the PR/MR

  2. Review the azurerm_network_security_rule resources where source_address_prefix contain /0 or *

    resource "azurerm_network_security_rule" "example" {
    name = "test123"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "Tcp"
    source_port_range = "*"
    destination_port_range = "*"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
  3. Ensure that the source_address_prefix are limited to required ports and IP address ranges

Option D: Ensure inbound traffic on GCP is restricted

GCP firewalls can be configured to allow all incoming traffic, which is in violation of the security best practices.

  1. Go through the issues that GuardRails identified in the PR/MR

  2. Review the google_compute_firewall resources where source_ranges contain /0

    resource "google_compute_firewall" "project-firewall-allow-ssh" {
    name = "${var.vpc_name}-allow-something"
    network = "${google_compute_network.project-network.self_link}"
    ....
    source_ranges = ["0.0.0.0/0"]
    }
  3. Ensure that the source_ranges is limited to required ports and IP address ranges

Network ACL With Unrestricted Access To RDP

RDP (TCP:3389) should not be public in an AWS Network ACL.

Rule-specific references:

Option A: Make sure that RDP port 3389 is not accessible to the world via Network ACL

RDP port (3389) ingress should not be accessible to the world (0.0.0.0/0).

  1. Locate one of the following vulnerable patterns or a pattern where the RDP port ingress is open to the world:

    Vulnerable Pattern 1:

    provider "aws" {
    region = "us-east-1"
    }

    terraform {
    required_providers {
    aws = {
    source = "hashicorp/aws"
    version = "~> 3.0"
    }
    }
    }

    resource "aws_network_acl" "positive1" {
    vpc_id = aws_vpc.main.id

    egress = [
    {
    protocol = "tcp"
    rule_no = 200
    action = "allow"
    cidr_block = "10.3.0.0/18"
    from_port = 443
    to_port = 443
    }
    ]

    ingress = [
    {
    protocol = "tcp"
    rule_no = 100
    action = "allow"
    cidr_block = "0.0.0.0/0"
    from_port = 3389
    to_port = 3389
    }
    ]

    tags = {
    Name = "main"
    }
    }

    Vulnerable Pattern 2:

    provider "aws" {
    region = "us-east-1"
    }

    terraform {
    required_providers {
    aws = {
    source = "hashicorp/aws"
    version = "~> 3.0"
    }
    }
    }

    resource "aws_network_acl" "positive2" {
    vpc_id = aws_vpc.main.id

    tags = {
    Name = "main"
    }
    }

    resource "aws_network_acl_rule" "postive2" {
    network_acl_id = aws_network_acl.positive2.id
    rule_number = 100
    egress = false
    protocol = "tcp"
    rule_action = "allow"
    from_port = 3389
    to_port = 3389
    cidr_block = "0.0.0.0/0"
    }
  2. Modify the config to something like the following:

    Replacement Pattern 1:

    provider "aws" {
    region = "us-east-1"
    }

    terraform {
    required_providers {
    aws = {
    source = "hashicorp/aws"
    version = "~> 3.0"
    }
    }
    }

    resource "aws_network_acl" "negative1" {
    vpc_id = aws_vpc.main.id

    egress = [
    {
    protocol = "tcp"
    rule_no = 200
    action = "allow"
    cidr_block = "10.3.0.0/18"
    from_port = 443
    to_port = 443
    }
    ]

    ingress = [
    {
    protocol = "tcp"
    rule_no = 100
    action = "allow"
    cidr_block = "10.3.0.0/18"
    from_port = 3389
    to_port = 3389
    }
    ]

    tags = {
    Name = "main"
    }
    }

    Replacement Pattern 2:

    provider "aws" {
    region = "us-east-1"
    }

    terraform {
    required_providers {
    aws = {
    source = "hashicorp/aws"
    version = "~> 3.0"
    }
    }
    }

    resource "aws_network_acl" "negative2" {
    vpc_id = aws_vpc.main.id

    tags = {
    Name = "main"
    }
    }

    resource "aws_network_acl_rule" "negative2" {
    network_acl_id = aws_network_acl.negative2.id
    rule_number = 100
    egress = false
    protocol = "tcp"
    rule_action = "allow"
    from_port = 3389
    to_port = 3389
    cidr_block = "10.3.0.0/18"
    }

    More Replacement Patterns:

    module "vpc" {
    source = "terraform-aws-modules/vpc/aws"
    version = "3.7.0"

    name = "my-vpc"
    cidr = "10.0.0.0/16"

    azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
    private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
    public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

    enable_nat_gateway = true
    enable_vpn_gateway = true

    tags = {
    Terraform = "true"
    Environment = "dev"
    }
    }
    module "vpc" {
    source = "terraform-aws-modules/vpc/aws"
    version = "3.7.0"

    name = "my-vpc"
    cidr = "10.0.0.0/16"

    azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
    private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
    public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

    default_network_acl_ingress = [
    {
    "action" : "allow",
    "cidr_block" : "0.0.0.0/0",
    "from_port" : 0,
    "protocol" : "-1",
    "rule_no" : 100,
    "to_port" : 0
    },
    {
    "action" : "allow",
    "cidr_block" : "10.3.0.0/18",
    "from_port" : 0,
    "protocol" : "-1",
    "rule_no" : 3389,
    "to_port" : 0
    }
    ]

    enable_nat_gateway = true
    enable_vpn_gateway = true

    tags = {
    Terraform = "true"
    Environment = "dev"
    }
    }
  3. Test it

  4. Although the (Modify the config to something like the following) patterns that have been presented above will pass this rule a much better option if possible is to remove the RDP port and use a VPN or SSH tunnel to pass all RDP data

  5. Ship it 🚢 and relax 🌴

RDP Access Is Not Restricted

Check if the Google compute firewall allows unrestricted RDP access (port 3389):

  • allow.protocol with value "tcp" or "udp"
  • allow.ports contains port 3389 somewhere in its range
  • source_ranges contains one or both of "0.0.0.0/0" (IPv4 all) | "::/0" (IPv6 all)

Rule-specific references:

Option A: Remove Google Cloud Platform (GCP) Compute Firewall Rule Allowing Unrestricted RDP Ingress Traffic

There should not be a google_compute_firewall resource with direction property value set or defaulting to "INGRESS" allowing ports "3389" with unrestricted source_ranges "0.0.0.0/0" (IPv4 all) | "::/0" (IPv6 all) and protocol with value "tcp" or "udp".

  1. Locate the following vulnerable pattern:

    resource "google_compute_firewall" "positive1" {
    name = "test-firewall"
    network = google_compute_network.default.name
    direction = "INGRESS"

    allow {
    protocol = "icmp"
    }

    allow {
    protocol = "tcp"
    ports = ["80", "8080", "1000-2000","3389"]
    }

    source_tags = ["web"]
    source_ranges = ["0.0.0.0/0"]
    }

    resource "google_compute_firewall" "positive2" {
    name = "test-firewall"
    network = google_compute_network.default.name

    allow {
    protocol = "udp"
    ports = ["80", "8080", "1000-2000","21-3390"]
    }

    source_tags = ["web"]
    source_ranges = ["::/0"]
    }
  2. Modify the config to something like the following:

    resource "google_compute_firewall" "negative1" {
    name = "test-firewall"
    network = google_compute_network.default.name

    allow {
    protocol = "icmp"
    }

    allow {
    protocol = "tcp"
    ports = ["80", "8080", "1000-2000"]
    }

    source_tags = ["web"]
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

RDP Is Exposed To The Internet

Port 3389 (Remote Desktop) should not be exposed to the internet.

Rule-specific references:

Option A: Make sure that RDP is not exposed to the world

The following properties of azurerm_network_security_rule and their values as specified should not be combined:

  • destination_port_range must not allow RDP port 3389
  • protocol must not be "UDP" or "TCP"
  • access must not be "Allow"
  • source_address_prefix: must now allow all (all can come in several forms)
  1. Locate the following vulnerable patterns:

    Vulnerable Pattern 1:

    resource "azurerm_network_security_rule" "positive1" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "3389"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable Pattern 2:

    resource "azurerm_network_security_rule" "positive2" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "3389-3390"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable Pattern 3:

    resource "azurerm_network_security_rule" "positive3" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "3388-3389"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable Pattern 4:

    resource "azurerm_network_security_rule" "positive4" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "3389"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable Pattern 5:

    resource "azurerm_network_security_rule" "positive5" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "3389,3391"
    source_address_prefix = "34.15.11.3/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable Pattern 6:

    resource "azurerm_network_security_rule" "positive6" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "3389"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable Pattern 7:

    resource "azurerm_network_security_rule" "positive7" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "3388-3390, 23000"
    source_address_prefix = "internet"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable Pattern 8:

    resource "azurerm_network_security_rule" "positive8" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "3387, 3389 , 3391 "
    source_address_prefix = "any"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable Pattern 9:

    resource "azurerm_network_security_rule" "positive9" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "3388, 3389-3390,2250"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable Pattern 10:

    resource "azurerm_network_security_rule" "positive10" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "111-211, 2000-4430, 1-2 , 3"
    source_address_prefix = "internet"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
  2. Modify the config to something more like the following:

    Replacement Pattern 1:

    resource "azurerm_network_security_rule" "negative1" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Deny"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "3389"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement Pattern 2:

    resource "azurerm_network_security_rule" "negative2" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "2000-5000"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement Pattern 3:

    resource "azurerm_network_security_rule" "negative3" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "4030-5100"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement Pattern 4:

    resource "azurerm_network_security_rule" "negative4" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "2100-5300"
    source_address_prefix = "192.168.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement Pattern 5:

    resource "azurerm_network_security_rule" "negative5" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "3389"
    source_address_prefix = "/1"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement Pattern 6:

    resource "azurerm_network_security_rule" "negative6" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "3388"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement Pattern 7:

    resource "azurerm_network_security_rule" "negative7" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "3389"
    source_address_prefix = "internet"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement Pattern 8:

    resource "azurerm_network_security_rule" "negative8" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "3388, 3390,1000-2000"
    source_address_prefix = "any"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement Pattern 9:

    resource "azurerm_network_security_rule" "negative9" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "3389"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement Pattern 10:

    resource "azurerm_network_security_rule" "negative10" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "3389 , 3390"
    source_address_prefix = "0.0.1.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Another Replacement Pattern:

    resource "azurerm_network_security_rule" "negative11" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "338,389"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket Allows Public Policy

S3 bucket should not allow public policy.

Rule-specific references:

Option A: Intentionally set S3 Bucket Block Public Policy to true

If you have an S3 bucket with block_public_policy set to false or not defined at all, whether it be directly or indirectly via aws_s3_bucket_public_access_block, be sure to set the block_public_policy value to true.

block_public_policy must be defined and have its value set to true.

  1. Locate one of the following vulnerable patterns:

    Vulnerable pattern via resource aws_s3_bucket_public_access_block. Also, keep in mind that if block_public_policy is not defined then the bucket is still vulnerable:

    resource "aws_s3_bucket" "positive1" {
    bucket = "example"
    }

    resource "aws_s3_bucket_public_access_block" "positive2" {
    bucket = aws_s3_bucket.example.id

    block_public_acls = true
    block_public_policy = false
    ignore_public_acls = false
    }

    resource "aws_s3_bucket_public_access_block" "positive3" {
    bucket = aws_s3_bucket.example.id

    block_public_acls = true
    ignore_public_acls = false
    }

    Vulnerable pattern via module s3_bucket. Also, keep in mind that if block_public_policy is not defined then the bucket is still vulnerable:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"
    restrict_public_buckets = true
    block_public_acls = true
    block_public_policy = false

    versioning = {
    enabled = true
    }

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  2. Modify the config to something like the following:

    Replacement pattern via resource aws_s3_bucket_public_access_block:

    resource "aws_s3_bucket" "negative1" {
    bucket = "example"
    }

    resource "aws_s3_bucket_public_access_block" "negative2" {
    bucket = aws_s3_bucket.example.id

    block_public_acls = true
    block_public_policy = true
    ignore_public_acls = false
    }

    Replacement pattern via module s3_bucket:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"
    restrict_public_buckets = true
    block_public_acls = true
    block_public_policy = true

    versioning = {
    enabled = true
    }

    policy = <<POLICY
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::my_tf_test_bucket/*",
    "Condition": {
    "IpAddress": {"aws:SourceIp": "8.8.8.8/32"}
    }
    }
    ]
    }
    POLICY
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Buckets Are Publicly Available

Option A: Limit access to S3 buckets

In the context of Terraform, when an S3 bucket has a certain ACL it is publicly accessible. In some cases that doesn't just allow read access to the data of the bucket, but even write access. The following ACLs are flagged:

  • public-read
  • public-read-write
  • website

Follow the steps below:

  1. Go through the issues that GuardRails identified

  2. Review the affected buckets to determine whether the ACLs are correct

    resource "aws_s3_bucket" "b" {
    bucket = "my-tf-test-bucket"
    acl = "public-read-write"

    tags = {
    Name = "My bucket"
    Environment = "Dev"
    }
    }
  3. If not, then either remove the acl argument or change it to the right alternative

  4. Test the changes and ensure that everything is working as expected

  5. Ship it 🚢 and relax 🌴

Security Group is Not Configured

Azure Virtual Network subnet must be configured with a Network Security Group, which means the attribute security_group must be defined and not empty.

Rule-specific references:

Option A: Make sure your subnet has a non-empty Security Group

azure_virtual_network.subnet.security_group should be defined and have a non-empty value.

  1. Locate the following vulnerable pattern:

    resource "azure_virtual_network" "positive1" {
    name = "test-network"
    address_space = ["10.1.2.0/24"]
    location = "West US"

    subnet {
    name = "subnet1"
    address_prefix = "10.1.2.0/25"
    // Notice no security_group defined... so vulnerable.
    }
    }

    resource "azure_virtual_network" "positive2" {
    name = "test-network"
    address_space = ["10.1.2.0/24"]
    location = "West US"

    subnet {
    name = "subnet1"
    address_prefix = "10.1.2.0/25"
    // security_group defined but empty... still vulnerable
    security_group = ""
    }
    }
  2. Modify the config to something like the following:

    resource "azure_virtual_network" "negative1" {
    name = "test-network"
    address_space = ["10.1.2.0/24"]
    location = "West US"

    subnet {
    name = "subnet1"
    address_prefix = "10.1.2.0/25"
    security_group = "a"
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Security Group With Unrestricted Access To SSH

SSH (TCP:22) should not be exposed to the world via AWS Security Group. There is very rarely a need for ranges of IP addresses to be able to access SSH port 22.

Rule-specific references:

Option A: Only specify single IP addresses or a very small range that can access SSH port 22

All ingress rules of any given aws_security_group or module should not have port 22 open to the world.

  1. Locate one of the following vulnerable patterns:

    Vulnerable resource with single non constrained cidr block pattern:

    resource "aws_security_group" "positive1" {
    name = "allow_tls"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    }

    tags = {
    Name = "allow_tls"
    }
    }

    Vulnerable resource with multiple cidr blocks pattern:

    resource "aws_security_group" "positive2" {
    name = "allow_tls"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["192.120.0.0/16", "0.0.0.0/0"]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    }

    tags = {
    Name = "allow_tls"
    }
    }

    Vulnerable module with single non constrained cidr block pattern:

    module "vote_service_sg" {
    source = "terraform-aws-modules/security-group/aws"
    version = "4.3.0"
    name = "user-service"
    description = "Security group for user-service with custom ports open within VPC, and PostgreSQL publicly open"
    vpc_id = "vpc-12345678"

    ingress {
    description = "TLS from VPC"
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    }

    tags = {
    Name = "allow_tls"
    }
    }

    Vulnerable module with multiple cidr blocks pattern:

    module "vote_service_sg" {
    source = "terraform-aws-modules/security-group/aws"
    version = "4.3.0"
    name = "user-service"
    description = "Security group for user-service with custom ports open within VPC, and PostgreSQL publicly open"
    vpc_id = "vpc-12345678"

    ingress {
    description = "TLS from VPC"
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["192.120.0.0/16", "0.0.0.0/0"]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    }

    tags = {
    Name = "allow_tls"
    }
    }
  2. Modify the config to something like one of the following:

    Replacement resource with multiple constrained cidr blocks pattern:


    resource "aws_security_group" "negative1" {
    name = "allow_tls"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["192.120.0.0/16", "75.132.0.0/16"]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    }

    tags = {
    Name = "allow_tls"
    }
    }

    Replacement module with multiple constrained cidr blocks pattern:

    module "vote_service_sg" {
    source = "terraform-aws-modules/security-group/aws"
    version = "4.3.0"
    name = "user-service"
    description = "Security group for user-service with custom ports open within VPC, and PostgreSQL publicly open"
    vpc_id = "vpc-12345678"

    ingress {
    description = "TLS from VPC"
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["192.120.0.0/16", "75.132.0.0/16"]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    }

    tags = {
    Name = "allow_tls"
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Sensitive Port Is Exposed To Entire Network (Azure)

In regards to Azure Resource Manager, a sensitive port, such as port 23 or port 110, is open for the whole network in either TCP or UDP protocol.

This rule is positive if all of the following conditions are true:

  • azurerm_network_security_rule access is "Allow"
  • azurerm_network_security_rule protocol is "UDP or "TCP"
  • azurerm_network_security_rule source_address_prefix has value "/0"
  • azurerm_network_security_rule destination_port_range includes a sensitive port

Rule-specific references:

Option A: Change one of the above conditions

From the following vulnerable patterns, change one of the above conditions.

  1. Locate one of the following vulnerable patterns:

    resource "azurerm_network_security_rule" "positive1" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "61621"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive2" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23-34"
    source_address_prefix = "1.1.1.1/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive3" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "21-23"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive4" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "0.0.0.0/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive5" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "23,245"
    source_address_prefix = "34.15.11.3/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive6" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive7" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "22-64, 94"
    source_address_prefix = "10.0.0.0/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive8" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "14, 23, 48"
    source_address_prefix = "12.12.12.12/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive9" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "12, 23-24,46"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive10" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "46-146, 18-36, 1-2, 3"
    source_address_prefix = "1.2.3.4/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
  2. Modify the config to something like one of the following:

    resource "azurerm_network_security_rule" "negative1" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Deny"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative2" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "Icmp"
    source_port_range = "*"
    destination_port_range = "23-34"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative3" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "8-174"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative4" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23-196"
    source_address_prefix = "192.168.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative5" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "/1"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative6" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "43"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative7" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "Icmp"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "internet"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative8" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "22, 24,49-67"
    source_address_prefix = "any"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative9" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "Icmp"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative10" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23 , 69"
    source_address_prefix = "0.0.1.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative11" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "2,310"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Sensitive Port Is Exposed To Entire Network (AWS)

In regards to AWS, this means that one or more of the following condition-sets is true:

  • cidr_blocks includes a value that ends with "/0" and the port range includes a sensitive port
  • or cidr_blocks includes a value that ends with "/0" and protocol is not "tcp" or "udp"

Rule-specific references:

Option A: Remove or modify rules that match one or more of the above condition-sets

The following patterns attempt to exhibit vulnerable rules and possible replacements.

  1. Locate one of the following vulnerable patterns:

    Vulnerable pattern because:
    cidr_blocks includes a value that ends with "/0" and the port range includes a sensitive port.

    resource "aws_security_group" "positive1" {
    name = "allow_tls1"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 2200
    to_port = 2500
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    }
    }

    Vulnerable pattern because:
    cidr_blocks includes a value that ends with "/0" and the port range includes a sensitive port.

    resource "aws_security_group" "positive2" {
    name = "allow_tls2"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 20
    to_port = 60
    protocol = "tcp"
    cidr_blocks = ["/0"]
    }
    }

    Vulnerable pattern because:
    cidr_blocks includes a value that ends with "/0" and the port range includes a sensitive port.
    cidr_blocks includes a value that ends with "/0" and protocol is not "tcp" or "udp".

    resource "aws_security_group" "positive3" {
    name = "allow_tls3"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {The following patterns attempt to exhibit vulnerable rules and possible replacements.

    Vulnerable pattern because:
    `cidr_blocks` includes a value that ends with "/0" and the port range includes a sensitive port.

    ```hcl
    resource "aws_security_group" "positive4" {
    name = "allow_tls4"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 20
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["/0"]
    }
    }

    Vulnerable pattern because:
    cidr_blocks includes a value that ends with "/0" and the port range includes a sensitive port.

    resource "aws_security_group" "positive5" {
    name = "allow_tls5"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 445
    to_port = 500
    protocol = "udp"
    cidr_blocks = ["1.1.1.1/1","0.0.0.0/0", "2.2.3.4/12"]
    }
    }

    Vulnerable pattern because:
    cidr_blocks includes a value that ends with "/0" and the port range includes a sensitive port.

    resource "aws_security_group" "positive6" {
    name = "allow_tls6"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 135
    to_port = 170
    protocol = "udp"
    cidr_blocks = ["10.68.0.0", "0.0.0.0/0"]
    }
    }

    Vulnerable pattern because:
    cidr_blocks includes a value that ends with "/0" and the port range includes a sensitive port.

    resource "aws_security_group" "positive7" {
    name = "allow_tls7"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 2383
    to_port = 2383
    protocol = "udp"
    cidr_blocks = ["/0", "1.2.3.4/12"]
    }
    }

    Vulnerable pattern because:
    cidr_blocks includes a value that ends with "/0" and protocol is not "tcp" or "udp".

    resource "aws_security_group" "positive8" {
    name = "allow_tls8"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["/0"]
    }
    }
  2. Modify the config to something like one of the following:

    Replacement pattern because:
    Only one condition (sensitive port) exists, so not vulnerable.

    resource "aws_security_group" "negative1" {
    name = "allow_tls1"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 2383
    to_port = 2383
    protocol = "tcp"
    cidr_blocks = [aws_vpc.main.cidr_block]
    }
    }

    Replacement pattern because:
    Only one condition (open cidr block) exists, so not vulnerable.

    resource "aws_security_group" "negative2" {
    name = "allow_tls2"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 2384
    to_port = 2386
    protocol = "tcp"
    cidr_blocks = ["/0"]
    }
    }

    Replacement pattern because:
    Only one condition (sensitive port range) exists, so not vulnerable.

    resource "aws_security_group" "negative3" {
    name = "allow_tls3"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 25
    to_port = 2500
    protocol = "tcp"
    cidr_blocks = ["1.2.3.4/5"]
    }
    }

    Replacement pattern because:
    Only one condition (sensitive port range) exists, so not vulnerable.

    resource "aws_security_group" "negative4" {
    name = "allow_tls4"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 25
    to_port = 2500
    protocol = "tcp"
    cidr_blocks = ["1.2.3.4/5"]
    }
    }

    Replacement pattern because:
    Only one condition (sensitive port range) exists, so not vulnerable.

    resource "aws_security_group" "negative5" {
    name = "allow_tls5"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 25
    to_port = 2500
    protocol = "udp"
    cidr_blocks = ["1.2.3.4/5","0.0.0.0/12"]
    }
    }

    Replacement pattern because:
    Only one condition (protocol is not "tcp" or "udp") exists, so not vulnerable.

    resource "aws_security_group" "negative6" {
    name = "allow_tls6"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["1.2.3.4/5","0.0.0.0/12"]
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

SQL DB Instance Is Publicly Accessible

Google Cloud SQL instances should not be publicly accessible.

Rule-specific references:

Option A: Make the following changes as necessary

  • authorized_network address must be trusted (not allow all (0.0.0.0/0))
  • ipv4_enabled is disabled and private_network is defined when there are no authorized_networks
  • If there are no authorized_networks ipv4_enabled must be disabled (have a value of false) and private_network must be defined
  • ip_configuration must be defined and allow only trusted networks
  1. Locate one of the following vulnerable patterns:

    resource "google_sql_database_instance" "positive1" {
    name = "master-instance"
    database_version = "POSTGRES_11"
    region = "us-central1"

    settings {
    # Second-generation instance tiers are based on the machine
    # type. See argument reference below.
    tier = "db-f1-micro"
    }
    }

    resource "google_sql_database_instance" "positive2" {
    name = "postgres-instance-2"
    database_version = "POSTGRES_11"

    settings {
    tier = "db-f1-micro"

    ip_configuration {

    authorized_networks {
    name = "pub-network"
    value = "0.0.0.0/0"
    }
    }
    }
    }

    resource "google_sql_database_instance" "positive3" {
    name = "master-instance"
    database_version = "POSTGRES_11"
    region = "us-central1"

    settings {
    # Second-generation instance tiers are based on the machine
    # type. See argument reference below.
    tier = "db-f1-micro"

    ip_configuration {
    ipv4_enabled = true
    }
    }
    }

    resource "google_sql_database_instance" "positive4" {
    name = "master-instance"
    database_version = "POSTGRES_11"
    region = "us-central1"

    settings {
    # Second-generation instance tiers are based on the machine
    # type. See argument reference below.
    tier = "db-f1-micro"

    ip_configuration {}
    }
    }
  2. Modify the config to something like the following replacement patterns:

    resource "google_sql_database_instance" "negative1" {

    name = "private-instance-1"
    database_version = "POSTGRES_11"
    settings {
    ip_configuration {
    ipv4_enabled = false
    private_network = "some_private_network"
    }
    }
    }

    resource "google_sql_database_instance" "negative2" {
    name = "postgres-instance-2"
    database_version = "POSTGRES_11"

    settings {
    tier = "db-f1-micro"

    ip_configuration {

    authorized_networks {

    content {
    name = "some_trusted_network"
    value = "some_trusted_network_address"
    }
    }

    authorized_networks {

    content {
    name = "another_trusted_network"
    value = "another_trusted_network_address"
    }
    }
    }
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Unrestricted Security Group Ingress

AWS Security Group should restrict ingress access.

Rule-specific references:

Option A: Make the following changes as necessary

  • aws_security_group_rule of type "ingress" must not have it's cidr_blocks list containing "0.0.0.0/0"
  • aws_security_group must not have it's ingress.cidr_blocks containing "0.0.0.0/0"
  • ingress_cidr_blocks must not contain "0.0.0.0/0"
  1. Locate one of the following vulnerable patterns:

    Vulnerable aws_security_group_rule.cidr_blocks pattern:

    resource "aws_security_group_rule" "positive1" {
    type = "ingress"
    from_port = 3306
    to_port = 3306
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    security_group_id = aws_security_group.default.id
    }

    Vulnerable aws_security_group.ingress.cidr_blocks pattern:

    resource "aws_security_group" "positive2" {
    ingress {
    from_port = 3306
    to_port = 3306
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    security_group_id = aws_security_group.default.id
    }
    }

    Vulnerable aws_security_group multiple ingress cidr_blocks pattern:

    resource "aws_security_group" "positive3" {
    ingress {
    from_port = 3306
    to_port = 3306
    protocol = "tcp"
    cidr_blocks = ["1.0.0.0/0"]
    }

    ingress {
    from_port = 3306
    to_port = 3306
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    }
    }

    Vulnerable ingress_cidr_blocks pattern:

    module "web_server_sg" {
    source = "terraform-aws-modules/security-group/aws"
    version = "4.3.0"

    name = "web-server"
    description = "Security group for web-server with HTTP ports open within VPC"
    vpc_id = "vpc-12345678"

    ingress_cidr_blocks = ["0.0.0.0/0"]
    }

    Vulnerable multiple elements in ingress_cidr_blocks pattern:

    module "web_server_sg" {
    source = "terraform-aws-modules/security-group/aws"
    version = "4.3.0"

    name = "web-server"
    description = "Security group for web-server with HTTP ports open within VPC"
    vpc_id = "vpc-12345678"

    ingress_cidr_blocks = ["10.10.0.0/16", "0.0.0.0/0"]
    }
  2. Modify the config to something like the following:

    Replacement aws_security_group_rule.cidr_blocks pattern:

    resource "aws_security_group_rule" "negative1" {
    type = "ingress"
    from_port = 3306
    to_port = 3306
    protocol = "tcp"
    cidr_blocks = ["0.0.2.0/0"]
    security_group_id = aws_security_group.default.id
    }

    Replacement aws_security_group.ingress.cidr_blocks pattern:

    resource "aws_security_group" "negative2" {
    ingress {
    from_port = 3306
    to_port = 3306
    protocol = "tcp"
    cidr_blocks = ["0.0.2.0/0"]
    security_group_id = aws_security_group.default.id
    }
    }

    Replacement aws_security_group multiple ingress cidr_blocks pattern:

    resource "aws_security_group" "negative3" {
    ingress {
    from_port = 3306
    to_port = 3306
    protocol = "tcp"
    cidr_blocks = ["1.0.0.0/0"]
    }

    ingress {
    from_port = 3306
    to_port = 3306
    protocol = "tcp"
    cidr_blocks = ["0.0.1.0/0"]
    }
    }

    Replacement ingress_cidr_blocks pattern:

    module "web_server_sg" {
    source = "terraform-aws-modules/security-group/aws"
    version = "4.3.0"

    name = "web-server"
    description = "Security group for web-server with HTTP ports open within VPC"
    vpc_id = "vpc-12345678"

    ingress_cidr_blocks = ["10.10.0.0/16"]
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

VPC Default Security Group Accepts All Traffic

The default Security Group attached to every VPC should restrict all traffic.

Rule-specific references:

Option A: Remove any ingress or egress rules from AWS Default Security Group

aws_default_security_group should not have any ingress or egress rules defined.

  1. Locate one of the following vulnerable patterns:

    resource "aws_vpc" "mainvpc" {
    cidr_block = "10.1.0.0/16"
    }

    resource "aws_default_security_group" "default" {
    vpc_id = aws_vpc.mainvpc.id

    ingress = [
    {
    protocol = -1
    self = true
    from_port = 0
    to_port = 0
    }
    ]

    egress = [
    {
    from_port = 0
    to_port = 0
    protocol = "-1"
    }
    ]
    }
    resource "aws_vpc" "mainvpc3" {
    cidr_block = "10.1.0.0/16"
    }

    resource "aws_default_security_group" "default3" {
    vpc_id = aws_vpc.mainvpc3.id

    ingress = [
    {
    protocol = -1
    self = true
    from_port = 0
    to_port = 0
    ipv6_cidr_blocks = ["::/0"]
    }
    ]

    egress = [
    {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    }
    ]
    }
  2. Modify the config to something like the following:

    resource "aws_vpc" "mainvpc2" {
    cidr_block = "10.1.0.0/16"
    }

    resource "aws_default_security_group" "default2" {
    vpc_id = aws_vpc.mainvpc2.id
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Network ACL With Unrestricted Access To SSH

SSH (TCP:22) should not be public in AWS Network ACL.

Rule-specific references:

Option A: Do not have SSH (port 22) open to the world

Do not have SSH (port 22) open to the world (0.0.0.0/0). Instead, you should ideally use single IP addresses.

  1. Locate one or more of the following vulnerable patterns:

    Vulnerable aws_network_acl with embedded ingress list pattern:

    provider "aws" {
    region = "us-east-1"
    }

    terraform {
    required_providers {
    aws = {
    source = "hashicorp/aws"
    version = "~> 3.0"
    }
    }
    }

    resource "aws_network_acl" "positive1" {
    vpc_id = aws_vpc.main.id

    egress = [
    {
    protocol = "tcp"
    rule_no = 200
    action = "allow"
    cidr_block = "10.3.0.0/18"
    from_port = 443
    to_port = 443
    }
    ]

    ingress = [
    {
    protocol = "tcp"
    rule_no = 100
    action = "allow"
    cidr_block = "0.0.0.0/0"
    from_port = 22
    to_port = 22
    }
    ]

    tags = {
    Name = "main"
    }
    }

    Vulnerable aws_network_acl with embedded ingress map pattern:

    provider "aws" {
    region = "us-east-1"
    }

    terraform {
    required_providers {
    aws = {
    source = "hashicorp/aws"
    version = "3.52.0"
    }
    }
    }

    resource "aws_network_acl" "positive3" {
    vpc_id = aws_vpc.main.id

    egress {
    protocol = "tcp"
    rule_no = 200
    action = "allow"
    cidr_block = "10.3.0.0/18"
    from_port = 443
    to_port = 443
    }

    ingress {
    protocol = "tcp"
    rule_no = 100
    action = "allow"
    cidr_block = "0.0.0.0/0"
    from_port = 22
    to_port = 22
    }

    tags = {
    Name = "main"
    }
    }

    Vulnerable aws_network_acl_rule pattern:

    provider "aws" {
    region = "us-east-1"
    }

    terraform {
    required_providers {
    aws = {
    source = "hashicorp/aws"
    version = "~> 3.0"
    }
    }
    }

    resource "aws_network_acl" "positive2" {
    vpc_id = aws_vpc.main.id

    tags = {
    Name = "main"
    }
    }

    resource "aws_network_acl_rule" "postive2" {
    network_acl_id = aws_network_acl.positive2.id
    rule_number = 100
    egress = false
    protocol = "tcp"
    rule_action = "allow"
    from_port = 22
    to_port = 22
    cidr_block = "0.0.0.0/0"
    }

    Vulnerable default_network_acl_ingress list pattern:

    module "vpc" {
    source = "terraform-aws-modules/vpc/aws"
    version = "3.7.0"

    name = "my-vpc"
    cidr = "10.0.0.0/16"

    azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
    private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
    public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

    default_network_acl_ingress = [
    {
    "action" : "allow",
    "cidr_block" : "0.0.0.0/0",
    "from_port" : 0,
    "protocol" : "tcp",
    "rule_no" : 22,
    "to_port" : 0
    }
    ]

    enable_nat_gateway = true
    enable_vpn_gateway = true

    tags = {
    Terraform = "true"
    Environment = "dev"
    }
    }
  2. Modify the config to something like one of the following:

    Replacement aws_network_acl with embedded ingress list pattern:

    provider "aws" {
    region = "us-east-1"
    }

    terraform {
    required_providers {
    aws = {
    source = "hashicorp/aws"
    version = "~> 3.0"
    }
    }
    }

    resource "aws_network_acl" "negative1" {
    vpc_id = aws_vpc.main.id

    egress = [
    {
    protocol = "tcp"
    rule_no = 200
    action = "allow"
    cidr_block = "10.3.0.0/18"
    from_port = 443
    to_port = 443
    }
    ]

    ingress = [
    {
    protocol = "tcp"
    rule_no = 100
    action = "allow"
    // Or better still... Provide single IP addresses.
    cidr_block = "10.3.0.0/18"
    from_port = 22
    to_port = 22
    }
    ]

    tags = {
    Name = "main"
    }
    }

    Replacement aws_network_acl with embedded ingress map pattern:

    provider "aws" {
    region = "us-east-1"
    }

    terraform {
    required_providers {
    aws = {
    source = "hashicorp/aws"
    version = "3.52.0"
    }
    }
    }

    resource "aws_network_acl" "negative3" {
    vpc_id = aws_vpc.main.id

    egress {
    protocol = "tcp"
    rule_no = 200
    action = "allow"
    cidr_block = "10.3.0.0/18"
    from_port = 443
    to_port = 443
    }

    ingress {
    protocol = "tcp"
    rule_no = 100
    action = "allow"
    // Or better still... Provide single IP addresses.
    cidr_block = "10.3.0.0/18"
    from_port = 22
    to_port = 22
    }

    tags = {
    Name = "main"
    }
    }

    Replacement aws_network_acl_rule pattern:

    provider "aws" {
    region = "us-east-1"
    }

    terraform {
    required_providers {
    aws = {
    source = "hashicorp/aws"
    version = "~> 3.0"
    }
    }
    }

    resource "aws_network_acl" "negative2" {
    vpc_id = aws_vpc.main.id

    tags = {
    Name = "main"
    }
    }

    resource "aws_network_acl_rule" "negative2" {
    network_acl_id = aws_network_acl.positive1.id
    rule_number = 100
    egress = false
    protocol = "tcp"
    rule_action = "allow"
    from_port = 22
    to_port = 22
    // Or better still... Provide single IP addresses.
    cidr_block = "10.3.0.0/18"
    }

    Replacement no default_network_acl_ingress list pattern:

    module "vpc" {
    source = "terraform-aws-modules/vpc/aws"
    version = "3.7.0"

    name = "my-vpc"
    cidr = "10.0.0.0/16"

    azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
    private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
    public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

    enable_nat_gateway = true
    enable_vpn_gateway = true

    tags = {
    Terraform = "true"
    Environment = "dev"
    }
    }

    Replacement default_network_acl_ingress list pattern:

    module "vpc" {
    source = "terraform-aws-modules/vpc/aws"
    version = "3.7.0"

    name = "my-vpc"
    cidr = "10.0.0.0/16"

    azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
    private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
    public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

    default_network_acl_ingress = [
    {
    "action" : "allow",
    "cidr_block" : "0.0.0.0/0",
    "from_port" : 0,
    "protocol" : "-1",
    "rule_no" : 100,
    "to_port" : 0
    },
    {
    "action" : "allow",
    "cidr_block" : "10.3.0.0/18",
    "from_port" : 0,
    "protocol" : "-1",
    "rule_no" : 22,
    "to_port" : 0
    }
    ]

    enable_nat_gateway = true
    enable_vpn_gateway = true

    tags = {
    Terraform = "true"
    Environment = "dev"
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Remote Desktop Port Open

The Remote Desktop port (3389) is open. If you need to provide Remote Desktop communications to an EC2 instance consider doing so via a VPN or SSH tunnel.

Rule-specific references:

Option A: Close the Remote Desktop ingress port (3389).

ingress rules of aws_security_group should not have an RDP port open.

Sensitive Port Is Exposed To Small Public Network

Azure

A sensitive port, such as port 23 or port 110, is open for a small public network in either TCP or UDP protocol.

This means that all of the following conditions must be true in order to match this rule and be vulnerable:

  • resource azurerm_network_security_rule access = "Allow"
  • and resource azurerm_network_security_rule destination_port_range needs to be assigned a value containing a sensitive port
  • and resource azurerm_network_security_rule source_address_prefix contains one of ("/25", "/26", "/27", "/28", "/29")

Rule-specific references:

Option A: Remove or modify rules that match all of the above conditions

The following patterns attempt to exhibit vulnerable rules and possible replacements.

  1. Locate one of the following vulnerable patterns:

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive2" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23-34"
    source_address_prefix = "1.1.1.1/25"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive3" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "21-23"
    source_address_prefix = "/26"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive4" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "0.0.0.0/27"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive5" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "23,245"
    source_address_prefix = "34.15.11.3/28"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive6" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "/29"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive7" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "22-64, 94"
    source_address_prefix = "10.0.0.0/28"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive8" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "14, 23, 48"
    source_address_prefix = "12.12.12.12/27"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive9" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "12, 23-24,46"
    source_address_prefix = "/26"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive10" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "46-146, 18-36, 1-2, 3"
    source_address_prefix = "1.2.3.4/25"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
  2. Modify the config to something like one of the following:

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative1" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Deny"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative2" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "Icmp"
    source_port_range = "*"
    destination_port_range = "23-34"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative3" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "8-174"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative4" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23-196"
    source_address_prefix = "192.168.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative5" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "/1"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative6" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "43"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative7" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "Icmp"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "internet"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative8" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "22, 24,49-67"
    source_address_prefix = "any"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative9" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "Icmp"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative10" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23 , 69"
    source_address_prefix = "0.0.1.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative11" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "2,310"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Sensitive Port Is Exposed To Small Public Network

AWS

A sensitive port, such as port 23 or port 110, is open for a small public network in either TCP or UDP protocol.

This means that all of the following conditions must be true in order to match this rule and be vulnerable:

  • resource aws_security_group source_address_prefix contains one of ("/25", "/26", "/27", "/28", "/29")
  • and destination_port_range needs to be assigned a value containing a sensitive port

Rule-specific references:

Option A: Remove or modify rules that match all of the above conditions

The following patterns attempt to exhibit vulnerable rules and possible replacements.

  1. Locate the following vulnerable pattern:

    Vulnerable pattern:

    resource "aws_security_group" "positive1" {
    name = "allow_tls1"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 2200
    to_port = 2500
    protocol = "-1"
    cidr_blocks = ["12.0.0.0/25"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive2" {
    name = "allow_tls2"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 20
    to_port = 60
    protocol = "tcp"
    cidr_blocks = ["1.2.3.4/26"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive3" {
    name = "allow_tls3"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 5000
    to_port = 6000
    protocol = "-1"
    cidr_blocks = ["2.12.22.33/27"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive4" {
    name = "allow_tls4"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 20
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["10.92.168.0/28"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive5" {
    name = "allow_tls5"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 445
    to_port = 500
    protocol = "udp"
    cidr_blocks = ["1.1.1.1/29","0.0.0.0/0", "2.2.3.4/12"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive6" {
    name = "allow_tls6"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 135
    to_port = 170
    protocol = "udp"
    cidr_blocks = ["10.68.0.0", "0.0.0.0/28"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive7" {
    name = "allow_tls7"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 2383
    to_port = 2383
    protocol = "udp"
    cidr_blocks = ["/0", "1.2.3.4/27"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive8" {
    name = "allow_tls8"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["10.68.0.0/26"]
    }
    }

  2. Modify the config to something like one of the following:

    Replacement pattern:

    resource "aws_security_group" "negative1" {
    name = "allow_tls1"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 2383
    to_port = 2383
    protocol = "tcp"
    cidr_blocks = [aws_vpc.main.cidr_block]
    }
    }

    Replacement pattern:

    resource "aws_security_group" "negative2" {
    name = "allow_tls2"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 2384
    to_port = 2386
    protocol = "tcp"
    cidr_blocks = ["/0"]
    }
    }

    Replacement pattern:

    resource "aws_security_group" "negative3" {
    name = "allow_tls3"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 25
    to_port = 2500
    protocol = "tcp"
    cidr_blocks = ["1.2.3.4/0"]
    }
    }

    Replacement pattern:

    resource "aws_security_group" "negative4" {
    name = "allow_tls4"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 25
    to_port = 2500
    protocol = "tcp"
    cidr_blocks = ["1.2.3.4/5"]
    }
    }

    Replacement pattern:

    resource "aws_security_group" "negative5" {
    name = "allow_tls5"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 25
    to_port = 2500
    protocol = "udp"
    cidr_blocks = ["1.2.3.4/5","0.0.0.0/12"]
    }
    }

    Replacement pattern:

    resource "aws_security_group" "negative6" {
    name = "allow_tls6"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["1.2.3.4","0.0.0.0/0"]
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Sensitive Port Is Exposed To Wide Private Network

Azure

A sensitive port, such as port 23 or port 110, is open for a wide private network in either TCP or UDP protocol.

This means that all of the following conditions must be true in order to match this rule and be vulnerable:

  • resource azurerm_network_security_rule access = "Allow"
  • and resource azurerm_network_security_rule destination_port_range needs to be assigned a value containing a sensitive port
  • and resource azurerm_network_security_rule source_address_prefix must be in the range of ["10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"]

Rule-specific references:

Option A: Remove or modify rules that match all of the above conditions

The following patterns attempt to exhibit vulnerable rules and possible replacements.

  1. Locate one of the following vulnerable patterns:

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive1" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "61621"
    source_address_prefix = "172.16.0.0/12"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive2" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23-34"
    source_address_prefix = "172.16.0.0/12"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive3" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "21-23"
    source_address_prefix = "172.16.0.0/12"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive4" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "192.168.0.0/16"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive5" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "23,245"
    source_address_prefix = "192.168.0.0/16"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive6" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "192.168.0.0/16"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive7" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "22-64, 94"
    source_address_prefix = "10.0.0.0/8"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive8" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "14, 23, 48"
    source_address_prefix = "10.0.0.0/8"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive9" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "12, 23-24,46"
    source_address_prefix = "10.0.0.0/8"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Vulnerable pattern:

    resource "azurerm_network_security_rule" "positive10" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "46-146, 18-36, 1-2, 3"
    source_address_prefix = "10.0.0.0/8"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
  2. Modify the config to something like one of the following:

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative1" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Deny"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative2" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "Icmp"
    source_port_range = "*"
    destination_port_range = "23-34"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative3" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "8-174"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative4" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23-196"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative5" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "/1"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative6" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "43"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative7" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "Icmp"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "internet"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative8" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "22, 24,49-67"
    source_address_prefix = "any"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative9" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "Icmp"
    source_port_range = "*"
    destination_port_range = "23"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative10" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "23 , 69"
    source_address_prefix = "0.0.1.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }

    Replacement pattern:

    resource "azurerm_network_security_rule" "negative11" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "2,310"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Sensitive Port Is Exposed To Wide Private Network

AWS

A sensitive port, such as port 23 or port 110, is open for a wide private network in either TCP or UDP protocol.

This means that all of the following resource conditions must be true in order to match this rule and be vulnerable
or all of the following module conditions must be true in order to match this rule and be vulnerable:

resource conditions:

  • resource aws_security_group ingress.from_port - ingress.to_port range needs to be assigned a value containing a sensitive port
  • resource aws_security_group ingress.cidr_blocks must be in the range of ["10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"]

module conditions:

  • modules containing ingress_with_cidr_blocks ingress.from_port - ingress.to_port range needs to be assigned a value containing a sensitive port
  • modules containing ingress_with_cidr_blocks ingress.cidr_blocks must be in the range of ["10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"]

Rule-specific references:

Option A: Remove or modify rules that match all of the above conditions

The following patterns attempt to exhibit vulnerable rules and possible replacements.

  1. Locate one of the following vulnerable patterns:

    Vulnerable pattern:

    resource "aws_security_group" "positive1" {
    name = "allow_tls1"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 2200
    to_port = 2500
    protocol = "-1"
    cidr_blocks = ["10.0.0.0/8"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive2" {
    name = "allow_tls2"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 20
    to_port = 60
    protocol = "tcp"
    cidr_blocks = ["192.168.0.0/16"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive3" {
    name = "allow_tls3"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 5000
    to_port = 6000
    protocol = "-1"
    cidr_blocks = ["172.16.0.0/12"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive4" {
    name = "allow_tls4"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 20
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["10.0.0.0/8"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive5" {
    name = "allow_tls5"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 445
    to_port = 500
    protocol = "udp"
    cidr_blocks = ["192.168.0.0/16", "0.0.0.0/0", "2.2.3.4/12"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive6" {
    name = "allow_tls6"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 135
    to_port = 170
    protocol = "udp"
    cidr_blocks = ["10.68.0.0", "172.16.0.0/12"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive7" {
    name = "allow_tls7"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 2383
    to_port = 2383
    protocol = "udp"
    cidr_blocks = ["192.168.0.0/16", "10.0.0.0/8"]
    }
    }

    Vulnerable pattern:

    resource "aws_security_group" "positive8" {
    name = "allow_tls8"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["172.16.0.0/12"]
    }
    }

    Vulnerable pattern:

    module "vote_service_sg" {
    source = "terraform-aws-modules/security-group/aws"
    version = "4.3.0"

    name = "user-service"
    description = "Security group for user-service with custom ports open within VPC, and PostgreSQL publicly open"
    vpc_id = "vpc-12345678"

    ingress_with_cidr_blocks = [
    {
    description = "TLS from VPC"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["172.16.0.0/12"]
    }
    ]
    }
  2. Modify the config to something like one of the following:

    Replacement pattern:

    resource "aws_security_group" "negative1" {
    name = "allow_tls1"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 2383
    to_port = 2383
    protocol = "tcp"
    cidr_blocks = [aws_vpc.main.cidr_block]
    }
    }

    Replacement pattern:

    resource "aws_security_group" "negative2" {
    name = "allow_tls2"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 2384
    to_port = 2386
    protocol = "tcp"
    cidr_blocks = ["/0"]
    }
    }

    Replacement pattern:

    resource "aws_security_group" "negative3" {
    name = "allow_tls3"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 25
    to_port = 2500
    protocol = "tcp"
    cidr_blocks = ["1.2.3.4/0"]
    }
    }

    Replacement pattern:

    resource "aws_security_group" "negative4" {
    name = "allow_tls4"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 25
    to_port = 2500
    protocol = "tcp"
    cidr_blocks = ["1.2.3.4/5"]
    }
    }

    Replacement pattern:

    resource "aws_security_group" "negative5" {
    name = "allow_tls5"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 25
    to_port = 2500
    protocol = "udp"
    cidr_blocks = ["1.2.3.4/5", "0.0.0.0/12"]
    }
    }

    Replacement pattern:

    resource "aws_security_group" "negative6" {
    name = "allow_tls6"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["1.2.3.4", "0.0.0.0/0"]
    }
    }

    Replacement pattern:

    module "vote_service_sg" {
    source = "terraform-aws-modules/security-group/aws"
    version = "4.3.0"

    name = "user-service"
    description = "Security group for user-service with custom ports open within VPC, and PostgreSQL publicly open"
    vpc_id = "vpc-12345678"

    ingress_with_cidr_blocks = [
    {
    description = "TLS from VPC"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["1.2.3.4", "0.0.0.0/0"]
    }
    ]
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

SSH Access Is Not Restricted

Check if Google Firewall allows SSH access (port 22) from the Internet (public CIDR block).

Rule-specific references:

Option A: Must not have port 22 (SSH) open on Ingress rule that allows all

  • For google_compute_firewall where direction is "INGRESS" (can be specific or default)
  • And google_compute_firewall source_ranges includes a cidr block that allows all
  • google_compute_firewall allow.ports must not include SSH port 22
  1. Locate one of the following vulnerable patterns:

    Vulnerable specific "INGRESS" pattern:

    resource "google_compute_firewall" "positive1" {
    name = "test-firewall"
    network = google_compute_network.default.name
    // Default is "INGRESS"
    direction = "INGRESS"
    source_ranges = ["0.0.0.0/0"]

    allow {
    protocol = "icmp"
    }

    allow {
    protocol = "tcp"
    ports = ["22", "80", "3389", "8080", "1000-2000"]
    }

    source_tags = ["web"]
    }

    Vulnerable default "INGRESS" pattern

    resource "google_compute_firewall" "positive2" {
    name = "test-firewall"
    network = google_compute_network.default.name

    source_ranges = ["0.0.0.0/0"]

    allow {
    protocol = "icmp"
    }

    allow {
    protocol = "tcp"
    ports = ["80", "8080", "1000-2000","21-3390"]
    }

    source_tags = ["web"]
    }
  2. Modify the config to something like the following:

    Replacement pattern:

    resource "google_compute_firewall" "negative1" {
    name = "test-firewall"
    network = google_compute_network.default.name

    allow {
    protocol = "icmp"
    }

    allow {
    protocol = "tcp"
    ports = ["80", "8080", "1000-2000"]
    }

    source_tags = ["web"]
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

SSH Is Exposed To The Internet

Port 22 (SSH) is exposed to the internet.

This rule is positive if all of the following conditions are true:

  • azurerm_network_security_rule access is "Allow"
  • azurerm_network_security_rule protocol is not "UDP and is not "ICMP"
  • azurerm_network_security_rule source_address_prefix is one of the following "*", "0.0.0.0", "/0", "internet", "any"
  • azurerm_network_security_rule destination_port_range includes 22

Rule-specific references:

Option A: Change one of the above conditions

From the following vulnerable patterns, change one of the above conditions.

  1. Locate one of the following vulnerable patterns:

    resource "azurerm_network_security_rule" "positive1" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "22"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive2" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "22-23"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive3" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "21-53"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive4" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "22"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive5" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "22,24"
    source_address_prefix = "34.15.11.3/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive6" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "22"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive7" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "21-24, 230"
    source_address_prefix = "internet"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive8" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "21, 22 , 24 "
    source_address_prefix = "any"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive9" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "21, 22-23,2250"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "positive10" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "111-211, 20-30, 1-2 , 3"
    source_address_prefix = "internet"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
  2. Modify the config to something like one of the following:

    resource "azurerm_network_security_rule" "negative1" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Deny"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "22"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative2" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "20-50"
    source_address_prefix = "*"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative3" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "30-50"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative4" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "20-50"
    source_address_prefix = "192.168.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative5" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "22"
    source_address_prefix = "/1"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative6" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "21"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative7" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "22"
    source_address_prefix = "internet"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative8" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "*"
    source_port_range = "*"
    destination_port_range = "21, 23,10-20"
    source_address_prefix = "any"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative9" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "UDP"
    source_port_range = "*"
    destination_port_range = "22"
    source_address_prefix = "/0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative10" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "22 , 23"
    source_address_prefix = "0.0.1.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
    resource "azurerm_network_security_rule" "negative11" {
    name = "example"
    priority = 100
    direction = "Inbound"
    access = "Allow"
    protocol = "TCP"
    source_port_range = "*"
    destination_port_range = "220,230"
    source_address_prefix = "0.0.0.0"
    destination_address_prefix = "*"
    resource_group_name = azurerm_resource_group.example.name
    network_security_group_name = azurerm_network_security_group.example.name
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Default AWS Security Groups With Unrestricted Traffic

Checks that the default security group does not restrict all inbound and outbound traffic. Security Groups set as default must deny traffic.

Rule-specific references:

Option A: Replace any CIDR values allowing all with restrictive alternatives

For aws_default_security_groups

  • ingress.cidr_blocks or egress.cidr_blocks must not contain the value "0.0.0.0/0"
  • And ingress.ipv6_cidr_blocks or egress.ipv6_cidr_blocks must not contain the value "::/0"
  1. Locate the following vulnerable patterns:

    resource "aws_default_security_group" "positive1" {
    vpc_id = aws_vpc.mainvpc.id

    ingress {
    protocol = -1
    self = true
    from_port = 0
    to_port = 0
    // Vulnerable.
    cidr_blocks = ["0.0.0.0/0"]
    }
    }

    resource "aws_default_security_group" "positive2" {
    vpc_id = aws_vpc.mainvpc.id

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    // Vulnerable.
    ipv6_cidr_blocks = ["::/0"]
    }
    }

    resource "aws_default_security_group" "positive3" {
    vpc_id = aws_vpc.mainvpc.id

    ingress {
    protocol = -1
    self = true
    from_port = 0
    to_port = 0
    // Vulnerable.
    cidr_blocks = ["0.0.0.0/0"]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    // Vulnerable.
    ipv6_cidr_blocks = ["::/0"]
    }
    }
  2. Modify the config to something like the following:

    resource "aws_default_security_group" "negative1" {
    vpc_id = aws_vpc.mainvpc.id

    ingress {
    protocol = -1
    self = true
    from_port = 0
    to_port = 0
    // Not vulnerable.
    cidr_blocks = ["10.1.0.0/16"]
    ipv6_cidr_blocks = ["250.250.250.1:8451"]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    // Not vulnerable.
    cidr_blocks = ["10.1.0.0/16"]
    ipv6_cidr_blocks = ["250.250.250.1:8451"]
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Security Group Not Used

Security groups must be used.

Rule-specific references:

Option A: Locate a Vulnerable pattern similar to the following vulnerable patterns and replace it with the suggested pattern

  1. Locate one of the following vulnerable patterns:

    Vulnerable aws_lb not using security_groups pattern:

    resource "aws_security_group" "allow_tls" {
    name = "allow_tls"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 443
    to_port = 443
    protocol = "tcp"
    cidr_blocks = [aws_vpc.main.cidr_block]
    ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
    }

    tags = {
    Name = "allow_tls"
    }
    }

    resource "aws_lb" "test" {
    name = "test"
    load_balancer_type = "application"
    subnets = [aws_subnet.subnet1.id, aws_subnet.subnet2.id]
    internal = true
    }

    Vulnerable aws_instance not using security_groups pattern:

    resource "aws_security_group" "unused_sg" {
    name = "unused-sg"
    description = "Unused security group"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "Some port"
    from_port = 42
    to_port = 42
    protocol = "tcp"
    cidr_blocks = [aws_vpc.main.cidr_block]
    ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
    }

    }

    resource "aws_security_group" "used_sg" {
    name = "used-sg"
    description = "Used security group"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "Some port"
    from_port = 43
    to_port = 43
    protocol = "tcp"
    cidr_blocks = [aws_vpc.main.cidr_block]
    ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
    }

    }

    resource "aws_instance" "positive1" {
    ami = "ami-003634241a8fcdec0"

    instance_type = "t2.micro"

    vpc_security_group_ids = [ aws_security_group.used_sg.id ]
    }
  2. Modify the config to something like one of the following:

    Replacement aws_lb using security_groups pattern:

    resource "aws_security_group" "allow_tls" {
    name = "allow_tls"
    description = "Allow TLS inbound traffic"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "TLS from VPC"
    from_port = 443
    to_port = 443
    protocol = "tcp"
    cidr_blocks = [aws_vpc.main.cidr_block]
    ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
    }

    tags = {
    Name = "allow_tls"
    }
    }

    resource "aws_lb" "test" {
    name = "test"
    load_balancer_type = "application"
    subnets = [aws_subnet.subnet1.id, aws_subnet.subnet2.id]
    internal = true
    security_groups = [aws_security_group.allow_tls.id]
    }

    Replacement aws_instance using security_groups pattern:

    resource "aws_security_group" "used_sg" {
    name = "used-sg"
    description = "Used security group"
    vpc_id = aws_vpc.main.id

    ingress {
    description = "Some port"
    from_port = 43
    to_port = 43
    protocol = "tcp"
    cidr_blocks = [aws_vpc.main.cidr_block]
    ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
    }

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
    }

    }

    resource "aws_instance" "negative3" {
    ami = "ami-003634241a8fcdec0"

    instance_type = "t2.micro"

    vpc_security_group_ids = [ "${aws_security_group.used_sg.id}" ]

    }
  3. Test it

  4. Ship it 🚢 and relax 🌴