Splunkの検証環境をAWS CloudFormationで簡単構築

# 1.All in Oneの環境をAWSで簡単に構築したい
新しいバージョンがリリースされたり、バージョンによる動作の際を確認する際に、なにかと検証環境を用意するシーンが多かった日々でした。
スタンドアローンの環境を構築する際にはCloudFormationでテンプレートを利用していました。
しかし、Splunkのダウンロードリンクを毎回取得し、テンプレートを編集しなければいけないのが煩わしかったのです...
前回の記事では、ダウンロードリンクを取得するLambda関数を作成致しました。
[Splunkのダウンロードリンクをスクレイピングで取得](https://qiita.com/minaminosima/items/1f4fa5475e613265ff95)
本記事ではCFn上でへ上記の関数を実行するテンプレートを作成しました。

# 2.使用する機能や技術
- AWS CloudFormation

他にもいろいろ使ってはいるのですが、本記事ではCFnのみ掲載いたします。
API GatewayやLambdaも利用しているのですが、前回投稿分と内容が重複するので、割愛いたします。

# 3.コード
以下が実装したコードになります。

```:splunk_launch.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: Sample template
Metadata: 
  "AWS::CloudFormation::Interface": 
    ParameterGroups: 
      - Label: 
          default: "Project Name Prefix"
        Parameters: 
          - PJPrefix
      - Label: 
          default: "Network Configuration"
        Parameters: 
          - VPCCIDR
          - PublicSubnetCIDR
      - Label:
          default: "Inbound rule Setting(Write in CIDR format)"
        Parameters:
          - MyIP
      - Label:
          default: "Keypair Setting"
        Parameters:
          - KeyPair
      - Label:
          default: "Splunk Configuration"
        Parameters:
          - SplunkAdminPassword
          - InstallerType
          - Version
          - OS
          - FileExtension
      - Label:
          default: "OS Configuration"
        Parameters:
          - HostName
          - Ec2userPassword
    ParameterLabels: 
      VPCCIDR: 
        default: "VPC CIDR"
      PublicSubnetCIDR: 
        default: "PublicSubnet CIDR"
      HostName:
        default: "Hostname"
      MyIP: 
        default: "MyIP range"
      KeyPair: 
        default: "KeyPair"
      SplunkAdminPassword:
        default: "Splunk User Password"
      InstallerType: 
        default: "Splunk Insraller"
      Version: 
        default: "Splunk Version"
      OS: 
        default: "OS"
      FileExtension: 
        default: "Installer file extension"
      Ec2userPassword:
        default: "EC2user Password"
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
  PJPrefix:
    Type: String
  VPCCIDR:
    Type: String
    Default: "10.1.0.0/16"
  PublicSubnetCIDR:
    Type: String
    Default: "10.1.1.0/24"
  HostName:
    Type: String
    Default: "aws_sever_1"
  MyIP:
    Type: String
  KeyPair:
    Type: AWS::EC2::KeyPair::KeyName
  SplunkAdminPassword:
    Type: String
    Default: "password"
  InstallerType:
    Type: String
    AllowedValues:
      - EP
      - UF
  Version:
    Type: String
  OS:
    Type: String
    Default: Linux
    AllowedValues:
      - Linux
      - Windows(DO NOT SELECT)
  FileExtension:
    Type: String
    AllowedValues:
      - rpm
      - tgz
      - msi(DO NOT SELECT)
  Ec2userPassword:
    Type: String
    Default: password

# ------------------------------------------------------------#
# Resource Settings
# ------------------------------------------------------------#
Resources:
  # VPC Setting
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-vpc"

  # Internet Gateway Setting
  # インターネットGWを作成
  IGW:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-igw"
  # インターネットGWをVPCへ設定
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref IGW

  # Subnet Setting
  # パブリックサブネットを作成
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      VpcId: !Ref VPC
      CidrBlock: !Ref PublicSubnetCIDR
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-subnet-public"
  
  # Rout Setting
  # ルートテーブルの作成
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-rt-public"
  # インターネットGWへのルートを作成
  DefaultPublicRoute:
      Type: AWS::EC2::Route
      Properties:
        RouteTableId: !Ref PublicRouteTable
        DestinationCidrBlock: 0.0.0.0/0
        GatewayId: !Ref IGW
  # 作成したルートをテーブルへ追加
  PublicSubnetRouteTableAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PublicSubnet 
      RouteTableId: !Ref PublicRouteTable
  
  # SecurityGroup Setting
  # SecurityGroupの作成
  SecGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub "${PJPrefix}-scg"
      GroupDescription: "Test Rule"
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # http
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: !Ref MyIP
        # https
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !Ref MyIP
        # ssh
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref MyIP
        # RDS
        - IpProtocol: tcp
          FromPort: 3389
          ToPort: 3389
          CidrIp: !Ref MyIP
        # Splunk Web
        - IpProtocol: tcp
          FromPort: 8000
          ToPort: 8000
          CidrIp: !Ref MyIP
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-scg"
  # Create EC2 Instance
  # パブリックインスタンスの作成
  EC2InstancePublic:
    Type: AWS::EC2::Instance
    Properties:
      KeyName: !Ref KeyPair
      ImageId: ami-0cc75a8978fbbc969
      InstanceType: t2.micro
      # ロールの付与(ロール名で設定)
      IamInstanceProfile: SSM_Role
      NetworkInterfaces: 
          - AssociatePublicIpAddress: "true"
            DeviceIndex: "0"
            SubnetId: !Ref PublicSubnet
            GroupSet:
              - !Ref SecGroup
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-public"
      UserData: !Base64
        Fn::Sub: |
          #!/bin/bash
          echo "[MESSAGE: Set Environment Variable.]"
          if [ ${InstallerType} = "EP" ] ; then
            export SPLUNK_HOME=/opt/splunk
          else
            export SPLUNK_HOME=/opt/splunkforwarder
          fi
          
          echo "[MESSAGE: Set Locale And Timezone.]"
          localectl set-locale LANG=ja_JP.utf8
          timedatectl set-timezone Asia/Tokyo
          hostnamectl set-hostname ${HostName}

          echo "[MESSAGE: Set sshd_config.]"
          echo ${Ec2userPassword} | passwd --stdin ec2-user
          cp -pv /etc/ssh/sshd_config /etc/ssh/sshd_config.org
          sed -i -e 's/^PasswordAuthentication no/#PasswordAuthentication no/g' /etc/ssh/sshd_config
          sed -i -e 's/#PasswordAuthentication yes/PasswordAuthentication yes/g' /etc/ssh/sshd_config
          diff -r /etc/ssh/sshd_config /etc/ssh/sshd_config.org
          systemctl restart sshd
          systemctl status sshd

          echo "[MESSAGE: Download Splunk Enterprise installer.]"
          cd /tmp
          # Lambda関数の実行
          link=`curl -X POST "https://xxxxxxxxxx.execute-api.ap-xxxxxxxxx-x.amazonaws.com/xxx/xxxxx" -d "{\"os\": \"${OS}\",\"installer\": \"${InstallerType}\",\"version\": \"${Version}\",\"filename_extension\": \"${FileExtension}\"}"`
          dl_link=`echo $link | sed -e 's/.*body\"\:\s*\"\(.*\)\"}/\1/'`
          wget $dl_link
          INSTALL_FILE=`ls -1 splunk*`
          
          echo "[MESSAGE: Install Splunk Enterprise.]"
          if [ ${FileExtension} = "rpm" ] ; then
            rpm -i /tmp/$INSTALL_FILE
          elif [ ${FileExtension} = "tgz" ] ; then
            tar -xzvf /tmp/$INSTALL_FILE -C /opt
            chown -R root: $SPLUNK_HOME
          fi

          echo "[MESSAGE: Start Splunk by root.]"
          $SPLUNK_HOME/bin/splunk start --accept-license --answer-yes --seed-passwd ${SplunkAdminPassword}

```
# 4.テンプレート設定
AWSのWebコンソールでテンプレートへ設定値を入れ込みます。
ここで、インストール対象となるSplunkのバージョンや、インストーラの拡張子などを設定します。
![コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/745643/1e0f627d-c768-b15e-4917-c57373763e48.png)


# 5.コード説明
出来上がる環境はこんな感じです。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/745643/5daaa317-c188-41b5-3d0f-4967b361ae33.png)

