1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS CloudFormation: 07. EC2インスタンスの構築とアクセス方法 (Session Manager / EC2 Instance Connect Endpoint)

Last updated at Posted at 2024-06-16

本記事について

key pair 管理 接続方法 配置場所
パターン1 ec2-instance-connect send-ssh-public-key Session Manager Public
パターン2 ec2-instance-connect send-ssh-public-key Session Manager Private
パターン3 ec2-instance-connect send-ssh-public-key EIC Endpoint Public
パターン4 ec2-instance-connect send-ssh-public-key EIC Endpoint Private

AWS System Manager (SSM) Session Manager を使ってEC2 Instance にアクセスする

EC2 InstanceをPublic Subnetに配置する場合

image.png

  • Network

    • VPCとPublic Subnetを作成します
  • EC2

    • Public Subnetに配置します
    • OSはUbuntu Server 22.04を使います。これにはssm-agentがデフォルトでインストールされています。ssm-agentがインストールされていないAMIを使う場合は自分でインストールする必要があります
    • Session Managerを使えるように arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore ポリシーを割り当てます
    • 常時起動するような使い方はしないため、Elastic IP アドレス (静的 IPv4 アドレス) は割り当てずにパブリックIPを自動割当しています
      • 設定は、 AssociatePublicIpAddress: true
      • パブリックIPv4アドレスが割り当てられると、0.005USD/hourの料金がかかります (24/2/1以降)
      • 一方、EIPを使うとインスタンスが起動しているときは無料ですが、インスタンスが起動していない場合は料金がかかります
      • インスタンスの使い方によってどちらにするか決めると良いかと思います
    • Security Groupはデフォルトのままで大丈夫です
      • ポート開放は不要です
  • テンプレート

ec2_ssm_eic_public.yaml
ec2_ssm_eic_public.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: |
  Create an EC2 and connect using SSM and EC2 Instance Connect (EIC)

Parameters:
  SystemName:
    Description: System Name
    Type: String
  AvailabilityZone:
    Description: Availability Zone
    Type: AWS::EC2::AvailabilityZone::Name

Resources:
  #-----------------------------------------------------------------------------
  # VPC
  #-----------------------------------------------------------------------------
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-vpc

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-igw

  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  #-----------------------------------------------------------------------------
  # Public Subnet
  #-----------------------------------------------------------------------------
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.0/20
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-public-subnet

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-public-rtb

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

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

  #-----------------------------------------------------------------------------
  # EC2
  #-----------------------------------------------------------------------------
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: 'Security Group for an EC2 server'
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-ec2-sg

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0595d6e81396a9efb   # Ubuntu Server 22.04
      InstanceType: t2.micro
      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeType: gp3
            VolumeSize: 64
      IamInstanceProfile:
        !Ref EC2InstanceProfile
      NetworkInterfaces: 
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          GroupSet:
            - !Ref EC2SecurityGroup
          SubnetId: !Ref PublicSubnet
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-ec2

  #-----------------------------------------------------------------------------
  # IAM Role for EC2 server
  #-----------------------------------------------------------------------------
  EC2Role:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${SystemName}-ec2-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore   # To connect to an instance using Session Manager

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles: 
        - !Ref EC2Role

EC2 InstanceをPrivate Subnetに配置する場合

image.png

  • Network

    • VPCとPublic Subnet、Private Subnetを作成します
  • NAT Gateway

    • Public Subnetに配置します
  • EC2

    • Private Subnetに配置します。Private SubnetのRouteTableではdefaultの宛先をNAT Gatewayに設定しています
    • OSはUbuntu Server 22.04を使います。これにはssm-agentがデフォルトでインストールされています。ssm-agentがインストールされていないAMIを使う場合は自分でインストールする必要があります
    • Session Managerを使えるように arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore ポリシーを割り当てます
    • Security Groupはデフォルトのままで大丈夫です
      • ポート開放は不要です
  • ノート

    • 今回、EC2 InstanceはNAT Gateway経由でインターネットに接続されています。インターネット接続がないVPCの場合にはSession Manager接続用にVPC Endpointが必要となります
  • テンプレート

