fortissimo1997's diary

備忘録的な使い方をする予定

API Gatewayのリソースポリシー指定時の制約

最近SAMのテンプレートを書く機会が増えてきた。 (多分一過性)

github.com

SAMと言っても、AWS::Serverless::Functionだけで事足りることが多かったものの、 今回新たにAWS::Serverless::Apiを使おうとして、痒いところに手が届かないことがあったのでメモ、、、

作りたかったもの

AWS::Serverless::Functionに接続するプライベートAPIの構築

以下を参考にテンプレートを作成 docs.aws.amazon.com

リソースポリシーで「ソースVPCホワイトリスト」を指定して、作成したVPCエンドポイントからのアクセスを許可したい

作ったテンプレート(抜粋)

VPCエンドポイントを同じテンプレートで作成 後述しますが、これが通らない、、、

Resource:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: hoge
      EndpointConfiguration: PRIVATE
      Auth:
        ResourcePolicy:
          SourceVpcWhitelist:
            Ref: MyEndpoint
  MyEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: vpc-1234
      VpcEndpointType: Interface
      SubnetIds:
        - subnet-1234
      ServiceName:
        Fn::Sub: com.amazonaws.${AWS::Region}.execute-api
      SecurityGroup:
        - sg-1234

何故通らなかったか

VPCのホワイト/ブラックリストに指定できる値は、VPCエンドポイント(vpce-hogehoge)だけでなくVPC(vpc-hogehoge)全体も指定できる

で、リソースポリシーで指定するときは、それぞれ以下のように指定するフィールド名が異なる

{ "Condition" : {
    "StringNotEquals": {
      "aws:SourceVpc": "vpc-hogehoge",
      "aws:SourceVpce": "vpce-hogehoge"
    }
  }
}

AWS::Serverless::Apiでは、これらを同じフィールドに指定させる仕様になっているので、変換時にどちらか確定できないと変換できない、ということなんですね、、、

ここで落ちていたので、 今回落ちたRefだけでなく、Fn::GetAttFn::ImportValueを使ってもやはりダメ、ということのようです。

解決策

大人しくAWS::ApiGateway::RestApiを使いましょう

Resource:
  MyApi:
    Type: AWS::ApiGateway::RestApi
    Properties:
      EndpointConfiguration:
        Types:
          - PRIVATE
      Policy:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal: "*"
            Action: execute-api:Invoke
            Resource: execute-api:/stage/Method/*
          - Effect: Deny
            Principal: "*"
            Action: execute-api:Invoke
            Resource: execute-api:/stage/Method/*
            Condition:
              StringNotEquals:
                aws:SourceVpce:
                  Ref: MyEndpoint

雑感

これバグっぽいなぁと思ってPRを出すつもりで読んでいたものの、実装やドキュメントを読んで見るとどうしてこうなったかある程度納得できる結果になりました。。。

プライベートAPIの機能自体が後発なので、そこまで考えてなかったのかなぁという気もするものの、SAM自体はライトなユーザ向けのものだと思うので、こういう使い方まで考慮しなくてもそんなに問題にならないんだろうなぁ

結局複雑な要件をテンプレートで満たしたい手練は素のリソースを指定しましょう(楽するな)ということなんですかね🤔