VPCにパブリックサブネットを作成し、そこにインスタンスを建てただけのシンプルな奴になってます。
作成時は以下の記事を参考にしました。
[CloudFormationを使ってVPCを構築する
](https://qiita.com/okubot55/items/b18a5dd5166f1ec2696c)

少しカスタマイズした点としては、
作成したインスタンスにはセッションマネージャーで接続できるようにロールの割り振りを行いました。
ちょっとした作業を行う際にセッションマネージャーは凄く重宝します。

あとはUserData部分に記載したスクリプトです。
以下にスクリプトの内容を記載します。

・環境変数設定
SPLUNK_HOMEを環境変数として設定します。
UFとEPをインストールするのでは、デフォルトのパスが異なるのでIF文で分岐させています。

```:環境変数設定
echo "[MESSAGE: Set Environment Variable.]"
if [ ${InstallerType} = "EP" ] ; then
  export SPLUNK_HOME=/opt/splunk
else
  export SPLUNK_HOME=/opt/splunkforwarder
fi
```

・時刻設定
ホスト名と時刻の設定もやっちゃいます。
この辺は後からやると面倒なので、テンプレートでやるに限りますね。

```:タイムゾーン等を設定
echo "[MESSAGE: Set Locale And Timezone.]"
localectl set-locale LANG=ja_JP.utf8
timedatectl set-timezone Asia/Tokyo
hostnamectl set-hostname ${HostName}
```

・パスワードでログインできるようにする
sedコマンドで置換することで、パスワードでログインできるようにします。
これでKeyPairがなくても簡単にログインできます。
簡単な検証を目的としているので、長期運用を考えていないため、すぐログインできる方がいいと思っています。

```:パスワードでログインできるようにする
echo "[MESSAGE: Set sshd_config.]"
echo ${Ec2userPassword} | passwd --stdin ec2-user
cp -pv /etc/ssh/sshd_config /etc/ssh/sshd_config.org
sed -i -e 's/^PasswordAuthentication no/#PasswordAuthentication no/g' /etc/ssh/sshd_config
sed -i -e 's/#PasswordAuthentication yes/PasswordAuthentication yes/g' /etc/ssh/sshd_config
diff -r /etc/ssh/sshd_config /etc/ssh/sshd_config.org
systemctl restart sshd
systemctl status sshd
```

・Splunkインストーラダウンロード
ここで関数の実行を行います。
JSON形式で結果が返ってくるのでsedコマンドでURLだけを取得します。
tmp配下へインストーラを保存します。

```:ダウンロードリンク取得
echo "[MESSAGE: Download Splunk Enterprise installer.]"
cd /tmp
# Lambda関数の実行
link=`curl -X POST "https://xxxxxxxxxx.execute-api.ap-xxxxxxxxx-x.amazonaws.com/xxx/xxxxx" -d "{\"os\": \"${OS}\",\"installer\": \"${InstallerType}\",\"version\": \"${Version}\",\"filename_extension\": \"${FileExtension}\"}"`
dl_link=`echo $link | sed -e 's/.*body\"\:\s*\"\(.*\)\"}/\1/'`
wget $dl_link
INSTALL_FILE=`ls -1 splunk*`
```

・Splunkインストール
ダウンロードしてきたファイルの拡張子でインストール方法を分岐させます。
THPやSELinuxの無効化はやりません。
ちょっとした検証を行いたいだけですので...

```:インストール
echo "[MESSAGE: Install Splunk Enterprise.]"
if [ ${FileExtension} = "rpm" ] ; then
  rpm -i /tmp/$INSTALL_FILE
elif [ ${FileExtension} = "tgz" ] ; then
  tar -xzvf /tmp/$INSTALL_FILE -C /opt
  chown -R root: $SPLUNK_HOME
fi
```

・Splunk起動
Splunkをrootで起動してUserDataは終わりです。
Splunkの公式ではrootでの実行を推奨していませんが、ちょっとした検s(ry

```:起動
echo "[MESSAGE: Start Splunk by root.]"
$SPLUNK_HOME/bin/splunk start --accept-license --answer-yes --seed-passwd ${SplunkAdminPassword}
```

# 6.参考
本記事の途中にも出しましたが、ここに改めて記載します。

[Splunkのダウンロードリンクをスクレイピングで取得](https://qiita.com/minaminosima/items/1f4fa5475e613265ff95)
前回投稿分の記事です。
ここでLambda関数を実行していますので、詳細を知りたい方はこちらまで。

[CloudFormationを使ってVPCを構築する](https://qiita.com/okubot55/items/b18a5dd5166f1ec2696c)
VPCの構築で参考にしました。
参考というか、ほぼそのまま利用させて頂いております。
簡潔にまとめられているので、CFnでVPCを構築する際は参考にしてみてください。

[SIBYL System - AWSのCloud initのログの場所](http://yamada.daiji.ro/blog/?p=191)
UserDataの実行結果を確認する際に利用しました。
どこに何があるかをこの記事で知ることが出来ました。
AWSのリファレンスにも載っているかもしれませんが、公式ドキュメントが見づらいんですよね...

# 7.まとめ
やはり、記事を書く上でどこまで書くのかは悩みますね。
分かりやすくまとめるって大変だなぁと思いました。