SSM アクセスOK!踏み台 EC2 インスタンスを一括で作成してみた(CloudFormation 利用)

SSM アクセスOK!踏み台 EC2 インスタンスを一括で作成してみた(CloudFormation 利用)

トラブルシューティングに便利な、SSM アクセスできる踏み台 EC2 インスタンスを一括で作成できる Cfn テンプレートです。
Clock Icon2025.05.01

アノテーション テクニカルサポートの Shimizu です。

前回執筆した記事「バックエンド EC2 への直接アクセスを検証してみた」ではプライベートサブネットに配置された EC2 インスタンスに対して踏み台 EC2 を経由し、直接アクセスを検証する方法をご紹介しました。

しかしながら踏み台 インスタンスや SSM 接続に必要な VPC エンドポイントには課金が生じるため、検証のたびに毎回リソースを作成・削除するのが面倒という方もいるかと思います。

そこで今回は 踏み台 EC2 インスタンスと VPC エンドポイントを一括で作成し、検証が終わったらすぐに削除できる CloudFormation テンプレートを作成してみました!

CloudFormation テンプレートの内容

下記のテンプレートコードを丸ごとコピーしてテキストファイルに貼り付け、bastion-ec2.yml などの適当なファイル名で保存して使用します。

テンプレートのコードはこちら
AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFormation template to launch Bastion EC2 instance with SSM access and optional VPC endpoints'

Parameters:

  # 踏み台インスタンスを起動する VPC ID とサブネット ID
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: VPC where the Bastion instance will be launched

  SubnetId:
    Type: AWS::EC2::Subnet::Id
    Description: Subnet where the Bastion instance will be launched

  # 踏み台インスタンスのインスタンスタイプ  
  InstanceType:
    Type: String
    Default: t3.medium
    Description: EC2 instance type
    AllowedValues:
      - t3.micro
      - t3.small
      - t3.medium
      - t3.large

  # 踏み台インスタンスの起動に使用する AMI ID が格納された SSM パラメータ名
  # ※ 下記ドキュメントのパブリックパラメータから指定することも、独自に作成した SSM パラメータを指定することも可能
  # https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/parameter-store-public-parameters-ami.html  
  AmiId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-windows-latest/Windows_Server-2022-English-Full-Base
    Description: SSM Parameter of AMI for Bastion instance (default - Windows Server 2022)

  # 踏み台インスタンスに紐づける既存のキーペア名
  KeyName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: Name of an existing EC2 KeyPair to connect Bastion instance
    Default: ""

  # VPC エンドポイントの作成有無
  # 対象サブネットにすでに SSM エンドポイントが存在する場合や、対象サブネットがパブリックの場合は No を選択する
  CreateVpcEndpoints:
    Type: String
    Default: "Yes"
    AllowedValues:
      - "Yes"
      - "No"
    Description: Create VPC Endpoints for SSM access (for private subnets)

Conditions:
  HasKeyName: !Not [!Equals [!Ref KeyName, ""]]
  ShouldCreateVpcEndpoints: !Equals [!Ref CreateVpcEndpoints, "Yes"]

Resources:
  # 踏み台インスタンスにアタッチする IAM ロール(SSM 接続に必要なポリシーのみ付与)
  EC2SSMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Path: /

  # Instance Profile for the EC2 instance
  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref EC2SSMRole

  # 踏み台インスタンスにアタッチするセキュリティグループ
  # SSM 接続するのみであればインバウンドルールの許可は不要
  BastionSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for Bation instance (No inbound access)
      VpcId: !Ref VpcId
      Tags:
        - Key: Name
          Value: bastion-server-sg

  # 踏み台 EC2 インスタンス
  BastionInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: !Ref AmiId
      SubnetId: !Ref SubnetId
      SecurityGroupIds:
        - !GetAtt BastionSecurityGroup.GroupId
      IamInstanceProfile: !Ref EC2InstanceProfile
      KeyName: !If [HasKeyName, !Ref KeyName, !Ref "AWS::NoValue"]
      Tags:
        - Key: Name
          Value: Bastion Server

  # VPC エンドポイントにアタッチするセキュリティグループ(踏み台インスタンスの SG からのみ接続を許可)
  VpcEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Condition: ShouldCreateVpcEndpoints
    Properties:
      GroupDescription: Security group for VPC Endpoints
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - Description: HTTPS from EC2 instance security group
          IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          SourceSecurityGroupId: !GetAtt BastionSecurityGroup.GroupId
      Tags:
        - Key: Name
          Value: vpc-endpoints-sg

  # SSM 接続に必要な VPC エンドポイント(ssm/ssmmessages)
  SSMEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Condition: ShouldCreateVpcEndpoints
    Properties:
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.ssm"
      VpcId: !Ref VpcId
      SubnetIds:
        - !Ref SubnetId
      SecurityGroupIds:
        - !Ref VpcEndpointSecurityGroup

  SSMMessagesEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Condition: ShouldCreateVpcEndpoints
    Properties:
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.ssmmessages"
      VpcId: !Ref VpcId
      SubnetIds:
        - !Ref SubnetId
      SecurityGroupIds:
        - !Ref VpcEndpointSecurityGroup

