LoginSignup
4
1

ALB から S3 にアクセス(CDKのコード付き)

Last updated at Posted at 2023-07-05

参考にしたのはこちら

ただ、この例はInternalなALBを用意し、そこから、Private SubnetVPC Endpoint+ privatelink → S3なので、別にPublic Subnetに置いたALBでもいけたのが、今回の記事の内容です。

結論

VPC Endpoint(Interface)を使うとうまくいきました。

ALB → Vpc Endpoint(Interface) → S3

何が嬉しいのか

  • ALB → S3 間で認証を完結できる

SSO(シングルサインオン)等で、社内のみで見れるようにしたい社内サイトとか、認証をALBに集約したい時はとても嬉しいと思います。
OIDCを使用して、ALBに認証後、S3にルーティングすると、アプリ側で認証を実装する手間が減ります。
ALB → S3で認証が完結するということは、特にwordpressなどで構築されたサイトだと、プラグインや自作で認証を実装すると思うのですが、それが不要になります。

概要図

下記の図でいう 4 → 2 です

ALB to s3.png

前提

  • VPC(Public Subnet)
  • ALB
  • S3(ホスト名と同一)

今回は、Public SubnetVPC Endpointをアタッチする例です。

Private Subnetの場合は、別途 Privatelink 使用するようです。

手順

前提のALBとVPCがあれば、VPC EndpointのIPアドレスをターゲットグループに設定しましょう。

  1. VPC Endpointを作成
  2. VPC Endpoint作成後、IPv4 アドレスをコピー
  3. ALBのターゲットグループ作成(ターゲットの種類 IP、 アドレスタイプ IPv4
  4. ターゲットグループのIPアドレス2でコピーしたIPアドレスを設定
  5. ターゲットグループのヘルスチェックを307,405にする
  6. 終了

これで、ALB → S3が設定できました。

ユースケース

  • ユーザー数少ないけど、認証が必要なアプリ。
  • サーバーサイドで認証実装できない(or 面倒)

パフォーマンス向上

  • 規模が大きくなってALBから出ていく通信料が気になるようになったら、ALBの前にCloudFront
  • ALB - S3間に FileCacheStorage Gatewayをキャッシュサーバーとして検討(未検証。条件:ALBのターゲットグループ設定、CDK対応)

注意

  • S3のバケット名
    手順どおりやっても、S3のバケット名が、ホスト名と同一にならないと見つからないです。
    例えば、https://sample-test.co.jp であれば、バケット名は sample-test.co.jpです。

  • 通信料
    もし動画や大きなファイルを扱うのであれば、通信料も大きくなっていくので、ALBの前段にCloudFrontを置くか、ALB - S3間の間にファイルキャッシュできるようなサービスをおくと通信料もレスポンスタイムも早くなるのでしょう。

CDKのコード

実はVpc Endpointから、IPアドレスとるの難しいんだなと。。。
Vpc Endpointから簡単にとれるように貢献したいところ。。。


    // vpc endpoint 作成
    const vpcEndpoint = vpc.addInterfaceEndpoint("InterfaceVpcEndpointForS3", {
      service: InterfaceVpcEndpointAwsService.S3,
      subnets: { subnetType: SubnetType.PUBLIC },
      privateDnsEnabled: false,
    });

    // vpc endpoint から IP Addressを取得
    const getEndpointPrivateIpAddress = (index: number) => {
      const privateIpAddressField = `NetworkInterfaces.${index}.PrivateIpAddress`;
      const resource = new AwsCustomResource(this, `GetEndpointIp${index}`, {
        onUpdate: {
          service: "EC2",
          action: "describeNetworkInterfaces",
          outputPaths: [privateIpAddressField],
          parameters: { NetworkInterfaceIds: vpcEndpoint.vpcEndpointNetworkInterfaceIds },
          physicalResourceId: PhysicalResourceId.of(privateIpAddressField),
        },
        policy: AwsCustomResourcePolicy.fromSdkCalls({ resources: AwsCustomResourcePolicy.ANY_RESOURCE }),
      });
      return resource.getResponseField(privateIpAddressField);
    };

    // publicSubnets を取得
    const { publicSubnets } = vpcEndpoint.node.scope as Vpc;

    // publicSubnets の個数 を取得
    const ipAddresses = publicSubnets.map((_, index) => Token.asString(getEndpointPrivateIpAddress(index)));

    // ALB の ターゲットグループを作成
    const vpcEndpointTargetGroup = new ApplicationTargetGroup(this, "VpcEndpointTargetGroup", {
      vpc,
      targetType: TargetType.IP,
      port: 443,
      protocol: ApplicationProtocol.HTTPS,
      healthCheck: {
        healthyHttpCodes: "307,405",
      },
    });

    // vpc endpoint の IPアドレス ALB の ターゲットグループに設定
    for (const ipAddress of ipAddresses) {
      vpcEndpointTargetGroup.addTarget(new IpTarget(ipAddress));
    }

CDKのほうが大変でした。。。
もっと簡単に、作ったVPC endpointからIPアドレス取得できる方法あったら教えてくださいmm

参考

4
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
4
1