🦶

AWS CDKでセッションマネージャーから接続できる踏み台サーバーを定義する

2022/08/13に公開

備忘録

結論

import { Construct } from "constructs";
import { Stack, StackProps, aws_ec2 as ec2 } from "aws-cdk-lib";

export class HogeStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const vpc = new ec2.Vpc(this, "VPC", {
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: "isolated",
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
        },
      ],
    });

    // 踏み台インスタンスのセキュリティグループ
    const bastionHostSG = new ec2.SecurityGroup(this, "BastionHostSG", {
      vpc,
      allowAllOutbound: true,
    });

    // 踏み台インスタンス
    new ec2.BastionHostLinux(this, "BastionHost", {
      vpc,
      subnetSelection: {
        subnetGroupName: "isolated",
      },
      securityGroup: bastionHostSG,
    });

    // VPCエンドポイントのセキュリティグループ
    const endpointSG = new ec2.SecurityGroup(this, "EndpointSG", {
      vpc,
      allowAllOutbound: true,
    });

    // 必須のVPCエンドポイント
    vpc.addInterfaceEndpoint("SSMEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.SSM,
      securityGroups: [endpointSG],
    });
    vpc.addInterfaceEndpoint("SSMMessagesEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.SSM_MESSAGES,
      securityGroups: [endpointSG],
    });
    vpc.addInterfaceEndpoint("EC2MessagesEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.EC2_MESSAGES,
      securityGroups: [endpointSG],
    });

    // 場合によって必要なVPCエンドポイント
    vpc.addInterfaceEndpoint("KMSEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.KMS,
      securityGroups: [endpointSG],
    });
    vpc.addInterfaceEndpoint("LogsEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS,
      securityGroups: [endpointSG],
    });
    vpc.addGatewayEndpoint("S3Endpoint", {
      service: ec2.GatewayVpcEndpointAwsService.S3,
      subnets: [
        {
          subnetGroupName: "isolated",
        },
      ],
    });

    // 踏み台インスタンスからVPCエンドポイントへのhttpsを許可
    endpointSG.addIngressRule(
      ec2.Peer.securityGroupId(bastionHostSG.securityGroupId),
      ec2.Port.tcp(443),
      "https from bastion host",
      false
    );
  }
}

説明

踏み台サーバー用EC2インスタンスの定義

aws_cdk_lib/aws_ec2BastionHostLinuxを使う。

    // 踏み台インスタンス
    new ec2.BastionHostLinux(this, "BastionHost", {
      vpc,
      subnetSelection: {
        subnetGroupName: "isolated",
      },
      securityGroup: bastionHostSG,
    });

OSは最新のAmazon Linux 2。インスタンスタイプのデフォルトは't3.nano'なので、適宜変更する。
AWS Systems Managerのセッションマネージャーから接続することを推奨しているので、実行ロールにはそれが可能な権限が最初から付与されている。

セッションマネージャーから接続するためのVPCエンドポイントの設定

ステップ 1: Session Manager の前提条件を満たす - AWS Systems Manager

上記の記事の「エンドポイントへの接続」に記載されている以下3つのVPCエンドポイントは必須。

  • ssm.region.amazonaws.com
  • ssmmessages.region.amazonaws.com
  • ec2messages.region.amazonaws.com
    // 必須のVPCエンドポイント
    vpc.addInterfaceEndpoint("SSMEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.SSM,
      securityGroups: [endpointSG],
    });
    vpc.addInterfaceEndpoint("SSMMessagesEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.SSM_MESSAGES,
      securityGroups: [endpointSG],
    });
    vpc.addInterfaceEndpoint("EC2MessagesEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.EC2_MESSAGES,
      securityGroups: [endpointSG],
    });

以下は場合によって必要。

    // 場合によって必要なVPCエンドポイント
    vpc.addInterfaceEndpoint("KMSEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.KMS,
      securityGroups: [endpointSG],
    });
    vpc.addInterfaceEndpoint("LogsEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS,
      securityGroups: [endpointSG],
    });
    vpc.addGatewayEndpoint("S3Endpoint", {
      service: ec2.GatewayVpcEndpointAwsService.S3,
      subnets: [
        {
          subnetGroupName: "isolated",
        },
      ],
    });

あとは、踏み台から設定したVPCエンドポイントに対してhttps(TCP 443番)を許可する。

    // 踏み台インスタンスからVPCエンドポイントへのhttpsを許可
    endpointSG.addIngressRule(
      ec2.Peer.securityGroupId(bastionHostSG.securityGroupId),
      ec2.Port.tcp(443),
      "https from bastion host",
      false
    );

Discussion