Outputs:
  InstanceId:
    Description: ID of the EC2 instance
    Value: !Ref BastionInstance

  PrivateIP:
    Description: Private IP address of the EC2 instance
    Value: !GetAtt BastionInstance.PrivateIp

  AMIId:
    Description: AMI ID used for this instance
    Value: !Ref AmiId

  SSMConnectionCommand:
    Description: Command to connect to the instance using SSM Session Manager
    Value: !Sub "aws ssm start-session --target ${BastionInstance}"

  SecurityGroupId:
    Description: Security Group ID attached to the instance
    Value: !GetAtt BastionSecurityGroup.GroupId

  KeyPairUsed:
    Description: Key pair used for this instance (if any)
    Value: !If [HasKeyName, !Ref KeyName, "No key pair specified"]

  PasswordRetrievalCommand:
    Description: Command to retrieve the Windows password (if key pair was specified)
    Value: !If 
      - HasKeyName
      - !Sub "aws ec2 get-password-data --instance-id ${BastionInstance} --priv-launch-key path/to/your/${KeyName}.pem"
      - "No key pair specified, password retrieval not available"

  VpcEndpointsCreated:
    Description: Whether VPC Endpoints were created
    Value: !If [ShouldCreateVpcEndpoints, "Yes", "No"]

  SSMEndpointId:
    Description: SSM VPC Endpoint ID (if created)
    Value: !If [ShouldCreateVpcEndpoints, !Ref SSMEndpoint, "Not created"]

  SSMMessagesEndpointId:
    Description: SSM Messages VPC Endpoint ID (if created)
    Value: !If [ShouldCreateVpcEndpoints, !Ref SSMMessagesEndpoint, "Not created"]

このテンプレートで作成されるリソースは以下の通りです。

  • EC2 インスタンス、アタッチする IAM ロールとセキュリティグループ
    (SSM 接続に必要な権限のみ付与)
  • オプション:VPC エンドポイント(ssm,ssmmessages)、アタッチするセキュリティグループ(EC2 からの接続のみを許可)

やってみた

まず上記のテンプレートコードを .yml ファイルとしてPC上に保存します。あと EC2 に紐づけるキーペアが必要になるため、無い場合は作成しておきましょう。

CloudFormation のコンソール画面より「スタックの作成 > 新しいリソースを使用(標準)」を選択します。次の画面で「テンプレートファイルのアップロード」を選択し、先ほどローカルに保存した .yml ファイルを指定して次に進みます

img-01

次の画面で各パラメータを以下のように入力して、次の画面に進みます。

  • スタック名
    適当で構いません。
  • AmiID
    踏み台 EC2 の起動元となる AMI の ID が格納された SSM パラメータを指定します。
    デフォルトでは Windows Server 2022 になっていますが、参考資料に記載された Amazon Linux 2023 に変更することも、自前で用意したカスタム AMI の ID を SSM パラメータに格納し、そのパラメータ名を指定することも可能です。
  • CreateVpcEndpoints
    SSM 接続に必要な VPC エンドポイント(ssm,ssmmessages)の作成有無を選択します。ターゲットの VPC にすでにこれらのエンドポイントがある場合や、パブリックサブネットに起動する場合は不要なので No を選択します。
  • InstanceType
    接続するだけなら最小限のインスタンスタイプでOKですが、追加ソフトウェアのインストールが必要な場合などは適宜大きいサイズを選びましょう。
  • KeyName
    踏み台 EC2 に紐づける既存のキーペア名を指定します。
  • SubnetId/VpcId
    踏み台 EC2 を起動する VPC / サブネットを選択します。

次の画面では特に何も変更しなくてOKです。
踏み台 EC2 にアタッチされる IAM ロールも同時に作成されるため承認にチェックを入れて次に進み、入力した内容を確認して「送信」をクリックします。

img-03a

一連のリソース作成が開始されるので、エラーが出ないか確認しつつ完了するまで待ちます。
(問題なければ数分で完了します)

スタックの作成が完了したら EC2 のコンソールに移動し「Bastion Server」という名前のインスタンスが起動していることを確認します。
画面上の「接続」をクリックし、次の画面で「Fleet Manager Remote Desktop」をクリックします。

次の画面の「ローカルマシンを参照して、キーペアファイルを選択します」でローカルPC上にある秘密鍵ファイル(.pem)を指定し「接続」をクリックします。

img-05

SSM 経由で踏み台 EC2 にリモートデスクトップ接続ができました!ここから他の EC2 に対してアクセス検証などが行えます。

img-06

検証が終わったら CloudFormation スタック一覧画面で今回作成したスタックを選択し「削除」ボタンをクリックするだけで、EC2 をはじめとして IAM ロールやセキュリティグループ、VPC エンドポイントなど、関連するリソースを一括で削除できます。

img-07

おわりに

いかがでしたでしょうか。

検証で踏み台 EC2 インスタンスや SSM エンドポイントを利用する機会が多いものの、毎回削除して課金を抑えたい方には便利なテンプレートだと思います。ぜひ活用いただけると幸いです!

参考資料

アノテーション株式会社について

アノテーション株式会社はクラスメソッドグループのオペレーション専門特化企業です。サポート・運用・開発保守・情シス・バックオフィスの専門チームが、最新 IT テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。当社は様々な職種でメンバーを募集しています。「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイトをぜひご覧ください。
img-03a

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.