CFn에 SNS 액세스 정책을 자동으로 추가하는 [Lambad-backed 사용자 정의 에셋]

배경.
예를 들어, EventBridge에서 기존 AWS SNS 주제를 그룹화하는 규칙을 작성할 때
1. AWS 콘솔에서 EventBridge를 수동으로 작성할 경우
→ 이전 SNS의 액세스 정책에 이벤트 브릿지의 라이센스 규칙도 자동으로 추가됩니다.
2. CLI와 CFn을 통해 EventBridge를 생성할 경우
→ SNS에 액세스 라이센스가 자동으로 추가되지 않습니다.이러다가는 이벤트브릿지에서 온 저글링이 SNS 쪽에서 거절당할 수도 있다.
따라서 이벤트브릿지의 인허가 정책도 CFn을 통해 자동으로 추가될 수 없다.
(파치를 수동으로 추가할 수도 있지만, 현장에서 AWS 계정을 많이 관리하기 때문에 간단하게 추가할 수 있기를 바랍니다. 어쨌든 편하게 하세요.)
솔루션 1 및 관심 분야
클라메소의 보도 팁은 CFn에 Lambda-Backed 사용자 정의 리소스를 기술하고 액세스 정책을 자동으로 업데이트합니다.
AWS SDK(python)set_topic_attributes를 통해 업데이트할 수 있습니다.
주목점
하지만 이것set_topic_attributes은 SNS 액세스 정책의'추가'가 아닌'덮어쓰기'다.
따라서 기존 SNS 주제에 다른 액세스 정책이 미리 추가된 상태에서 이 사용자 정의 에셋이 적용된 경우 미리 설정된 정책이 삭제됩니다.
이런 분쟁의 원인이 되는 맞춤형 자원을 만들고 싶지 않아 개선책을 모색했다.
해결 방법2
답은 간단하다.SDKget_topic_attribets에서만 SNS의 화제 정책을 획득하고 이벤트브릿지의 접근 허가set_topic_attributes를 추기합니다.
사용자 정의 리소스에 사용되는 Lambda 함수는 다음과 같습니다.TopicArn, AwsAccountId는 사용자 정의 자원에서 전송되는 매개 변수이다.
lambda-addSnsAccessPolicy.py
import json
import boto3
import logging
import cfnresponse

logger = logging.getLogger()
logger.setLevel(logging.INFO)

sns = boto3.client('sns')

def lambda_handler(event, context):
  logger.info("event == {}".format(event))
  response = None

  topicArn = event['ResourceProperties']['TopicArn']
  awsAccountId = event['ResourceProperties']['AwsAccountId']

  addPolicy = {
    "Sid": "AWSEvent_Allow",
    "Effect": "Allow",
    "Principal": {
      "Service": "events.amazonaws.com"
    },
    "Action": "sns:Publish",
    "Resource": topicArn,
    "Condition": {
      "StringEquals": {
        "AWS:SourceAccount": awsAccountId
      }
    }
  }

  if event['RequestType'] == 'Create':
    # 既存のトピックポリシーを取得
    attributes = sns.get_topic_attributes(TopicArn = topicArn)
    policy = eval(attributes["Attributes"]["Policy"])
    logger.info("policy = {}".format(policy))

    # EventBridgeからのパブリッシュ許可を追記
    policy["Statement"].append(addPolicy)
    logger.info("updatepolicy = {}".format(policy))

    # トピックポリシーを上書き
    responce=sns.set_topic_attributes(
      TopicArn=topicArn,
      AttributeName='Policy',
      AttributeValue=json.dumps(policy)
    )

  if event['RequestType'] == 'Update':
    cfnresponse.send(event, context, cfnresponse.SUCCESS, {})

  if event['RequestType'] == 'Update':
    cfnresponse.send(event, context, cfnresponse.SUCCESS, {})

  logger.info("response == {}".format(responce))
  cfnresponse.send(event, context, cfnresponse.SUCCESS, responce)
