VS Code を利用しながら、EC2インスタンスコネクトを利用してセッションマネージャー経由で接続してみた

VS Code を利用しながら、EC2インスタンスコネクトを利用してセッションマネージャー経由で接続してみた

Clock Icon2025.04.10

こんにちは!アノテーション AWS テクニカルサポートチームの大高です。

EC2 インスタンスへの接続方法の1つとして、インスタンスコネクトとセッションマネージャを利用した接続方法があります。

EC2 インスタンスに対して「EC2 インスタンスコネクトを利用してセッションマネージャ経由で接続」をすると、以下のメリットがあるため私はよくこの方法を利用しています。

  • SSH で接続ができる(公開鍵・秘密鍵はローカル端末で生成して使い捨てることも出来る)
  • プライベートネットワーク上のインスタンスに接続できる
  • 単純にセッションマネージャを利用して作業している場合、セッションが切れた場合に作業内容が失われるが、SSH の場合だとセッションが維持される
  • SSH 接続をすることで、VS Code の Remote Development が利用できる

とくに、わたしは「VS Code の Remote Development が利用できる」ことで、EC2 インスタンス上のファイルを VS Code のエクスプローラから開いたり、VS Code 上でターミナルを複数同時に開いたりすることが出来るので、よく利用しています。

そこで、実際の接続方法を以下にまとめておきたいと思います。

前提

以下のエントリで紹介されている方法を組み合わせて対応します。
エントリ内で書かれているような、IAM ユーザーへのポリシー付与や、接続先インスタンスのセッションマネージャ設定などは済まされていることを前提とします。

https://dev.classmethod.jp/articles/ec2-instance-connect/

https://dev.classmethod.jp/articles/session-manager-launches-tunneling-support-for-ssh-and-scp/

公開鍵・秘密鍵の作成

まずは利用する公開鍵・秘密鍵を作成します。
ここではキー名を deploy_rsa としました。また、パスフレーズ( -N オプション)は空文字(省略)としています。

$ cd ~/.ssh
$ ssh-keygen -f deploy_rsa -N ""

また、併せてファイルの権限を read のみにしておきます。

# 権限設定
$ chmod 400 deploy_rsa*

# 権限確認
$ ls -l
total 72
-r--------  1 ootaka.daisuke  staff   419  4  9 17:20 deploy_rsa
-r--------  1 ootaka.daisuke  staff   110  4  9 17:20 deploy_rsa.pub

~/.ssh/config ファイルの設定

次にアクセスしたい EC2 インスタンスへ SSH 接続するための設定を、 ~/.ssh/config へ明示的に記述しておきます。

CLI から SSH 接続するための設定は、以下のエントリにある汎用的な設定( host i-* mi-* への設定 )が良いのですが、今回のケースでは VS Code を併用するため、明示的に記述します。

https://dev.classmethod.jp/articles/session-manager-launches-tunneling-support-for-ssh-and-scp/

設定例としては、以下のような感じです。

Host deploy-server
    HostName i-xxxxxxxxxxxxxxxxx
    Port 22
    User ec2-user
    IdentityFile /Users/foo.bar/.ssh/deploy_rsa
    ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p' --profile deploy"

IdentityFile に、先ほど作成した秘密鍵へのパスを記載しています。
また、 ProxyCommand にはセッションマネージャを利用して接続するようにコマンドを記述しています。今回の例ではプロファイル指定もしたかったので、 --profile deploy のようにプロファイル指定をしています。

Instance Connect で公開鍵を送る処理をスクリプト化しておく

あとは Instance Connect で公開鍵を送り、すばやく VS Code で SSH 接続するだけなのですが、
手間を省くために Instance Connect で公開鍵を送る処理をスクリプト化しておきます。

私は以下のようなシェルスクリプトを作成して利用しています。

# シェルスクリプト作成
$ touch send-ssh-public-key.sh
#!/bin/bash
AWS_PROFILE=deploy
INSTANCE_ID=i-xxxxxxxxxxxxxxxxx # i-xxxxxxxxxxxxxxxxx (deploy-server)
SSH_KEY_NAME=deploy_rsa
SSH_PRIVATE_KEY=${HOME}/.ssh/${SSH_KEY_NAME}
SSH_PUBLIC_KEY=${HOME}/.ssh/${SSH_KEY_NAME}.pub

aws ec2-instance-connect send-ssh-public-key \
    --profile ${AWS_PROFILE}  \
    --region ap-northeast-1  \
    --instance-id ${INSTANCE_ID}  \
    --instance-os-user ec2-user  \
    --ssh-public-key file://${SSH_PUBLIC_KEY}
# シェルスクリプトに実行権限を付与
$ chmod 755 send-ssh-public-key.sh

EC2インスタンスを用意する

今回は例として、以下のような簡単な CloudFormation テンプレートを利用してEC2インスタンスを用意してみました。

AWSTemplateFormatVersion: "2010-09-09"
Description: "Simple Private Server Template."