ec2_ssm_eic_private.yaml
ec2_ssm_eic_private.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: |
  Create an EC2 and connect using SSM and EC2 Instance Connect (EIC)

Parameters:
  SystemName:
    Description: System Name
    Type: String
  AvailabilityZone:
    Description: Availability Zone
    Type: AWS::EC2::AvailabilityZone::Name

Resources:
  #-----------------------------------------------------------------------------
  # VPC
  #-----------------------------------------------------------------------------
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-vpc

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-igw

  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  #-----------------------------------------------------------------------------
  # Public Subnet
  #-----------------------------------------------------------------------------
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.0/20
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-public-subnet

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-public-rtb

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

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

  #-----------------------------------------------------------------------------
  # Private Subnet
  #-----------------------------------------------------------------------------
  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone
      VpcId: !Ref VPC
      CidrBlock: 10.0.16.0/20
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-private-subnet

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-private-rtb

  PrivateSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet
      RouteTableId: !Ref PrivateRouteTable

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

  #-----------------------------------------------------------------------------
  # Nat Gateway
  #-----------------------------------------------------------------------------
  NatGatewayEIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-ngw-eip

  NatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      SubnetId: !Ref PublicSubnet
      AllocationId: !GetAtt NatGatewayEIP.AllocationId
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-ngw

  #-----------------------------------------------------------------------------
  # EC2
  #-----------------------------------------------------------------------------
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: 'Security Group for an EC2 server'
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-ec2-sg

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0595d6e81396a9efb   # Ubuntu Server 22.04
      InstanceType: t2.micro
      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeType: gp3
            VolumeSize: 64
      IamInstanceProfile:
        !Ref EC2InstanceProfile
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      SubnetId: !Ref PrivateSubnet
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-ec2

  #-----------------------------------------------------------------------------
  # IAM Role for EC2 server
  #-----------------------------------------------------------------------------
  EC2Role:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${SystemName}-ec2-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore   # To connect to an instance using Session Manager

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles: 
        - !Ref EC2Role

デプロイ方法

EC2 Instanceをどちらに配置したいかに応じて、以下コマンド内で使うテンプレートファイルを切り替えてください

Region=ap-northeast-1
AvailabilityZone=ap-northeast-1a

SystemName=sample-ec2-ssm-eic-public
TemplateFileName=./ec2_ssm_eic_public.yaml

# SystemName=sample-ec2-ssm-eic-private
# TemplateFileName=./ec2_ssm_eic_private.yaml

aws cloudformation deploy \
--region "${Region}" \
--stack-name "${SystemName}" \
--template-file ${TemplateFileName} \
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides \
SystemName="${SystemName}" \
AvailabilityZone="${AvailabilityZone}"

EC2へのアクセス方法

EC2 Instanceの配置場所に関わらずアクセス方法は同じです

準備

簡単な接続確認

  • 下記コマンドでインスタンスにアクセスできることを確認します
aws ssm start-session --target i-00000000000000000

sshの設定

  • ~/.ssh/config を開き、以下を追記します

    • Windowsの場合
      • 場所は、 C:\Users\ooo\.ssh
      • sh -cC:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe に置き換えます
      • 改行区切りを && から ;(セミコロン) に変えます。Linuxでのエラー処理を気にしなければどちらもセミコロンで大丈夫です
  • 設定の説明

    • i-00000000000000000 というホスト名にsshアクセスしようとしたら記載したコマンドが動きます
    • まず、ローカルPCの公開鍵をEC2 Instanceに一時的に登録します
    • その後、SSH sessionを開始しています
  • ssh接続のたびに毎回インスタンス名を入力するのが面倒な場合は、configにあらかじめ記載して、普段は ec2-server という名前のホストを使うと便利です (名前は任意)