이 Lambda 함수, 사용자 정의 자원 등 CloudFormation 템플릿은 GiitHub 웨어하우스에 있습니다.
자세히 보고 싶은 사람은 보세요.
실제로 해 보다
먼저 기존 SNS의 액세스 정책을 확인합니다.기본 정책 및 S3 라이센스가 설정되어 있습니다.
$ aws sns get-topic-attributes --topic-arn arn:aws:sns:ap-northeast-1:{AWSアカウントID}:TestTopic
(ポリシーの部分だけ抜粋)
"Policy": 
"{\"Version\":\"2008-10-17\",
\"Id\":\"__default_policy_ID\",
\"Statement\":[
↓デフォルトのポリシー
{\"Sid\":\"__default_statement_ID\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":[\"SNS:GetTopicAttributes\",\"SNS:SetTopicAttributes\",\"SNS:AddPermission\",\"SNS:RemovePermission\",\"SNS:DeleteTopic\",\"SNS:Subscribe\",\"SNS:ListSubscriptionsByTopic\",\"SNS:Publish\"],\"Resource\":\"arn:aws:sns:ap-northeast-1:{AWSアカウントID}:TestTopic\",\"Condition\":{\"StringEquals\":{\"AWS:SourceOwner\":\"{AWSアカウントID}\"}}},
↓S3からのパブリッシュ許可ポリシー
{\"Sid\":\"S3_Allow\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"s3.amazonaws.com\"},\"Action\":\"sns:Publish\",\"Resource\":\"arn:aws:sns:ap-northeast-1:{AWSアカウントID}:TestTopic\",\"Condition\":{\"StringEquals\":{\"AWS:SourceAccount\":\"{AWSアカウントID}\"}}}
]}"
사용자 지정 리소스가 포함된 CFn을 추출합니다.


액세스 정책을 다시 확인합니다.EventBridge의 추가 라이센스 정책이 확인되었습니다!!원래 설정한 정책도 사라지지 않고 그대로 남아있다.
$ aws sns get-topic-attributes --topic-arn arn:aws:sns:ap-northeast-1:{AWSアカウントID}:TestTopic
(ポリシーの部分だけ抜粋)
"Policy": 
"{\"Version\":\"2008-10-17\",
\"Id\":\"__default_policy_ID\",
\"Statement\":[
↓ もともとあったポリシー
{\"Sid\":\"__default_statement_ID\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":[\"SNS:GetTopicAttributes\",\"SNS:SetTopicAttributes\",\"SNS:AddPermission\",\"SNS:RemovePermission\",\"SNS:DeleteTopic\",\"SNS:Subscribe\",\"SNS:ListSubscriptionsByTopic\",\"SNS:Publish\"],\"Resource\":\"arn:aws:sns:ap-northeast-1:{AWSアカウントID}:TestTopic\",\"Condition\":{\"StringEquals\":{\"AWS:SourceOwner\":\"{AWSアカウントID}\"}}},
{\"Sid\":\"S3_Allow\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"s3.amazonaws.com\"},\"Action\":\"sns:Publish\",\"Resource\":\"arn:aws:sns:ap-northeast-1:{AWSアカウントID}:TestTopic\",\"Condition\":{\"StringEquals\":{\"AWS:SourceAccount\":\"{AWSアカウントID}\"}}},
↓ 今回追加されたEventBridgeからの許可ポリシー
{\"Sid\":\"AWSEvent_Allow\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"events.amazonaws.com\"},\"Action\":\"sns:Publish\",\"Resource\":\"arn:aws:sns:ap-northeast-1:{AWSアカウントID}:TestTopic\",\"Condition\":{\"StringEquals\":{\"AWS:SourceAccount\":\"{AWSアカウントID}\"}}}
]}"
최후
조사해도 의외로 이 자동 추가 방법이 없다는 기사를 스스로 시도해 봤다.번거로운 SNS 액세스 정책을 손쉽게 관리할 수 있어서 다행입니다.
(해결 방법은 간단하지만, AWS 지지자 w에게 별 볼일 없이 좌우로 흔들며 묻기도 한다)
사용자 정의 자원을 별로 사용하지 않았지만 자유도가 높아 편리하다.공부를 잘하다.
참고 자료
・[클래식 뉴스] 이벤트브릿지가 SNS에 알리지 못해 푹 빠진 이야기
・[문서] Amazon EventBridge 리소스 기반 정책 사용 - Amazon SNS 액세스 허용
・[GiitHub 창고] CFn Lambda-backed 사용자 정의 자원을 사용하여 SNS 화제 전략 자동 증가

좋은 웹페이지 즐겨찾기