Parameters:
  # ------------------------------------------------------------#
  # Common
  # ------------------------------------------------------------#
  Prefix:
    Type: String
    Default: "prefix"

  # ------------------------------------------------------------#
  # Network
  # ------------------------------------------------------------#
  VpcCidr:
    Type: String
    Default: "10.0.0.0/16"

  PrivateSubnetCidr:
    Type: String
    Default: "10.0.0.0/24"

  # ------------------------------------------------------------#
  # EC2
  # ------------------------------------------------------------#
  EC2InstanceName:
    Type: String
    Default: "ec2"
  EC2InstanceAMI:
    Type: AWS::EC2::Image::Id
    Default: "ami-0b6e7ccaa7b93e898" # Amazon Linux 2023 AMI 2023.7.20250331.0 x86_64 HVM kernel-6.1
  EC2InstanceInstanceType:
    Type: String
    Default: "t3.nano"
  EC2InstanceVolumeType:
    Type: String
    Default: "gp3"
  EC2InstanceVolumeSize:
    Type: String
    Default: "8"

Resources:
  # ------------------------------------------------------------#
  #  Network
  # ------------------------------------------------------------#
  Vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCidr
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${Prefix}-vpc

  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref PrivateSubnetCidr
      VpcId: !Ref Vpc
      AvailabilityZone:
        Fn::Select:
          - "0"
          - Fn::GetAZs: ""
      Tags:
        - Key: Name
          Value: !Sub ${Prefix}-private-subnet

  SecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: !Ref Vpc
      GroupName: !Sub "${Prefix}-sg"
      GroupDescription: "-"
      Tags:
        - Key: "Name"
          Value: !Sub "${Prefix}-sg"

  SsmVpcEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub ${Prefix}-ssm-vpc-endpoint-sg
      GroupName: !Sub ${Prefix}-ssm-vpc-endpoint-sg
      VpcId: !Ref Vpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          SourceSecurityGroupId: !Ref SecurityGroup
      Tags:
        - Key: Name
          Value: !Sub ${Prefix}-ssm-vpc-endpoint-sg

  SsmVpcEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      VpcId: !Ref Vpc
      SubnetIds:
        - !Ref PrivateSubnet
      SecurityGroupIds:
        - !Ref SsmVpcEndpointSecurityGroup

  SsmMessagesVpcEndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub ${Prefix}-ssmmessages-vpc-endpoint-sg
      GroupName: !Sub ${Prefix}-ssmmessages-vpc-endpoint-sg
      VpcId: !Ref Vpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          SourceSecurityGroupId: !Ref SecurityGroup
      Tags:
        - Key: Name
          Value: !Sub ${Prefix}-ssmmessages-vpc-endpoint-sg

  SsmMessagesVpcEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcEndpointType: Interface
      PrivateDnsEnabled: true
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      VpcId: !Ref Vpc
      SubnetIds:
        - !Ref PrivateSubnet
      SecurityGroupIds:
        - !Ref SsmMessagesVpcEndpointSecurityGroup

  # ------------------------------------------------------------#
  #  Ec2InstanceProfile
  # ------------------------------------------------------------#
  Ec2Role:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${Prefix}-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

  Ec2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: !Sub ${Prefix}-ec2-instance-profile
      Roles:
        - !Ref Ec2Role

  # ------------------------------------------------------------#
  #  EC2Instance
  # ------------------------------------------------------------#
  EC2Instance:
    Type: "AWS::EC2::Instance"
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "${Prefix}-${EC2InstanceName}"
      ImageId: !Ref EC2InstanceAMI
      InstanceType: !Ref EC2InstanceInstanceType
      IamInstanceProfile: !Ref Ec2InstanceProfile
      DisableApiTermination: false
      EbsOptimized: false
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            DeleteOnTermination: true
            VolumeType: !Ref EC2InstanceVolumeType
            VolumeSize: !Ref EC2InstanceVolumeSize
      SecurityGroupIds:
        - !Ref SecurityGroup
      SubnetId: !Ref PrivateSubnet
      UserData: !Base64 |
        #! /bin/bash
        yum update -y

接続してみる

あとは実際に接続するだけです。

まずは、先程作成したシェルスクリプトを実行して公開鍵を EC2 インスタンスへ送ります。

$ ./send-ssh-public-key.sh

公開鍵を送ったら、VS Code 左下の >< アイコンの箇所をクリックし、「ホストに接続する... - Remote SSH」を選択します。
すると、設定ファイル ~/.ssh/config に記載した deploy-server がリストに出てくるので、そのままクリックします。

必要に応じて本当に接続してよいかなどを聞かれます。問題なければ Yes として進めて、最後に /home/ec2-userフォルダを VS Code で開くと以下のようになります。

6Zs8DnGSZpSn719ij5ykv6_001

これで、Remote SSH 接続ができました!
インスタンス内のディレクトリがエクスプローラで表示されており、ターミナルも利用出来るので便利ですね。

注意点

接続対象のインスタンスが ECS on EC2 の場合などで、定期的にインスタンス ID が変わる場合には、シェルスクリプトや SSH の config ファイルも併せて修正が必要になります。
私は仕方なく毎回書き換えていましたが、もっと良い方法もあるかもしれません。

まとめ

以上、VS Code を利用しながら、EC2 インスタンスコネクトを利用してセッションマネージャ経由で接続してみました。

EC2 インスタンス接続後にファイルをエディタで変更したり、ターミナルを複数開いて作業したい場合には便利な方法かなと思います。

どなたかのお役に立てば幸いです。それでは!

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

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

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.