🧚‍♀️

[AWS]EC2にパブリック IPv4 アドレスがなくてセッションマネージャーは繋がらなかった件

2022/08/09に公開

こんにちは。深緑です。

先日CloudFormationでEC2インスタンスを起動+セッションマネージャーで接続可能なところまで持ってこうとしたのですがどハマりしたので原因を記しておきます。
書いたのはこのようなCloudFormationです。

VPCを作るCloudFormation

VPCを作るCloudFormation
training-vpc.yaml
Description:
  Simple VPC

Parameters:
  EnvironmentName:
    Description: An environment name that is prefixed to resource names
    Type: String

  VpcCIDR:
    Description: Please enter the IP range (CIDR notation) for this VPC
    Type: String
    Default: 10.192.0.0/16

  PublicSubnet1CIDR:
    Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
    Type: String
    Default: 10.192.10.0/24

  PublicSubnet2CIDR:
    Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone
    Type: String
    Default: 10.192.11.0/24

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

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

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

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [0, !GetAZs ""]
      CidrBlock: !Ref PublicSubnet1CIDR
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-public-subnet-1

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [1, !GetAZs ""]
      CidrBlock: !Ref PublicSubnet2CIDR
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-public-subnet-2

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

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

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

  PublicSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet2

Outputs:
  TrainingVPC:
    Description: A reference to the created VPC
    Value: !Ref VPC
    Export:
      Name: !Sub ${EnvironmentName}-vpc

  TrainingPublicSubnets:
    Description: A list of the public subnets
    Value: !Join [",", [!Ref PublicSubnet1, !Ref PublicSubnet2]]
    Export:
      Name: !Sub ${EnvironmentName}-public-subnets
      
  TrainingPublicSubnet1:
    Description: A reference to the public subnet in the 1st Availability Zone
    Value: !Ref PublicSubnet1
    Export:
      Name: !Sub ${EnvironmentName}-public-subnet1

  TrainingPublicSubnet2:
    Description: A reference to the public subnet in the 2nd Availability Zone
    Value: !Ref PublicSubnet2
    Export:
      Name: !Sub ${EnvironmentName}-public-subnet2

EC2を作るCloudFormation

EC2を作るCloudFormation
training-ec2-web
Description:
  Simple web server

Parameters:
  EnvironmentName:
    Description: An environment name that is prefixed to resource names
    Type: String

  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: must be the name of an existing EC2 KeyPair.

  ImageId:
    Description: AMI ID
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id> 
    Default: "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"

  InstanceType:
    Description: WebServer EC2 instance type
    Type: String
    Default: t3.micro
    AllowedValues:
      - t3.micro
      - t3.small
      - t3.medium
    ConstraintDescription: must be a valid EC2 instance type.

Resources:
  WebSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${EnvironmentName}-sg-web
      GroupDescription: Security group for web server
      VpcId: !ImportValue 
        "Fn::Sub": "${EnvironmentName}-vpc"
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-sg-web

  WebRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      RoleName: !Sub ${EnvironmentName}-iamrole-web

      Description: IAM Role for web server
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      MaxSessionDuration: 3600
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-iamrole-web

  WebInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref WebRole

  WebInstance1:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      IamInstanceProfile: !Ref WebInstanceProfile
      KeyName: !Ref KeyName
      ImageId: !Ref ImageId
      NetworkInterfaces:
        - SubnetId: !ImportValue 
            "Fn::Sub": "${EnvironmentName}-public-subnet1"
          GroupSet: 
            - !Ref WebSecurityGroup
          AssociatePublicIpAddress: false
          DeviceIndex: "0"            
      UserData: !Base64
        Fn::Sub: |
          #cloud-config
          repo_update: true
          repo_upgrade: all
          runcmd:
            - yum install -y https://s3.region.amazonaws.com/amazon-ssm-region/latest/linux_amd64/amazon-ssm-agent.rpm
            - systemctl enable amazon-ssm-agent
            - systemctl start amazon-ssm-agent
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-ec2-web1

Outputs:
    
  TrainingWebInstance1:
    Description: A reference to the created web server instance
    Value: !Ref WebInstance1
    Export:
      Name: !Sub ${EnvironmentName}-ec2-web1

  TrainingWebSecurityGroup:
    Description: A reference to the created security group for web server
    Value: !Ref WebSecurityGroup
    Export:
      Name: !Sub ${EnvironmentName}-sg-web

セッションマネージャーに繋がらない

上記CloudFormationでVPCとEC2はできたのですが、
セッションマネージャーでインスタンスが選択肢に出てきませんでした。

ロールは正しいはずです。

      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

UserDataでamazon-ssm-agentもインストール、起動できています。

      UserData: !Base64
        Fn::Sub: |
          #cloud-config
          repo_update: true
          repo_upgrade: all
          runcmd:
            - yum install -y https://s3.region.amazonaws.com/amazon-ssm-region/latest/linux_amd64/amazon-ssm-agent.rpm
            - systemctl enable amazon-ssm-agent
            - systemctl start amazon-ssm-agent

しばらく悩んだところ、AssociatePublicIpAddressをtrueにしたら繋がるようになりました。

          AssociatePublicIpAddress: true

セッションマネージャーはパブリックIPで接続する?

AssociatePublicIpAddressをtrueにしないと接続できないということは、
セッションマネージャーはパブリックIPで接続してるのかもしれませんね。
この観点で調べてみたところ、パブリックIPを持たせてないプライベートサブネットのEC2でも、NATゲートウェイを経由していれば接続できました。
NATゲートウェイはIPを持ってるからパブリックIPアドレスを持ってるのと同等なんですかね。

Discussion