Repository: localstack/localstack

Issue:
feature request: Support for SSE in SQS
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Feature description

LocalStack should support Server-Side-Encryption for SQS if possible, or at least pretend it does so that scripts that assume this working against AWS don't break with LocalStack.

Currently terraform for example fails when trying to create an SQS queue with `sqs_managed_sse_enabled     = true` 

### 🧑‍💻 Implementation

It would probably be fine for now to at least simulate this in a basic `CRUD` way for at least the case when using AWS managed keys for the "encryption".


Example terraform:

```hcl
provider "aws" { 
  access_key                  = "test"
  secret_key                  = "test"
  region                      = "us-east-1"
  s3_force_path_style         = true
  skip_credentials_validation = true
  skip_metadata_api_check     = true
  skip_requesting_account_id  = true

  endpoints {
    sqs            = "http://localhost:4566"
    iam            = "http://localhost:4566"
  }
}

resource "aws_sqs_queue" "sqs" {
  name                        = "myq.fifo"
  fifo_queue                  = true
  content_based_deduplication = true
  sqs_managed_sse_enabled     = true
  
  tags = {
    service     = "myq"
  }
}
```

### Anything else?

- https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-configure-sqs-sse-queue.html
- https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html


Discussion:

Resolving patch:
diff --git a/localstack/aws/api/sqs/__init__.py b/localstack/aws/api/sqs/__init__.py
--- a/localstack/aws/api/sqs/__init__.py
+++ b/localstack/aws/api/sqs/__init__.py
@@ -1,4 +1,10 @@
-from typing import Dict, List, Optional, TypedDict
+import sys
+from typing import Dict, List, Optional
+
+if sys.version_info >= (3, 8):
+    from typing import TypedDict
+else:
+    from typing_extensions import TypedDict
 
 from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler
 
@@ -49,6 +55,7 @@ class QueueAttributeName(str):
     DeduplicationScope = "DeduplicationScope"
     FifoThroughputLimit = "FifoThroughputLimit"
     RedriveAllowPolicy = "RedriveAllowPolicy"
+    SqsManagedSseEnabled = "SqsManagedSseEnabled"
 
 
 class BatchEntryIdsNotDistinct(ServiceException):
@@ -162,7 +169,6 @@ class UnsupportedOperation(ServiceException):
 
 
 AWSAccountIdList = List[String]
-
 ActionNameList = List[String]
 
 
@@ -188,7 +194,6 @@ class BatchResultErrorEntry(TypedDict, total=False):
 
 
 BatchResultErrorEntryList = List[BatchResultErrorEntry]
-
 Binary = bytes
 BinaryList = List[Binary]
 
@@ -594,7 +599,7 @@ def add_permission(
         :param queue_url: The URL of the Amazon SQS queue to which permissions are added.
         :param label: The unique identification of the permission you're setting (for example,
         ``AliceSendMessage``).
-        :param aws_account_ids: The account numbers of the
+        :param aws_account_ids: The Amazon Web Services account numbers of the
         `principals <https://docs.
         :param actions: The action the client wants to allow for the specified principal.
         :raises OverLimit:
@@ -914,7 +919,8 @@ def get_queue_url(
         in the *Amazon SQS Developer Guide*.
 
         :param queue_name: The name of the queue whose URL must be fetched.
-        :param queue_owner_aws_account_id: The account ID of the account that created the queue.
+        :param queue_owner_aws_account_id: The Amazon Web Services account ID of the account that created the
+        queue.
         :returns: GetQueueUrlResult
         :raises QueueDoesNotExist:
         """
@@ -1140,13 +1146,13 @@ def send_message(
         message_deduplication_id: String = None,
         message_group_id: String = None,
     ) -> SendMessageResult:
-        """Delivers a message to the specified queue.
+        r"""Delivers a message to the specified queue.
 
         A message can include only XML, JSON, and unformatted text. The
         following Unicode characters are allowed:
 
-        ``#x9`` | ``#xA`` | ``#xD`` | ``#x20`` to ``#xD7FF`` | ``#xE000`` to
-        ``#xFFFD`` | ``#x10000`` to ``#x10FFFF``
+        ``#x9`` \| ``#xA`` \| ``#xD`` \| ``#x20`` to ``#xD7FF`` \| ``#xE000`` to
+        ``#xFFFD`` \| ``#x10000`` to ``#x10FFFF``
 
         Any characters not included in this list will be rejected. For more
         information, see the `W3C specification for