Linuxのconfig
Host i-* mi-*
    ProxyCommand sh -c "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_rsa.pub' && aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"

# (Optional) To specify host id
Host ec2-server
    HostName i-00000000000000000
    User ubuntu
    ProxyCommand sh -c "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_rsa.pub' && aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
Windowsのconfig
Host i-* mi-*
    ProxyCommand C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_rsa.pub' ; aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"

# (Optional) To specify host id
Host ec2-server
    HostName i-0b723aba7cd8e8183
    User ubuntu
    ProxyCommand C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_rsa.pub' ; aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"

sshで接続する

  • 以下のいずれかのコマンドで接続できるはずです
  • また、~/.ssh/config に設定があるため、VSCodeからもRemote Explorerで接続できるはずです
ssh ubuntu@i-00000000000000000

ssh ec2-server
  • もしも以下のようなエラーが発生したら、known_hosts ファイルを削除するか、sshに -o 'StrictHostKeyChecking no' オプションをつけてください
    • kex_exchange_identification: Connection closed by remote host

EC2 Instance Connect Endpoint (EIC Endpoint) を使ってEC2 Instance にアクセスする

EC2 InstanceをPublic Subnetに配置する場合

image.png

  • Network

    • VPCとPublic Subnetを作成します
  • EIC Endpoint

    • Public Subnetに配置します
    • Securiy Groupはデフォルトのままとしました
  • EC2

    • Public Subnetに配置します
    • OSはUbuntu Server 22.04を使います
    • 常時起動するような使い方はしないため、Elastic IP アドレス (静的 IPv4 アドレス) は割り当てずにパブリックIPを自動割当しています
      • 設定は、 AssociatePublicIpAddress: true
      • パブリックIPv4アドレスが割り当てられると、0.005USD/hourの料金がかかります (24/2/1以降)
      • 一方、EIPを使うとインスタンスが起動しているときは無料ですが、インスタンスが起動していない場合は料金がかかります
      • インスタンスの使い方によってどちらにするか決めると良いかと思います
    • Security Group
      • EIC Endpointからのsshのみ受け付けるように設定します
  • テンプレート

ec2_eic_public.yaml
ec2_eic_public.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: |
  Create an EC2 and connect using SSM and EC2 Instance Connect (EIC) Endpoint

Parameters:
  SystemName:
    Description: System Name
    Type: String
  AvailabilityZone:
    Description: Availability Zone
    Type: AWS::EC2::AvailabilityZone::Name

Resources:
  #-----------------------------------------------------------------------------
  # VPC
  #-----------------------------------------------------------------------------
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-vpc

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-igw

  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  #-----------------------------------------------------------------------------
  # Public Subnet
  #-----------------------------------------------------------------------------
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.0/20
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-public-subnet

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-public-rtb

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

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

  #-----------------------------------------------------------------------------
  # EC2 Instance Connect Endpoint
  #-----------------------------------------------------------------------------
  EICSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: 'Security Group for an EC2 Instance Connect Endpoint'
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-eic-sg

  EICEndpoint:
    Type: AWS::EC2::InstanceConnectEndpoint
    Properties: 
      SecurityGroupIds: 
        - !Ref EICSecurityGroup
      SubnetId: !Ref PublicSubnet

  #-----------------------------------------------------------------------------
  # EC2
  #-----------------------------------------------------------------------------
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: 'Security Group for an EC2 server'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          SourceSecurityGroupId: !Ref EICSecurityGroup
        # - IpProtocol: tcp
        #   FromPort: 3389
        #   ToPort: 3389
        #   SourceSecurityGroupId: !Ref EICSecurityGroup
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-ec2-sg

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0595d6e81396a9efb   # Ubuntu Server 22.04
      InstanceType: t2.micro
      # InstanceType: m7i.xlarge
      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeType: gp3
            VolumeSize: 64
      IamInstanceProfile:
        !Ref EC2InstanceProfile
      NetworkInterfaces: 
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          GroupSet:
            - !Ref EC2SecurityGroup
          SubnetId: !Ref PublicSubnet
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-ec2

  #-----------------------------------------------------------------------------
  # IAM Role for EC2 server
  #-----------------------------------------------------------------------------
  EC2Role:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${SystemName}-ec2-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles: 
        - !Ref EC2Role

