0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SSMを使ってプライベートなEC2に接続する

0
Posted at

はじめに

EC2 へのリモートアクセス方法の一つである AWS Systems Manager (SSM) Session Manager を試してみた記録です。CloudFormationを使って、プライベートサブネットのEC2にSSM接続できる環境をゼロから構築しました。

SSM Session Manager はAWSが提供するマネージドなリモートアクセスサービスです。SSH鍵やインバウンドポートの開放が不要で、IAMによるアクセス制御と CloudTrail による監査ログが利用できます。

構成

デプロイすると、以下の構成でリソースが作成されます。

ローカルPC(AWS CLI)
  ↓ HTTPS(SSM API)
VPCエンドポイント × 3(ssm / ssmmessages / ec2messages)
  ↓
EC2(プライベートサブネット)
  ※ インターネットゲートウェイ・NATゲートウェイなし

VPC・サブネットからEC2まで、すべてCloudFormation一枚で作成します。

CloudFormationテンプレートの確認

今回使用するテンプレートは cfn-ssm.yaml (後述)です。パラメータは InstanceType(デフォルト: t3.micro)のみで、VPCを含むすべてのリソースを自動作成します。

リソース 役割
VPC / PrivateSubnet 10.0.0.0/16 のVPCとプライベートサブネット(10.0.1.0/24)
PrivateRouteTable インターネットへのルートなし
SSMRole / SSMInstanceProfile EC2にSSM操作権限を付与(AmazonSSMManagedInstanceCore
EC2SecurityGroup インバウンドなし・アウトバウンドは全許可
EndpointSecurityGroup VPCエンドポイント向け Inbound 443 許可
SSMEndpoint / SSMMessagesEndpoint / EC2MessagesEndpoint SSM接続に必要なVPCエンドポイント3種
EC2Instance Amazon Linux 2023、KeyNameなし(SSH不要)
cfn-ssm.yaml(全文)
AWSTemplateFormatVersion: "2010-09-09"
Description: >
  EC2 SSM Session Manager セットアップ(VPC込み・プライベートサブネット)
  VPCエンドポイントを使用してインターネット接続なしでSSM接続を確立する。

Parameters:
  InstanceType:
    Type: String
    Default: t3.micro
    Description: EC2 インスタンスタイプ

  LatestAmiId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
    Description: Amazon Linux 2023 の最新 AMI ID(SSM Parameter Store から自動取得)

# ============================================================
# Resources
# ============================================================
Resources:

  # ----------------------------------------------------------
  # VPC・ネットワーク
  # ----------------------------------------------------------
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-vpc"

  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [0, !GetAZs ""]
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-private-subnet"

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

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

  # ----------------------------------------------------------
  # IAM: SSM接続用ロールとインスタンスプロファイル
  # ----------------------------------------------------------
  SSMRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${AWS::StackName}-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: !Sub "${AWS::StackName}-ssm-role"

  SSMInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: !Sub "${AWS::StackName}-ssm-instance-profile"
      Roles:
        - !Ref SSMRole

  # ----------------------------------------------------------
  # Security Groups
  # ----------------------------------------------------------
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub "${AWS::StackName}-ec2-sg"
      GroupDescription: EC2 for SSM - No inbound rules required
      VpcId: !Ref VPC
      SecurityGroupEgress:
       - IpProtocol: -1
         CidrIp: 0.0.0.0/0
         Description: Allow all outbound traffic
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-ec2-sg"

  EndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub "${AWS::StackName}-endpoint-sg"
      GroupDescription: VPC Endpoints for SSM Session Manager
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          SourceSecurityGroupId: !Ref EC2SecurityGroup
          Description: Allow HTTPS from EC2 instances
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-endpoint-sg"

  # ----------------------------------------------------------
  # VPC Endpoints(プライベートサブネットからSSMへの通信に必須)
  # ----------------------------------------------------------
  SSMEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.ssm"
      VpcEndpointType: Interface
      SubnetIds:
        - !Ref PrivateSubnet
      SecurityGroupIds:
        - !Ref EndpointSecurityGroup
      PrivateDnsEnabled: true

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

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

  # ----------------------------------------------------------
  # EC2 Instance
  # ----------------------------------------------------------
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: !Ref LatestAmiId
      SubnetId: !Ref PrivateSubnet
      IamInstanceProfile: !Ref SSMInstanceProfile
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-ec2"

# ============================================================
# Outputs
# ============================================================
Outputs:
  InstanceId:
    Description: SSM接続時に使用するEC2インスタンスID
    Value: !Ref EC2Instance

  ConnectCommand:
    Description: SSM Session Manager で接続するコマンド
    Value: !Sub "aws ssm start-session --target ${EC2Instance} --region ${AWS::Region}"

  VpcId:
    Description: 作成されたVPC ID
    Value: !Ref VPC

デプロイ

以下のコマンドでスタックを作成します。パラメータ指定は不要です。

aws cloudformation deploy \
  --template-file cfn-ssm.yaml \
  --stack-name ec2-ssm-setup \
  --capabilities CAPABILITY_NAMED_IAM

3分ほどで完了しました。完了後、インスタンスIDを取得します。

aws cloudformation describe-stacks \
  --stack-name ec2-ssm-setup \
  --query "Stacks[0].Outputs[?OutputKey=='InstanceId'].OutputValue" \
  --output text

接続確認

インスタンス起動後、SSM Agentの登録に1〜2分かかります。以下のコマンドで Online になっていることを確認します。

aws ssm describe-instance-information \
  --filters "Key=InstanceIds,Values=<INSTANCE_ID>" \
  --query "InstanceInformationList[0].PingStatus" \
  --output text

Online になったらセッションを開始します。

aws ssm start-session --target <INSTANCE_ID>

Session Manager セッションを開始するには、ローカルマシンにAWS CLI 用の Session Manager プラグインをインストールする必要があります。
AWS CLI 用の Session Manager プラグインをインストールする

接続が成功するとプロンプトが表示されます。

Starting session with SessionId: xxxxxxxxxxxxxxxxxxxxxxxx
sh-5.2$

試しにいくつか実行してみます。

# 実行ユーザーの確認
sh-5.2$ whoami
ssm-user

# インターネット接続がないことを確認(タイムアウトすればOK)
sh-5.2$ curl --connect-timeout 3 https://example.com
curl: (28) Connection timed out after 3001 milliseconds

インターネットに出られないことも確認でき、閉じたプライベート環境でSSM接続だけが通っている状態になっています。

おわりに

CloudFormationで3つのVPCエンドポイントとIAMロールを定義するだけで、プライベートサブネットのEC2にSSH不要・ポート開放なしで接続できる環境が手に入りました。

今後は Kiro CLI を使って、EC2に接続する際のよくある接続エラーのトラブルシューティングをしてみたいです。

また、EC2への接続方法はSSM Session Manager以外にも EC2 Instance ConnectEC2 Instance Connect Endpoint があります。それぞれ特性が異なるので、今後試してみたいと思います。

参考

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?