Repository: cloud-custodian/cloud-custodian

Issue:
aws - modify sg by tags
### Describe the bug

When trying to modify sgs by tag on resources like lambda/rds, the policy fails since the test for vpcid doesn't take the right related id [here](https://github.com/cloud-custodian/cloud-custodian/blob/main/c7n/actions/network.py#L267)

### What did you expect to happen?

I expect the SG modifications to happen

### Cloud Provider

Amazon Web Services (AWS)

### Cloud Custodian version and dependency information

_No response_

### Policy

```shell
policies:
  - name: rds-add-sg-by-tag
    resource: aws.rds
    filters:
      - type: security-group
        key: "tag:c7n"
        op: equal
        value: "test"
    actions:
      - type: modify-security-groups
        remove: matched
        add-by-tag:
          key: c7n
          values:
            - "add"
```


### Relevant log/traceback output

```shell
Traceback (most recent call last):
File "/var/task/c7n/handler.py", line 167, in dispatch_event
p.push(event, context)
File "/var/task/c7n/policy.py", line 1317, in push
return mode.run(event, lambda_ctx)
File "/var/task/c7n/policy.py", line 599, in run
return PullMode.run(self)
File "/var/task/c7n/policy.py", line 364, in run
results = a.process(resources)
File "/var/task/c7n/resources/awslambda.py", line 675, in process
groups = super(LambdaModifyVpcSecurityGroups, self).get_groups(
File "/var/task/c7n/actions/network.py", line 267, in get_groups
if sg['VpcId'] == r['VpcId']:
KeyError: 'VpcId'
KeyError: 'VpcId'
Traceback (most recent call last):
File "/var/task/custodian_policy.py", line 4, in run
return handler.dispatch_event(event, context)
File "/var/task/c7n/handler.py", line 167, in dispatch_event
p.push(event, context)
File "/var/task/c7n/policy.py", line 1317, in push
return mode.run(event, lambda_ctx)
File "/var/task/c7n/policy.py", line 599, in run
return PullMode.run(self)
File "/var/task/c7n/policy.py", line 364, in run
results = a.process(resources)
File "/var/task/c7n/resources/rds.py", line 1549, in process
groups = super(RDSModifyVpcSecurityGroups, self).get_groups(
File "/var/task/c7n/actions/network.py", line 267, in get_groups
if sg['VpcId'] == r['VpcId']:
[ERROR] KeyError: 'VpcId' Traceback (most recent call last): File "/var/task/custodian_policy.py", line 4, in run return handler.dispatch_event(event, context) File "/var/task/c7n/handler.py", line 167, in dispatch_event p.push(event, context) File "/var/task/c7n/policy.py", line 1317, in push return mode.run(event, lambda_ctx) File "/var/task/c7n/policy.py", line 599, in run return PullMode.run(self) File "/var/task/c7n/policy.py", line 364, in run results = a.process(resources) File "/var/task/c7n/resources/rds.py", line 1549, in process groups = super(RDSModifyVpcSecurityGroups, self).get_groups( File "/var/task/c7n/actions/network.py", line 267, in get_groups if sg['VpcId'] == r['VpcId']:
```


### Extra information or context

_No response_


Discussion:

Resolving patch:
diff --git a/c7n/actions/network.py b/c7n/actions/network.py
--- a/c7n/actions/network.py
+++ b/c7n/actions/network.py
@@ -4,6 +4,7 @@
 
 from c7n.exceptions import PolicyExecutionError, PolicyValidationError
 from c7n import utils
+import jmespath
 
 from .core import Action
 
@@ -264,7 +265,8 @@ def get_groups(self, resources):
                 r, self._get_array('isolation-group'), resolved_groups)
 
             for sg in tag_filtered_groups:
-                if sg['VpcId'] == r['VpcId']:
+                if sg['VpcId'] == jmespath.search(
+                    self.manager.filter_registry.get('vpc').RelatedIdsExpression, r):
                     add_groups.append(sg['GroupId'])
 
             for g in remove_groups:


Test patch:
diff --git a/tests/data/placebo/test_rds_sg_add_by_tag/ec2.DescribeSecurityGroups_1.json b/tests/data/placebo/test_rds_sg_add_by_tag/ec2.DescribeSecurityGroups_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_rds_sg_add_by_tag/ec2.DescribeSecurityGroups_1.json
@@ -0,0 +1,23 @@
+{
+    "status_code": 200,
+    "data": {
+        "SecurityGroups": [
+            {
+                "Description": "Isolation",
+                "GroupName": "isolate-sg",
+                "IpPermissions": [],
+                "OwnerId": "644160558196",
+                "GroupId": "sg-08398fd5994d8971d",
+                "IpPermissionsEgress": [],
+                "Tags": [
+                    {
+                        "Key": "c7n",
+                        "Value": "test"
+                    }
+                ],
+                "VpcId": "vpc-d2d616b5"
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_rds_sg_add_by_tag/ec2.DescribeSecurityGroups_2.json b/tests/data/placebo/test_rds_sg_add_by_tag/ec2.DescribeSecurityGroups_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_rds_sg_add_by_tag/ec2.DescribeSecurityGroups_2.json
@@ -0,0 +1,48 @@
+{
+    "status_code": 200,
+    "data": {
+        "SecurityGroups": [
+            {
+                "Description": "Security Group for Amazon MWAA Environment timmy-airflow",
+                "GroupName": "airflow-security-group-timmy-airflow-FeGrLJ",
+                "IpPermissions": [
+                    {
+                        "IpProtocol": "-1",
+                        "IpRanges": [],
+                        "Ipv6Ranges": [],
+                        "PrefixListIds": [],
+                        "UserIdGroupPairs": [
+                            {
+                                "GroupId": "sg-065a2edad041c289c",
+                                "UserId": "644160558196"
+                            }
+                        ]
+                    }
+                ],
+                "OwnerId": "644160558196",
+                "GroupId": "sg-065a2edad041c289c",
+                "IpPermissionsEgress": [
+                    {
+                        "IpProtocol": "-1",
+                        "IpRanges": [
+                            {
+                                "CidrIp": "0.0.0.0/0"
+                            }
+                        ],
+                        "Ipv6Ranges": [],
+                        "PrefixListIds": [],
+                        "UserIdGroupPairs": []
+                    }
+                ],
+                "Tags": [
+                    {
+                        "Key": "c7n",
+                        "Value": "add"
+                    }
+                ],
+                "VpcId": "vpc-d2d616b5"
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_rds_sg_add_by_tag/rds.DescribeDBInstances_1.json b/tests/data/placebo/test_rds_sg_add_by_tag/rds.DescribeDBInstances_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_rds_sg_add_by_tag/rds.DescribeDBInstances_1.json
@@ -0,0 +1,145 @@
+{
+    "status_code": 200,
+    "data": {
+        "DBInstances": [
+            {
+                "DBInstanceIdentifier": "database-1",
+                "DBInstanceClass": "db.t3.micro",
+                "Engine": "mysql",
+                "DBInstanceStatus": "available",
+                "MasterUsername": "admin",
+                "Endpoint": {
+                    "Address": "database-1.cz6wy8cci3uf.us-east-1.rds.amazonaws.com",
+                    "Port": 3306,
+                    "HostedZoneId": "Z2R2ITUGPM61AM"
+                },
+                "AllocatedStorage": 20,
+                "InstanceCreateTime": {
+                    "__class__": "datetime",
+                    "year": 2023,
+                    "month": 10,
+                    "day": 18,
+                    "hour": 17,
+                    "minute": 46,
+                    "second": 34,
+                    "microsecond": 829000
+                },
+                "PreferredBackupWindow": "09:04-09:34",
+                "BackupRetentionPeriod": 1,
+                "DBSecurityGroups": [],
+                "VpcSecurityGroups": [
+                    {
+                        "VpcSecurityGroupId": "sg-08398fd5994d8971d",
+                        "Status": "active"
+                    }
+                ],
+                "DBParameterGroups": [
+                    {
+                        "DBParameterGroupName": "default.mysql8.0",
+                        "ParameterApplyStatus": "in-sync"
+                    }
+                ],
+                "AvailabilityZone": "us-east-1a",
+                "DBSubnetGroup": {
+                    "DBSubnetGroupName": "default",
+                    "DBSubnetGroupDescription": "default",
+                    "VpcId": "vpc-d2d616b5",
+                    "SubnetGroupStatus": "Complete",
+                    "Subnets": [
+                        {
+                            "SubnetIdentifier": "subnet-3a334610",
+                            "SubnetAvailabilityZone": {
+                                "Name": "us-east-1d"
+                            },
+                            "SubnetOutpost": {},
+                            "SubnetStatus": "Active"
+                        },
+                        {
+                            "SubnetIdentifier": "subnet-efbcccb7",
+                            "SubnetAvailabilityZone": {
+                                "Name": "us-east-1b"
+                            },
+                            "SubnetOutpost": {},
+                            "SubnetStatus": "Active"
+                        },
+                        {
+                            "SubnetIdentifier": "subnet-e3b194de",
+                            "SubnetAvailabilityZone": {
+                                "Name": "us-east-1e"
+                            },
+                            "SubnetOutpost": {},
+                            "SubnetStatus": "Active"
+                        },
+                        {
+                            "SubnetIdentifier": "subnet-914763e7",
+                            "SubnetAvailabilityZone": {
+                                "Name": "us-east-1a"
+                            },
+                            "SubnetOutpost": {},
+                            "SubnetStatus": "Active"
+                        }
+                    ]
+                },
+                "PreferredMaintenanceWindow": "fri:06:44-fri:07:14",
+                "PendingModifiedValues": {},
+                "LatestRestorableTime": {
+                    "__class__": "datetime",
+                    "year": 2023,
+                    "month": 10,
+                    "day": 18,
+                    "hour": 17,
+                    "minute": 50,
+                    "second": 0,
+                    "microsecond": 0
+                },
+                "MultiAZ": false,
+                "EngineVersion": "8.0.33",
+                "AutoMinorVersionUpgrade": true,
+                "ReadReplicaDBInstanceIdentifiers": [],
+                "LicenseModel": "general-public-license",
+                "OptionGroupMemberships": [
+                    {
+                        "OptionGroupName": "default:mysql-8-0",
+                        "Status": "in-sync"
+                    }
+                ],
+                "PubliclyAccessible": false,
+                "StorageType": "gp2",
+                "DbInstancePort": 0,
+                "StorageEncrypted": true,
+                "KmsKeyId": "arn:aws:kms:us-east-1:644160558196:key/b10f842a-feb7-4318-92d5-0640a75b7688",
+                "DbiResourceId": "db-5DJZIRR2BJA54CWPZYSDTXHU6U",
+                "CACertificateIdentifier": "rds-ca-2019",
+                "DomainMemberships": [],
+                "CopyTagsToSnapshot": true,
+                "MonitoringInterval": 0,
+                "DBInstanceArn": "arn:aws:rds:us-east-1:644160558196:db:database-1",
+                "IAMDatabaseAuthenticationEnabled": false,
+                "PerformanceInsightsEnabled": false,
+                "DeletionProtection": false,
+                "AssociatedRoles": [],
+                "MaxAllocatedStorage": 1000,
+                "TagList": [],
+                "CustomerOwnedIpEnabled": false,
+                "ActivityStreamStatus": "stopped",
+                "BackupTarget": "region",
+                "NetworkType": "IPV4",
+                "StorageThroughput": 0,
+                "CertificateDetails": {
+                    "CAIdentifier": "rds-ca-2019",
+                    "ValidTill": {
+                        "__class__": "datetime",
+                        "year": 2024,
+                        "month": 8,
+                        "day": 22,
+                        "hour": 17,
+                        "minute": 8,
+                        "second": 50,
+                        "microsecond": 0
+                    }
+                }
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_rds_sg_add_by_tag/rds.DescribeDBInstances_2.json b/tests/data/placebo/test_rds_sg_add_by_tag/rds.DescribeDBInstances_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_rds_sg_add_by_tag/rds.DescribeDBInstances_2.json
@@ -0,0 +1,149 @@
+{
+    "status_code": 200,
+    "data": {
+        "DBInstances": [
+            {
+                "DBInstanceIdentifier": "database-1",
+                "DBInstanceClass": "db.t3.micro",
+                "Engine": "mysql",
+                "DBInstanceStatus": "modifying",
+                "MasterUsername": "admin",
+                "Endpoint": {
+                    "Address": "database-1.cz6wy8cci3uf.us-east-1.rds.amazonaws.com",
+                    "Port": 3306,
+                    "HostedZoneId": "Z2R2ITUGPM61AM"
+                },
+                "AllocatedStorage": 20,
+                "InstanceCreateTime": {
+                    "__class__": "datetime",
+                    "year": 2023,
+                    "month": 10,
+                    "day": 18,
+                    "hour": 17,
+                    "minute": 46,
+                    "second": 34,
+                    "microsecond": 829000
+                },
+                "PreferredBackupWindow": "09:04-09:34",
+                "BackupRetentionPeriod": 1,
+                "DBSecurityGroups": [],
+                "VpcSecurityGroups": [
+                    {
+                        "VpcSecurityGroupId": "sg-065a2edad041c289c",
+                        "Status": "adding"
+                    },
+                    {
+                        "VpcSecurityGroupId": "sg-08398fd5994d8971d",
+                        "Status": "active"
+                    }
+                ],
+                "DBParameterGroups": [
+                    {
+                        "DBParameterGroupName": "default.mysql8.0",
+                        "ParameterApplyStatus": "in-sync"
+                    }
+                ],
+                "AvailabilityZone": "us-east-1a",
+                "DBSubnetGroup": {
+                    "DBSubnetGroupName": "default",
+                    "DBSubnetGroupDescription": "default",
+                    "VpcId": "vpc-d2d616b5",
+                    "SubnetGroupStatus": "Complete",
+                    "Subnets": [
+                        {
+                            "SubnetIdentifier": "subnet-3a334610",
+                            "SubnetAvailabilityZone": {
+                                "Name": "us-east-1d"
+                            },
+                            "SubnetOutpost": {},
+                            "SubnetStatus": "Active"
+                        },
+                        {
+                            "SubnetIdentifier": "subnet-efbcccb7",
+                            "SubnetAvailabilityZone": {
+                                "Name": "us-east-1b"
+                            },
+                            "SubnetOutpost": {},
+                            "SubnetStatus": "Active"
+                        },
+                        {
+                            "SubnetIdentifier": "subnet-e3b194de",
+                            "SubnetAvailabilityZone": {
+                                "Name": "us-east-1e"
+                            },
+                            "SubnetOutpost": {},
+                            "SubnetStatus": "Active"
+                        },
+                        {
+                            "SubnetIdentifier": "subnet-914763e7",
+                            "SubnetAvailabilityZone": {
+                                "Name": "us-east-1a"
+                            },
+                            "SubnetOutpost": {},
+                            "SubnetStatus": "Active"
+                        }
+                    ]
+                },
+                "PreferredMaintenanceWindow": "fri:06:44-fri:07:14",
+                "PendingModifiedValues": {},
+                "LatestRestorableTime": {
+                    "__class__": "datetime",
+                    "year": 2023,
+                    "month": 10,
+                    "day": 18,
+                    "hour": 17,
+                    "minute": 50,
+                    "second": 0,
+                    "microsecond": 0
+                },
+                "MultiAZ": false,
+                "EngineVersion": "8.0.33",
+                "AutoMinorVersionUpgrade": true,
+                "ReadReplicaDBInstanceIdentifiers": [],
+                "LicenseModel": "general-public-license",
+                "OptionGroupMemberships": [
+                    {
+                        "OptionGroupName": "default:mysql-8-0",
+                        "Status": "in-sync"
+                    }
+                ],
+                "PubliclyAccessible": false,
+                "StorageType": "gp2",
+                "DbInstancePort": 0,
+                "StorageEncrypted": true,
+                "KmsKeyId": "arn:aws:kms:us-east-1:644160558196:key/b10f842a-feb7-4318-92d5-0640a75b7688",
+                "DbiResourceId": "db-5DJZIRR2BJA54CWPZYSDTXHU6U",
+                "CACertificateIdentifier": "rds-ca-2019",
+                "DomainMemberships": [],
+                "CopyTagsToSnapshot": true,
+                "MonitoringInterval": 0,
+                "DBInstanceArn": "arn:aws:rds:us-east-1:644160558196:db:database-1",
+                "IAMDatabaseAuthenticationEnabled": false,
+                "PerformanceInsightsEnabled": false,
+                "DeletionProtection": false,
+                "AssociatedRoles": [],
+                "MaxAllocatedStorage": 1000,
+                "TagList": [],
+                "CustomerOwnedIpEnabled": false,
+                "ActivityStreamStatus": "stopped",
+                "BackupTarget": "region",
+                "NetworkType": "IPV4",
+                "StorageThroughput": 0,
+                "CertificateDetails": {
+                    "CAIdentifier": "rds-ca-2019",
+                    "ValidTill": {
+                        "__class__": "datetime",
+                        "year": 2024,
+                        "month": 8,
+                        "day": 22,
+                        "hour": 17,
+                        "minute": 8,
+                        "second": 50,
+                        "microsecond": 0
+                    }
+                }
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_rds_sg_add_by_tag/rds.ModifyDBInstance_1.json b/tests/data/placebo/test_rds_sg_add_by_tag/rds.ModifyDBInstance_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_rds_sg_add_by_tag/rds.ModifyDBInstance_1.json
@@ -0,0 +1,146 @@
+{
+    "status_code": 200,
+    "data": {
+        "DBInstance": {
+            "DBInstanceIdentifier": "database-1",
+            "DBInstanceClass": "db.t3.micro",
+            "Engine": "mysql",
+            "DBInstanceStatus": "available",
+            "MasterUsername": "admin",
+            "Endpoint": {
+                "Address": "database-1.cz6wy8cci3uf.us-east-1.rds.amazonaws.com",
+                "Port": 3306,
+                "HostedZoneId": "Z2R2ITUGPM61AM"
+            },
+            "AllocatedStorage": 20,
+            "InstanceCreateTime": {
+                "__class__": "datetime",
+                "year": 2023,
+                "month": 10,
+                "day": 18,
+                "hour": 17,
+                "minute": 46,
+                "second": 34,
+                "microsecond": 829000
+            },
+            "PreferredBackupWindow": "09:04-09:34",
+            "BackupRetentionPeriod": 1,
+            "DBSecurityGroups": [],
+            "VpcSecurityGroups": [
+                {
+                    "VpcSecurityGroupId": "sg-065a2edad041c289c",
+                    "Status": "adding"
+                },
+                {
+                    "VpcSecurityGroupId": "sg-08398fd5994d8971d",
+                    "Status": "active"
+                }
+            ],
+            "DBParameterGroups": [
+                {
+                    "DBParameterGroupName": "default.mysql8.0",
+                    "ParameterApplyStatus": "in-sync"
+                }
+            ],
+            "AvailabilityZone": "us-east-1a",
+            "DBSubnetGroup": {
+                "DBSubnetGroupName": "default",
+                "DBSubnetGroupDescription": "default",
+                "VpcId": "vpc-d2d616b5",
+                "SubnetGroupStatus": "Complete",
+                "Subnets": [
+                    {
+                        "SubnetIdentifier": "subnet-3a334610",
+                        "SubnetAvailabilityZone": {
+                            "Name": "us-east-1d"
+                        },
+                        "SubnetOutpost": {},
+                        "SubnetStatus": "Active"
+                    },
+                    {
+                        "SubnetIdentifier": "subnet-efbcccb7",
+                        "SubnetAvailabilityZone": {
+                            "Name": "us-east-1b"
+                        },
+                        "SubnetOutpost": {},
+                        "SubnetStatus": "Active"
+                    },
+                    {
+                        "SubnetIdentifier": "subnet-e3b194de",
+                        "SubnetAvailabilityZone": {
+                            "Name": "us-east-1e"
+                        },
+                        "SubnetOutpost": {},
+                        "SubnetStatus": "Active"
+                    },
+                    {
+                        "SubnetIdentifier": "subnet-914763e7",
+                        "SubnetAvailabilityZone": {
+                            "Name": "us-east-1a"
+                        },
+                        "SubnetOutpost": {},
+                        "SubnetStatus": "Active"
+                    }
+                ]
+            },
+            "PreferredMaintenanceWindow": "fri:06:44-fri:07:14",
+            "PendingModifiedValues": {},
+            "LatestRestorableTime": {
+                "__class__": "datetime",
+                "year": 2023,
+                "month": 10,
+                "day": 18,
+                "hour": 17,
+                "minute": 50,
+                "second": 0,
+                "microsecond": 0
+            },
+            "MultiAZ": false,
+            "EngineVersion": "8.0.33",
+            "AutoMinorVersionUpgrade": true,
+            "ReadReplicaDBInstanceIdentifiers": [],
+            "LicenseModel": "general-public-license",
+            "OptionGroupMemberships": [
+                {
+                    "OptionGroupName": "default:mysql-8-0",
+                    "Status": "in-sync"
+                }
+            ],
+            "PubliclyAccessible": false,
+            "StorageType": "gp2",
+            "DbInstancePort": 0,
+            "StorageEncrypted": true,
+            "KmsKeyId": "arn:aws:kms:us-east-1:644160558196:key/b10f842a-feb7-4318-92d5-0640a75b7688",
+            "DbiResourceId": "db-5DJZIRR2BJA54CWPZYSDTXHU6U",
+            "CACertificateIdentifier": "rds-ca-2019",
+            "DomainMemberships": [],
+            "CopyTagsToSnapshot": true,
+            "MonitoringInterval": 0,
+            "DBInstanceArn": "arn:aws:rds:us-east-1:644160558196:db:database-1",
+            "IAMDatabaseAuthenticationEnabled": false,
+            "PerformanceInsightsEnabled": false,
+            "DeletionProtection": false,
+            "AssociatedRoles": [],
+            "MaxAllocatedStorage": 1000,
+            "TagList": [],
+            "CustomerOwnedIpEnabled": false,
+            "BackupTarget": "region",
+            "NetworkType": "IPV4",
+            "StorageThroughput": 0,
+            "CertificateDetails": {
+                "CAIdentifier": "rds-ca-2019",
+                "ValidTill": {
+                    "__class__": "datetime",
+                    "year": 2024,
+                    "month": 8,
+                    "day": 22,
+                    "hour": 17,
+                    "minute": 8,
+                    "second": 50,
+                    "microsecond": 0
+                }
+            }
+        },
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/test_rds.py b/tests/test_rds.py
--- a/tests/test_rds.py
+++ b/tests/test_rds.py
@@ -1769,6 +1769,31 @@ def test_rds_filter_by_vpcid(self):
         self.assertEqual(len(resources), 4)
         self.assertEqual("vpc-09b75e60", resources[0]["DBSubnetGroup"]["VpcId"])
 
+    def test_rds_sg_add_by_tag(self):
+        session_factory = self.replay_flight_data("test_rds_sg_add_by_tag")
+        client = session_factory().client('rds')
+        policy = self.load_policy({
+            "name": "add-sg-via-tags",
+            "resource": "rds",
+                "filters": [
+                    {"type": "security-group", "key": "tag:c7n", "value": "add", "op": "ne"}],
+            "actions": [
+                {"type": "modify-security-groups",
+                 "add-by-tag": {
+                      "key": "c7n",
+                      "values": ["add"]}}]},
+            session_factory=session_factory,
+        )
+        resources = policy.run()
+        if self.recording:
+            time.sleep(60)
+        self.assertEqual(len(resources), 1)
+        self.assertAlmostEqual(
+            len(resources[0]['VpcSecurityGroups']), 1)
+        db = client.describe_db_instances(DBInstanceIdentifier="database-1")
+        mod_sgs = db.get('DBInstances')[0].get('VpcSecurityGroups')
+        self.assertTrue(len(mod_sgs), 2)
+
 
 class TestHealthEventsFilter(BaseTest):