EC2 InstanceをPrivate Subnetに配置する場合

image.png

  • Network

    • VPCとPublic Subnet、Private Subnetを作成します
  • NAT Gateway

    • Public Subnetに配置します
  • EIC Endpoint

    • Public Subnetに配置します
    • Securiy Groupはデフォルトのままとしました
  • EC2

    • Private Subnetに配置します。Private SubnetのRouteTableではdefaultの宛先をNAT Gatewayに設定しています
    • OSはUbuntu Server 22.04を使います
    • Security Group
      • EIC Endpointからのsshのみ受け付けるように設定します
  • テンプレート

ec2_eic_private.yaml
ec2_eic_private.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: |
  Create an EC2 and connect using SSM and EC2 Instance Connect (EIC) Endpoint

Parameters:
  SystemName:
    Description: System Name
    Type: String
  AvailabilityZone:
    Description: Availability Zone
    Type: AWS::EC2::AvailabilityZone::Name

Resources:
  #-----------------------------------------------------------------------------
  # VPC
  #-----------------------------------------------------------------------------
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-vpc

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-igw

  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  #-----------------------------------------------------------------------------
  # Public Subnet
  #-----------------------------------------------------------------------------
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.0/20
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-public-subnet

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-public-rtb

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

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

  #-----------------------------------------------------------------------------
  # Private Subnet
  #-----------------------------------------------------------------------------
  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZone
      VpcId: !Ref VPC
      CidrBlock: 10.0.16.0/20
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-private-subnet

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-private-rtb

  PrivateSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet
      RouteTableId: !Ref PrivateRouteTable

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

  #-----------------------------------------------------------------------------
  # Nat Gateway
  #-----------------------------------------------------------------------------
  NatGatewayEIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-ngw-eip

  NatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      SubnetId: !Ref PublicSubnet
      AllocationId: !GetAtt NatGatewayEIP.AllocationId
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-ngw

  #-----------------------------------------------------------------------------
  # EC2 Instance Connect Endpoint
  #-----------------------------------------------------------------------------
  EICSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: 'Security Group for an EC2 Instance Connect Endpoint'
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-eic-sg

  EICEndpoint:
    Type: AWS::EC2::InstanceConnectEndpoint
    Properties: 
      SecurityGroupIds: 
        - !Ref EICSecurityGroup
      SubnetId: !Ref PublicSubnet

  #-----------------------------------------------------------------------------
  # EC2
  #-----------------------------------------------------------------------------
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: 'Security Group for an EC2 server'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          SourceSecurityGroupId: !Ref EICSecurityGroup
        # - IpProtocol: tcp
        #   FromPort: 3389
        #   ToPort: 3389
        #   SourceSecurityGroupId: !Ref EICSecurityGroup
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-ec2-sg

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0595d6e81396a9efb   # Ubuntu Server 22.04
      # ImageId: ami-09b74ffed30c40197   # Deep Learning Base OSS Nvidia Driver GPU AMI (Ubuntu 22.04) 20240610
      InstanceType: t2.micro
      # InstanceType: m7i.xlarge
      # InstanceType: g5.4xlarge
      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeType: gp3
            VolumeSize: 64
      IamInstanceProfile:
        !Ref EC2InstanceProfile
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      SubnetId: !Ref PrivateSubnet
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-ec2

  #-----------------------------------------------------------------------------
  # IAM Role for EC2 server
  #-----------------------------------------------------------------------------
  EC2Role:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${SystemName}-ec2-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles: 
        - !Ref EC2Role

