Repository: cloud-custodian/cloud-custodian

Issue:
aws - check-permissions - support permission boundaries
aws iam policy simulator supports permission boundaries as of january, 2020
https://awsapichanges.info/archive/changes/98b098-iam.html

check-permissions filter should utilize that on applicable iam resources (user, role).


Discussion:

Patch:
diff --git a/c7n/resources/dms.py b/c7n/resources/dms.py
index 924327f2f..e72afdbdd 100644
--- a/c7n/resources/dms.py
+++ b/c7n/resources/dms.py
@@ -21,7 +21,7 @@ from c7n.utils import local_session, chunks, type_schema, get_retry
 from c7n.filters.vpc import SecurityGroupFilter, SubnetFilter, VpcFilter
 from c7n.filters.kms import KmsRelatedFilter
 from c7n.filters import FilterRegistry
-from c7n.tags import RemoveTag, Tag, TagActionFilter, TagDelayedAction
+from c7n.tags import RemoveTag, Tag, TagActionFilter, TagDelayedAction, universal_augment
 
 
 @resources.register('dms-instance')
@@ -55,6 +55,10 @@ class DmsEndpoints(QueryResourceManager):
         enum_spec = ('describe_endpoints', 'Endpoints', None)
         arn = id = 'EndpointArn'
         name = 'EndpointIdentifier'
+        arn_type = 'endpoint'
+        universal_taggable = object()
+
+    augment = universal_augment
 
 
 class InstanceDescribe(DescribeSource):
diff --git a/c7n/resources/iam.py b/c7n/resources/iam.py
index 76830579d..7b6d3f1d2 100644
--- a/c7n/resources/iam.py
+++ b/c7n/resources/iam.py
@@ -110,6 +110,8 @@ class DescribeRole(DescribeSource):
         client = local_session(self.manager.session_factory).client('iam')
         resources = []
         for rid in resource_ids:
+            if rid.startswith('arn'):
+                rid = Arn.parse(rid).resource
             try:
                 result = self.manager.retry(client.get_role, RoleName=rid)
             except client.exceptions.NoSuchEntityException:
@@ -495,6 +497,8 @@ class CheckPermissions(Filter):
                 match: allowed
                 actions:
                  - iam:CreateUser
