Repository: aws-cloudformation/cfn-lint

Issue:
E1152 and dynamic parameters
### CloudFormation Lint Version

cfn_lint-1.3.0-py3-none-any

### What operating system are you using?

Alpine in docker (python:3.12-alpine / python@sha256:a982997504b8ec596f553d78f4de4b961bbdf5254e0177f6e99bb34f4ef16f95)

### Describe the bug

The linter complains that a [dynamic parameter](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html) is not a valid value for the `LaunchTemplateData.ImageId` field in `AWS::EC2::LaunchTemplate`.

The error message is:
```
E1152 'resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2023/recommended/image_id' is not a 'AWS::EC2::Image.Id'
```

### Expected behavior

cfn-lint should not produce errors for this template

### Reproduction template

```yaml
AWSTemplateFormatVersion: "2010-09-09"

Resources:
  LaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateData:
        ImageId: resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2023/recommended/image_id
```


Discussion:

Patch:
diff --git a/src/cfnlint/rules/formats/ImageId.py b/src/cfnlint/rules/formats/ImageId.py
index 5dc199b867..d552d329eb 100644
--- a/src/cfnlint/rules/formats/ImageId.py
+++ b/src/cfnlint/rules/formats/ImageId.py
@@ -27,6 +27,13 @@ def format(self, validator: Validator, instance: Any) -> bool:
         if not isinstance(instance, str):
             return True
 
+        if validator.context.path.cfn_path_string == (
+            "Resources/AWS::EC2::LaunchTemplate/"
+            "Properties/LaunchTemplateData/ImageId"
+        ):
+            if instance.startswith("resolve:ssm"):
+                return True
+
         if re.match(r"^ami-([0-9a-z]{8}|[0-9a-z]{17})$", instance):
             return True
 


Test patch:
diff --git a/test/unit/rules/formats/test_image_id.py b/test/unit/rules/formats/test_image_id.py
index a6165993b5..833fb77e84 100644
--- a/test/unit/rules/formats/test_image_id.py
+++ b/test/unit/rules/formats/test_image_id.py
@@ -3,8 +3,11 @@
 SPDX-License-Identifier: MIT-0
 """
 
+from collections import deque
+
 import pytest
 
+from cfnlint.context import Path
 from cfnlint.rules.formats.ImageId import ImageId
 
 
@@ -15,26 +18,72 @@ def rule():
 
 
 @pytest.mark.parametrize(
-    "name,instance,expected",
+    "name,instance,path,expected",
     [
         (
             "Valid image id",
             "ami-abcd1234",
+            deque([]),
             True,
         ),
         (
             "Valid image id long",
             "ami-abcdefa1234567890",
+            deque([]),
+            True,
+        ),
+        (
+            "Valid image id using ssm",
+            "resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2023/recommended/image_id",
+            deque(
+                [
+                    "Resources",
+                    "AWS::EC2::LaunchTemplate",
+                    "Properties",
+                    "LaunchTemplateData",
+                    "ImageId",
+                ]
+            ),
+            True,
+        ),
+        (
+            "Invalid image id using ssm",
+            "resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2023/recommended/image_id",
+            deque([]),
+            False,
+        ),
+        (
+            "Valid image id in exception",
+            "ami-abcd1234",
+            deque(
+                [
+                    "Resources",
+                    "AWS::EC2::LaunchTemplate",
+                    "Properties",
+                    "LaunchTemplateData",
+                    "ImageId",
+                ]
+            ),
             True,
         ),
         (
             "Valid type",
             [],
+            deque([]),
             True,
         ),
-        ("Invalid image ID", "ami-abc", False),
+        ("Invalid image ID", "ami-abc", deque([]), False),
     ],
 )
-def test_validate(name, instance, expected, rule, validator):
+def test_validate(name, instance, path, expected, rule, validator):
+    validator = validator.evolve(
+        context=validator.context.evolve(
+            path=Path(
+                path=deque([]),
+                cfn_path=path,
+            ),
+        )
+    )
+
     result = rule.format(validator, instance)
     assert result == expected, f"Test {name!r} got {result!r}"