AWS EC2初期設定をユーザーデータで


AWSでサーバー構築する用になって数年経つのに、実は**ユーザーデータ**を使ったことがなかったので
ユーザーデータを使った初歩的なサーバー初期設定に挑戦してみました。
せっかくなので、**CloudFormation**とも組み合わせてみました。


## やったこと
・ホスト名変更
・システムロケール/時刻設定
・ユーザー/グループ作成
・パッケージ更新
・再起動

実際の設定値はこんな感じ
| 項目 | 設定値 |
| ---- | ---- |
| ホスト名 | test |
| システムロケール | ja_JP.UTF-8 |
| タイムゾーン | Asia/Tokyo |
| 作成ユーザー | testuser01 |
| 作成ユーザーのパスワード | p@ssw0rd |
| 作成ユーザー所属グループ | testgroup01,wheel |

## ユーザーデータ
CloudFormationのコードは後述しますが、先に今回の肝となるユーザーデータを、、、

```yaml:ユーザーデータ
#!/bin/bash
groupadd testgroup01
useradd testuser01 -g testgroup01
gpasswd -a testuser01 wheel
echo p@ssw0rd | passwd --stdin testuser01
hostnamectl set-hostname test
localectl set-locale LANG=ja_JP.UTF-8
timedatectl set-timezone Asia/Tokyo
dnf update -y
shutdown -r now
```

## CloudFormationのコード
以前投稿した記事と内容はほぼ一緒。こちらにユーザーデータを追加しました。
[【初心者】AWS CloudFormationでVPC構築～EC2起動](https://qiita.com/AlmondTofu/items/dced05073aafb3a9d6b7)


```yaml:CloudFormation-VPC-EC2-userdata.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: VPC-EC2-tamplate

#####################################################################
# Parameters Setting
#####################################################################
Parameters:
  Region:
    Description: Region
    Type: String
    Default: ap-northeast-3
  SystemName:
    Description: ServerName
    Type: String
    Default: hogehoge
  VpcCidrBlock:
    Description: CidrBlock
    Type: String
    Default: '192.168.0.0/16'
  SubnetCidrBlock:
    Description: CidrBlock
    Type: String
    Default: '192.168.1.0/24'
  Ec2ImageId:
    Description: Amazon Linux 2023 AMI
    Type: String
    Default: ami-0ca0742afa9ee482f
  Ec2InstanceType:
    Description: Ec2 InstanceType
    Type: String
    Default: t3.micro

#####################################################################
# Resources
#####################################################################
Resources:
# Network Setting
  Vpc:
    Type: 'AWS::EC2::VPC'
    Properties:
      CidrBlock: !Sub ${VpcCidrBlock}
      Tags:
        - Key: 'Name'
          Value: !Sub ${SystemName}-vpc

  Subnet:
    Type: 'AWS::EC2::Subnet'
    Properties:
      CidrBlock: !Sub ${SubnetCidrBlock}
      AvailabilityZone: !Sub ${Region}a
      MapPublicIpOnLaunch: true
      Tags:
        - Key: 'Name'
          Value: !Sub ${SystemName}-subnet
      VpcId: !Ref Vpc

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

  AttachGateway:
    Type: 'AWS::EC2::VPCGatewayAttachment'
    Properties:
      VpcId: !Ref Vpc
      InternetGatewayId: !Ref InternetGateway

  RouteTable:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      Tags:
        - Key: 'Name'
          Value: !Sub ${SystemName}-rt
      VpcId: !Ref Vpc
  Route:
    Type: 'AWS::EC2::Route'
    DependsOn: InternetGateway
    Properties:
      RouteTableId: !Ref RouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  SubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Subnet
      RouteTableId: !Ref RouteTable

# IamRole Setting
  IamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - sts:AssumeRole
            Principal:
              Service:
                - ec2.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Policies:
        - PolicyName: ssmPutParameter
          PolicyDocument: 
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - ssm:PutParameter
                Resource: '*'      
      RoleName: !Sub ${SystemName}-role

# EC2 Setting
  NewKeyPair:
    Type: 'AWS::EC2::KeyPair'
    Properties: 
      KeyName: !Sub ${SystemName}-key-pair

  SecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      GroupDescription: !Sub ${SystemName}-SecurityGroup
      VpcId: !Ref Vpc
      Tags:
        - Key: 'Name'
          Value: !Sub ${SystemName}-sg
      SecurityGroupIngress:
        # http
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0
        # ICMP
        - IpProtocol: icmp
          FromPort: -1
          ToPort: -1
          CidrIp: 0.0.0.0/0

  ElasticIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: "/"
      Roles:
      - !Ref IamRole

  EC2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: !Ref Ec2ImageId
      InstanceType: !Ref Ec2InstanceType
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref Subnet
          GroupSet:
            - !Ref SecurityGroup
      UserData:      #ここにユーザーデータ入ってます
        Fn::Base64: |
            #!/bin/bash
            
            groupadd testgroup01
            useradd testuser01 -g testgroup01
            gpasswd -a testuser01 wheel
            echo p@ssw0rd | passwd --stdin testuser01
            hostnamectl set-hostname test
            localectl set-locale LANG=ja_JP.UTF-8
            timedatectl set-timezone Asia/Tokyo
            dnf update -y
            shutdown -r now

      IamInstanceProfile: !Ref InstanceProfile
      BlockDeviceMappings:
        - DeviceName: '/dev/xvda'
          Ebs:
            VolumeType: 'gp2'
            VolumeSize: 8
      Tags:
        - Key: 'Name'
          Value: !Sub ${SystemName}-ec2-instance'
      KeyName: !Ref NewKeyPair

  IPAssoc:
    Type: AWS::EC2::EIPAssociation
    Properties:
      InstanceId: !Ref EC2Instance
      EIP: !Ref ElasticIP
```

## 感想
もはやサーバーに一切はいらず初期設定できますね。楽ちん＼(^o^)／