+
+    By default permission boundaries are checked.
     """
 
     schema = type_schema(
@@ -503,6 +507,7 @@ class CheckPermissions(Filter):
                 {'enum': ['allowed', 'denied']},
                 {'$ref': '#/definitions/filters/valuekv'},
                 {'$ref': '#/definitions/filters/value'}]},
+            'boundaries': {'type': 'boolean'},
             'match-operator': {'enum': ['and', 'or']},
             'actions': {'type': 'array', 'items': {'type': 'string'}},
             'required': ('actions', 'match')})
@@ -512,8 +517,12 @@ class CheckPermissions(Filter):
 
     def get_permissions(self):
         if self.manager.type == 'iam-policy':
-            return ('iam:SimulateCustomPolicy',)
-        return ('iam:SimulatePrincipalPolicy',)
+            return ('iam:SimulateCustomPolicy', 'iam:GetPolicyVersion')
+        perms = ('iam:SimulatePrincipalPolicy', 'iam:GetPolicy', 'iam:GetPolicyVersion')
+        if self.manager.type not in ('iam-user', 'iam-role',):
+            # for simulating w/ permission boundaries
+            perms += ('iam:GetRole',)
+        return perms
 
     def process(self, resources, event=None):
         client = local_session(self.manager.session_factory).client('iam')
@@ -521,9 +530,11 @@ class CheckPermissions(Filter):
         matcher = self.get_eval_matcher()
         operator = self.data.get('match-operator', 'and') == 'and' and all or any
 
+        arn_resources = list(zip(self.get_iam_arns(resources), resources))
+        self.initialize_boundaries(client, arn_resources)
         results = []
         eval_cache = {}
-        for arn, r in zip(self.get_iam_arns(resources), resources):
+        for arn, r in arn_resources:
             if arn is None:
                 continue
             if arn in eval_cache:
@@ -531,7 +542,6 @@ class CheckPermissions(Filter):
             else:
                 evaluations = self.get_evaluations(client, arn, r, actions)
                 eval_cache[arn] = evaluations
-
             matches = []
             matched = []
             for e in evaluations:
@@ -544,6 +554,49 @@ class CheckPermissions(Filter):
                 results.append(r)
         return results
 
+    def initialize_boundaries(self, client, iam_resources):
+        """For IAM boundaries we need to retrieve boundary policy content.
+        """
+        # boundaries aren't attached to these.
+        if (self.manager.type in ('iam-policy', 'iam-group') or
+                self.data.get('boundary', True) is False):
+            return
+
+        # if boundary attributes aren't directly on the resource, fetch
+        # the iam role for the resource to get the boundary.
+        if self.manager.type not in ('iam-role', 'iam-user'):
+            iam_arns = {iam_arn for iam_arn, r in iam_resources if iam_arn is not None}
+            roles = self.manager.get_resource_manager(
+                'iam-role').get_resources(list(iam_arns), augment=False)
+            boundary_iam_map = {
+                r['Arn']: r.get('PermissionsBoundary', {}).get('PermissionsBoundaryArn')
+                for r in roles}
+            boundary_map = {}
+            for iam_arn, r in iam_resources:
+                boundary_map[self.manager.get_arns((r,))[0]] = boundary_iam_map.get(iam_arn)
+        else:
+            boundary_map = {
+                resource_arn: r.get('PermissionsBoundary', {}).get('PermissionsBoundaryArn')
+                for resource_arn, r in iam_resources}
+
+        # fetch boundary policies text
+        boundary_arns = set(boundary_map.values())
+        if None in boundary_arns:
+            boundary_arns.remove(None)
+        policies = self.manager.get_resource_manager(
+            'iam-policy').get_resources(list(boundary_arns))
+        boundaries = {}
+        for p in policies:
+            boundaries[p['Arn']] = json.dumps(client.get_policy_version(
+                PolicyArn=p['Arn'],
+                VersionId=p['DefaultVersionId'])['PolicyVersion']['Document'])
+
+        for resource_arn, boundary_arn in list(boundary_map.items()):
+            if boundary_arn is None:
+                continue
+            boundary_map[resource_arn] = boundaries[boundary_arn]
+        self.boundaries = boundary_map
+
     def get_iam_arns(self, resources):
         return self.manager.get_arns(resources)
 
@@ -558,11 +611,17 @@ class CheckPermissions(Filter):
                 client.simulate_custom_policy,
                 PolicyInputList=[json.dumps(policy['Document'])],
                 ActionNames=actions).get('EvaluationResults', ())
-        else:
-            evaluations = self.manager.retry(
-                client.simulate_principal_policy,
-                PolicySourceArn=arn,
-                ActionNames=actions).get('EvaluationResults', ())
+            return evaluations
+
+        params = dict(PolicySourceArn=arn, ActionNames=actions)
+        if self.boundaries:
+            boundary_policy = self.boundaries.get(
+                self.manager.get_arns([r])[0])
+            if boundary_policy:
+                params['PermissionsBoundaryPolicyInputList'] = [boundary_policy]
+
+        evaluations = self.manager.retry(
+            client.simulate_principal_policy, **params).get('EvaluationResults', ())
         return evaluations
 
     def get_eval_matcher(self):


Test patch:
diff --git a/tests/data/placebo/test_dms_endpoint_delete/dms.DeleteEndpoint_1.json b/tests/data/placebo/test_dms_endpoint_delete/dms.DeleteEndpoint_1.json
index c11ffe7eb..3890eb052 100644
--- a/tests/data/placebo/test_dms_endpoint_delete/dms.DeleteEndpoint_1.json
+++ b/tests/data/placebo/test_dms_endpoint_delete/dms.DeleteEndpoint_1.json
@@ -2,29 +2,18 @@
     "status_code": 200,
     "data": {
         "Endpoint": {
-            "Username": "erwerwerrs",
-            "Status": "deleting",
-            "EndpointArn": "arn:aws:dms:us-east-1:0123456789012:endpoint:BICKTYIAQR4U6TPFW7Z7ORGSY4",
-            "ServerName": "c7n-test",
-            "CertificateArn": "arn:aws:dms:us-east-1:0123456789012:cert:KAU6PM6MZGOKW7NUFW2LYQD6TA",
-            "EndpointType": "SOURCE",
-            "SslMode": "verify-ca",
-            "KmsKeyId": "arn:aws:kms:us-east-1:0123456789012:key/1462981a-3f7f-40d1-a81f-f10728064be9",
-            "EngineDisplayName": "MariaDB",
-            "EngineName": "mariadb",
             "EndpointIdentifier": "c7n-test",
-            "Port": 32342
+            "EndpointType": "SOURCE",
+            "EngineName": "aurora",
+            "EngineDisplayName": "Amazon Aurora MySQL",
+            "Username": "1234",
+            "ServerName": "test",
+            "Port": 1234,
+            "Status": "deleting",
+            "KmsKeyId": "arn:aws:kms:us-east-1:1112223334445:key/219c196b-3893-4778-b277-a05322f0ea0d",
+            "EndpointArn": "arn:aws:dms:us-east-1:1112223334445:endpoint:TS4PNUPPMTS3VDXUFUUGLKM2FQ",
+            "SslMode": "none"
         },
-        "ResponseMetadata": {
-            "RetryAttempts": 0,
-            "HTTPStatusCode": 200,
-            "RequestId": "017b3a78-4b50-11e8-844c-6bd72d6d5073",
-            "HTTPHeaders": {
-                "x-amzn-requestid": "017b3a78-4b50-11e8-844c-6bd72d6d5073",
-                "date": "Sun, 29 Apr 2018 01:52:42 GMT",
-                "content-length": "542",
-                "content-type": "application/x-amz-json-1.1"
-            }
-        }
+        "ResponseMetadata": {}
     }
-}
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_dms_endpoint_delete/dms.DescribeEndpoints_1.json b/tests/data/placebo/test_dms_endpoint_delete/dms.DescribeEndpoints_1.json
index 76ccc36f2..b80e6fb0d 100644
--- a/tests/data/placebo/test_dms_endpoint_delete/dms.DescribeEndpoints_1.json
+++ b/tests/data/placebo/test_dms_endpoint_delete/dms.DescribeEndpoints_1.json
@@ -3,86 +3,19 @@
     "data": {
         "Endpoints": [
             {
-                "Username": "erwerwerrs",
-                "Status": "active",
-                "EndpointArn": "arn:aws:dms:us-east-1:123456789012:endpoint:BICKTYIDPR4U6TPFW7Z7ORGSY4",
-                "ServerName": "c7n-test",
-                "CertificateArn": "arn:aws:dms:us-east-1:123456789012:cert:KAU6PM6MFLOKW7NUFW2LYQD6TA",
-                "EndpointType": "SOURCE",
-                "SslMode": "verify-ca",
-                "KmsKeyId": "arn:aws:kms:us-east-1:123456789012:key/fffffffff-3f7f-40d1-a81f-f10728064be9",
-                "EngineDisplayName": "MariaDB",
-                "EngineName": "mariadb",
                 "EndpointIdentifier": "c7n-test",
-                "Port": 32342
-            },
-            {
-                "Username": "admin",
-                "Status": "active",
-                "EndpointArn": "arn:aws:dms:us-east-1:123456789012:endpoint:2YQDQ2L56H2HKJPMADIRK5E5QU",
-                "ServerName": "rds-isamdev-mysql-cluster.cluster-chlbxczddovi.us-east-1.rds.amazonaws.com",
-                "EndpointType": "TARGET",
-                "SslMode": "none",
-                "KmsKeyId": "arn:aws:kms:us-east-1:123456789012:key/fffffff-0ae2-42af-9494-f946f8df695c",
-                "ExtraConnectionAttributes": "parallelLoadThreads=1",
-                "EngineDisplayName": "MySQL",
-                "EngineName": "mysql",
-                "EndpointIdentifier": "dms-isamdev-mysql",
-                "Port": 3306
-            },
-            {
-                "Username": "system",
-                "Status": "active",
-                "EndpointArn": "arn:aws:dms:us-east-1:123456789012:endpoint:PO3YXFKLUQDY4HA4CWGRBROXHM",
-                "ServerName": "161.179.239.118",
                 "EndpointType": "SOURCE",
-                "SslMode": "none",
-                "KmsKeyId": "arn:aws:kms:us-east-1:123456789012:key/ffffffff-0ae2-42af-9494-f946f8df695c",
-                "DatabaseName": "isamdev.world",
-                "EngineDisplayName": "Oracle",
-                "EngineName": "oracle",
-                "EndpointIdentifier": "dms-isamdev-oracle",
-                "Port": 1562
-            },
-            {
-                "Username": "AWS",
-                "Status": "active",
-                "EndpointArn": "arn:aws:dms:us-east-1:123456789012:endpoint:3SNCBLLMQBJUPB47RI4Q4VMS6Y",
-                "ServerName": "1234556.company.domain.com",
-                "EndpointType": "SOURCE",
-                "SslMode": "none",
-                "KmsKeyId": "arn:aws:kms:us-east-1:123456789012:key/1462981a-3f7f-40d1-a81f-f10728064be9",
-                "DatabaseName": "IDWQ",
-                "EngineDisplayName": "Oracle",
-                "EngineName": "oracle",
-                "EndpointIdentifier": "prodendpoint",
-                "Port": 1532
-            },
-            {
-                "Username": "AWS",
+                "EngineName": "aurora",
+                "EngineDisplayName": "Amazon Aurora MySQL",
+                "Username": "1234",
+                "ServerName": "test",
+                "Port": 1234,
                 "Status": "active",
-                "EndpointArn": "arn:aws:dms:us-east-1:123456789012:endpoint:P4WO7C3HTQU66LE6JYJ3MWF2XI",
-                "ServerName": "1234556.company.domain.com",
-                "EndpointType": "SOURCE",
-                "SslMode": "none",
-                "KmsKeyId": "arn:aws:kms:us-east-1:123456789012:key/1462981a-3f7f-40d1-a81f-f10728064be9",
-                "DatabaseName": "IDWQ",
-                "EngineDisplayName": "Oracle",
-                "EngineName": "oracle",
-                "EndpointIdentifier": "prodendpoint333",
-                "Port": 1532
+                "KmsKeyId": "arn:aws:kms:us-east-1:1112223334445:key/219c196b-3893-4778-b277-a05322f0ea0d",
+                "EndpointArn": "arn:aws:dms:us-east-1:1112223334445:endpoint:TS4PNUPPMTS3VDXUFUUGLKM2FQ",
+                "SslMode": "none"
             }
         ],
-        "ResponseMetadata": {
-            "RetryAttempts": 0,
-            "HTTPStatusCode": 200,
-            "RequestId": "013c353f-4b50-11e8-a505-61dbe6461519",
-            "HTTPHeaders": {
-                "x-amzn-requestid": "013c353f-4b50-11e8-a505-61dbe6461519",
-                "date": "Sun, 29 Apr 2018 01:52:41 GMT",
-                "content-length": "2512",
-                "content-type": "application/x-amz-json-1.1"
-            }
-        }
+        "ResponseMetadata": {}
     }
-}
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_dms_endpoint_delete/dms.DescribeEndpoints_2.json b/tests/data/placebo/test_dms_endpoint_delete/dms.DescribeEndpoints_2.json
index 8b444de84..201dfa472 100644
--- a/tests/data/placebo/test_dms_endpoint_delete/dms.DescribeEndpoints_2.json
+++ b/tests/data/placebo/test_dms_endpoint_delete/dms.DescribeEndpoints_2.json
@@ -3,30 +3,19 @@
     "data": {
         "Endpoints": [
             {
-                "Username": "erwerwerrs",
-                "Status": "deleting",
-                "EndpointArn": "arn:aws:dms:us-east-1:123456789012:endpoint:BICKTYIAQIJD8TPFW7Z7ORGSY4",
-                "ServerName": "c7n-test",
-                "CertificateArn": "arn:aws:dms:us-east-1:123456789012:cert:KAU6PM6MZGOKODVUFW2LYQD6TA",
-                "EndpointType": "SOURCE",
-                "SslMode": "verify-ca",
-                "KmsKeyId": "arn:aws:kms:us-east-1:123456789012:key/1212212121-3f7f-40d1-a81f-f10728064be9",
-                "EngineDisplayName": "MariaDB",
-                "EngineName": "mariadb",
                 "EndpointIdentifier": "c7n-test",
-                "Port": 32342
+                "EndpointType": "SOURCE",
+                "EngineName": "aurora",
+                "EngineDisplayName": "Amazon Aurora MySQL",
+                "Username": "1234",
+                "ServerName": "test",
+                "Port": 1234,
+                "Status": "deleting",
+                "KmsKeyId": "arn:aws:kms:us-east-1:1112223334445:key/219c196b-3893-4778-b277-a05322f0ea0d",
+                "EndpointArn": "arn:aws:dms:us-east-1:1112223334445:endpoint:TS4PNUPPMTS3VDXUFUUGLKM2FQ",
+                "SslMode": "none"
             }
         ],
-        "ResponseMetadata": {
-            "RetryAttempts": 0,
-            "HTTPStatusCode": 200,
-            "RequestId": "01bd257c-4b50-11e8-844c-6bd72d6d5073",
-            "HTTPHeaders": {
-                "x-amzn-requestid": "01bd257c-4b50-11e8-844c-6bd72d6d5073",
-                "date": "Sun, 29 Apr 2018 01:52:42 GMT",
-                "content-length": "545",
-                "content-type": "application/x-amz-json-1.1"
-            }
-        }
+        "ResponseMetadata": {}
     }
-}
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_dms_endpoint_delete/tagging.GetResources_1.json b/tests/data/placebo/test_dms_endpoint_delete/tagging.GetResources_1.json
new file mode 100644
index 000000000..8b704d185
--- /dev/null
+++ b/tests/data/placebo/test_dms_endpoint_delete/tagging.GetResources_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_dms_modify_endpoint_sql/dms.DescribeEndpoints_1.json b/tests/data/placebo/test_dms_modify_endpoint_sql/dms.DescribeEndpoints_1.json
index 83ec6c675..5d33424c5 100644
--- a/tests/data/placebo/test_dms_modify_endpoint_sql/dms.DescribeEndpoints_1.json
+++ b/tests/data/placebo/test_dms_modify_endpoint_sql/dms.DescribeEndpoints_1.json
@@ -1,31 +1,21 @@
 {
-    "status_code": 200, 
+    "status_code": 200,
     "data": {
         "Endpoints": [
             {
-                "Username": "madmin", 
-                "Status": "active", 
-                "EndpointArn": "arn:aws:dms:us-east-1:644160558196:endpoint:XNUBIZJM2WRWOEEOZJHNEM6IYE", 
-                "ServerName": "c7n-sql-db", 
-                "EndpointType": "SOURCE", 
-                "KmsKeyId": "arn:aws:kms:us-east-1:644160558196:key/f1f33a6b-91aa-4b0a-904c-f2a0378277f0", 
-                "DatabaseName": "c7n-db", 
-                "SslMode": "none", 
-                "EngineName": "sqlserver", 
-                "EndpointIdentifier": "c7n-dms-sql-ep", 
-                "Port": 1443
+                "EndpointIdentifier": "c7n-dms-sql-ep",
+                "EndpointType": "SOURCE",
+                "EngineName": "sqlserver",
+                "EngineDisplayName": "Microsoft SQL Server",
+                "Username": "1234",
+                "ServerName": "c7n-sql-db",
+                "Port": 1234,
+                "Status": "active",
+                "KmsKeyId": "arn:aws:kms:us-east-1:1112223334445:key/219c196b-3893-4778-b277-a05322f0ea0d",
+                "EndpointArn": "arn:aws:dms:us-east-1:1112223334445:endpoint:QOEESZJWK5BMGC7AT7QNZ56S44",
+                "SslMode": "none"
             }
-        ], 
-        "ResponseMetadata": {
-            "RetryAttempts": 0, 
-            "HTTPStatusCode": 200, 
-            "RequestId": "06c89b3a-261c-11e8-807c-61ba73499dd1", 
-            "HTTPHeaders": {
-                "x-amzn-requestid": "06c89b3a-261c-11e8-807c-61ba73499dd1", 
-                "date": "Mon, 12 Mar 2018 17:37:24 GMT", 
-                "content-length": "494", 
-                "content-type": "application/x-amz-json-1.1"
-            }
-        }
+        ],
+        "ResponseMetadata": {}
     }
 }
\ No newline at end of file
diff --git a/tests/data/placebo/test_dms_modify_endpoint_sql/dms.DescribeEndpoints_2.json b/tests/data/placebo/test_dms_modify_endpoint_sql/dms.DescribeEndpoints_2.json
index 677c2198c..197872b10 100644
--- a/tests/data/placebo/test_dms_modify_endpoint_sql/dms.DescribeEndpoints_2.json
+++ b/tests/data/placebo/test_dms_modify_endpoint_sql/dms.DescribeEndpoints_2.json
@@ -1,31 +1,22 @@
 {
-    "status_code": 200, 
+    "status_code": 200,
     "data": {
         "Endpoints": [
             {
-                "Username": "admin", 
-                "Status": "active", 
-                "EndpointArn": "arn:aws:dms:us-east-1:644160558196:endpoint:XNUBIZJM2WRWOEEOZJHNEM6IYE", 
-                "ServerName": "c7n-sql-db-02", 
-                "EndpointType": "SOURCE", 
-                "KmsKeyId": "arn:aws:kms:us-east-1:644160558196:key/f1f33a6b-91aa-4b0a-904c-f2a0378277f0", 
-                "DatabaseName": "c7n-db-02", 
-                "SslMode": "require", 
-                "EngineName": "sqlserver", 
-                "EndpointIdentifier": "c7n-dms-sql-ep", 
-                "Port": 3305
+                "EndpointIdentifier": "c7n-dms-sql-ep",
+                "EndpointType": "SOURCE",
+                "EngineName": "sqlserver",
+                "EngineDisplayName": "Microsoft SQL Server",
+                "Username": "admin",
+                "ServerName": "c7n-sql-db-02",
+                "Port": 3305,
+                "DatabaseName": "c7n-db-02",
+                "Status": "active",
+                "KmsKeyId": "arn:aws:kms:us-east-1:1112223334445:key/219c196b-3893-4778-b277-a05322f0ea0d",
+                "EndpointArn": "arn:aws:dms:us-east-1:1112223334445:endpoint:QOEESZJWK5BMGC7AT7QNZ56S44",
+                "SslMode": "require"
             }
-        ], 
-        "ResponseMetadata": {
-            "RetryAttempts": 0, 
-            "HTTPStatusCode": 200, 
-            "RequestId": "0764db3e-261c-11e8-807c-61ba73499dd1", 
-            "HTTPHeaders": {
-                "x-amzn-requestid": "0764db3e-261c-11e8-807c-61ba73499dd1", 
-                "date": "Mon, 12 Mar 2018 17:37:25 GMT", 
-                "content-length": "502", 
-                "content-type": "application/x-amz-json-1.1"
-            }
-        }
+        ],
+        "ResponseMetadata": {}
     }
 }
\ No newline at end of file
diff --git a/tests/data/placebo/test_dms_modify_endpoint_sql/dms.ModifyEndpoint_1.json b/tests/data/placebo/test_dms_modify_endpoint_sql/dms.ModifyEndpoint_1.json
index 8b305b27e..c530e45fa 100644
--- a/tests/data/placebo/test_dms_modify_endpoint_sql/dms.ModifyEndpoint_1.json
+++ b/tests/data/placebo/test_dms_modify_endpoint_sql/dms.ModifyEndpoint_1.json
@@ -1,29 +1,20 @@
 {
-    "status_code": 200, 
+    "status_code": 200,
     "data": {
         "Endpoint": {
-            "Username": "admin", 
-            "Status": "active", 
-            "EndpointArn": "arn:aws:dms:us-east-1:644160558196:endpoint:XNUBIZJM2WRWOEEOZJHNEM6IYE", 
-            "ServerName": "c7n-sql-db-02", 
-            "EndpointType": "SOURCE", 
-            "KmsKeyId": "arn:aws:kms:us-east-1:644160558196:key/f1f33a6b-91aa-4b0a-904c-f2a0378277f0", 
-            "DatabaseName": "c7n-db-02", 
-            "SslMode": "require", 
-            "EngineName": "sqlserver", 
-            "EndpointIdentifier": "c7n-dms-sql-ep", 
-            "Port": 3305
-        }, 
-        "ResponseMetadata": {
-            "RetryAttempts": 0, 
-            "HTTPStatusCode": 200, 
-            "RequestId": "07116452-261c-11e8-8019-531c4ec63182", 
-            "HTTPHeaders": {
-                "x-amzn-requestid": "07116452-261c-11e8-8019-531c4ec63182", 
-                "date": "Mon, 12 Mar 2018 17:37:24 GMT", 
-                "content-length": "499", 
-                "content-type": "application/x-amz-json-1.1"
-            }
-        }
+            "EndpointIdentifier": "c7n-dms-sql-ep",
+            "EndpointType": "SOURCE",
+            "EngineName": "sqlserver",
+            "EngineDisplayName": "Microsoft SQL Server",
+            "Username": "admin",
+            "ServerName": "c7n-sql-db-02",
+            "Port": 3305,
+            "DatabaseName": "c7n-db-02",
+            "Status": "active",
+            "KmsKeyId": "arn:aws:kms:us-east-1:1112223334445:key/219c196b-3893-4778-b277-a05322f0ea0d",
+            "EndpointArn": "arn:aws:dms:us-east-1:1112223334445:endpoint:QOEESZJWK5BMGC7AT7QNZ56S44",
+            "SslMode": "require"
+        },
+        "ResponseMetadata": {}
     }
 }
\ No newline at end of file
diff --git a/tests/data/placebo/test_dms_modify_endpoint_sql/tagging.GetResources_1.json b/tests/data/placebo/test_dms_modify_endpoint_sql/tagging.GetResources_1.json
new file mode 100644
index 000000000..8b704d185
--- /dev/null
+++ b/tests/data/placebo/test_dms_modify_endpoint_sql/tagging.GetResources_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_dms_resource_query/dms.DescribeEndpoints_1.json b/tests/data/placebo/test_dms_resource_query/dms.DescribeEndpoints_1.json
index 68c08c043..2f637ce6f 100644
--- a/tests/data/placebo/test_dms_resource_query/dms.DescribeEndpoints_1.json
+++ b/tests/data/placebo/test_dms_resource_query/dms.DescribeEndpoints_1.json
@@ -1,33 +1,21 @@
 {
-    "status_code": 200, 
+    "status_code": 200,
     "data": {
         "Endpoints": [
             {
-                "Status": "active", 
-                "S3Settings": {
-                    "ServiceAccessRoleArn": "arn:aws:iam::644160558196:role/dms-vpc-role", 
-                    "ExternalTableDefinition": "{\n    \"TableCount\": \"1\",\n    \"Tables\": [\n        {\n            \"TableName\": \"employee\",\n            \"TablePath\": \"hr/employee/\",\n            \"TableOwner\": \"hr\",\n            \"TableColumns\": [\n                {\n                    \"ColumnName\": \"Id\",\n                    \"ColumnType\": \"INT8\",\n                    \"ColumnNullable\": \"false\",\n                    \"ColumnIsPk\": \"true\"\n                },\n                {\n                    \"ColumnName\": \"LastName\",\n                    \"ColumnType\": \"STRING\",\n                    \"ColumnLength\": \"20\"\n                },\n                {\n                    \"ColumnName\": \"FirstName\",\n                    \"ColumnType\": \"STRING\",\n                    \"ColumnLength\": \"30\"\n                },\n                {\n                    \"ColumnName\": \"HireDate\",\n                    \"ColumnType\": \"DATETIME\"\n                },\n                {\n                    \"ColumnName\": \"OfficeLocation\",\n                    \"ColumnType\": \"STRING\",\n                    \"ColumnLength\": \"20\"\n                }\n            ],\n            \"TableColumnsTotal\": \"5\"\n        }\n    ]\n}", 
-                    "BucketName": "c7n-sm-test", 
-                    "BucketFolder": "dms"
-                }, 
-                "EndpointType": "SOURCE", 
-                "EndpointArn": "arn:aws:dms:us-east-1:644160558196:endpoint:YWWPQ44VI4JFKHFFASJ2AXBOXE", 
-                "ExtraConnectionAttributes": "bucketName=c7n-sm-test;bucketFolder=dms;cdcPath=dms/cdc", 
-                "SslMode": "require", 
-                "EngineName": "s3", 
-                "EndpointIdentifier": "endpointtest"
+                "EndpointIdentifier": "c7n-dms-sql-ep",
+                "EndpointType": "SOURCE",
+                "EngineName": "mysql",
+                "EngineDisplayName": "MySQL",
+                "Username": "1234",
+                "ServerName": "c7n-sql-db",
+                "Port": 1234,
+                "Status": "active",
+                "KmsKeyId": "arn:aws:kms:us-east-1:1112223334445:key/219c196b-3893-4778-b277-a05322f0ea0d",
+                "EndpointArn": "arn:aws:dms:us-east-1:1112223334445:endpoint:QOEESZJWK5BMGC7AT7QNZ56S44",
+                "SslMode": "none"
             }
-        ], 
-        "ResponseMetadata": {
-            "RetryAttempts": 0, 
-            "HTTPStatusCode": 200, 
-            "RequestId": "93495f1a-1e56-11e8-8e6e-61fbd598f11f", 
-            "HTTPHeaders": {
-                "x-amzn-requestid": "93495f1a-1e56-11e8-8e6e-61fbd598f11f", 
-                "date": "Fri, 02 Mar 2018 20:16:21 GMT", 
-                "content-length": "3103", 
-                "content-type": "application/x-amz-json-1.1"
-            }
-        }
+        ],
+        "ResponseMetadata": {}
     }
 }
\ No newline at end of file
diff --git a/tests/data/placebo/test_dms_resource_query/tagging.GetResources_1.json b/tests/data/placebo/test_dms_resource_query/tagging.GetResources_1.json
new file mode 100644
index 000000000..8b704d185
--- /dev/null
+++ b/tests/data/placebo/test_dms_resource_query/tagging.GetResources_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_dms_tag_filter/dms.DescribeEndpoints_1.json b/tests/data/placebo/test_dms_tag_filter/dms.DescribeEndpoints_1.json
new file mode 100644
index 000000000..efd99ad54
--- /dev/null
+++ b/tests/data/placebo/test_dms_tag_filter/dms.DescribeEndpoints_1.json
@@ -0,0 +1,22 @@
+{
+    "status_code": 200,
+    "data": {
+        "Endpoints": [
+            {
+                "EndpointIdentifier": "myendpoint",
+                "EndpointType": "SOURCE",
+                "EngineName": "oracle",
+                "EngineDisplayName": "Oracle",
+                "Username": "1234",
+                "ServerName": "orkie",
+                "Port": 1234,
+                "DatabaseName": "orkle",
+                "Status": "active",
+                "KmsKeyId": "arn:aws:kms:us-east-1:1112223334445:key/219c196b-3893-4778-b277-a05322f0ea0d",
+                "EndpointArn": "arn:aws:dms:us-east-1:1112223334445:endpoint:AFDRQSDLIZ2X6KNOS4PBGNWUWQ",
+                "SslMode": "none"
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_dms_tag_filter/tagging.GetResources_1.json b/tests/data/placebo/test_dms_tag_filter/tagging.GetResources_1.json
new file mode 100644
index 000000000..aa2e87e9e
--- /dev/null
+++ b/tests/data/placebo/test_dms_tag_filter/tagging.GetResources_1.json
@@ -0,0 +1,18 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [
+            {
+                "ResourceARN": "arn:aws:dms:us-east-1:1112223334445:endpoint:AFDRQSDLIZ2X6KNOS4PBGNWUWQ",
+                "Tags": [
+                    {
+                        "Key": "Owner",
+                        "Value": "pikachu"
+                    }
+                ]
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_ec2_permissions/ec2.DescribeInstances_1.json b/tests/data/placebo/test_ec2_permissions/ec2.DescribeInstances_1.json
index d2320f75f..816e33a39 100644
--- a/tests/data/placebo/test_ec2_permissions/ec2.DescribeInstances_1.json
+++ b/tests/data/placebo/test_ec2_permissions/ec2.DescribeInstances_1.json
@@ -1,165 +1,154 @@
 {
-    "status_code": 200,
-    "data": {
-        "Reservations": [
-            {
-                "Groups": [],
-                "Instances": [
-                    {
-                        "AmiLaunchIndex": 0,
-                        "ImageId": "ami-0bbe6b35405ecebdb",
-                        "InstanceId": "i-0cdbc9746913097d5",
-                        "InstanceType": "t2.micro",
-                        "LaunchTime": {
-                            "__class__": "datetime",
-                            "year": 2019,
-                            "month": 2,
-                            "day": 28,
-                            "hour": 14,
-                            "minute": 7,
-                            "second": 46,
-                            "microsecond": 0
-                        },
-                        "Monitoring": {
-                            "State": "disabled"
-                        },
-                        "Placement": {
-                            "AvailabilityZone": "us-west-2a",
-                            "GroupName": "",
-                            "Tenancy": "default"
-                        },
-                        "PrivateDnsName": "ip-172-31-25-97.us-west-2.compute.internal",
-                        "PrivateIpAddress": "172.31.25.97",
-                        "ProductCodes": [],
-                        "PublicDnsName": "ec2-18-237-70-187.us-west-2.compute.amazonaws.com",
-                        "PublicIpAddress": "18.237.70.187",
-                        "State": {
-                            "Code": 16,
-                            "Name": "running"
-                        },
-                        "StateTransitionReason": "",
-                        "SubnetId": "subnet-15452171",
-                        "VpcId": "vpc-4a9ff72e",
-                        "Architecture": "x86_64",
-                        "BlockDeviceMappings": [
-                            {
-                                "DeviceName": "/dev/sda1",
-                                "Ebs": {
-                                    "AttachTime": {
-                                        "__class__": "datetime",
-                                        "year": 2019,
-                                        "month": 2,
-                                        "day": 28,
-                                        "hour": 14,
-                                        "minute": 7,
-                                        "second": 47,
-                                        "microsecond": 0
-                                    },
-                                    "DeleteOnTermination": true,
-                                    "Status": "attached",
-                                    "VolumeId": "vol-09e24ed598d8ad490"
-                                }
-                            }
-                        ],
-                        "ClientToken": "",
-                        "EbsOptimized": false,
-                        "EnaSupport": true,
-                        "Hypervisor": "xen",
-                        "IamInstanceProfile": {
-                            "Arn": "arn:aws:iam::644160558196:instance-profile/CloudCustodianRole",
-                            "Id": "AIPAJO5EMJ3YEMNUF5ZWM"
-                        },
-                        "NetworkInterfaces": [
-                            {
-                                "Association": {
-                                    "IpOwnerId": "amazon",
-                                    "PublicDnsName": "ec2-18-237-70-187.us-west-2.compute.amazonaws.com",
-                                    "PublicIp": "18.237.70.187"
-                                },
-                                "Attachment": {
-                                    "AttachTime": {
-                                        "__class__": "datetime",
-                                        "year": 2019,
-                                        "month": 2,
-                                        "day": 28,
-                                        "hour": 14,
-                                        "minute": 7,
-                                        "second": 46,
-                                        "microsecond": 0
-                                    },
-                                    "AttachmentId": "eni-attach-028f9f4eab73b33e3",
-                                    "DeleteOnTermination": true,
-                                    "DeviceIndex": 0,
-                                    "Status": "attached"
-                                },
-                                "Description": "",
-                                "Groups": [
-                                    {
-                                        "GroupName": "default",
-                                        "GroupId": "sg-f9cc4d9f"
-                                    }
-                                ],
-                                "Ipv6Addresses": [],
-                                "MacAddress": "02:1f:11:0f:a1:06",
-                                "NetworkInterfaceId": "eni-029655e1e425bc4a1",
-                                "OwnerId": "644160558196",
-                                "PrivateDnsName": "ip-172-31-25-97.us-west-2.compute.internal",
-                                "PrivateIpAddress": "172.31.25.97",
-                                "PrivateIpAddresses": [
-                                    {
-                                        "Association": {
-                                            "IpOwnerId": "amazon",
-                                            "PublicDnsName": "ec2-18-237-70-187.us-west-2.compute.amazonaws.com",
-                                            "PublicIp": "18.237.70.187"
-                                        },
-                                        "Primary": true,
-                                        "PrivateDnsName": "ip-172-31-25-97.us-west-2.compute.internal",
-                                        "PrivateIpAddress": "172.31.25.97"
-                                    }
-                                ],
-                                "SourceDestCheck": true,
-                                "Status": "in-use",
-                                "SubnetId": "subnet-15452171",
-                                "VpcId": "vpc-4a9ff72e"
-                            }
-                        ],
-                        "RootDeviceName": "/dev/sda1",
-                        "RootDeviceType": "ebs",
-                        "SecurityGroups": [
-                            {
-                                "GroupName": "default",
-                                "GroupId": "sg-f9cc4d9f"
-                            }
-                        ],
-                        "SourceDestCheck": true,
-                        "VirtualizationType": "hvm",
-                        "CpuOptions": {
-                            "CoreCount": 1,
-                            "ThreadsPerCore": 1
-                        },
-                        "CapacityReservationSpecification": {
-                            "CapacityReservationPreference": "open"
-                        },
-                        "HibernationOptions": {
-                            "Configured": false
-                        }
-                    }
+  "status_code": 200,
+  "data": {
+    "Reservations": [
+      {
+        "Groups": [],
+        "Instances": [
+          {
+            "AmiLaunchIndex": 0,
+            "ImageId": "ami-0bbe6b35405ecebdb",
+            "InstanceId": "i-0cdbc9746913097d5",
+            "InstanceType": "t2.micro",
+            "LaunchTime": {
+              "__class__": "datetime",
+              "year": 2019,
+              "month": 2,
+              "day": 28,
+              "hour": 14,
+              "minute": 7,
+              "second": 46,
+              "microsecond": 0
+            },
+            "Monitoring": {
+              "State": "disabled"
+            },
+            "Placement": {
+              "AvailabilityZone": "us-west-2a",
+              "GroupName": "",
+              "Tenancy": "default"
+            },
+            "PrivateDnsName": "ip-172-31-25-97.us-west-2.compute.internal",
+            "PrivateIpAddress": "172.31.25.97",
+            "ProductCodes": [],
+            "PublicDnsName": "ec2-18-237-70-187.us-west-2.compute.amazonaws.com",
+            "PublicIpAddress": "18.237.70.187",
+            "State": {
+              "Code": 16,
+              "Name": "running"
+            },
+            "StateTransitionReason": "",
+            "SubnetId": "subnet-15452171",
+            "VpcId": "vpc-4a9ff72e",
+            "Architecture": "x86_64",
+            "BlockDeviceMappings": [
+              {
+                "DeviceName": "/dev/sda1",
+                "Ebs": {
+                  "AttachTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 2,
+                    "day": 28,
+                    "hour": 14,
+                    "minute": 7,
+                    "second": 47,
+                    "microsecond": 0
+                  },
+                  "DeleteOnTermination": true,
+                  "Status": "attached",
+                  "VolumeId": "vol-09e24ed598d8ad490"
+                }
+              }
+            ],
+            "ClientToken": "",
+            "EbsOptimized": false,
+            "EnaSupport": true,
+            "Hypervisor": "xen",
+            "IamInstanceProfile": {
+              "Arn": "arn:aws:iam::644160558196:instance-profile/CloudCustodianRole",
+              "Id": "AIPAJO5EMJ3YEMNUF5ZWM"
+            },
+            "NetworkInterfaces": [
+              {
+                "Association": {
+                  "IpOwnerId": "amazon",
+                  "PublicDnsName": "ec2-18-237-70-187.us-west-2.compute.amazonaws.com",
+                  "PublicIp": "18.237.70.187"
+                },
+                "Attachment": {
+                  "AttachTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 2,
+                    "day": 28,
+                    "hour": 14,
+                    "minute": 7,
+                    "second": 46,
+                    "microsecond": 0
+                  },
+                  "AttachmentId": "eni-attach-028f9f4eab73b33e3",
+                  "DeleteOnTermination": true,
+                  "DeviceIndex": 0,
+                  "Status": "attached"
+                },
+                "Description": "",
+                "Groups": [
+                  {
+                    "GroupName": "default",
+                    "GroupId": "sg-f9cc4d9f"
+                  }
                 ],
+                "Ipv6Addresses": [],
+                "MacAddress": "02:1f:11:0f:a1:06",
+                "NetworkInterfaceId": "eni-029655e1e425bc4a1",
                 "OwnerId": "644160558196",
-                "ReservationId": "r-0de107f29ed16d364"
+                "PrivateDnsName": "ip-172-31-25-97.us-west-2.compute.internal",
+                "PrivateIpAddress": "172.31.25.97",
+                "PrivateIpAddresses": [
+                  {
+                    "Association": {
+                      "IpOwnerId": "amazon",
+                      "PublicDnsName": "ec2-18-237-70-187.us-west-2.compute.amazonaws.com",
+                      "PublicIp": "18.237.70.187"
+                    },
+                    "Primary": true,
+                    "PrivateDnsName": "ip-172-31-25-97.us-west-2.compute.internal",
+                    "PrivateIpAddress": "172.31.25.97"
+                  }
+                ],
+                "SourceDestCheck": true,
+                "Status": "in-use",
+                "SubnetId": "subnet-15452171",
+                "VpcId": "vpc-4a9ff72e"
+              }
+            ],
+            "RootDeviceName": "/dev/sda1",
+            "RootDeviceType": "ebs",
+            "SecurityGroups": [
+              {
+                "GroupName": "default",
+                "GroupId": "sg-f9cc4d9f"
+              }
+            ],
+            "SourceDestCheck": true,
+            "VirtualizationType": "hvm",
+            "CpuOptions": {
+              "CoreCount": 1,
+              "ThreadsPerCore": 1
+            },
+            "CapacityReservationSpecification": {
+              "CapacityReservationPreference": "open"
+            },
+            "HibernationOptions": {
+              "Configured": false
             }
+          }
         ],
-        "ResponseMetadata": {
-            "RequestId": "a33aeeb3-fe37-48ca-9a13-906771862572",
-            "HTTPStatusCode": 200,
-            "HTTPHeaders": {
-                "content-type": "text/xml;charset=UTF-8",
-                "transfer-encoding": "chunked",
-                "vary": "Accept-Encoding",
-                "date": "Thu, 28 Feb 2019 14:28:00 GMT",
-                "server": "AmazonEC2"
-            },
-            "RetryAttempts": 0
-        }
-    }
+        "OwnerId": "644160558196",
+        "ReservationId": "r-0de107f29ed16d364"
+      }
+    ],
+    "ResponseMetadata": {}
+  }
 }
\ No newline at end of file
diff --git a/tests/data/placebo/test_ec2_permissions/ec2.DescribeTags_1.json b/tests/data/placebo/test_ec2_permissions/ec2.DescribeTags_1.json
index 3660bfb4d..814446fdf 100644
--- a/tests/data/placebo/test_ec2_permissions/ec2.DescribeTags_1.json
+++ b/tests/data/placebo/test_ec2_permissions/ec2.DescribeTags_1.json
@@ -1,54 +1,44 @@
 {
-    "status_code": 200,
-    "data": {
-        "Tags": [
-            {
-                "Key": "aws:autoscaling:groupName",
-                "ResourceId": "i-0aca1d4f8f943d73e",
-                "ResourceType": "instance",
-                "Value": "test2"
-            },
-            {
-                "Key": "aws:ec2launchtemplate:id",
-                "ResourceId": "i-0aca1d4f8f943d73e",
-                "ResourceType": "instance",
-                "Value": "lt-0877401c93c294001"
-            },
-            {
-                "Key": "aws:ec2launchtemplate:version",
-                "ResourceId": "i-0aca1d4f8f943d73e",
-                "ResourceType": "instance",
-                "Value": "4"
-            },
-            {
-                "Key": "aws:autoscaling:groupName",
-                "ResourceId": "i-0db184a69847143fb",
-                "ResourceType": "instance",
-                "Value": "test2"
-            },
-            {
-                "Key": "aws:ec2launchtemplate:id",
-                "ResourceId": "i-0db184a69847143fb",
-                "ResourceType": "instance",
-                "Value": "lt-0877401c93c294001"
-            },
-            {
-                "Key": "aws:ec2launchtemplate:version",
-                "ResourceId": "i-0db184a69847143fb",
-                "ResourceType": "instance",
-                "Value": "4"
-            }
-        ],
-        "ResponseMetadata": {
-            "RequestId": "9ba8de1b-bd9d-43f1-a69f-e94707e4c481",
-            "HTTPStatusCode": 200,
-            "HTTPHeaders": {
-                "content-type": "text/xml;charset=UTF-8",
-                "content-length": "1573",
-                "date": "Thu, 28 Feb 2019 14:28:01 GMT",
-                "server": "AmazonEC2"
-            },
-            "RetryAttempts": 0
-        }
-    }
+  "status_code": 200,
+  "data": {
+    "Tags": [
+      {
+        "Key": "aws:autoscaling:groupName",
+        "ResourceId": "i-0aca1d4f8f943d73e",
+        "ResourceType": "instance",
+        "Value": "test2"
+      },
+      {
+        "Key": "aws:ec2launchtemplate:id",
+        "ResourceId": "i-0aca1d4f8f943d73e",
+        "ResourceType": "instance",
+        "Value": "lt-0877401c93c294001"
+      },
+      {
+        "Key": "aws:ec2launchtemplate:version",
+        "ResourceId": "i-0aca1d4f8f943d73e",
+        "ResourceType": "instance",
+        "Value": "4"
+      },
+      {
+        "Key": "aws:autoscaling:groupName",
+        "ResourceId": "i-0db184a69847143fb",
+        "ResourceType": "instance",
+        "Value": "test2"
+      },
+      {
+        "Key": "aws:ec2launchtemplate:id",
+        "ResourceId": "i-0db184a69847143fb",
+        "ResourceType": "instance",
+        "Value": "lt-0877401c93c294001"
+      },
+      {
+        "Key": "aws:ec2launchtemplate:version",
+        "ResourceId": "i-0db184a69847143fb",
+        "ResourceType": "instance",
+        "Value": "4"
+      }
+    ],
+    "ResponseMetadata": {}
+  }
 }
\ No newline at end of file
diff --git a/tests/data/placebo/test_ec2_permissions/iam.GetRole_1.json b/tests/data/placebo/test_ec2_permissions/iam.GetRole_1.json
new file mode 100644
index 000000000..310357d79
--- /dev/null
+++ b/tests/data/placebo/test_ec2_permissions/iam.GetRole_1.json
@@ -0,0 +1,19 @@
+{
+    "status_code": 200,
+    "data": {
+    "Role": {
+        "Path": "/",
+        "RoleName": "CloudCustodianRole",
+        "RoleId": "AROAI7ZS26HIW5UKQGHRM",
+        "Arn": "arn:aws:iam::644160558196:role/CloudCustodianRole",
+        "CreateDate": "2016-10-29T19:39:43Z",
+        "AssumeRolePolicyDocument": "%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D",
+        "MaxSessionDuration": 3600,
+        "RoleLastUsed": {
+            "LastUsedDate": "2020-04-01T17:38:54Z",
+            "Region": "us-east-1"
+        }
+    },
+	"ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_ec2_permissions/iam.ListInstanceProfiles_1.json b/tests/data/placebo/test_ec2_permissions/iam.ListInstanceProfiles_1.json
index 178f892b2..9ae3e910e 100644
--- a/tests/data/placebo/test_ec2_permissions/iam.ListInstanceProfiles_1.json
+++ b/tests/data/placebo/test_ec2_permissions/iam.ListInstanceProfiles_1.json
@@ -1,55 +1,44 @@
 {
-    "status_code": 200,
-    "data": {
-        "InstanceProfiles": [
-            {
-                "Path": "/",
-                "InstanceProfileName": "CloudCustodianRole",
-                "InstanceProfileId": "AIPAJO5EMJ3YEMNUF5ZWM",
-                "Arn": "arn:aws:iam::644160558196:instance-profile/CloudCustodianRole",
-                "CreateDate": {
-                    "__class__": "datetime",
-                    "year": 2016,
-                    "month": 10,
-                    "day": 29,
-                    "hour": 19,
-                    "minute": 39,
-                    "second": 43,
-                    "microsecond": 0
-                },
-                "Roles": [
-                    {
-                        "Path": "/",
-                        "RoleName": "CloudCustodianRole",
-                        "RoleId": "AROAI7ZS26HIW5UKQGHRM",
-                        "Arn": "arn:aws:iam::644160558196:role/CloudCustodianRole",
-                        "CreateDate": {
-                            "__class__": "datetime",
-                            "year": 2016,
-                            "month": 10,
-                            "day": 29,
-                            "hour": 19,
-                            "minute": 39,
-                            "second": 43,
-                            "microsecond": 0
-                        },
-                        "AssumeRolePolicyDocument": "%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22AWS%22%3A%5B%22arn%3Aaws%3Aiam%3A%3A644160558196%3Auser%2Fkapil%22%2C%22arn%3Aaws%3Aiam%3A%3A644160558196%3Aroot%22%5D%2C%22Service%22%3A%5B%22ec2.amazonaws.com%22%2C%22lambda.amazonaws.com%22%5D%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D"
-                    }
-                ]
-            }
-        ],
-        "IsTruncated": false,
-        "ResponseMetadata": {
-            "RequestId": "0ddc0758-3b65-11e9-a5d1-cd2bc2e0baac",
-            "HTTPStatusCode": 200,
-            "HTTPHeaders": {
-                "x-amzn-requestid": "0ddc0758-3b65-11e9-a5d1-cd2bc2e0baac",
-                "content-type": "text/xml",
-                "content-length": "9732",
-                "vary": "Accept-Encoding",
-                "date": "Thu, 28 Feb 2019 14:28:01 GMT"
+  "status_code": 200,
+  "data": {
+    "InstanceProfiles": [
+      {
+        "Path": "/",
+        "InstanceProfileName": "CloudCustodianRole",
+        "InstanceProfileId": "AIPAJO5EMJ3YEMNUF5ZWM",
+        "Arn": "arn:aws:iam::644160558196:instance-profile/CloudCustodianRole",
+        "CreateDate": {
+          "__class__": "datetime",
+          "year": 2016,
+          "month": 10,
+          "day": 29,
+          "hour": 19,
+          "minute": 39,
+          "second": 43,
+          "microsecond": 0
+        },
+        "Roles": [
+          {
+            "Path": "/",
+            "RoleName": "CloudCustodianRole",
+            "RoleId": "AROAI7ZS26HIW5UKQGHRM",
+            "Arn": "arn:aws:iam::644160558196:role/CloudCustodianRole",
+            "CreateDate": {
+              "__class__": "datetime",
+              "year": 2016,
+              "month": 10,
+              "day": 29,
+              "hour": 19,
+              "minute": 39,
+              "second": 43,
+              "microsecond": 0
             },
-            "RetryAttempts": 0
-        }
-    }
-}
+            "AssumeRolePolicyDocument": "%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22AWS%22%3A%5B%22arn%3Aaws%3Aiam%3A%3A644160558196%3Auser%2Fkapil%22%2C%22arn%3Aaws%3Aiam%3A%3A644160558196%3Aroot%22%5D%2C%22Service%22%3A%5B%22ec2.amazonaws.com%22%2C%22lambda.amazonaws.com%22%5D%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D"
+          }
+        ]
+      }
+    ],
+    "IsTruncated": false,
+    "ResponseMetadata": {}
+  }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_ec2_permissions/iam.SimulatePrincipalPolicy_1.json b/tests/data/placebo/test_ec2_permissions/iam.SimulatePrincipalPolicy_1.json
index 3759e81bb..bd13a953a 100644
--- a/tests/data/placebo/test_ec2_permissions/iam.SimulatePrincipalPolicy_1.json
+++ b/tests/data/placebo/test_ec2_permissions/iam.SimulatePrincipalPolicy_1.json
@@ -1,38 +1,28 @@
 {
-    "status_code": 200,
-    "data": {
-        "EvaluationResults": [
-            {
-                "EvalActionName": "lambda:CreateFunction",
-                "EvalResourceName": "*",
-                "EvalDecision": "allowed",
-                "MatchedStatements": [
-                    {
-                        "SourcePolicyId": "AdministratorAccess",
-                        "StartPosition": {
-                            "Line": 3,
-                            "Column": 17
-                        },
-                        "EndPosition": {
-                            "Line": 8,
-                            "Column": 6
-                        }
-                    }
-                ],
-                "MissingContextValues": []
+  "status_code": 200,
+  "data": {
+    "EvaluationResults": [
+      {
+        "EvalActionName": "lambda:CreateFunction",
+        "EvalResourceName": "*",
+        "EvalDecision": "allowed",
+        "MatchedStatements": [
+          {
+            "SourcePolicyId": "AdministratorAccess",
+            "StartPosition": {
+              "Line": 3,
+              "Column": 17
+            },
+            "EndPosition": {
+              "Line": 8,
+              "Column": 6
             }
+          }
         ],
-        "IsTruncated": false,
-        "ResponseMetadata": {
-            "RequestId": "0de7c754-3b65-11e9-8491-8fd0be1cf9c2",
-            "HTTPStatusCode": 200,
-            "HTTPHeaders": {
-                "x-amzn-requestid": "0de7c754-3b65-11e9-8491-8fd0be1cf9c2",
-                "content-type": "text/xml",
-                "content-length": "995",
-                "date": "Thu, 28 Feb 2019 14:28:01 GMT"
-            },
-            "RetryAttempts": 0
-        }
-    }
+        "MissingContextValues": []
+      }
+    ],
+    "IsTruncated": false,
+    "ResponseMetadata": {}
+  }
 }
\ No newline at end of file
diff --git a/tests/data/placebo/test_lambda_check_permission/iam.GetPolicyVersion_1.json b/tests/data/placebo/test_lambda_check_permission/iam.GetPolicyVersion_1.json
new file mode 100644
index 000000000..44894a1f5
--- /dev/null
+++ b/tests/data/placebo/test_lambda_check_permission/iam.GetPolicyVersion_1.json
@@ -0,0 +1,21 @@
+{
+  "status_code": 200,
+  "data": {
+    "PolicyVersion": {
+      "Document": "%7B%0A%20%20%20%20%22Version%22%3A%20%222012-10-17%22%2C%0A%20%20%20%20%22Statement%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Sid%22%3A%20%22VisualEditor0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Effect%22%3A%20%22Deny%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Action%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListRoleTags%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListServerCertificates%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListPoliciesGrantingServiceAccess%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListServiceSpecificCredentials%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListMFADevices%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListSigningCertificates%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListVirtualMFADevices%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListInstanceProfilesForRole%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListSSHPublicKeys%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListAttachedRolePolicies%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListAttachedUserPolicies%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListAttachedGroupPolicies%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListRolePolicies%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListAccessKeys%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListPolicies%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListSAMLProviders%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListGroupPolicies%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListEntitiesForPolicy%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListRoles%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListUserPolicies%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListInstanceProfiles%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListPolicyVersions%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListOpenIDConnectProviders%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListGroupsForUser%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListAccountAliases%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListUsers%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListGroups%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AGetLoginProfile%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AListUserTags%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22iam%3AGetAccountSummary%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Resource%22%3A%20%22%2A%22%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%5D%0A%7D",
+      "VersionId": "v2",
+      "IsDefaultVersion": true,
+      "CreateDate": {
+        "__class__": "datetime",
+        "year": 2020,
+        "month": 4,
+        "day": 1,
+        "hour": 17,
+        "minute": 29,
+        "second": 45,
+        "microsecond": 0
+      }
+    },
+    "ResponseMetadata": {}
+  }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_lambda_check_permission/iam.GetPolicy_1.json b/tests/data/placebo/test_lambda_check_permission/iam.GetPolicy_1.json
new file mode 100644
index 000000000..c554f31ec
--- /dev/null
+++ b/tests/data/placebo/test_lambda_check_permission/iam.GetPolicy_1.json
@@ -0,0 +1,36 @@
+{
+  "status_code": 200,
+  "data": {
+    "Policy": {
+      "PolicyName": "BlackListIamList",
+      "PolicyId": "ANPAZL6XWCR2MBNLHREFH",
+      "Arn": "arn:aws:iam::644160558196:policy/BlackListIamList",
+      "Path": "/",
+      "DefaultVersionId": "v2",
+      "AttachmentCount": 0,
+      "PermissionsBoundaryUsageCount": 1,
+      "IsAttachable": true,
+      "CreateDate": {
+        "__class__": "datetime",
+        "year": 2020,
+        "month": 4,
+        "day": 1,
+        "hour": 17,
+        "minute": 29,
+        "second": 23,
+        "microsecond": 0
+      },
+      "UpdateDate": {
+        "__class__": "datetime",
+        "year": 2020,
+        "month": 4,
+        "day": 1,
+        "hour": 17,
+        "minute": 29,
+        "second": 45,
+        "microsecond": 0
+      }
+    },
+    "ResponseMetadata": {}
+  }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_lambda_check_permission/iam.GetRole_1.json b/tests/data/placebo/test_lambda_check_permission/iam.GetRole_1.json
new file mode 100644
index 000000000..e2a2d6367
--- /dev/null
+++ b/tests/data/placebo/test_lambda_check_permission/iam.GetRole_1.json
@@ -0,0 +1,41 @@
+{
+  "status_code": 200,
+  "data": {
+    "Role": {
+      "Path": "/",
+      "RoleName": "custodian-mu",
+      "RoleId": "AROAJQ7B35GGHTQXLQCNY",
+      "Arn": "arn:aws:iam::644160558196:role/custodian-mu",
+      "CreateDate": {
+        "__class__": "datetime",
+        "year": 2016,
+        "month": 8,
+        "day": 27,
+        "hour": 12,
+        "minute": 2,
+        "second": 50,
+        "microsecond": 0
+      },
+      "AssumeRolePolicyDocument": "%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22lambda.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D",
+      "MaxSessionDuration": 3600,
+      "PermissionsBoundary": {
+        "PermissionsBoundaryType": "Policy",
+        "PermissionsBoundaryArn": "arn:aws:iam::644160558196:policy/BlackListIamList"
+      },
+      "RoleLastUsed": {
+        "LastUsedDate": {
+          "__class__": "datetime",
+          "year": 2020,
+          "month": 4,
+          "day": 1,
+          "hour": 16,
+          "minute": 59,
+          "second": 24,
+          "microsecond": 0
+        },
+        "Region": "us-east-1"
+      }
+    },
+    "ResponseMetadata": {}
+  }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_lambda_check_permission/iam.SimulatePrincipalPolicy_1.json b/tests/data/placebo/test_lambda_check_permission/iam.SimulatePrincipalPolicy_1.json
new file mode 100644
index 000000000..f9b5fe49d
--- /dev/null
+++ b/tests/data/placebo/test_lambda_check_permission/iam.SimulatePrincipalPolicy_1.json
@@ -0,0 +1,44 @@
+{
+  "status_code": 200,
+  "data": {
+    "EvaluationResults": [
+      {
+        "EvalActionName": "iam:ListUsers",
+        "EvalResourceName": "arn:aws:iam::644160558196:user/",
+        "EvalDecision": "explicitDeny",
+        "MatchedStatements": [
+          {
+            "SourcePolicyId": "IAMReadOnlyAccess",
+            "SourcePolicyType": "IAM Policy",
+            "StartPosition": {
+              "Line": 3,
+              "Column": 17
+            },
+            "EndPosition": {
+              "Line": 15,
+              "Column": 6
+            }
+          },
+          {
+            "SourcePolicyId": "PermissionsBoundaryPolicyInputList.1",
+            "SourcePolicyType": "Permissions Boundary Policy",
+            "StartPosition": {
+              "Line": 1,
+              "Column": 41
+            },
+            "EndPosition": {
+              "Line": 1,
+              "Column": 908
+            }
+          }
+        ],
+        "MissingContextValues": [],
+        "PermissionsBoundaryDecisionDetail": {
+          "AllowedByPermissionsBoundary": false
+        }
+      }
+    ],
+    "IsTruncated": false,
+    "ResponseMetadata": {}
+  }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_lambda_check_permission/lambda.ListFunctions_1.json b/tests/data/placebo/test_lambda_check_permission/lambda.ListFunctions_1.json
new file mode 100644
index 000000000..0bd5a11b0
--- /dev/null
+++ b/tests/data/placebo/test_lambda_check_permission/lambda.ListFunctions_1.json
@@ -0,0 +1,31 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {},
+        "Functions": [
+            {
+                "FunctionName": "custodian-log-age",
+                "FunctionArn": "arn:aws:lambda:us-east-1:644160558196:function:custodian-log-age",
+                "Runtime": "python3.7",
+                "Role": "arn:aws:iam::644160558196:role/custodian-mu",
+                "Handler": "custodian_policy.run",
+                "CodeSize": 567503,
+                "Description": "cloud-custodian lambda policy",
+                "Timeout": 900,
+                "MemorySize": 512,
+                "LastModified": "2019-06-18T21:05:47.053+0000",
+                "CodeSha256": "ntfYchL2tf+xoRRXip+C2uEjAdWa73zdKFJMbRCrwJg=",
+                "Version": "$LATEST",
+                "VpcConfig": {
+                    "SubnetIds": [],
+                    "SecurityGroupIds": [],
+                    "VpcId": ""
+                },
+                "TracingConfig": {
+                    "Mode": "PassThrough"
+                },
+                "RevisionId": "51415854-cfdd-4461-ab71-e45bf9e6bc0e"
+            }
+        ]
+    }
+}
diff --git a/tests/data/placebo/test_lambda_check_permission/tagging.GetResources_1.json b/tests/data/placebo/test_lambda_check_permission/tagging.GetResources_1.json
new file mode 100644
index 000000000..958027559
--- /dev/null
+++ b/tests/data/placebo/test_lambda_check_permission/tagging.GetResources_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [],
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/test_dms.py b/tests/test_dms.py
index bfaef766b..168f31ccc 100644
--- a/tests/test_dms.py
+++ b/tests/test_dms.py
@@ -250,6 +250,22 @@ class DmsEndpointTests(BaseTest):
             [3305, "require", "admin", "c7n-sql-db-02", "c7n-db-02"],
         )
 
+    def test_endpoint_tag_filter(self):
+        session_factory = self.replay_flight_data("test_dms_tag_filter")
+        p = self.load_policy(
+            {
+                "name": "dms-sql-ssl",
+                "resource": "dms-endpoint",
+                "filters": [
+                    {"tag:Owner": "pikachu"},
+                ]
+            },
+            session_factory=session_factory,
+        )
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+        self.assertEqual(resources[0]['Tags'], [{'Key': 'Owner', 'Value': 'pikachu'}])
+
     def test_dms_endpoint_delete(self):
         session_factory = self.replay_flight_data("test_dms_endpoint_delete")
         policy = {
diff --git a/tests/test_lambda.py b/tests/test_lambda.py
index 7b3dc120c..611b4327c 100644
--- a/tests/test_lambda.py
+++ b/tests/test_lambda.py
@@ -156,6 +156,24 @@ class LambdaLayerTest(BaseTest):
 
 class LambdaTest(BaseTest):
 
+    def test_lambda_check_permission(self):
+        # lots of pre-conditions, iam role with iam read only policy attached
+        # and a permission boundary with deny on iam read access.
+        factory = self.replay_flight_data('test_lambda_check_permission')
+        p = self.load_policy(
+            {
+                'name': 'lambda-check',
+                'resource': 'lambda',
+                'filters': [
+                    {'FunctionName': 'custodian-log-age'},
+                    {'type': 'check-permissions',
+                     'match': 'allowed',
+                     'actions': ['iam:ListUsers']}]
+            },
+            session_factory=factory)
+        resources = p.run()
+        assert not resources
+
     def test_lambda_config_source(self):
         factory = self.replay_flight_data("test_aws_lambda_config_source")
         p = self.load_policy(