デプロイ方法

EC2 Instanceをどちらに配置したいかに応じて、以下コマンド内で使うテンプレートファイルを切り替えてください

Region=ap-northeast-1
AvailabilityZone=ap-northeast-1a

SystemName=sample-ec2-eic-public
TemplateFileName=./ec2_eic_public.yaml

# SystemName=sample-ec2-eic-private
# TemplateFileName=./ec2_eic_private.yaml

aws cloudformation deploy \
--region "${Region}" \
--stack-name "${SystemName}" \
--template-file ${TemplateFileName} \
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides \
SystemName="${SystemName}" \
AvailabilityZone="${AvailabilityZone}"

EC2へのアクセス方法

EC2 Instanceの配置場所に関わらずアクセス方法は同じです

準備

  • ローカルPC (Windows/Linux/Macなど) で、以下を用意します
    • sshコマンド
    • AWS CLI
  • AWSコンソール -> EC2 -> Isntanceから、作成したインスタンス名 (i-00000000000000000) を確認しておきます
    • 以後、記事内の i-00000000000000000 は適宜置き換えをしてください

簡単な接続確認

  • 下記コマンドでインスタンスにアクセスできることを確認します
aws ec2-instance-connect ssh --instance-id i-00000000000000000 --os-user ubuntu --connection-type eice

sshの設定

  • ~/.ssh/config を開き、以下を追記します
    • Windowsの場合
      • 場所は、 C:\Users\ooo\.ssh
      • sh -cC:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe に置き換えます
      • 改行区切りを && から ;(セミコロン) に変えます。Linuxでのエラー処理を気にしなければどちらもセミコロンで大丈夫です
  • 設定の説明
    • i-00000000000000000 というホスト名にsshアクセスしようとしたら記載したコマンドが動きます
    • まず、ローカルPCの公開鍵をEC2 Instanceに一時的に登録します
    • その後、open-tunnelコマンドによってインスタンスへのプライベートトンネルを作成します
  • ssh接続のたびに毎回インスタンス名を入力するのが面倒な場合は、configにあらかじめ記載して、普段は ec2-server という名前のホストを使うと便利です
  • 参考としてトンネル作成だけを行うコマンドも記載しています。 ec2-server-tunnel
  • 後述するリモートデスクトップ接続のための設定もここで記載します。 ec2-server-tunnel-rdp
Linuxのconfig
Host i-* mi-*
    ProxyCommand sh -c "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_rsa.pub' && aws ec2-instance-connect open-tunnel --instance-id %h"

# (Optional) To specify host id
Host ec2-server
    HostName i-00000000000000000
    User ubuntu
    ProxyCommand sh -c "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_rsa.pub' && aws ec2-instance-connect open-tunnel --instance-id %h"

# (Optional) Sample to create tunnel
Host ec2-server-tunnel
    HostName i-00000000000000000
    User ubuntu
    ProxyCommand sh -c "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_rsa.pub' && aws ec2-instance-connect open-tunnel --instance-id %h --remote-port 22 --local-port 2222"

# (Optional) Sample to create tunnel for rdp
Host ec2-server-tunnel-rdp
    HostName i-00000000000000000
    User ubuntu
    ProxyCommand sh -c "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_rsa.pub' && aws ec2-instance-connect open-tunnel --instance-id %h --remote-port 3389 --local-port 3389"
Windowsのconfig
Host i-* mi-*
    ProxyCommand C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_rsa.pub' ; aws ec2-instance-connect open-tunnel --instance-id %h"

# (Optional) To specify host id
Host ec2-server
    HostName i-00000000000000000
    User ubuntu
    ProxyCommand C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_rsa.pub' ; aws ec2-instance-connect open-tunnel --instance-id %h"

# (Optional) Sample to create tunnel
Host ec2-server-tunnel
    HostName i-00000000000000000
    User ubuntu
    ProxyCommand C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_rsa.pub' ; aws ec2-instance-connect open-tunnel --instance-id %h --remote-port 22 --local-port 2222"

