如何在 CloudFormation 中的 Amazon SQS 队列和 Amazon SNS 主题之间创建订阅?

4 分钟阅读
0

我想在 AWS CloudFormation 中的 Amazon Simple Queue Service (Amazon SQS) 队列和 Amazon Simple Notification Service (Amazon SNS) 主题之间创建订阅。

解决方法

如果主题和队列在同一个堆栈中,则使用 CloudFormation 模板创建一个主题,向 SQS 队列发送消息

如果主题在一个堆栈中而队列在另一个堆栈中,则创建跨堆栈引用。两个堆栈必须位于同一 AWS 区域。创建跨堆栈引用时,将 SQS 队列的 ARN 导出到一个堆栈中。然后,将 ARN 导入另一个堆栈中 SNS 主题的订阅端点属性中。

如果您的 SNS 主题和 SQS 队列位于不同的区域或 AWS 账户,则使用 AWS::SNS::Subscription 设置跨账户或跨区域订阅。

设置跨账户订阅

配置账户 A

在源堆栈的 CloudFormation 模板中,配置以下设置:

JSON 模板示例:

{
  "Parameters": {
    "CrossAccountNumber": {
      "AllowedPattern": "[0-9]+",
      "Description": "The 12 digit AWS account number to grant access to.",
      "MaxLength": "12",
      "MinLength": "12",
      "Type": "String",
      "Default": 123456789101
    }
  },
  "Resources": {
    "SnsTopic": {
      "Type": "AWS::SNS::Topic"
    },
    "SnsTopicPolicy": {
      "Type": "AWS::SNS::TopicPolicy",
      "DependsOn": "SnsTopic",
      "Properties": {
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Sid": "SnsTopicPolicy",
              "Effect": "Allow",
              "Principal": {
                "AWS": {
                  "Fn::Sub": "arn:aws:iam::${CrossAccountNumber}:root"
                }
              },
              "Action": [
                "sns:Subscribe"
              ],
              "Resource": {
                "Ref": "SnsTopic"
              }
            }
          ]
        },
        "Topics": [
          {
            "Ref": "SnsTopic"
          }
        ]
      }
    }
  },
  "Outputs": {
    "SnsTopicArn": {
      "Value": {
        "Ref": "SnsTopic"
      }
    }
  }
}

YAML 模板示例:

Parameters:
 CrossAccountNumber:
  AllowedPattern: '[0-9]+'
  Description: The 12 digit AWS account number to grant access to.
  MaxLength: '12'
  MinLength: '12'
  Type: String
  Default: 123456789101
Resources:
 SnsTopic:
  Type: AWS::SNS::Topic
 SnsTopicPolicy:
  Type: AWS::SNS::TopicPolicy
  DependsOn: SnsTopic
  Properties:
   PolicyDocument:
    Version: '2012-10-17'
    Statement:
    - Sid: SnsTopicPolicy
      Effect: Allow
      Principal:
       AWS: !Sub arn:aws:iam::${CrossAccountNumber}:root
      Action:
       - sns:Subscribe
      Resource: !Ref SnsTopic
   Topics:
    - !Ref SnsTopic
Outputs:
 SnsTopicArn:
  Value: !Ref SnsTopic

配置账户 B

在目标堆栈的 CloudFormation 模板的资源中,声明 AWS::SNS::Subscription 资源、AWS::SQS::QueueAWS::SQS::QueuePolicy

JSON 模板示例:

{
 "Parameters": {
  "SNSTopicARN": {
   "Type": "String",
   "Default": "awsSNSTopicArn"
  },
  "TopicRegion": {
   "Type": "String",
   "Default": "us-east-1"
  }
 },
 "Resources": {
  "Queue": {
   "Type": "AWS::SQS::Queue"
  },
  "SqsQueuePolicy": {
   "Type": "AWS::SQS::QueuePolicy",
   "Properties": {
    "PolicyDocument": {
     "Version": "2012-10-17",
     "Id": "MyQueuePolicy",
     "Statement": [
      {
       "Sid": "Allow-SNS-SendMessage",
       "Effect": "Allow",
       "Principal": "*",
       "Action": [
        "sqs:SendMessage"
       ],
       "Resource": {
        "Fn::GetAtt": [
         "Queue",
         "Arn"
        ]
       },
       "Condition": {
        "ArnEquals": {
         "aws:SourceArn": {
          "Ref": "SNSTopicARN"
         }
        }
       }
      }
     ]
    },
    "Queues" : [
     {
      "Ref" : "Queue"
     }
    ]
   }
  },
  "SnsSubscription": {
   "Type": "AWS::SNS::Subscription",
   "Properties": {
    "Protocol": "sqs",
    "Endpoint": {
     "Fn::GetAtt": [
      "Queue",
      "Arn"
     ]
    },
    "Region": {
     "Ref": "TopicRegion"
    },
    "TopicArn": {
     "Ref": "SNSTopicARN"
    }
   }
  }
 }
}

