1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TerraformでAmazon API Gatewayを構築する(プライベートAPI編)

Posted at

はじめに

API Gateway + Terraform 記事第6弾。
Private の API Gateway は、以下のクラスメソッドの記事の通り、ちゃんと理解して使わないとセキュアではなくなってしまう。

【Developers.IO】Amazon API Gateway プライベート API の「プライベート」を誤解してると、とても危ないという話。

このあたりを理解しながら、Terraform で API Gateway を作っていこう。

API Gateway の REST API は既に構築できている前提とする。
構築方法については、以下の記事を参考にしていただければ。

やること

API Gateway を Private 化するのに必要な手順は以下だ。

  • VPC エンドポイントとセキュリティグループを作成する
  • REST API のエンドポイント設定を PRIVATE にして VPC エンドポイントと紐付ける
  • REST API のリソースポリシーを設定する

VPC エンドポイントとセキュリティグループを作成する

以下のようにリソースを作っておこう。

################################################################################
# VPC Endpoint                                                                 #
################################################################################
resource "aws_vpc_endpoint" "api_gateway" {
  vpc_id            = data.aws_vpc.my.id
  service_name      = data.aws_vpc_endpoint_service.execute_api.service_name
  vpc_endpoint_type = "Interface"

  subnet_ids         = data.aws_subnet_ids.my_vpc.ids
  security_group_ids = [aws_security_group.vpc_endpoint.id]

  private_dns_enabled = true
}

data "aws_vpc_endpoint_service" "execute_api" {
  service = "execute-api"
}

################################################################################
# Security Group                                                               #
################################################################################
resource "aws_security_group" "vpc_endpoint" {
  name        = local.vpcendpoint_sg_name
  description = "VPC Endpoint Security Group"
  vpc_id      = data.aws_vpc.my.id

  ingress {
    description = "HTTPS"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

セキュリティグループは、API Gateway 向け(HTTPS)なので、443番ポートのインバウンド設定をする。

REST API のエンドポイント設定を PRIVATE にして VPC エンドポイントと紐付ける

これは簡単、aws_api_gateway_rest_api を以下のように設定する。

################################################################################
# API Gateway                                                                  #
################################################################################
resource "aws_api_gateway_rest_api" "private" {
  name        = local.api_gateway_name
  description = "プライベートAPI検証用API Gateway"

  endpoint_configuration {
    types            = ["PRIVATE"]
    vpc_endpoint_ids = [aws_vpc_endpoint.api_gateway.id]
  }

  policy = data.aws_iam_policy_document.private_api.json
}

vpc_endpoint_idsには先ほど作った VPC エンドポイントのIDを設定すれば良い。

REST API のリソースポリシーを設定する

リソースポリシーは↑の policy に設定しているものである。
ここでは、作った VPC エンドポイント経由のものを Allow すれば良い。デフォルトを Allow にして不要なものを拒否するというセオリーに従うと、以下のようになる。

data "aws_iam_policy_document" "private_api" {
  statement {
    effect = "Allow"

    principals {
      type = "*"
      identifiers = [
        "*",
      ]
    }

    actions = [
      "execute-api:Invoke",
    ]

    resources = [
      "*",
    ]
  }
  statement {
    effect = "Deny"

    principals {
      type = "*"
      identifiers = [
        "*",
      ]
    }

    actions = [
      "execute-api:Invoke",
    ]

    resources = [
      "*",
    ]

    condition {
      test     = "StringNotEquals"
      variable = "aws:SourceVpce"

      values = [
        aws_vpc_endpoint.api_gateway.id,
      ]
    }
  }
}

これを JSON にエンコードすると以下のようになる。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "*"
        },
        {
            "Sid": "",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "*",
            "Condition": {
                "StringNotEquals": {
                    "aws:SourceVpce": "vpce-xxxxxxxxxxxxxxxxx"
                }
            }
        }
    ]
}

これで、設定したVPCからのアクセスは、

  • https://[APIのID].execute-api.[リージョン].amazonaws.com/[ステージ名]
  • https://[APIのID]-vpce-[VPCエンドポイントのID].execute-api.[リージョン].amazonaws.com/[ステージ名]

で通るようになる。当然ながら、CloudShell のような非 VPC リソースやインターネット経由でのアクセスはエラーになる。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?