# (Optional) Sample to create tunnel for rdp
Host ec2-server-tunnel-rdp
    HostName i-00000000000000000
    User ubuntu
    ProxyCommand C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_rsa.pub' ; aws ec2-instance-connect open-tunnel --instance-id %h --remote-port 3389 --local-port 3389"

sshで接続する

  • 以下のいずれかのコマンドで接続できるはずです
  • また、~/.ssh/config に設定があるため、VSCodeからもRemote Explorerで接続できるはずです
ssh ubuntu@i-00000000000000000
ssh ec2-server
  • トンネル作成とssh接続をあえて分けると以下のようになります
ssh ec2-server-tunnel
ssh ubuntu@localhost -p 2222

リモートデスクトップ (xrdp) 環境を構築する

  • 最後に構築したパターン4 (以下の環境) に対して、リモートデスクトップ (xrdp) 追加します
    • key pairはec2-instance-connect send-ssh-public-key で管理
    • 接続にはEC2 Instance Connect Endpoint (EIC Endpoint) を使用
    • EC2 InstanceはPrivate Subnetに配置
  • ここまで使用したテンプレートだと、インスタンスタイプは t2.micro とデスクトップ環境には貧弱なものとなっています。適当に m7i.xlarge あたりに変更しておいてください

xrdp用のポートを開放する

  • EIC Endpoint -> EC2 Instance に対してRDP用のポート (3389) を開放します
    • 外部に対するポート開放ではないです。送信元はEIC Endpointに限定します
    • 以下のいずれかの方法で開放します
  • なお、EIC Endpointにおいて使用可能なポートはSSH用の22とRDP用の3389のみになります。もしも他のポートを使おうとしたら以下のようなエラーが発生します
    • awscli.customizations.ec2instanceconnect.websocket - ERROR - {"ErrorCode":"InvalidParameter","Message":"The specified RemotePort is not valid. Specify either 22 or 3389 as the RemotePort and retry your request."}
  • 手段1: テンプレートにInboundルールを追加する
    • テンプレート内の EC2SecurityGroup に以下を追加します
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3389
          ToPort: 3389
          SourceSecurityGroupId: !Ref EICSecurityGroup
      
  • 手段2: AWSコンソール上で手動でInboundルールを追加する
    • Type: RDP (3389)
    • Source: Custom (EICSecurityGroup)

image.png

EC2の設定を行う

  • EC2 Instance内にユーザーを追加します
    • ここでは user0 というユーザーを作りsudo権限を付与しています
    • デフォルトの ubuntu ユーザーをそのまま使用する場合はパスワード設定だけ行います
  • デスクトップ環境とxrdpをインストールします
  • 上記を行うために、EC2にSSHでログイン後下記コマンドを実行します
    • デスクトップ環境はお好みで
# sudo passwd ubuntu
sudo adduser user0
sudo usermod -aG sudo user0

sudo apt update
sudo apt install -y ubuntu-desktop xrdp
sudo systemctl enable xrdp
sudo reboot

リモートデスクトップ接続する

  • まず、ローカルPCから下記コマンドでRDP用のトンネルを作成します。 (設定は前述のconfig参照)
ssh ec2-server-tunnel-rdp
  • 以下のホストに対してリモートデスクトップ接続します
    • localhost:3389
    • Windowsだと標準の「リモートデスクトップ接続」が使えます

xrdp_host_1.png

xrdp_host_2.png

xrdp_host_3.png

(おまけ) VNCを使いたい場合

  • リモートデスクトップだと、キーボード入力など局所的な画面変化への応答性は高いのですが、画面全体が変わるようなシーンで遅延が大きいように見えます
  • 負荷は高くなりますが、VNCを使いたい場合もあるかと思います
  • 一応以下で出来ました
    • 適当にtigervncあたりをインストールする
    • 3389ポートを使うように設定する
1
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?