Repository: localstack/localstack

Issue:
bug: Dynamodb table describe output missing SSEDescription key 
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current Behavior

MusicCollection
{
    "Table": {
        "AttributeDefinitions": [
            {
                "AttributeName": "Artist",
                "AttributeType": "S"
            },
            {
                "AttributeName": "SongTitle",
                "AttributeType": "S"
            }
        ],
        "TableName": "MusicCollection",
        "KeySchema": [
            {
                "AttributeName": "Artist",
                "KeyType": "HASH"
            },
            {
                "AttributeName": "SongTitle",
                "KeyType": "RANGE"
            }
        ],
        "TableStatus": "ACTIVE",
        "CreationDateTime": "2021-09-12T00:30:23.741000-07:00",
        "ProvisionedThroughput": {
            "LastIncreaseDateTime": "1969-12-31T16:00:00-08:00",
            "LastDecreaseDateTime": "1969-12-31T16:00:00-08:00",
            "NumberOfDecreasesToday": 0,
            "ReadCapacityUnits": 5,
            "WriteCapacityUnits": 5
        },
        "TableSizeBytes": 0,
        "ItemCount": 0,
        "TableArn": "arn:aws:dynamodb:us-east-1:000000000000:table/MusicCollection"
    }
}

### Expected Behavior

{
    "TableDescription": {
        "AttributeDefinitions": [
            {
                "AttributeName": "Artist",
                "AttributeType": "S"
            },
            {
                "AttributeName": "SongTitle",
                "AttributeType": "S"
            }
        ],
        "TableName": "MusicCollection",
        "KeySchema": [
            {
                "AttributeName": "Artist",
                "KeyType": "HASH"
            },
            {
                "AttributeName": "SongTitle",
                "KeyType": "RANGE"
            }
        ],
        "TableStatus": "CREATING",
        "CreationDateTime": "2020-05-27T11:12:16.431000-07:00",
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "ReadCapacityUnits": 5,
            "WriteCapacityUnits": 5
        },
        "TableSizeBytes": 0,
        "ItemCount": 0,
        "TableArn": "arn:aws:dynamodb:us-west-2:123456789012:table/MusicCollection",
        "TableId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
        "SSEDescription": {
            "Status": "ENABLED",
            "SSEType": "KMS",
            "KMSMasterKeyArn": "arn:aws:kms:us-west-2:123456789012:key/abcd1234-abcd-1234-a123-ab1234a1b234"
        }
    }
}

### How are you starting LocalStack?

Custom (please describe below)

### Steps To Reproduce

#### How are you starting localstack (e.g., `bin/localstack` command, arguments, or `docker-compose.yml`)

-> docker run --rm -it -p 4566:4566 -p 4571:4571 localstack/localstack


#### Client commands (e.g., AWS SDK code snippet, or sequence of "awslocal" commands)

## Create the dynamodb table from separate terminal
-> aws --endpoint-url http://localhost:4566 dynamodb create-table \
    --table-name MusicCollection \
    --attribute-definitions AttributeName=Artist,AttributeType=S AttributeName=SongTitle,AttributeType=S \
    --key-schema AttributeName=Artist,KeyType=HASH AttributeName=SongTitle,KeyType=RANGE \
    --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
    --sse-specification Enabled=true,SSEType=KMS,KMSMasterKeyId=abcd1234-abcd-1234-a123-ab1234a1b234

## Describe the table
->  aws --endpoint-url http://localhost:4566 dynamodb describe-table --table-name MusicCollection

Not able to see the description of the server-side encryption status on the specified table.


### Environment

```markdown
- OS: macOS Big Sur
- LocalStack: 0.12.17.5
```


### Anything else?

_No response_


Discussion:

Resolving patch:
diff --git a/localstack/services/dynamodb/dynamodb_listener.py b/localstack/services/dynamodb/dynamodb_listener.py
--- a/localstack/services/dynamodb/dynamodb_listener.py
+++ b/localstack/services/dynamodb/dynamodb_listener.py
@@ -18,7 +18,15 @@
 from localstack.utils.analytics import event_publisher
 from localstack.utils.aws import aws_responses, aws_stack
 from localstack.utils.bootstrap import is_api_enabled
-from localstack.utils.common import clone, json_safe, select_attributes, short_uid, to_bytes, to_str
+from localstack.utils.common import (
+    clone,
+    json_safe,
+    long_uid,
+    select_attributes,
+    short_uid,
+    to_bytes,
+    to_str,
+)
 
 # set up logger
 LOGGER = logging.getLogger(__name__)
@@ -462,24 +470,41 @@ def return_response(self, method, path, data, headers, response):
                     record["dynamodb"]["StreamViewType"] = stream_spec["StreamViewType"]
 
         elif action == "CreateTable":
