Amazon Linux サーバ基本設定メモ

# Amazon Linux サーバセットアップメモ

私がAWSでEC2サーバ（Amazon Linux）を１から作るときに行う、サーバのセットアップのメモ。
Qiitaなどで公開されている先人諸兄のありがたい知恵も参考にしている。

サーバ設定の話なので、ELBやVPC、セキィリティグループ設定などの通信ルールなど、別レイヤの設定の話は割愛。


## OS設定

OSレベルの設定を行う。この設定を行ったあとには再起動をする。

### yum アップデート

インストールされているソフトウェアを最新の状態にする。

```shell-session
# yum update -y
```

### ローケル設定

ローケル情報の設定する。

* OSレベルで、環境変数LANGの設定はしない。各アカウント単位で必要ならばしてもらう方針のため。
* ntpdの設定はしない。Amazon Linuxは、デフォルトで所定のタイムサーバと同期するよう設定されているから。

**時差情報の設定**

シンボリックリンク `/etc/localtime` を作る。

```shell-session
# # ローケル設定
# cp -p /etc/localtime /etc/localtime.org
# ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
```

**タイムゾーン設定**

`/etc/sysconfig/clock` を編集する。[^1]

```sh:/etc/sysconfig/clock
ZONE="Asia/Tokyo"
UTC=true    # ここは変更しなくてOK
```

