A reference to a resource type must be followed by at least one attribute

Hello, I am new to terraform, and am trying to run a Cloud Formation template in AWS, I keep getting this error and am unsure how to ix it, TF code below. The issue is from line 146:

   {"CustomerAccountName":"intactfc","ExternalId":"${ExternalId}","featureMap":{"CLOUD_NATIVE_ARCHIVAL":3}}
        - "ExternalId": !Select

Full code:

############################ RubrikRoleCreationStack #####################################################
resource "aws_cloudformation_stack" "RubrikRoleCreationRole" {
  name = "RubrikRoleCreationStack"
  description = "Stack used to create the Rubrik Roles needed to test backup"
  permission_model = "SERVICE_MANAGED"
  auto_deployment {
     enabled = true
     retain_stacks_on_account_removal = true
  }
  capabilities = ["CAPABILITY_NAMED_IAM"]
  template_body = <<TEMPLATE
  AWSTemplateFormatVersion: 2010-09-09
Description: >-
  This template creates/updates roles and resources required for integration
  with Rubrik Security Cloud.
Mappings:
  regionTopicMap:
    ap-northeast-1:
      TopicArn: >-
        arn:aws:sns:ap-northeast-1:389263825261:spark-cloud-accounts-prod-001-intactfc-a1ed00fc-0044-4f78-9640-493b427f52f3
    ap-northeast-2:
      TopicArn: >-
        arn:aws:sns:ap-northeast-2:389263825261:spark-cloud-accounts-prod-001-intactfc-ce4ef0b7-97f3-427a-a453-722d570ad707
    ap-south-1:
      TopicArn: >-
        arn:aws:sns:ap-south-1:389263825261:spark-cloud-accounts-prod-001-intactfc-ab882605-15bc-4c14-a93e-fe00ba7f75f6
    ap-southeast-1:
      TopicArn: >-
        arn:aws:sns:ap-southeast-1:389263825261:spark-cloud-accounts-prod-001-intactfc-b700b7ee-f519-45e4-8ebb-f1a3d2ed92f0
    ap-southeast-2:
      TopicArn: >-
        arn:aws:sns:ap-southeast-2:389263825261:spark-cloud-accounts-prod-001-intactfc-e94f9c55-29a0-472e-802b-59f3fa278707
    ca-central-1:
      TopicArn: >-
        arn:aws:sns:ca-central-1:389263825261:spark-cloud-accounts-prod-001-intactfc-d00e43c7-e70d-4340-a578-5d1602ff76a0
    eu-central-1:
      TopicArn: >-
        arn:aws:sns:eu-central-1:389263825261:spark-cloud-accounts-prod-001-intactfc-0648231e-70c3-4aed-bea5-a8f7e4a28fb4
    eu-north-1:
      TopicArn: >-
        arn:aws:sns:eu-north-1:389263825261:spark-cloud-accounts-prod-001-intactfc-6051183e-2b55-498c-ad07-deba31947d59
    eu-west-1:
      TopicArn: >-
        arn:aws:sns:eu-west-1:389263825261:spark-cloud-accounts-prod-001-intactfc-41b74f12-46ee-4d20-9b14-9768e9f0ae17
    eu-west-2:
      TopicArn: >-
        arn:aws:sns:eu-west-2:389263825261:spark-cloud-accounts-prod-001-intactfc-5f458c82-323e-4119-b686-5ff24f4034ec
    eu-west-3:
      TopicArn: >-
        arn:aws:sns:eu-west-3:389263825261:spark-cloud-accounts-prod-001-intactfc-fdb38b71-4829-4085-bdd8-2d65bafb3482
    sa-east-1:
      TopicArn: >-
        arn:aws:sns:sa-east-1:389263825261:spark-cloud-accounts-prod-001-intactfc-4c435d86-7251-4446-8cc8-75903cc7dec1
    us-east-1:
      TopicArn: >-
        arn:aws:sns:us-east-1:389263825261:spark-cloud-accounts-prod-001-intactfc-da9de8a5-c392-443c-8585-3f8779d15f1d
    us-east-2:
      TopicArn: >-
        arn:aws:sns:us-east-2:389263825261:spark-cloud-accounts-prod-001-intactfc-7a3d6aef-17ef-4ce8-b8e7-dc51cf658459
    us-west-1:
      TopicArn: >-
        arn:aws:sns:us-west-1:389263825261:spark-cloud-accounts-prod-001-intactfc-37dfbc5f-d549-4333-8d48-b96c117777d4
    us-west-2:
      TopicArn: >-
        arn:aws:sns:us-west-2:389263825261:spark-cloud-accounts-prod-001-intactfc-183c857d-03d3-436d-a753-9e52358798b4
Outputs:
  RoleARN:
    Description: >-
      Cross account role ARN used by Rubrik to access feature specific
      resources.
    Value: !GetAtt
      - CrossAccountRole
      - Arn
  StackARN:
    Description: The ARN of the stack created as a result of this cloud formation script
    Value: !Ref 'AWS::StackId'
Resources:
  CrossAccountRole:
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action:
              - 'sts:AssumeRole'
            Condition:
              StringEquals:
                'sts:ExternalId':
                  - !Select
                    - 2
                    - !Split
                      - /
                      - !Ref 'AWS::StackId'
            Effect: Allow
            Principal:
              AWS: 'arn:aws:iam::389263825261:user/intactfc-6f1de'
        Version: 2012-10-17
      Path: /
      Policies:
        - PolicyDocument:
            Statement:
              - Action:
                  - 's3:CreateBucket'
                  - 's3:PutObject'
                  - 's3:GetObject'
                  - 's3:ListBucket'
                  - 's3:GetBucketLocation'
                  - 's3:AbortMultipartUpload'
                  - 's3:ListMultipartUploadParts'
                  - 's3:RestoreObject'
                  - 's3:GetObjectVersion'
                  - 's3:GetObjectRetention'
                  - 's3:GetBucketVersioning'
                  - 's3:GetBucketObjectLockConfiguration'
                  - 's3:PutObjectRetention'
                  - 's3:PutBucketVersioning'
                  - 's3:PutBucketObjectLockConfiguration'
                Effect: Allow
                Resource:
                  - '*'
                Sid: archivalStoragePermissions
              - Action:
                  - 's3:DeleteObject'
                  - 's3:DeleteObjectVersion'
                Effect: Allow
                Resource:
                  - 'arn:*:s3:::rubrik*'
                Sid: archivalStorageDeletePermissions
              - Action:
                  - 'kms:Encrypt'
                  - 'kms:Decrypt'
                  - 'kms:GenerateDataKeyWithoutPlaintext'
                  - 'kms:GenerateDataKey'
                  - 'kms:DescribeKey'
                  - 'kms:ListAliases'
                Effect: Allow
                Resource:
                  - '*'
                Sid: archivalKmsPermissions
            Version: 2012-10-17
          PolicyName: CloudNativeArchivalLocationPolicy
    Type: 'AWS::IAM::Role'
  RubrikSecurityCloudNotifier:
    Properties:
      AccountId: !Ref 'AWS::AccountId'
      MetaData: !Sub
        - >-
          {"CustomerAccountName":"intactfc","ExternalId":"${ExternalId}","featureMap":{"CLOUD_NATIVE_ARCHIVAL":3}}
        - "ExternalId": !Select
            - 2
            - !Split
              - /
              - !Ref 'AWS::StackId'
      MetaDataVersion: '1'
      RoleArn: !GetAtt
        - CrossAccountRole
        - Arn
      ServiceToken: !FindInMap
        - regionTopicMap
        - !Ref 'AWS::Region'
        - TopicArn
    Type: 'Custom::cloudAccountCustomResource'
    Version: 2012-10-17
TEMPLATE
  tags = var.common_tags

  lifecycle {
    ignore_changes = [
      administration_role_arn
    ]
  }
}

