Repository: cloud-custodian/cloud-custodian

Issue:
include alias name in kms-key for filtering and notifications
**Is your feature request related to a problem? Please describe.**
I'd like the `AliasName` available in the kms-key resource information for more enriched notifications.

**Describe the solution you'd like**
We could do this one of two ways:
1. augment all the resources with the alias info when the resources are queried.  list-aliases is just one additional api call.
2. only pull in alias info if an `alias` filter is used. to use the alias in a notification, we'd need an extra no-op filter to trigger the extra info.

It seems a lot easier and simpler to go with option 1, but I know you've been leaning away from additional api calls and augmentations by default... thoughts? 


Discussion:
Looking through the existing code, there are already two mechanisms for filtering on kms keys and aliases ... one is via the `KmsRelatedFilter` class which pulls in the kms key and augments it with a `c7n:AliasName` key if there's an alias.  The other is the `ResourceKmsKeyAlias` class which embeds the entire kms alias structure under the `KeyAlias` key.  Given that these are both pulling in alias information when requesting related kms keys, it seems appropriate that the kms key itself should just always include it's alias in the `c7n:AliasName` key to maintain some consistency with the related-keys functionality.  The `ResourceKmsKeyAlias` filter is only used by ebs and rds resources and looks like the anti-pattern these days.
@kapilt thoughts?
Honestly, now I'm thinking we should just augment the keys with an `AliasName` field instead of `c7n:AliasName`.  The colon really makes simple name filtering annoying because you have to quote it for jmespath to process it correctly: (`"key": "'c7n:AliasName'"`).  So, I think I advocate that for a `kms-key` resource type, we just use `AliasName`.

Resolving patch:
diff --git a/c7n/resources/kms.py b/c7n/resources/kms.py
--- a/c7n/resources/kms.py
+++ b/c7n/resources/kms.py
@@ -63,12 +63,20 @@ def get_resources(self, ids, cache=True):
         return super().get_resources(ids, cache)
 
     def augment(self, resources):
-        client = local_session(self.manager.session_factory).client('kms')
+        aliases = KeyAlias(self.manager.ctx, {}).resources()
+        alias_map = {}
+        for a in aliases:
+            key_id = a['TargetKeyId']
+            alias_map[key_id] = alias_map.get(key_id, []) + [a['AliasName']]
 
+        client = local_session(self.manager.session_factory).client('kms')
         for r in resources:
             try:
-                key_id = r.get('KeyArn', r.get('KeyId'))
-                info = client.describe_key(KeyId=key_id)['KeyMetadata']
+                key_id = r.get('KeyId')
+                key_arn = r.get('KeyArn', key_id)
+                info = client.describe_key(KeyId=key_arn)['KeyMetadata']
+                if key_id in alias_map:
+                    info['AliasNames'] = alias_map[key_id]
                 r.update(info)
             except ClientError as e:
                 if e.response['Error']['Code'] == 'AccessDeniedException':
diff --git a/tools/dev/dockerpkg.py b/tools/dev/dockerpkg.py
--- a/tools/dev/dockerpkg.py
+++ b/tools/dev/dockerpkg.py
@@ -349,7 +349,7 @@ def retry(retry_count, exceptions, func, *args, **kw):
     attempts = 1
     while attempts <= retry_count:
         try:
-            func(*args, **kw)
+            return func(*args, **kw)
         except exceptions:
             log.warn('retrying on %s' % func)
             attempts += 1
@@ -484,7 +484,7 @@ def push_image(client, image_id, image_refs):
     if "HUB_TOKEN" in os.environ and "HUB_USER" in os.environ:
         log.info("docker hub login %s" % os.environ["HUB_USER"])
         result = client.login(os.environ["HUB_USER"], os.environ["HUB_TOKEN"])
-        if result["Status"] != "Login Succeeded":
+        if result.get("Status", "") != "Login Succeeded":
             raise RuntimeError("Docker Login failed %s" % (result,))
 
     for (repo, tag) in image_refs:


Test patch:
diff --git a/tests/data/placebo/test_cross_account_kms/kms.ListAliases_1.json b/tests/data/placebo/test_cross_account_kms/kms.ListAliases_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_cross_account_kms/kms.ListAliases_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "Aliases": [],
+        "Truncated": false,
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_key_rotation/kms.ListAliases_1.json b/tests/data/placebo/test_key_rotation/kms.ListAliases_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_key_rotation/kms.ListAliases_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "Aliases": [],
+        "Truncated": false,
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_key_rotation_set/kms.ListAliases_1.json b/tests/data/placebo/test_key_rotation_set/kms.ListAliases_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_key_rotation_set/kms.ListAliases_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "Aliases": [],
+        "Truncated": false,
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_kms_key_alias/kms.DescribeKey_1.json b/tests/data/placebo/test_kms_key_alias/kms.DescribeKey_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_kms_key_alias/kms.DescribeKey_1.json
@@ -0,0 +1,27 @@
+{
+    "status_code": 200,
+    "data": {
+        "KeyMetadata": {
+            "AWSAccountId": "644160558196",
+            "KeyId": "f1f33a6b-91aa-4b0a-904c-f2a0378277f0",
+            "Arn": "arn:aws:kms:us-east-1:644160558196:key/f1f33a6b-91aa-4b0a-904c-f2a0378277f0",
+            "CreationDate": {
+                "__class__": "datetime",
+                "year": 2017,
+                "month": 10,
+                "day": 31,
+                "hour": 5,
+                "minute": 2,
+                "second": 54,
+                "microsecond": 335000
+            },
+            "Enabled": true,
+            "Description": "Default master key that protects my DMS replication instance volumes when no other key is defined",
+            "KeyUsage": "ENCRYPT_DECRYPT",
+            "KeyState": "Enabled",
+            "Origin": "AWS_KMS",
+            "KeyManager": "AWS"
+        },
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_kms_key_alias/kms.ListAliases_1.json b/tests/data/placebo/test_kms_key_alias/kms.ListAliases_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_kms_key_alias/kms.ListAliases_1.json
@@ -0,0 +1,14 @@
+{
+    "status_code": 200,
+    "data": {
+        "Aliases": [
+            {
+                "AliasName": "alias/aws/dms",
+                "AliasArn": "arn:aws:kms:us-east-1:644160558196:alias/aws/dms",
+                "TargetKeyId": "f1f33a6b-91aa-4b0a-904c-f2a0378277f0"
+            }
+        ],
+        "Truncated": false,
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_kms_key_alias/kms.ListKeys_1.json b/tests/data/placebo/test_kms_key_alias/kms.ListKeys_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_kms_key_alias/kms.ListKeys_1.json
@@ -0,0 +1,13 @@
+{
+    "status_code": 200,
+    "data": {
+        "Keys": [
+            {
+                "KeyId": "f1f33a6b-91aa-4b0a-904c-f2a0378277f0",
+                "KeyArn": "arn:aws:kms:us-east-1:644160558196:key/f1f33a6b-91aa-4b0a-904c-f2a0378277f0"
+            }
+        ],
+        "Truncated": false,
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_kms_key_alias/tagging.GetResources_1.json b/tests/data/placebo/test_kms_key_alias/tagging.GetResources_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_kms_key_alias/tagging.GetResources_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [],
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_kms_key_remove_tag/kms.ListAliases_1.json b/tests/data/placebo/test_kms_key_remove_tag/kms.ListAliases_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_kms_key_remove_tag/kms.ListAliases_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "Aliases": [],
+        "Truncated": false,
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_kms_key_tag/kms.ListAliases_1.json b/tests/data/placebo/test_kms_key_tag/kms.ListAliases_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_kms_key_tag/kms.ListAliases_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "Aliases": [],
+        "Truncated": false,
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_kms_remove_matched/kms.ListAliases_1.json b/tests/data/placebo/test_kms_remove_matched/kms.ListAliases_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_kms_remove_matched/kms.ListAliases_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "Aliases": [],
+        "Truncated": false,
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_kms_remove_named/kms.ListAliases_1.json b/tests/data/placebo/test_kms_remove_named/kms.ListAliases_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_kms_remove_named/kms.ListAliases_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "Aliases": [],
+        "Truncated": false,
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/test_kms.py b/tests/test_kms.py
--- a/tests/test_kms.py
+++ b/tests/test_kms.py
@@ -35,6 +35,28 @@ def test_kms_grant(self):
         resources = p.run()
         self.assertEqual(len(resources), 0)
 
+    def test_kms_key_alias_augment(self):
+        session_factory = self.replay_flight_data("test_kms_key_alias")
+        p = self.load_policy(
+            {
+                "name": "kms-key-alias-filter",
+                "resource": "kms-key",
+                "filters": [
+                    {
+                        "type": "value",
+                        "key": "AliasNames",
+                        "op": "in",
+                        "value": "alias/aws/dms",
+                        "value_type": "swap"
+                    }
+                ],
+            },
+            session_factory=session_factory,
+        )
+
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+
     def test_key_rotation(self):
         session_factory = self.replay_flight_data("test_key_rotation")
         p = self.load_policy(