😸

Amazon EC2への接続方法を整理する

2023/09/13に公開

はじめに

Amazon EC2への接続方法はいくつか存在しますが、改めてそれぞれの長所・短所など整理したかったので、ここにまとめています。

4つの方法と比較

Amazon EC2にアクセスする方法は現状以下の4通りがあります。ただしシリアルコンソールでのアクセスはトラブルシューティングが目的であること、利用できるインスタンスが限られること、OSユーザーにログインパスワードを設定する必要があることなどから、ここでは特に触れていません。

種別 概要 アクセスコントロール
SSH インスタンス起動時に指定するキーペアのプライベートキーを利用してアクセスする。AWSのサービスに依存せず、従来サーバーにログインする際に使われる方法。 プライベートキーの有無・ユーザー所有権、Security Group
Session Manager AWS Systems Manager Session Managerを利用し、AWSマネジメントコンソールやローカル環境からアクセスする。IAMポリシーでアクセスを制御する。 IAMポリシー
Instance Connect インスタンス起動時に指定するSSH鍵を利用し、AWSマネジメントコンソールからアクセスする。プライベートキーを使用せずSecurity Groupでアクセスを制御する。 IAMポリシー、Security Group
シリアルコンソール 一部のインスタンスタイプに対し、シリアルポートにアクセスする方法。トラブルシューティングで利用する。 IAMポリシー

それぞれの使い分けは以下のように考えています。

  • 基本的にはSession Manager / Instance Connectのどちらかを利用する。対応するOSの種類やバージョンの多さ、可用性、Security Groupインバウンド方向のポート開放が不要な点から、個人的にはSession Managerを利用するほうが良いのではと考える。
  • SSHは運用面・セキュリティ面からできる限り利用しないようにする。
  • シリアルコンソールは現状利用する場面があまりないかもしれません。

方法1. SSH

SSHでのアクセスを利用するには、EC2インスタンス作成時にEC2キーペアを指定し、そのキーペアに対応するプライベートキー (.pem ファイル) を所有している必要があります。またアクセス元の環境 (ローカル環境や別のEC2インスタンス、AWS Cloud Shellなどの環境) からEC2にアクセスするため、Security Groupなどのアクセス制限でアクセスが許可されている必要があります。細かな条件などは公式ドキュメントに記載されています。

アクセス方法ですが、アクセス用のプライベートキーを既に所有している場合は、Linux / Windowsターミナルから ssh コマンドを実行したり、Tera Term / Putty / RLoginなどのクライアントソフトを利用します。

# ssh -i <.pemファイルのファイルパス> <EC2インスタンスOSユーザー名>@<パブリックIPアドレス or DNSホスト名>
$ ssh -i ~/.ssh/test-key.pem ec2-user@1.2.3.4

なお、プライベートキーの取得方法は、EC2インスタンス及びSSH鍵をどう作成したかによって変わります。

  • AWSマネジメントコンソール: キーペアor EC2インスタンス作成時に、.pem ファイルを団ロードするよう案内されます。プライベートキーを取得できるのはこのタイミングだけです。
  • AWS CLI: aws ec2 create-key-pair コマンドを実行してキーペアを作成し、作成に成功した場合のレスポンスに含まれる文字列を .pem ファイルとして保存します。
  • CloudFormation: CloudFormationでキーペアを作成した場合、AWS Systems Manager Parameter Storeに /ec2/keypair/{key_pair_id} という名称でプライベートキーが保存されます。Parameter Storeに保存された文字列を .pem ファイルとして保存します。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/create-key-pairs.html

方法2. Session Manager

AWS Systems Manager はEC2の運用に関するサービスを多数提供していますが、その中にSession Managerも含まれます。Session Managerは前述のSSH鍵を使用せずEC2インスタンスにアクセスする方法を提供しており、主にAWSマネジメントコンソールからEC2にアクセスすることができます (設定をすることで、ローカル環境からSession Managerを使用してアクセスすることも可能です) 。