-            if "StreamSpecification" in data:
-                if response.status_code == 200:
-                    content = json.loads(to_str(response._content))
+            if response.status_code == 200:
+
+                table_definitions = (
+                    DynamoDBRegion.get().table_definitions.get(data["TableName"]) or {}
+                )
+                if "TableId" not in table_definitions:
+                    table_definitions["TableId"] = long_uid()
+
+                if "SSESpecification" in table_definitions:
+                    sse_specification = table_definitions.pop("SSESpecification")
+                    table_definitions["SSEDescription"] = get_sse_description(sse_specification)
+
+                content = json.loads(to_str(response.content))
+                if table_definitions:
+                    table_content = content.get("Table", {})
+                    table_content.update(table_definitions)
+                    content["TableDescription"].update(table_content)
+                    update_response_content(response, content)
+
+                if "StreamSpecification" in data:
                     create_dynamodb_stream(
                         data, content["TableDescription"].get("LatestStreamLabel")
                     )
 
+                if data.get("Tags"):
+                    table_arn = content["TableDescription"]["TableArn"]
+                    DynamoDBRegion.TABLE_TAGS[table_arn] = {
+                        tag["Key"]: tag["Value"] for tag in data["Tags"]
+                    }
+
             event_publisher.fire_event(
                 event_publisher.EVENT_DYNAMODB_CREATE_TABLE,
                 payload={"n": event_publisher.get_hash(table_name)},
             )
 
-            if data.get("Tags") and response.status_code == 200:
-                table_arn = json.loads(response._content)["TableDescription"]["TableArn"]
-                DynamoDBRegion.TABLE_TAGS[table_arn] = {
-                    tag["Key"]: tag["Value"] for tag in data["Tags"]
-                }
-
             return
 
         elif action == "DeleteTable":
@@ -534,11 +559,21 @@ def return_response(self, method, path, data, headers, response):
         elif action == "DescribeTable":
             table_name = data.get("TableName")
             table_props = DynamoDBRegion.get().table_properties.get(table_name)
+
             if table_props:
                 content = json.loads(to_str(response.content))
                 content.get("Table", {}).update(table_props)
                 update_response_content(response, content)
 
+            # Update only TableId and SSEDescription if present
+            table_definitions = DynamoDBRegion.get().table_definitions.get(table_name)
+            if table_definitions:
+                for key in ["TableId", "SSEDescription"]:
+                    if table_definitions.get(key):
+                        content = json.loads(to_str(response.content))
+                        content.get("Table", {})[key] = table_definitions[key]
+                        update_response_content(response, content)
+
         elif action == "TagResource":
             table_arn = data["ResourceArn"]
             table_tags = DynamoDBRegion.TABLE_TAGS
@@ -749,6 +784,14 @@ def _thread_local(name, default=None):
             return default
 
 
+def get_sse_description(data):
+    return {
+        "Status": "ENABLED" if data["Enabled"] else "UPDATING",
+        "SSEType": data["SSEType"],
+        "KMSMasterKeyArn": aws_stack.kms_key_arn(data["KMSMasterKeyId"]),
+    }
+
+
 def handle_special_request(method, path, data, headers):
     if path.startswith("/shell") or method == "GET":
         if path == "/shell":


Test patch:
diff --git a/tests/integration/test_dynamodb.py b/tests/integration/test_dynamodb.py
--- a/tests/integration/test_dynamodb.py
+++ b/tests/integration/test_dynamodb.py
@@ -14,7 +14,7 @@
 from localstack.utils.aws import aws_stack
 from localstack.utils.aws.aws_models import KinesisStream
 from localstack.utils.aws.aws_stack import get_environment
-from localstack.utils.common import json_safe, retry, short_uid
+from localstack.utils.common import json_safe, long_uid, retry, short_uid
 from localstack.utils.testutil import check_expected_lambda_log_events_length
 
 PARTITION_KEY = "id"
@@ -826,6 +826,32 @@ def test_dynamodb_batch_write_item(self):
 
         self.assertEqual({}, result.get("UnprocessedItems"))
 
+    def test_dynamodb_create_table_with_sse_specification(self):
+        dynamodb = aws_stack.connect_to_service("dynamodb")
+        table_name = "ddb-table-%s" % short_uid()
+
+        kms_master_key_id = long_uid()
+        sse_specification = {"Enabled": True, "SSEType": "KMS", "KMSMasterKeyId": kms_master_key_id}
+        kms_master_key_arn = aws_stack.kms_key_arn(kms_master_key_id)
+
+        result = dynamodb.create_table(
+            TableName=table_name,
+            KeySchema=[{"AttributeName": "id", "KeyType": "HASH"}],
+            AttributeDefinitions=[{"AttributeName": "id", "AttributeType": "S"}],
+            ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
+            SSESpecification=sse_specification,
+            Tags=TEST_DDB_TAGS,
+        )
+
+        self.assertTrue(result["TableDescription"]["SSEDescription"])
+        self.assertEqual("ENABLED", result["TableDescription"]["SSEDescription"]["Status"])
+        self.assertEqual(
+            kms_master_key_arn,
+            result["TableDescription"]["SSEDescription"]["KMSMasterKeyArn"],
+        )
+
+        delete_table(table_name)
+
 
 def delete_table(name):
     dynamodb_client = aws_stack.connect_to_service("dynamodb")