Repository: cloud-custodian/cloud-custodian

Issue:
Add CodeBuild as resource to scan for unused security-group filter
**Is your feature request related to a problem? Please describe.**
We recently found that our unused security-group filter was marking security groups used by Codebuild projects as unused.  Some of the codebuild projects security groups got deleted and then the codebuild projects failed. Looking at the code I see it is not set to check CodeBuild for security group group ids to see if they are using them - https://github.com/cloud-custodian/cloud-custodian/blob/master/c7n/resources/vpc.py#L699

**Describe the solution you'd like**
On this section of code https://github.com/cloud-custodian/cloud-custodian/blob/master/c7n/resources/vpc.py#L699 it would be good to have it check if codebuild projects are using any of the security groups before stating they are unused.

**Describe alternatives you've considered**
I thought about writing another policy to look for security group attachements to codebuild and tagging them with an identifier but then cleanup becomes an issue as once the codebuild project is gone it would then need another policy to remove the tag from the SG so it gets complex

**Additional context**
Nope, it would just be good to have to avoid breaking codebuild projects by mistake



Discussion:
Yes I agree and would like to see this included to stop CodeBuild Projects that don't run that often from Breaking due to Security Group being deleted.

Resolving patch:
diff --git a/c7n/resources/vpc.py b/c7n/resources/vpc.py
--- a/c7n/resources/vpc.py
+++ b/c7n/resources/vpc.py
@@ -719,7 +719,8 @@ def get_scanners(self):
             ("sg-perm-refs", self.get_sg_refs),
             ('lambdas', self.get_lambda_sgs),
             ("launch-configs", self.get_launch_config_sgs),
-            ("ecs-cwe", self.get_ecs_cwe_sgs)
+            ("ecs-cwe", self.get_ecs_cwe_sgs),
+            ("codebuild", self.get_codebuild_sgs),
         )
 
     def scan_groups(self):
@@ -761,6 +762,12 @@ def get_eni_sgs(self):
                 sg_ids.add(g['GroupId'])
         return sg_ids
 
+    def get_codebuild_sgs(self):
+        sg_ids = set()
+        for cb in self.manager.get_resource_manager('codebuild').resources():
+            sg_ids |= set(cb.get('vpcConfig', {}).get('securityGroupIds', []))
+        return sg_ids
+
     def get_sg_refs(self):
         sg_ids = set()
         for sg in self.manager.get_resource_manager('security-group').resources():