YAML 模板示例:

Parameters:
 SNSTopicARN:
  Type: String
  Default: awsSNSTopicArn
 TopicRegion:
  Type: String
  Default: us-east-1
Resources:
 Queue:
  Type: AWS::SQS::Queue
 SqsQueuePolicy:
  Type: AWS::SQS::QueuePolicy
  Properties:
   PolicyDocument:
    Version: '2012-10-17'
    Id: MyQueuePolicy
    Statement:
    - Sid: Allow-SNS-SendMessage
      Effect: Allow
      Principal: "*"
      Action:
      - sqs:SendMessage
      Resource: !GetAtt Queue.Arn
      Condition:
       ArnEquals:
        aws:SourceArn: !Ref SNSTopicARN
   Queues:
    - !Ref Queue
 SnsSubscription:
  Type: AWS::SNS::Subscription
  Properties:
   Protocol: sqs
   Endpoint: !GetAtt Queue.Arn
   Region: !Ref TopicRegion
   TopicArn: !Ref SNSTopicARN

注意:在前面的模板示例中的参数下,将 awsSNSTopicArn 替换为您的 SNS 主题 ARN。另外,将 us-east-1 替换为源账户(账户 A)中堆栈的区域。

设置跨区域订阅

配置区域 A

在一个区域的堆栈的 CloudFormation 模板中,配置以下设置:

  • 对于资源,声明 AWS::SNS::Topic
  • 创建 Outputs 部分以返回 SnsTopicArn

JSON 模板示例:

{
 "Resources": {
  "SnsTopic": {
   "Type": "AWS::SNS::Topic"
  }
 },
 "Outputs": {
  "SnsTopicArn": {
   "Value": {
     "Ref": "SnsTopic"
   }
  }
 }
}

YAML 模板示例:

Resources:
  SnsTopic:
    Type: AWS::SNS::Topic
Outputs:
  SnsTopicArn:
    Value: !Ref SnsTopic

配置区域 B

在其他区域堆栈的 CloudFormation 模板中,对于资源,声明 AWS::SNS::Subscription 资源和 AWS::SQS::Queue

JSON 模板示例:

{
 "Parameters": {
  "SNSTopicARN": {
   "Type": "String",
   "Default": "awsSNSTopicArnExample"
  },
  "TopicRegion": {
   "Type": "String",
   "Default": "us-east-1"
  }
 },
 "Resources": {
  "Queue": {
   "Type": "AWS::SQS::Queue"
  },
  "SnsSubscription": {
   "Type": "AWS::SNS::Subscription",
   "Properties": {
    "Protocol": "sqs",
    "Endpoint": {
     "Fn::GetAtt": [
      "Queue",
      "Arn"
     ]
    },
    "Region": {
     "Ref": "TopicRegion"
    },
    "TopicArn": {
     "Ref": "SNSTopicARN"
    }
   }
  }
 }
}

YAML 模板示例:

Parameters:
  SNSTopicARN:
    Type: String
    Default: awsSNSTopicArnExample
  TopicRegion:
    Type: String
    Default: us-east-1

Resources:
  Queue:
    Type: AWS::SQS::Queue

  SnsSubscription:
    Type: AWS::SNS::Subscription
    Properties:
      Protocol: sqs
      Endpoint: !GetAtt Queue.Arn
      Region: !Ref TopicRegion
      TopicArn: !Ref SNSTopicARN

注意:在前面的模板示例中的参数下,将 awsSNSTopicArnExample 替换为您的 SNS 主题 ARN。另外,将 us-east-1 替换为区域 A 中堆栈的区域。

AWS 官方
AWS 官方已更新 7 个月前