Session Managerを利用することのメリットは公式ドキュメントで紹介されており、いくつか抜粋します。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager.html

  • ポートを開放する必要がない: SSHアクセスのためにSecurity Groupでポートを開放する必要がありません。不必要に開放するポートは攻撃リスクを高めるため、ポートを開放しないことがセキュリティ向上につながります。
  • SSH鍵の管理が不要: Session ManagerはAWSのマネージドサービスであり、インスタンスへの接続はSSM Agentなどを利用します。SSH鍵の管理は不要となり、鍵の管理をする必要がなくなります。
  • 踏み台サーバーが不要: 前項と似た理由ですが、SSM Agentによるアクセスを提供しており、踏み台サーバーも不要になります。
  • IAMポリシーによるアクセス制御: Session ManagerによるアクセスはIAMポリシーによって制御されるため、IAMユーザー・グループに対してアクセス制御を一元化できます。
  • ログ記録・監査機能の提供: Session Managerによるアクセスを行う場合、誰がアクセスしたか、セッション中にどんなコマンドを実行したか記録することができます。運用やセキュリティ上の理由でこれら情報の管理・提供が求められる場合も対応できます。

なお、Session Managerによるアクセスを試す用のCloudFormationは以下に配置します。ここではPrivate Subnet上のEC2インスタンスに対して、AWS PrivateLinkを使用してアクセスを行っています。

CloudFormationテンプレート
AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  EnvName:
    Type: String
    Default: ec2-example

  VPCCIDR:
    Type: String
    Default: "10.0.0.0/16"

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

  Ec2ImageId:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

  Ec2InstanceType:
    Type: String
    Default: t3.medium

  KeyPair:
    Type: String

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${EnvName}-VPC

  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select [0, !GetAZs ""]
      CidrBlock: !Ref PrivateSubnetCIDR
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvName}-PrivateSubnet

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

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

  EndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EndpointSecurityGroup
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvName}-EndpointSecurityGroup
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !Ref VPCCIDR

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

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

  EndpointEC2Messages:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref EndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
      SubnetIds:
        - !Ref PrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VPC

  EC2IAMRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${EnvName}-SSM-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - Ref: EC2IAMRole
      InstanceProfileName: !Sub ${EnvName}-EC2InstanceProfile

  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EC2SecurityGroup
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvName}-EC2SecurityGroup

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref Ec2InstanceType
      SubnetId: !Ref PrivateSubnet
      ImageId: !Ref Ec2ImageId
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      IamInstanceProfile: !Ref EC2InstanceProfile
      KeyName: !Ref KeyPair
      Tags:
        - Key: Name
          Value: !Sub ${EnvName}-EC2Instance

方法3. Instance Connect

Instance ConnectはSSH鍵を利用してインスタンスにアクセスする方法ですが、ここでのSSH鍵は認証ユーザーがアクセスするたびに一時的なSSHキーを生成し、それを利用します。アクセスはAWSマネジメントコンソール、もしくはAWS CLIから行います。

Instance Connectの利点はいくつかあります。

  • IAMポリシーによるアクセス制御の一元化: EC2インスタンスへのアクセスをIAMポリシーベースで制御できます。
  • ephemeralなSSHキーの利用: 一時的なSSHキーを利用することで、ユーザーがプライベートキーを管理する必要がなくなります。
  • CloudTrailによる監査: Instance Connectによる接続はCloudTrailに記録されるため、監査に対応しやすくなります。
  • プライベート空間のインスタンスにも対応: Instance ConnectはSession managerと同様、パブリック・プライベートどちらのEC2インスタンスにも対応しています。プライベートの場合はInstance Connect Endpointを利用して接続します。

https://aws.amazon.com/jp/blogs/compute/new-using-amazon-ec2-instance-connect-for-ssh-access-to-your-ec2-instances/

Instance Connectは利用するうえでいくつか制約があります。本サービスは比較的最近登場したこともあり、新しいバージョンのAmazon Linux / Ubuntuにしか対応していません。またInstance Connectを利用するには、特定のIPレンジまたはInstance Connect EndpointからEC2インスタンスへのインバウンド方向の通信を許可する必要があります。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-instance-connect-prerequisites.html

Instance ConnectもCloudFormationテンプレートを置いておきます。ここではパブリック・プライベート両方のパターンを置いており、プライベートのほうはInstance Connect Endpointを利用しています。

