77Lifeworkベータ版

77Lifeworkベータ版

ITツール開発・インフラ構築をメインとして、その他投資等雑記用のブログです。ブログの内容が少しでも皆様の参考となれば嬉しいです。

【AWS】CloudFormationでEC2(WindowsServer)を構築してアクセスする方法

はじめに

今回はAWS CloudFormation(CFn)のテンプレートを記述し、スタックを作成する形式でEC2(OS:WindowsServer)を構築し、利用できる状態にする方法を書いていきます。
検証用途でWindowsの環境が欲しいけど自分のPCがMacだったり、PCはWindowsだけどローカル環境を汚したくない、などの理由で、一時的にサーバが使いたいシーンありますよね。
そんな時に、手動で構築作業してアクセスできるよう設定するのが億劫だったので、テンプレート一発ですぐに使える状態にできると便利かなーと思って、やってみました。

事前準備

AWSアカウントの作成やIAMユーザの作成など、アカウント作成後の初期設定はあらかじめ実施しておきましょう。ここから先はAWSマネジメントコンソールにサインインして操作できる前提で進めます。

キーペアの生成は手動でマネジメントコンソールから実施しておき、キー情報(.pemファイル)をダウンロードしておきます。
「test-key-01」という名前のキーを作成します。キーの名前は後述するCFnテンプレートの中で参照しているので、キーの名前を変更する場合は、それに合わせてテンプレートの記載も変更してください。




CloudFormationのテンプレート

今回作成したテンプレートは以下です。EC2の他に、必要なVPCやサブネット、セキュリティグループなどのリソースもすべて含めています。
とりあえずこのテンプレートを使ってデプロイすればEC2が立ち上がります。

AWSTemplateFormatVersion: '2010-09-09'
Description: VPC/public subnet/private subnet/NAT Gateway/EC2.

Resources:
  UserVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: test-vpc-01

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: test-igw-01

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref UserVPC
      InternetGatewayId: !Ref InternetGateway

  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref UserVPC
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: true
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: test-pub-subnet-01

  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref UserVPC
      CidrBlock: 10.0.2.0/24
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: test-pri-subnet-01

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref UserVPC
      Tags:
        - Key: Name
          Value: test-pub-route-table-01

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable

  ElasticIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  NatGateway:
    Type: AWS::EC2::NatGateway
    DependsOn: AttachGateway
    Properties:
      AllocationId: !GetAtt ElasticIP.AllocationId
      SubnetId: !Ref PublicSubnet
      Tags:
        - Key: Name
          Value: test-natgw-01

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref UserVPC
      Tags:
        - Key: Name
          Value: test-pri-route-table-01

  PrivateRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway

  PrivateSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet
      RouteTableId: !Ref PrivateRouteTable
      
  # EC2 Instance     
  PrivateInstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow RDP from within VPC
      VpcId: !Ref UserVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3389
          ToPort: 3389
          CidrIp: 10.0.0.0/16
      Tags:
        - Key: Name
          Value: test-pri-sg-01

  WindowsInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.micro
      SubnetId: !Ref PrivateSubnet
      SecurityGroupIds:
        - !Ref PrivateInstanceSecurityGroup
      ImageId: ami-0a8695921de0ed4f6  # Windows_Server-2022-Japanese-Full-Base-2025.04.09
      KeyName: test-key-01
      IamInstanceProfile: !Ref SsmInstanceProfile
      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeSize: 50 # GiB
            VolumeType: gp3
            DeleteOnTermination: true      
      Tags:
        - Key: Name
          Value: test-pri-instance-01
          
  SsmRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: test-ec2-ssm-role
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Tags:
        - Key: Name
          Value: test-ec2-ssm-role

  SsmInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: test-ec2-ssm-profile
      Roles:
        - !Ref SsmRole

Outputs:
  VpcId:
    Description: VPC ID
    Value: !Ref UserVPC
  PublicSubnetId:
    Description: Public Subnet ID
    Value: !Ref PublicSubnet
  PrivateSubnetId:
    Description: Private Subnet ID
    Value: !Ref PrivateSubnet
  NatGatewayId:
    Description: NAT Gateway ID
    Value: !Ref NatGateway

CFnテンプレートのデプロイ方法

AWSのマネジメントコンソールにログインして、CloudShellを起動します。
CloudShell上に上記のyamlテンプレート(ここではvpc-ec2-win-cfn.ymlというファイル名とします)を配置し、スタックを作成します。
私はCFnデプロイ時にrainを使用しているので、以下コマンドを実行します。

rain deploy vpc-ec2-win-cfn.yml ec2-win-test-stack

rainのインストール方法や使い方は以下の記事で書いています。
www.77-lifework.com


EC2インスタンスの一覧を確認すると、正常に起動できていますね。

構築したEC2(WIndowsServer)にアクセスする方法

構築したEC2に対しては、Systems Managerのフリートマネージャーを用いて、AWSコンソール経由でリモートデスクトップでログインします。
まずはAWSコンソールで、Systems Managerを開き、フリートマネージャーにアクセスします。

アクセスするEC2インスタンスを選択し、ノードアクション>接続>リモートデスクトップで接続を選択します。

認証タイプはキーペアを選択し、あらかじめ作成したキーの情報をアップロードします。

アップロードできたら接続を押しましょう。

すると、リモートデスクトップで接続できました。

構築したEC2(WIndowsServer)の削除

利用が終了したら、作成したリソース一式を削除しましょう。
CloudShellを起動し、以下コマンドを実行します。このお手軽さがIaCの良いところですね。

rain rm ec2-win-test-stack

「Successfully deleted stack」と表示されていればOKです。

手動で作成したキーペアは、別途AWSコンソールからの操作で削除しておきましょう。