@@ -1172,7 +1178,7 @@ def send_message_batch(
         queue_url: String,
         entries: SendMessageBatchRequestEntryList,
     ) -> SendMessageBatchResult:
-        """Delivers up to ten messages to the specified queue. This is a batch
+        r"""Delivers up to ten messages to the specified queue. This is a batch
         version of ``SendMessage.`` For a FIFO queue, multiple messages within a
         single batch are enqueued in the order they are sent.
 
@@ -1188,8 +1194,8 @@ def send_message_batch(
         A message can include only XML, JSON, and unformatted text. The
         following Unicode characters are allowed:
 
-        ``#x9`` | ``#xA`` | ``#xD`` | ``#x20`` to ``#xD7FF`` | ``#xE000`` to
-        ``#xFFFD`` | ``#x10000`` to ``#x10FFFF``
+        ``#x9`` \| ``#xA`` \| ``#xD`` \| ``#x20`` to ``#xD7FF`` \| ``#xE000`` to
+        ``#xFFFD`` \| ``#x10000`` to ``#x10FFFF``
 
         Any characters not included in this list will be rejected. For more
         information, see the `W3C specification for
diff --git a/localstack/services/sqs/provider.py b/localstack/services/sqs/provider.py
--- a/localstack/services/sqs/provider.py
+++ b/localstack/services/sqs/provider.py
@@ -532,7 +532,8 @@ def validate_queue_attributes(self, attributes):
             if k not in valid:
                 raise InvalidAttributeName(f"Unknown attribute name {k}")
         # Special Cases
-        if attributes.get(QueueAttributeName.FifoQueue).lower() != "true":
+        fifo = attributes.get(QueueAttributeName.FifoQueue)
+        if fifo and fifo.lower() != "true":
             raise InvalidAttributeValue(
                 "Invalid value for the parameter FifoQueue. Reason: Modifying queue type is not supported."
             )


Test patch:
diff --git a/tests/integration/test_sqs.py b/tests/integration/test_sqs.py
--- a/tests/integration/test_sqs.py
+++ b/tests/integration/test_sqs.py
@@ -1590,6 +1590,27 @@ def test_deduplication_interval(self, sqs_client, sqs_create_queue):
             "Messages"
         )[0].get("MD5OfBody")
 
+    @pytest.mark.skipif(
+        os.environ.get("PROVIDER_OVERRIDE_SQS") != "asf",
+        reason="New provider test which isn't covered by old one",
+    )
+    def test_sse_attributes_are_accepted(self, sqs_client, sqs_create_queue):
+        queue_name = f"queue-{short_uid()}"
+        queue_url = sqs_create_queue(QueueName=queue_name)
+        attributes = {
+            "KmsMasterKeyId": "testKeyId",
+            "KmsDataKeyReusePeriodSeconds": "6000",
+            "SqsManagedSseEnabled": "true",
+        }
+        sqs_client.set_queue_attributes(QueueUrl=queue_url, Attributes=attributes)
+        result_attributes = sqs_client.get_queue_attributes(
+            QueueUrl=queue_url, AttributeNames=["All"]
+        )["Attributes"]
+        keys = result_attributes.keys()
+        for k in attributes.keys():
+            assert k in keys
+            assert attributes[k] == result_attributes[k]
+
 
 def get_region():
     return os.environ.get("AWS_DEFAULT_REGION") or TEST_REGION