Hi @dion.abbott,

Terraform thinks that your expression ExternalId is the beginning of a reference to a resource.

For example, if you were referring to the resource you showed here then you’d use an expression like aws_cloudformation_stack.RubrickRoleCreationRole, which includes two parts:

  1. The resource type aws_cloudformation_stack.
  2. The resource name RubrickRoleCreationRole.

Terraform is incorrectly guessing that ExternalId is similarly a reference to a resource "ExternalId" "..." block, but there is no such block, and so it returns this error.

I’m not familiar enough with CloudFormation to know what ExternalId is intended to mean here, but I suspect that you intended that whole ${ExternalId} sequence to be evaluated by CloudFormation as part of the YAML template, rather than by Terraform as part of the Terraform configuration. If that’s true then you’ll need to escape the ${ sequence so that Terraform will know that it should just pass the data through literally, rather than trying to understand the sequence as a template interpolation:

   {"CustomerAccountName":"intactfc","ExternalId":"$${ExternalId}","featureMap":{"CLOUD_NATIVE_ARCHIVAL":3}}
        - "ExternalId": !Select

That’s using the $${ sequence documented under Escape Sequences, which Terraform will then replace with just ${ so that CloudFormation will “see” the ${ExternalId} sequence and then can evaluate it however CloudFormation evaluates such things.

I hope that helps!