Test patch:
diff --git a/tests/data/placebo/test_security_group_codebuild_unused/codebuild.BatchGetProjects_1.json b/tests/data/placebo/test_security_group_codebuild_unused/codebuild.BatchGetProjects_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_security_group_codebuild_unused/codebuild.BatchGetProjects_1.json
@@ -0,0 +1,105 @@
+{
+    "status_code": 200,
+    "data": {
+        "projects": [
+            {
+                "name": "test-project",
+                "arn": "arn:aws:codebuild:us-east-1:644160558196:project/test-project",
+                "description": "test_codebuild_project",
+                "source": {
+                    "type": "GITHUB",
+                    "location": "https://github.com/mitchellh/packer.git",
+                    "gitCloneDepth": 1,
+                    "gitSubmodulesConfig": {
+                        "fetchSubmodules": true
+                    },
+                    "buildspec": "",
+                    "reportBuildStatus": false,
+                    "insecureSsl": false
+                },
+                "sourceVersion": "master",
+                "artifacts": {
+                    "type": "NO_ARTIFACTS",
+                    "overrideArtifactName": false
+                },
+                "cache": {
+                    "type": "NO_CACHE"
+                },
+                "environment": {
+                    "type": "LINUX_CONTAINER",
+                    "image": "aws/codebuild/standard:1.0",
+                    "computeType": "BUILD_GENERAL1_SMALL",
+                    "environmentVariables": [
+                        {
+                            "name": "SOME_KEY1",
+                            "value": "SOME_VALUE1",
+                            "type": "PLAINTEXT"
+                        },
+                        {
+                            "name": "SOME_KEY2",
+                            "value": "SOME_VALUE2",
+                            "type": "PARAMETER_STORE"
+                        }
+                    ],
+                    "privilegedMode": false,
+                    "imagePullCredentialsType": "CODEBUILD"
+                },
+                "serviceRole": "arn:aws:iam::644160558196:role/example",
+                "timeoutInMinutes": 5,
+                "queuedTimeoutInMinutes": 480,
+                "encryptionKey": "arn:aws:kms:us-east-1:644160558196:alias/aws/s3",
+                "tags": [
+                    {
+                        "key": "Environment",
+                        "value": "Test"
+                    }
+                ],
+                "created": {
+                    "__class__": "datetime",
+                    "year": 2020,
+                    "month": 9,
+                    "day": 28,
+                    "hour": 15,
+                    "minute": 12,
+                    "second": 49,
+                    "microsecond": 769000
+                },
+                "lastModified": {
+                    "__class__": "datetime",
+                    "year": 2020,
+                    "month": 9,
+                    "day": 28,
+                    "hour": 15,
+                    "minute": 12,
+                    "second": 49,
+                    "microsecond": 769000
+                },
+                "vpcConfig": {
+                    "vpcId": "vpc-0e2ce3db654f9651a",
+                    "subnets": [
+                        "subnet-05fe17b6b2587502e"
+                    ],
+                    "securityGroupIds": [
+                        "sg-0f31edd750f0b3f9f"
+                    ]
+                },
+                "badge": {
+                    "badgeEnabled": false
+                },
+                "logsConfig": {
+                    "cloudWatchLogs": {
+                        "status": "ENABLED",
+                        "groupName": "log-group",
+                        "streamName": "log-stream"
+                    },
+                    "s3Logs": {
+                        "status": "DISABLED",
+                        "encryptionDisabled": false
+                    }
+                }
+            }
+        ],
+        "projectsNotFound": [],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_security_group_codebuild_unused/codebuild.ListProjects_1.json b/tests/data/placebo/test_security_group_codebuild_unused/codebuild.ListProjects_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_security_group_codebuild_unused/codebuild.ListProjects_1.json
@@ -0,0 +1,9 @@
+{
+    "status_code": 200,
+    "data": {
+        "projects": [
+            "test-project"
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_security_group_codebuild_unused/ec2.DescribeSecurityGroupReferences_1.json b/tests/data/placebo/test_security_group_codebuild_unused/ec2.DescribeSecurityGroupReferences_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_security_group_codebuild_unused/ec2.DescribeSecurityGroupReferences_1.json
@@ -0,0 +1,7 @@
+{
+    "status_code": 200,
+    "data": {
+        "SecurityGroupReferenceSet": [],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_security_group_codebuild_unused/ec2.DescribeSecurityGroups_1.json b/tests/data/placebo/test_security_group_codebuild_unused/ec2.DescribeSecurityGroups_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_security_group_codebuild_unused/ec2.DescribeSecurityGroups_1.json
@@ -0,0 +1,148 @@
+{
+    "status_code": 200,
+    "data": {
+        "SecurityGroups": [
+            {
+                "Description": "default VPC security group",
+                "GroupName": "default",
+                "IpPermissions": [
+                    {
+                        "IpProtocol": "-1",
+                        "IpRanges": [],
+                        "Ipv6Ranges": [],
+                        "PrefixListIds": [],
+                        "UserIdGroupPairs": [
+                            {
+                                "GroupId": "sg-053f54b1170d9c80e",
+                                "UserId": "644160558196"
+                            }
+                        ]
+                    }
+                ],
+                "OwnerId": "644160558196",
+                "GroupId": "sg-053f54b1170d9c80e",
+                "IpPermissionsEgress": [
+                    {
+                        "IpProtocol": "-1",
+                        "IpRanges": [
+                            {
+                                "CidrIp": "0.0.0.0/0"
+                            }
+                        ],
+                        "Ipv6Ranges": [],
+                        "PrefixListIds": [],
+                        "UserIdGroupPairs": []
+                    }
+                ],
+                "VpcId": "vpc-0e2ce3db654f9651a"
+            },
+            {
+                "Description": "default VPC security group",
+                "GroupName": "default",
+                "IpPermissions": [
+                    {
+                        "IpProtocol": "-1",
+                        "IpRanges": [],
+                        "Ipv6Ranges": [],
+                        "PrefixListIds": [],
+                        "UserIdGroupPairs": [
+                            {
+                                "GroupId": "sg-092723c6c101804b9",
+                                "UserId": "644160558196"
+                            }
+                        ]
+                    }
+                ],
+                "OwnerId": "644160558196",
+                "GroupId": "sg-092723c6c101804b9",
+                "IpPermissionsEgress": [
+                    {
+                        "IpProtocol": "-1",
+                        "IpRanges": [
+                            {
+                                "CidrIp": "0.0.0.0/0"
+                            }
+                        ],
+                        "Ipv6Ranges": [],
+                        "PrefixListIds": [],
+                        "UserIdGroupPairs": []
+                    }
+                ],
+                "VpcId": "vpc-0a238ebd387b44e4e"
+            },
+            {
+                "Description": "Unused",
+                "GroupName": "example2",
+                "IpPermissions": [
+                    {
+                        "FromPort": 443,
+                        "IpProtocol": "tcp",
+                        "IpRanges": [
+                            {
+                                "CidrIp": "10.0.0.0/16",
+                                "Description": "TLS from VPC"
+                            }
+                        ],
+                        "Ipv6Ranges": [],
+                        "PrefixListIds": [],
+                        "ToPort": 443,
+                        "UserIdGroupPairs": []
+                    }
+                ],
+                "OwnerId": "644160558196",
+                "GroupId": "sg-0ed6c6d872d445a0d",
+                "IpPermissionsEgress": [
+                    {
+                        "IpProtocol": "-1",
+                        "IpRanges": [
+                            {
+                                "CidrIp": "0.0.0.0/0"
+                            }
+                        ],
+                        "Ipv6Ranges": [],
+                        "PrefixListIds": [],
+                        "UserIdGroupPairs": []
+                    }
+                ],
+                "VpcId": "vpc-0e2ce3db654f9651a"
+            },
+            {
+                "Description": "In use",
+                "GroupName": "example1",
+                "IpPermissions": [
+                    {
+                        "FromPort": 443,
+                        "IpProtocol": "tcp",
+                        "IpRanges": [
+                            {
+                                "CidrIp": "10.0.0.0/16",
+                                "Description": "TLS from VPC"
+                            }
+                        ],
+                        "Ipv6Ranges": [],
+                        "PrefixListIds": [],
+                        "ToPort": 443,
+                        "UserIdGroupPairs": []
+                    }
+                ],
+                "OwnerId": "644160558196",
+                "GroupId": "sg-0f31edd750f0b3f9f",
+                "IpPermissionsEgress": [
+                    {
+                        "IpProtocol": "-1",
+                        "IpRanges": [
+                            {
+                                "CidrIp": "0.0.0.0/0"
+                            }
+                        ],
+                        "Ipv6Ranges": [],
+                        "PrefixListIds": [],
+                        "UserIdGroupPairs": []
+                    }
+                ],
+                "VpcId": "vpc-0e2ce3db654f9651a"
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_security_group_codebuild_unused/tagging.GetResources_1.json b/tests/data/placebo/test_security_group_codebuild_unused/tagging.GetResources_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_security_group_codebuild_unused/tagging.GetResources_1.json
@@ -0,0 +1,18 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [
+            {
+                "ResourceARN": "arn:aws:codebuild:us-east-1:644160558196:project/test-project",
+                "Tags": [
+                    {
+                        "Key": "Environment",
+                        "Value": "Test"
+                    }
+                ]
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_security_group_unused/codebuild.ListProjects_1.json b/tests/data/placebo/test_security_group_unused/codebuild.ListProjects_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_security_group_unused/codebuild.ListProjects_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "projects": [
+        ],
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_security_group_used/codebuild.ListProjects_1.json b/tests/data/placebo/test_security_group_used/codebuild.ListProjects_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_security_group_used/codebuild.ListProjects_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "projects": [
+        ],
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/terraform/aws_code_build_vpc/codebuild_project.tf b/tests/terraform/aws_code_build_vpc/codebuild_project.tf
new file mode 100644
--- /dev/null
+++ b/tests/terraform/aws_code_build_vpc/codebuild_project.tf
@@ -0,0 +1,150 @@
+# resource "aws_s3_bucket" "example" {
+#   bucket = "example"
+#   acl    = "private"
+# }
+
+resource "aws_iam_role" "example" {
+  name = "example"
+
+  assume_role_policy = <<EOF
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Principal": {
+        "Service": "codebuild.amazonaws.com"
+      },
+      "Action": "sts:AssumeRole"
+    }
+  ]
+}
+EOF
+}
+
+resource "aws_iam_role_policy" "example" {
+  role = aws_iam_role.example.name
+
+  policy = <<POLICY
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Resource": [
+        "*"
+      ],
+      "Action": [
+        "logs:CreateLogGroup",
+        "logs:CreateLogStream",
+        "logs:PutLogEvents"
+      ]
+    },
+    {
+      "Effect": "Allow",
+      "Action": [
+        "ec2:CreateNetworkInterface",
+        "ec2:DescribeDhcpOptions",
+        "ec2:DescribeNetworkInterfaces",
+        "ec2:DeleteNetworkInterface",
+        "ec2:DescribeSubnets",
+        "ec2:DescribeSecurityGroups",
+        "ec2:DescribeVpcs"
+      ],
+      "Resource": "*"
+    },
+    {
+      "Effect": "Allow",
+      "Action": [
+        "ec2:CreateNetworkInterfacePermission"
+      ],
+      "Resource": [
+        "arn:aws:ec2:us-east-1:123456789012:network-interface/*"
+      ],
+      "Condition": {
+        "StringEquals": {
+          "ec2:Subnet": [
+            "${aws_subnet.example.arn}"
+          ],
+          "ec2:AuthorizedService": "codebuild.amazonaws.com"
+        }
+      }
+    }
+  ]
+}
+POLICY
+}
+
+resource "aws_codebuild_project" "example" {
+  name          = "test-project"
+  description   = "test_codebuild_project"
+  build_timeout = "5"
+  service_role  = aws_iam_role.example.arn
+
+  artifacts {
+    type = "NO_ARTIFACTS"
+  }
+
+  # cache {
+  #   type     = "S3"
+  #   location = aws_s3_bucket.example.bucket
+  # }
+
+  environment {
+    compute_type                = "BUILD_GENERAL1_SMALL"
+    image                       = "aws/codebuild/standard:1.0"
+    type                        = "LINUX_CONTAINER"
+    image_pull_credentials_type = "CODEBUILD"
+
+    environment_variable {
+      name  = "SOME_KEY1"
+      value = "SOME_VALUE1"
+    }
+
+    environment_variable {
+      name  = "SOME_KEY2"
+      value = "SOME_VALUE2"
+      type  = "PARAMETER_STORE"
+    }
+  }
+
+  logs_config {
+    cloudwatch_logs {
+      group_name  = "log-group"
+      stream_name = "log-stream"
+    }
+
+    # s3_logs {
+    #   status   = "ENABLED"
+    #   location = "${aws_s3_bucket.example.id}/build-log"
+    # }
+  }
+
+  source {
+    type            = "GITHUB"
+    location        = "https://github.com/mitchellh/packer.git"
+    git_clone_depth = 1
+
+    git_submodules_config {
+      fetch_submodules = true
+    }
+  }
+
+  source_version = "master"
+
+  vpc_config {
+    vpc_id = aws_vpc.example.id
+
+    subnets = [
+      aws_subnet.example.id,
+    ]
+
+    security_group_ids = [
+      aws_security_group.example1.id,
+    ]
+  }
+
+  tags = {
+    Environment = "Test"
+  }
+}
diff --git a/tests/terraform/aws_code_build_vpc/security_group.tf b/tests/terraform/aws_code_build_vpc/security_group.tf
new file mode 100644
--- /dev/null
+++ b/tests/terraform/aws_code_build_vpc/security_group.tf
@@ -0,0 +1,42 @@
+resource "aws_security_group" "example1" {
+  name        = "example1"
+  description = "In use"
+  vpc_id      = aws_vpc.example.id
+
+  ingress {
+    description = "TLS from VPC"
+    from_port   = 443
+    to_port     = 443
+    protocol    = "tcp"
+    cidr_blocks = [aws_vpc.example.cidr_block]
+  }
+
+  egress {
+    from_port   = 0
+    to_port     = 0
+    protocol    = "-1"
+    cidr_blocks = ["0.0.0.0/0"]
+  }
+}
+
+resource "aws_security_group" "example2" {
+  name        = "example2"
+  description = "Unused"
+  vpc_id      = aws_vpc.example.id
+
+  ingress {
+    description = "TLS from VPC"
+    from_port   = 443
+    to_port     = 443
+    protocol    = "tcp"
+    cidr_blocks = [aws_vpc.example.cidr_block]
+  }
+
+  egress {
+    from_port   = 0
+    to_port     = 0
+    protocol    = "-1"
+    cidr_blocks = ["0.0.0.0/0"]
+  }
+}
+
diff --git a/tests/terraform/aws_code_build_vpc/tf_resources.json b/tests/terraform/aws_code_build_vpc/tf_resources.json
new file mode 100644
--- /dev/null
+++ b/tests/terraform/aws_code_build_vpc/tf_resources.json
@@ -0,0 +1,266 @@
+{
+    "pytest-terraform": 1,
+    "outputs": {},
+    "resources": {
+        "aws_codebuild_project": {
+            "example": {
+                "arn": "arn:aws:codebuild:us-east-1:644160558196:project/test-project",
+                "artifacts": [
+                    {
+                        "artifact_identifier": "",
+                        "encryption_disabled": false,
+                        "location": "",
+                        "name": "",
+                        "namespace_type": "",
+                        "override_artifact_name": false,
+                        "packaging": "",
+                        "path": "",
+                        "type": "NO_ARTIFACTS"
+                    }
+                ],
+                "badge_enabled": false,
+                "badge_url": "",
+                "build_timeout": 5,
+                "cache": [
+                    {
+                        "location": "",
+                        "modes": [],
+                        "type": "NO_CACHE"
+                    }
+                ],
+                "description": "test_codebuild_project",
+                "encryption_key": "arn:aws:kms:us-east-1:644160558196:alias/aws/s3",
+                "environment": [
+                    {
+                        "certificate": "",
+                        "compute_type": "BUILD_GENERAL1_SMALL",
+                        "environment_variable": [
+                            {
+                                "name": "SOME_KEY1",
+                                "type": "PLAINTEXT",
+                                "value": "SOME_VALUE1"
+                            },
+                            {
+                                "name": "SOME_KEY2",
+                                "type": "PARAMETER_STORE",
+                                "value": "SOME_VALUE2"
+                            }
+                        ],
+                        "image": "aws/codebuild/standard:1.0",
+                        "image_pull_credentials_type": "CODEBUILD",
+                        "privileged_mode": false,
+                        "registry_credential": [],
+                        "type": "LINUX_CONTAINER"
+                    }
+                ],
+                "id": "arn:aws:codebuild:us-east-1:644160558196:project/test-project",
+                "logs_config": [
+                    {
+                        "cloudwatch_logs": [
+                            {
+                                "group_name": "log-group",
+                                "status": "ENABLED",
+                                "stream_name": "log-stream"
+                            }
+                        ],
+                        "s3_logs": [
+                            {
+                                "encryption_disabled": false,
+                                "location": "",
+                                "status": "DISABLED"
+                            }
+                        ]
+                    }
+                ],
+                "name": "test-project",
+                "queued_timeout": 480,
+                "secondary_artifacts": [],
+                "secondary_sources": [],
+                "service_role": "arn:aws:iam::644160558196:role/example",
+                "source": [
+                    {
+                        "auth": [],
+                        "buildspec": "",
+                        "git_clone_depth": 1,
+                        "git_submodules_config": [
+                            {
+                                "fetch_submodules": true
+                            }
+                        ],
+                        "insecure_ssl": false,
+                        "location": "https://github.com/mitchellh/packer.git",
+                        "report_build_status": false,
+                        "type": "GITHUB"
+                    }
+                ],
+                "source_version": "master",
+                "tags": {
+                    "Environment": "Test"
+                },
+                "vpc_config": [
+                    {
+                        "security_group_ids": [
+                            "sg-0f31edd750f0b3f9f"
+                        ],
+                        "subnets": [
+                            "subnet-05fe17b6b2587502e"
+                        ],
+                        "vpc_id": "vpc-0e2ce3db654f9651a"
+                    }
+                ]
+            }
+        },
+        "aws_iam_role": {
+            "example": {
+                "arn": "arn:aws:iam::644160558196:role/example",
+                "assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"codebuild.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}",
+                "create_date": "2020-09-28T13:12:33Z",
+                "description": "",
+                "force_detach_policies": false,
+                "id": "example",
+                "max_session_duration": 3600,
+                "name": "example",
+                "name_prefix": null,
+                "path": "/",
+                "permissions_boundary": null,
+                "tags": null,
+                "unique_id": "AROA37RXYDBAX5PVMOXU2"
+            }
+        },
+        "aws_iam_role_policy": {
+            "example": {
+                "id": "example:terraform-644160558196",
+                "name": "terraform-644160558196",
+                "name_prefix": null,
+                "policy": "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Resource\": [\n        \"*\"\n      ],\n      \"Action\": [\n        \"logs:CreateLogGroup\",\n        \"logs:CreateLogStream\",\n        \"logs:PutLogEvents\"\n      ]\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"ec2:CreateNetworkInterface\",\n        \"ec2:DescribeDhcpOptions\",\n        \"ec2:DescribeNetworkInterfaces\",\n        \"ec2:DeleteNetworkInterface\",\n        \"ec2:DescribeSubnets\",\n        \"ec2:DescribeSecurityGroups\",\n        \"ec2:DescribeVpcs\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"ec2:CreateNetworkInterfacePermission\"\n      ],\n      \"Resource\": [\n        \"arn:aws:ec2:us-east-1:644160558196:network-interface/*\"\n      ],\n      \"Condition\": {\n        \"StringEquals\": {\n          \"ec2:Subnet\": [\n            \"arn:aws:ec2:us-east-1:644160558196:subnet/subnet-05fe17b6b2587502e\"\n          ],\n          \"ec2:AuthorizedService\": \"codebuild.amazonaws.com\"\n        }\n      }\n    }\n  ]\n}\n",
+                "role": "example"
+            }
+        },
+        "aws_security_group": {
+            "example1": {
+                "arn": "arn:aws:ec2:us-east-1:644160558196:security-group/sg-0f31edd750f0b3f9f",
+                "description": "In use",
+                "egress": [
+                    {
+                        "cidr_blocks": [
+                            "0.0.0.0/0"
+                        ],
+                        "description": "",
+                        "from_port": 0,
+                        "ipv6_cidr_blocks": [],
+                        "prefix_list_ids": [],
+                        "protocol": "-1",
+                        "security_groups": [],
+                        "self": false,
+                        "to_port": 0
+                    }
+                ],
+                "id": "sg-0f31edd750f0b3f9f",
+                "ingress": [
+                    {
+                        "cidr_blocks": [
+                            "10.0.0.0/16"
+                        ],
+                        "description": "TLS from VPC",
+                        "from_port": 443,
+                        "ipv6_cidr_blocks": [],
+                        "prefix_list_ids": [],
+                        "protocol": "tcp",
+                        "security_groups": [],
+                        "self": false,
+                        "to_port": 443
+                    }
+                ],
+                "name": "example1",
+                "name_prefix": "",
+                "owner_id": "644160558196",
+                "revoke_rules_on_delete": false,
+                "tags": null,
+                "timeouts": null,
+                "vpc_id": "vpc-0e2ce3db654f9651a"
+            },
+            "example2": {
+                "arn": "arn:aws:ec2:us-east-1:644160558196:security-group/sg-0ed6c6d872d445a0d",
+                "description": "Unused",
+                "egress": [
+                    {
+                        "cidr_blocks": [
+                            "0.0.0.0/0"
+                        ],
+                        "description": "",
+                        "from_port": 0,
+                        "ipv6_cidr_blocks": [],
+                        "prefix_list_ids": [],
+                        "protocol": "-1",
+                        "security_groups": [],
+                        "self": false,
+                        "to_port": 0
+                    }
+                ],
+                "id": "sg-0ed6c6d872d445a0d",
+                "ingress": [
+                    {
+                        "cidr_blocks": [
+                            "10.0.0.0/16"
+                        ],
+                        "description": "TLS from VPC",
+                        "from_port": 443,
+                        "ipv6_cidr_blocks": [],
+                        "prefix_list_ids": [],
+                        "protocol": "tcp",
+                        "security_groups": [],
+                        "self": false,
+                        "to_port": 443
+                    }
+                ],
+                "name": "example2",
+                "name_prefix": "",
+                "owner_id": "644160558196",
+                "revoke_rules_on_delete": false,
+                "tags": null,
+                "timeouts": null,
+                "vpc_id": "vpc-0e2ce3db654f9651a"
+            }
+        },
+        "aws_subnet": {
+            "example": {
+                "arn": "arn:aws:ec2:us-east-1:644160558196:subnet/subnet-05fe17b6b2587502e",
+                "assign_ipv6_address_on_creation": false,
+                "availability_zone": "us-east-1b",
+                "availability_zone_id": "use1-az2",
+                "cidr_block": "10.0.1.0/24",
+                "id": "subnet-05fe17b6b2587502e",
+                "ipv6_cidr_block": "",
+                "ipv6_cidr_block_association_id": "",
+                "map_public_ip_on_launch": false,
+                "outpost_arn": "",
+                "owner_id": "644160558196",
+                "tags": null,
+                "timeouts": null,
+                "vpc_id": "vpc-0e2ce3db654f9651a"
+            }
+        },
+        "aws_vpc": {
+            "example": {
+                "arn": "arn:aws:ec2:us-east-1:644160558196:vpc/vpc-0e2ce3db654f9651a",
+                "assign_generated_ipv6_cidr_block": false,
+                "cidr_block": "10.0.0.0/16",
+                "default_network_acl_id": "acl-08c7e175c3362b2e4",
+                "default_route_table_id": "rtb-05693b29a75468fff",
+                "default_security_group_id": "sg-053f54b1170d9c80e",
+                "dhcp_options_id": "dopt-f8bedb82",
+                "enable_classiclink": false,
+                "enable_classiclink_dns_support": false,
+                "enable_dns_hostnames": false,
+                "enable_dns_support": true,
+                "id": "vpc-0e2ce3db654f9651a",
+                "instance_tenancy": "default",
+                "ipv6_association_id": "",
+                "ipv6_cidr_block": "",
+                "main_route_table_id": "rtb-05693b29a75468fff",
+                "owner_id": "644160558196",
+                "tags": null
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/terraform/aws_code_build_vpc/vpc.tf b/tests/terraform/aws_code_build_vpc/vpc.tf
new file mode 100644
--- /dev/null
+++ b/tests/terraform/aws_code_build_vpc/vpc.tf
@@ -0,0 +1,8 @@
+resource "aws_vpc" "example" {
+  cidr_block = "10.0.0.0/16"
+}
+
+resource "aws_subnet" "example" {
+  vpc_id     = aws_vpc.example.id
+  cidr_block = "10.0.1.0/24"
+}
diff --git a/tests/test_vpc.py b/tests/test_vpc.py
--- a/tests/test_vpc.py
+++ b/tests/test_vpc.py
@@ -8,6 +8,25 @@
 from botocore.exceptions import ClientError as BotoClientError
 from c7n.exceptions import PolicyValidationError
 from c7n.resources.aws import shape_validate
+from pytest_terraform import terraform
+
+
+@terraform('aws_code_build_vpc')
+def test_codebuild_unused(test, aws_code_build_vpc):
+    factory = test.replay_flight_data("test_security_group_codebuild_unused")
+    p = test.load_policy(
+        {"name": "sg-unused", "resource": "security-group", "filters": ["unused"]},
+        session_factory=factory,
+    )
+    unused = p.resource_manager.filters[0]
+    test.patch(
+        unused,
+        'get_scanners',
+        lambda: (('codebuild', unused.get_codebuild_sgs),))
+    resources = p.run()
+    sg_names = [resource['GroupName'] for resource in resources]
+    assert 'example2' in sg_names
+    assert 'example1' not in sg_names
 
 
 class VpcTest(BaseTest):