Repository: getmoto/moto

Issue:
SNS KmsMasterKeyId not returned as part of get_topic_attributes response
when sns mock is used to get topic attributes:

`response = client.get_topic_attributes(
    TopicArn='string'
)`

KmsMasterKeyId - The ID of an AWS-managed customer master key (CMK) for Amazon SNS or a custom CMK - is not included as part of the response.



Discussion:
Thanks for raising this @hanjb - marking this as an enhancement

Resolving patch:
diff --git a/moto/sns/models.py b/moto/sns/models.py
--- a/moto/sns/models.py
+++ b/moto/sns/models.py
@@ -45,6 +45,7 @@ def __init__(self, name, sns_backend):
         self.account_id = DEFAULT_ACCOUNT_ID
         self.display_name = ""
         self.delivery_policy = ""
+        self.kms_master_key_id = ""
         self.effective_delivery_policy = json.dumps(DEFAULT_EFFECTIVE_DELIVERY_POLICY)
         self.arn = make_arn_for_topic(self.account_id, name, sns_backend.region_name)
 
diff --git a/moto/sns/responses.py b/moto/sns/responses.py
--- a/moto/sns/responses.py
+++ b/moto/sns/responses.py
@@ -158,28 +158,28 @@ def get_topic_attributes(self):
         topic = self.backend.get_topic(topic_arn)
 
         if self.request_json:
-            return json.dumps(
-                {
-                    "GetTopicAttributesResponse": {
-                        "GetTopicAttributesResult": {
-                            "Attributes": {
-                                "Owner": topic.account_id,
-                                "Policy": topic.policy,
-                                "TopicArn": topic.arn,
-                                "DisplayName": topic.display_name,
-                                "SubscriptionsPending": topic.subscriptions_pending,
-                                "SubscriptionsConfirmed": topic.subscriptions_confimed,
-                                "SubscriptionsDeleted": topic.subscriptions_deleted,
-                                "DeliveryPolicy": topic.delivery_policy,
-                                "EffectiveDeliveryPolicy": topic.effective_delivery_policy,
-                            }
-                        },
-                        "ResponseMetadata": {
-                            "RequestId": "057f074c-33a7-11df-9540-99d0768312d3"
-                        },
-                    }
+            attributes = {
+                "Owner": topic.account_id,
+                "Policy": topic.policy,
+                "TopicArn": topic.arn,
+                "DisplayName": topic.display_name,
+                "SubscriptionsPending": topic.subscriptions_pending,
+                "SubscriptionsConfirmed": topic.subscriptions_confimed,
+                "SubscriptionsDeleted": topic.subscriptions_deleted,
+                "DeliveryPolicy": topic.delivery_policy,
+                "EffectiveDeliveryPolicy": topic.effective_delivery_policy,
+            }
+            if topic.kms_master_key_id:
+                attributes["KmsMasterKeyId"] = topic.kms_master_key_id
+            response = {
+                "GetTopicAttributesResponse": {
+                    "GetTopicAttributesResult": {"Attributes": attributes},
+                    "ResponseMetadata": {
+                        "RequestId": "057f074c-33a7-11df-9540-99d0768312d3"
+                    },
                 }
-            )
+            }
+            return json.dumps(response)
 
         template = self.response_template(GET_TOPIC_ATTRIBUTES_TEMPLATE)
         return template.render(topic=topic)
@@ -827,6 +827,12 @@ def untag_resource(self):
         <key>EffectiveDeliveryPolicy</key>
         <value>{{ topic.effective_delivery_policy }}</value>
       </entry>
+      {% if topic.kms_master_key_id %}
+      <entry>
+        <key>KmsMasterKeyId</key>
+        <value>{{ topic.kms_master_key_id }}</value>
+      </entry>
+      {% endif %}
     </Attributes>
   </GetTopicAttributesResult>
   <ResponseMetadata>


Test patch:
diff --git a/tests/test_sns/test_topics.py b/tests/test_sns/test_topics.py
--- a/tests/test_sns/test_topics.py
+++ b/tests/test_sns/test_topics.py
@@ -168,3 +168,25 @@ def test_topic_paging():
 
     topics_list.should.have.length_of(int(DEFAULT_PAGE_SIZE / 2))
     next_token.should.equal(None)
+
+
+@mock_sns_deprecated
+def test_topic_kms_master_key_id_attribute():
+    conn = boto.connect_sns()
+
+    conn.create_topic("test-sns-no-key-attr")
+    topics_json = conn.get_all_topics()
+    topic_arn = topics_json["ListTopicsResponse"]["ListTopicsResult"]["Topics"][0][
+        "TopicArn"
+    ]
+    attributes = conn.get_topic_attributes(topic_arn)["GetTopicAttributesResponse"][
+        "GetTopicAttributesResult"
+    ]["Attributes"]
+    attributes.should_not.have.key("KmsMasterKeyId")
+
+    conn.set_topic_attributes(topic_arn, "KmsMasterKeyId", "test-key")
+    attributes = conn.get_topic_attributes(topic_arn)["GetTopicAttributesResponse"][
+        "GetTopicAttributesResult"
+    ]["Attributes"]
+    attributes.should.have.key("KmsMasterKeyId")
+    attributes["KmsMasterKeyId"].should.equal("test-key")
diff --git a/tests/test_sns/test_topics_boto3.py b/tests/test_sns/test_topics_boto3.py
--- a/tests/test_sns/test_topics_boto3.py
+++ b/tests/test_sns/test_topics_boto3.py
@@ -520,3 +520,27 @@ def test_untag_resource_error():
     conn.untag_resource.when.called_with(
         ResourceArn="not-existing-topic", TagKeys=["tag_key_1"]
     ).should.throw(ClientError, "Resource does not exist")
+
+
+@mock_sns
+def test_topic_kms_master_key_id_attribute():
+    client = boto3.client("sns", region_name="us-west-2")
+    resp = client.create_topic(Name="test-sns-no-key-attr",)
+    topic_arn = resp["TopicArn"]
+    resp = client.get_topic_attributes(TopicArn=topic_arn)
+    resp["Attributes"].should_not.have.key("KmsMasterKeyId")
+
+    client.set_topic_attributes(
+        TopicArn=topic_arn, AttributeName="KmsMasterKeyId", AttributeValue="test-key"
+    )
+    resp = client.get_topic_attributes(TopicArn=topic_arn)
+    resp["Attributes"].should.have.key("KmsMasterKeyId")
+    resp["Attributes"]["KmsMasterKeyId"].should.equal("test-key")
+
+    resp = client.create_topic(
+        Name="test-sns-with-key-attr", Attributes={"KmsMasterKeyId": "key-id",}
+    )
+    topic_arn = resp["TopicArn"]
+    resp = client.get_topic_attributes(TopicArn=topic_arn)
+    resp["Attributes"].should.have.key("KmsMasterKeyId")
+    resp["Attributes"]["KmsMasterKeyId"].should.equal("key-id")