[^1]: `/etc/sysconfig/clock`では、初期状態で`UTC=true`になっている。**ここは変更しないこと**。意味はハードウェアクロックをUTCにするかどうかということで、OS側がローケルを設定すればよいのでtrueのままにしておく。（参考）[Linux インスタンスの時刻の設定 - AWSドキュメント](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/set-time.html#change_time_zone)


### スワップ領域追加

スワップは基本用意されていないので、必要であれば、既存ボリュームからスワップ領域を確保する。[^2]

[^2]: 注意として、EBSにSWAP領域を割り当てないほうがよい。I/Oのたびに利用料が発生するからだ。本格運用するのであればメモリを増やしたり、インスタンスストアボリュームなどを利用するなど、別途検討すべし。また、Swap発生時にアラートを発出するなどの状態監視なども取りいれるとよいだろう。

```shell-session
# # /swap に、1G(1Mx1024)の領域を確保の場合
# dd if=/dev/zero of=/swap bs=1M count=1024
# mkswap /swap; chmod 0600 /swap; swapon /swap
```
```shell-session
$ free    # check
```
```sh:/etc/rc.local
#...略...
swapon /swap
```

これは固定サイズの手動作成方法なので、スケールアップなどでメモリが増えた場合は作り直しが必要になる。
動的に確保する場合は下記リンクを参照してほしい。参考になる。

参考：[Amazon EC2(Linux)のswap領域ベストプラクティス](http://dev.classmethod.jp/cloud/ec2linux-swap-bestpractice/)


### ホスト名設定

#### a. 自動設定の場合

Amazon Linuxの場合、cloud-init設定ファイル`/etc/cloud/cloud.cfg`の中の設定値、`preserve_hostname`で設定できる。
この値を`false`にすることで、マシン立ち上げ時に、プライベートIPアドレスをベースとしたホスト名に自動で設定される。

Auto Scalingなどで自動的に発生・消滅するインスタンスの場合は、ホスト名は固定ではなく、自動的につけられるホスト名にしたほうが良いと考えている。自動的に作られたホスト名はプライベートのIPアドレスをベースとしているので（例：`ip-10-0-0-123`）、syslogなどで記録される時に、どのインスタンスから来たログかを判別しやすくなるからだ。

```sh:/etc/cloud/cloud.cfg
#...略...
preserve_hostname: false
```

#### b. 手動設定の場合

ホスト名を任意に設定したい場合や、Amazon Linux以外のOSを使っている場合などは、`/etc/sysconfig/network` で、`HOSTNAME`の値を変更する。
なおAmazon Linuxでは、`HOSTNAME`を`localhost`や`localhost.localdomain`とすると、自動設定と同じようなホスト名がつけられる。

```sh:/etc/sysconfig/network
#...略...
HOSTNAME=myserver.localdomain
```

`/etc/hosts`ファイルも更新しておく。

```sh:/etc/hosts
#...略...
127.0.0.1 myserver.localdomain myserver localhost localhost.localdomain
```

（参考）
http://dev.classmethod.jp/cloud/five-confs-of-ec2-linux-sysops/#toc-5-
http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/set-hostname.html


### ネットワーク設定

IPv6は使わない場合、`/etc/sysconfig/network`に`NETWORKING_IPV6=no`を設定する。
`ip6tables`サービスの停止は、`ntsysv`などで止めると良い（次項参照）。

```sh:/etc/sysconfig/network
#...略...
NETWORKING_IPV6=no
```

### 再起動

ここまでで一度、再起動しておく。

```shell-session
# reboot
```



## サービスの設定

不必要なサービスを止めたり、逆に必要なサービスを自動的に起動するよう設定する。

### Daemonの一括設定

オーソドックスな方法の１つに、`chkconfig`の利用があるが、一括で設定するのであれば`ntsysv`を使った方が楽。
グラフィカルに設定できるので便利である。

```shell-session
# ntsysv
```

私は、主に下記のDaemonを残し、それ以外を除いている。

```
atd                 # キュージョブ at コマンド用
auditd              # （※任意）後述「セキュリティ要件」参照
cloud-config        # cloud-init用 (AWSのEC2設定ユーティリティ)
cloud-final         # cloud-init用 (AWSのEC2設定ユーティリティ) 
cloud-init          # cloud-init用 (AWSのEC2設定ユーティリティ)
cloud-init-local    # cloud-init用 (AWSのEC2設定ユーティリティ)
crond               # cron
irqbalance          # IRQ割込み処理のCPU間での負荷分散. コアが1つなら要らない.
netfs               # （※任意）NFSを使うならば必要
network             # ネットワーク利用で必要
ntpd                # 時刻合わせで必要
ntpdate             # OS起動時の時刻合わせ
psacct              # （※任意）後述「セキュリティ要件」参照
rngd                # （※任意）乱数ジェネレータ。サービスとしてユーザー認証が頻繁にあるシステムとかなら導入。
rsyslog             # syslogクライアントまたはsyslogサーバとして必要
sshd                # sshd接続に必要
```

なお、`httpd`や`sendmail`など、ビジネス上必要になってくるミドルウェアなどは、設定を行ってから稼働させるべきだろう。なので初期設定では稼働させない。

## ソフトウェアの設定

GCCなどがデフォルトでは入ってない。その他、個人的には使うであろうソフトウェアを導入する。

**（参考）よく使うソフトウェアで入っていないものの導入例**

```shell-session
# yum install -y gcc
# yum install -y xinetd
# yum install -y dstat sysstat iotop
# yum install -y git
# yum install -y jq
```

### AWS-CLI / AWS_completer

Amazon Linux ならば、AWS-CLIはデフォルトで入っているので、改めて導入する必要はない。
ここでは、Tab補完機能を有効にする。

```shell-session
# echo 'complete -C /usr/bin/aws_completer aws' > /etc/profile.d/aws-cli.sh
```

### Rsyslog

Syslogクライアント、そしてSyslogホスト（いわゆるログサーバ）用にRsyslogを使っている。ホスト側ではログを受け付ける設定。クライアントはホストへログを飛ばす設定をする。[^3]
基本的には、次のログをログホストへ飛ばすようにしている。

* `/var/log/secure`
* `/var/log/message`

また、展開するサービスによって、Webサーバやその他Daemonなどのログや、セキュリティ要件として必要なログなどを`local`ファシリティを利用して飛ばしたりする。
具体的なConfigのサンプルはまたの機会に。

[^3]: ログを飛ばす際には、クライアントとホストのそれぞれの属するセキュリティグループの通信設定を忘れずに。


## ユーザーの導入

必要なユーザー設定をする。
アカウントの運用およびユーザー設定の基本は、次の要件でまずは進めている。

* ec2-user は使わない
* 共有アカウントは使わない
* 公開鍵によるsshログイン（パスワード（だけの）ログインはしない）

### ユーザーの作成

サンプル

```shell-session
# useradd -g users -m precure
# sudo su - precure
precure $ mkdir .ssh
precure $ chmod 0700 .ssh
precure $ vi .ssh/authorized_keys           # 当人の公開鍵追加
precure $ chmod 0400 .ssh/authorized_keys 
precure $ # 接続テスト
```

### 特権ユーザーの設定

#### sudoes の設定

wheel グループに属するユーザーが sudo できるようにする。
要件によって、パスワードが必要であればそう設定する。

```shell-session
# visudo
```
```vim:visudo
#...略...
%wheel  ALL=(ALL)   ALL
```

#### 対象アカウントの設定

`sudo` できるように、必要なユーザーアカウントは wheel グループに属させる。
最初から属させることがわかっている場合は、

```
# useradd -g users -G wheel -m pamyurin
```

といった具合に、`useradd`でアカウント作成時に属させてもよい。
後づけで属させる場合は、

```
# gpasswd -a pamyurin wheel
```

のように`gpasswd`コマンドで*追加*することをオススメする。`usermod -G` を使ってもいいが、wheel以外のグループにすでに属している場合に困る[^4]。

[^4]: 使い方は `usermod -G grp1[,grp2,...]` で、つまるところ置き換わってしまう。


### 各ユーザーアカウントの環境設定

ユーザー毎に設定する必要なものは、基本的にユーザーに任す。
ログインできるかテストしてもらいついでに、個々人で設定するよう伝える。

* .bashrc
* vim の設定
* git の設定
* Perl/Ruby/Phython などのスクリプト環境

など。



## セキュリティ要件対応

設定することで監査・セキュリティ的な向上を期待できる機能がある。一方でそれらは設定や運用・管理などを別に考える必要があるだろう。
取捨選択して導入・設定する。[^5]
なお、ここの各項目、設定ミスによって最悪ログインできなくなる可能性があるので、念のためインスタンスのバックアップを取っておいてからテストするとよいかも。特にSSH周り。

[^5]: `iptables`, `ip6tables`の利用も考えられるが、セキュリティグループ側で設定したほうが圧倒的に楽なので、特段使う理由はないだろう。

### ユーザーアカウント

前項で掲げた要件のうち、

* ec2-user は使わない
* 共有アカウントは使わない

はマストかな、と思っている。

### psacct

ユーザーが実行したコマンドを記録するといった、オペレーションのログを取ることができる。
ただし、コマンドの引数が記録されなかったりと完璧ではない。なので必要に応じて`script`との併用を検討する。
比較的簡単に監査ログの仕組みを導入できるので良いのではないかなと私は思っている。

（参考）
[scriptとpsacctでオペレーションログを記録する - Developers.IO](http://dev.classmethod.jp/operation/logging_operation_using_script_and_psacct/)

### auditd

SELinuxと組み合わせて活用できたりする監査ツール。単体でも監査ログを記録できる。
全コマンドを記録できるので、`script`コマンドや`psacct`サービスでできない部分を穴埋めできる証跡監査が可能。

（参考）
[全実行コマンドの記録(CentOS7) - Qiita](http://qiita.com/_norin_/items/18aebfe88a2836610264)
[auditdによるシステム監査の概要 - レンタルサーバーでLinuxのお勉強](http://hono-linux.seesaa.net/article/382259213.html)

### SELinux

Amazon Linux ではデフォルトで無効になっている。
要件に合わせて、必要であれば設定する。

[Amazon LinuxでSELinuxを有効にする。 - Qiita](http://qiita.com/hichon/items/b80fecd3a4875b827985)

### SSH

マスト要件として、

* root アカウントのログインの禁止
* パスワードのみのログイン禁止（つまり公開鍵ログイン）

があるが[^6]、オプションとして次の内容を検討する。

* 利用ポート番号の変更（要：セキュリティグループの設定変更）
* ２段階認証
    * 公開鍵 + アカウントパスワード入力[^7]
    * 公開鍵 + ワンタイムパスワード 
* アクセス元制限

利用ポート番号の変更によって、つつかれたり攻撃されたり確率がだいぶ下がる。
２段階認証では、なりすまし防止の向上が期待できる。それぞれ、下記リンクが設定の参考になる。

アクセス元制限は、SSHで設定するより、セキュリティグループ側で設定するほうが楽だろう。なお、サービス・ネットワーク環境上に複数台サーバがあった場合、１台を外部から接続用のホップサーバとして、それ以外のサーバは外部ネットワークからのログインを許可させないようにする（ネットワーク設計の話ではあるが）。

[「OpenSSHによる二段階認証について」 - WebPay Engineering Blog](http://engineering.webpay.co.jp/2014/08/27/ssh-two-factor-authentication/)
[「OpenSSHによる二段階認証について ワンタイムパスワード編」 - WebPay Engineering Blog](http://engineering.webpay.co.jp/2014/09/10/ssh-one-time-password/)

[^6]: root ユーザーのログイン禁止は、SSHのデフォルト設定で禁止になっているはず。
[^7]: ちなみに私は、アカウントのパスワード入力のほうをよく使う。十分長いパスワードを使おう。

### ec2-user の削除

ec2-user があることで、次の弊害が発生する。

* 攻撃者は、サーバにどんなアカウントが存在するかは知らないが、サーバが AmazonLinux であるならば少なくとも ec2-user が存在しうる、ということは知っている。
* ec2-user になりすませば、業務上でもそうでなくても、通常ユーザー（身内）も証跡を残すことなく行動できてしまう可能性がある。

なので、できるだけ（別なアカウントを用意した後速やかに）削除したほうが良い。
なお、もちろん他のユーザーアカウントを作ってからの話。

### ログのモニタリング

ログは、証跡として利用する他に、リアルタイム監視用データとして役立てることができる。
Syslog ホストに集まってきたログの中から、特定の条件（キーワードなど）を元にオペレーション・センターに情報をポストする、などといった方策。

私は、IBM謹製 logmon ＋ [Slack](https://slack.com)の特定チャネルにメッセージを流す自前スクリプトを使っている[^8]。

* /var/log/messages の異常検知目的
* 特定ユーザーのログイン状況確認目的
* `su`や`sudo`の監視
 
有名どころでSwatchや、他のログチェックツールなどの導入を検討してみてはどうだろうか。

[^8]: …しかし、あくまでサンプルとして公開されていたlogmon。長年の役目を終え、2016/7現在、公開されていない状態となってしまった。嗚呼。2017/4/13追記： こちらを参照あれ。 http://qiita.com/inouet/items/cc1eacef237f2328e98f


### その他

#### Prompt 色変更

わたしは誤認・誤操作の防止目的で、サーバのセグメントや役割ごとに、プロンプトを色分けしている。視覚的に（ぱっと見で）どのサーバか、（開発環境やテスト環境か、おいそれとコマンド実行してはいけない環境かが）分かるので、だいぶ役立つと思う。

（参考）
[Bashのプロンプトに色を付けてサーバやユーザを区別する - Qiita](http://qiita.com/fernet/items/4dcb6f82520d87227121)

`/etc/profile.d/prompt.sh`を作成し、ここで設定する。下記はサンプル。

```bash:/etc/profile.d/prompt.sh
#!/bin/bash

set_ps1() {
    local _PS1
    if [ $UID = 0 ] ; then
        #root
        _PS1="\[\033[1;31m\][\u@\h \W]#\[\033[0m\] "
    else
        _PS1="[\e[1;32m\u\e[00m@\e[1;32m\h\e[00m \e[1;33m\w\e[00m] (\e[1;34m$1\e[00m)\n$ "
    fi
    export PS1=$_PS1
}
set_ps1 "AWS WEB!"
```

#### 監視設定

Amazon Cloud Watch や、サードパーティーの監視ツールをほどなく導入しておく。
Amazon Cloud Watch だと、残念ながら監視できるリソースは限定的なので、それを補う監視は必要になってくると思う。
Nagios の導入だったり、New Relic の検討とか、かな。


（以上）

----