Instance Connect CloudFormationテンプレート
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  EnvName:
    Description: "Environment Name"
    Default: "ec2-example"
    Type: String
  VPCCidr: 
    Description: "VPC CIDR"
    Default: "10.0.0.0/16"
    Type: String
  PublicSubnet1Cidr:
    Description: "Public Subnet 1 CIDR"
    Default: "10.0.0.0/24"
    Type: String
  PrivateSubnet1Cidr:
    Description: "Private Subnet 1 CIDR"
    Default: "10.0.2.0/24"
    Type: String
  PublicSubnet1AZ:
    Description: "Public Subnet 1 AZ"
    Default: "ap-northeast-1a"
    Type: String
  Ec2ImageId:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
  Ec2InstanceType:
    Type: String
    Default: t3.medium

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCidr
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: environment
          Value: !Ref EnvName

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    DependsOn: AttachGateway
    Properties:
      CidrBlock: !Ref PublicSubnet1Cidr
      VpcId: !Ref VPC
      AvailabilityZone: !Ref PublicSubnet1AZ
      Tags:
        - Key: environment
          Value: !Ref EnvName

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: environment
          Value: !Ref EnvName

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    DependsOn: AttachGateway
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: environment
          Value: !Ref EnvName

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

  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EC2SecurityGroup
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvName}-EC2SecurityGroup
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: "3.112.23.0/29"

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref Ec2InstanceType
      ImageId: !Ref Ec2ImageId
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnet1
          GroupSet:
            - !Ref EC2SecurityGroup
      Tags:
        - Key: Name
          Value: !Sub ${EnvName}-EC2Instance
Instance Connect Endpoint CloudFormationテンプレート
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  EnvName:
    Type: String
    Default: ec2-example
  VPCCIDR:
    Type: String
    Default: "10.0.0.0/16"
  PrivateSubnetCIDR:
    Type: String
    Default: "10.0.0.0/24"
  Ec2ImageId:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
  Ec2InstanceType:
    Type: String
    Default: t3.medium

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${EnvName}-VPC

  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select [0, !GetAZs ""]
      CidrBlock: !Ref PrivateSubnetCIDR
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvName}-PrivateSubnet

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

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

  InstanceConnectEndpoint:
    Type: AWS::EC2::InstanceConnectEndpoint
    Properties:
      SecurityGroupIds:
        - !Ref EndpointSecurityGroup
      SubnetId: !Ref PrivateSubnet

  EndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EndpointSecurityGroup
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvName}-EndpointSecurityGroup

  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EC2SecurityGroup
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvName}-EC2SecurityGroup
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          SourceSecurityGroupId: !Ref EndpointSecurityGroup

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref Ec2InstanceType
      SubnetId: !Ref PrivateSubnet #{ Fn::ImportValue: !Sub "PrivateSubnet1-${EnvName}" }
      ImageId: !Ref Ec2ImageId
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      Tags:
        - Key: Name
          Value: !Sub ${EnvName}-EC2Instance

Session Manager / Instance Connectの比較

最後に、EC2インスタンスへの4つの接続方法のうち、特に利用機会が多そうなSession Manager / Instance Connectの比較をしています。

対応するOS

  • Session Manager
    • Linux: AWS Systems ManagerのサポートするすべてのOS (詳細はこちら)
    • Windows: Windows Server 2012 - 2022
  • Instance Connect
    • インストール済み: Amazon Linux 2023 / Amazln Linux 2 2.0.20190618 以降/ Ubuntu 20.04以降
    • インストール可能: Amazon Linux 2 / Ubuntu 16.04以降

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-instance-connect-prerequisites.html

セキュリティ

  • Session Manager
    • Security Group
      • Inbound: 特になし
      • Outbound: 特定のエンドポイントへの443番ポートの許可
        • ec2messages.region.amazonaws.com
        • ssm.region.amazonaws.com
        • ssmmessages.region.amazonaws.com
    • IAMポリシー: 接続対象のEC2インスタンスに AmazonSSMManagedInstanceCore というAWSマネージドポリシーを付与する
  • Instance Connect
    • Security Group:
    • IAMポリシー: 利用するIAMユーザーは以下の権限を付与される必要がある
      • ec2-instance-connect:SendSSHPublicKey
      • ec2:osuser
      • ec2:DescribeInstances

可用性

  • Session Manager
    • プライベートサブネットの場合はVPCエンドポイントを利用する。VPCエンドポイントはVPCあたり複数作成することができるため、複数のサブネットに作成することでAZ障害に対応できる
  • Instance Connect
    • Instance Connect EndpointはVPC当たり1つしか作成できないため、AZ障害に対応できない

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/eice-quotas.html

コスト

  • Session Manager
  • Instance Connect
    • 無料で利用できる

参考

Discussion