Repository: aws-cloudformation/cfn-lint

Issue:
v1: E1040 that does not match 'AWS::EC2::Image.Id'
### CloudFormation Lint Version

v1.3.0

### What operating system are you using?

Ubuntu

### Describe the bug

The full error is: `E1040 {'Fn::GetAtt': ['SelectAMI', 'AMI']} that does not match 'AWS::EC2::Image.Id'`
``` yaml 
LaunchTemplate:
    Type: 'AWS::EC2::LaunchTemplate'
    Properties:
      LaunchTemplateName: !Sub '${ShortName}-Template'
      LaunchTemplateData:
        ImageId: !GetAtt 'SelectAMI.AMI'
        :

  SelectAMI:
    Type: 'Custom::SelectAMI'
    Properties:
      ServiceToken: !GetAtt 'SelectAMICustomLambda.Arn'
      :

```
The custom lambda use some more information to select right image to the LaunchTemplate and then return it as:

```python
    import cfnresponse
     :      
 
     def lambda_handler(event, context):
           
            : 
            # ami is a string
            response_data = {"AMI": ami}
            cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)
```


### Expected behavior

Expected is that the type check do accept string too as it say in the documentation https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatedata.html



### Reproduction template

```yaml
---
AWSTemplateFormatVersion: 2010-09-09
Description: 'Bug E1040 and E3014'

Parameters:

  BuildId:
    Type: 'AWS::SSM::Parameter::Value<String>'

  ShortName:
    Type: 'String'

Resources:

  LaunchTemplate:
    Type: 'AWS::EC2::LaunchTemplate'
    Properties:
      LaunchTemplateName: !Sub '${ShortName}-Template'
      # E3014 - bug in cfn-lint 1.3.0 ?
      LaunchTemplateData:
        # E1040 - bug in cfn-lint 1.3.0 ?
        ImageId: !GetAtt 'SelectAMI.AMI'

  SelectAMI:
    Type: 'Custom::SelectAMI'
    Properties:
      # expected: E1010 - due to missing lambda function in this test
      ServiceToken: !GetAtt 'SelectAMICustomLambda.Arn'
      RandomNumber: !Ref 'BuildId'


```


Discussion:

Patch:
diff --git a/src/cfnlint/rules/functions/GetAttFormat.py b/src/cfnlint/rules/functions/GetAttFormat.py
index b7c1a382a6..a7fd660855 100644
--- a/src/cfnlint/rules/functions/GetAttFormat.py
+++ b/src/cfnlint/rules/functions/GetAttFormat.py
@@ -27,6 +27,10 @@ def __init__(self):
             "AWS::EC2::SecurityGroup.GroupId",
             "AWS::EC2::SecurityGroup.GroupIds",
         ]
+        self._resource_type_exceptions = [
+            "AWS::CloudFormation::CustomResource",
+            "AWS::CloudFormation::Stack",
+        ]
 
     def validate(
         self, validator: Validator, _, instance: Any, schema: Any
@@ -40,6 +44,9 @@ def validate(
         getatt_ptr = validator.context.resources[resource].get_atts[attr]
         t = validator.context.resources[resource].type
 
+        if t in self._resource_type_exceptions:
+            return
+
         for (
             _,
             resource_schema,


Test patch:
diff --git a/test/unit/rules/functions/test_getatt_format.py b/test/unit/rules/functions/test_getatt_format.py
index 3ab385aa94..33e6f7c931 100644
--- a/test/unit/rules/functions/test_getatt_format.py
+++ b/test/unit/rules/functions/test_getatt_format.py
@@ -22,6 +22,8 @@ def template():
             "MyBucket": {"Type": "AWS::S3::Bucket"},
             "MyVpc": {"Type": "AWS::EC2::VPC"},
             "MySecurityGroup": {"Type": "AWS::EC2::SecurityGroup"},
+            "MyCustomResource": {"Type": "Custom::CustomResource"},
+            "MySubTemplate": {"Type": "AWS::CloudFormation::Stack"},
         },
     }
 
@@ -35,6 +37,18 @@ def template():
             {"format": "AWS::EC2::VPC.Id"},
             [],
         ),
+        (
+            "Valid GetAtt to a custom resource",
+            ["MyCustomResource", "ImageId"],
+            {"format": "AWS::EC2::VPC.Id"},
+            [],
+        ),
+        (
+            "Valid GetAtt to a sub template ",
+            ["MySubTemplate", "Outputs.ImageId"],
+            {"format": "AWS::EC2::VPC.Id"},
+            [],
+        ),
         (
             "Valid GetAtt because of exception",
             ["MyBucket", "Arn"],