vague memory

うろ覚えを無くしていこうともがき苦しむ人の備忘録

Amazon Inspector CVEルールを試してみる

AWSのセキュリティ評価サービス Amazon Inspector に触れる機会があったので記録しておこうと思います。
CVE(共通脆弱性識別子)ルールパッケージでの実行結果です。

何をどう検査しているのかという細かな情報は公開されていないようでしたので、パッケージ導入状態と実行時間により評価結果が変わるかを調べました。 (結果謎な部分は謎なままです)

評価テンプレートの時間が長いほど、Amazon Inspector は、より詳細かつ包括的なテレメトリーのセットを収集して分析します。 つまり、分析時間が長くなることで、Amazon Inspector は評価ターゲットの動作を細部にわたって確認し、より詳細な結果を提示できるようになります。

評価検証

  • AmazonLinux に対して Common Vulnerabilities and Exposures-1.1 で評価を実行
  • Duration 15min/1h/8h/12h/24h の結果を比較

結果

今回の検証結果は以下のとおりです。

  • コンパイルした置き換えバイナリと同様に標準以外のリポジトリからの導入パッケージは検査されない
    • パッケージの changelog のみで評価を行っているわけではない
  • 今回の検証では実行時間による評価結果の変動は無かった
  • サポートされるOSでも AWSエージェントのインストールは行えてしまう、コンソール上も特にエラー・警告は無い

実行時間が長くなる事により外部パッケージでの導入状態も検査するようになってくれるかなという期待があったのですが、 変動はありませんでした。 せめて誤検知(ソースからの導入等)用に除外条件設定ができるようになると使い勝手が良くなるのではと思いました。



評価実施OS

CentOSも検証しようと思いましたが、AMI立ち上げ時点で検出結果0だったため、パターン検証からは除外しています。 (Findings としては Informational で No potential security issues found の出力となりました)

OS(Amazon Linux)状態パターン

  • a) 初期状態
    • AMIから起動しただけで他に何も手を入れていない状態
  • b) yum upgrade 実施
    • AMIから起動後に yum upgrade でパッケージ最新化
    • yum で Nginx、MySQL5.6 を導入
  • c) 外部リポジトリからパッケージ導入
    • Nginx、MySQL5.7 を公式 rpm から導入
  • d) 外部リポジトリからパッケージ導入 + changelog書き換え
    • Nginx を公式 rpm から導入し、changelog に CVE No を追記

Findings(検出結果)

Duration(実行時間)で選択可能な時間全てで実施しています。

  • Duration別検出数
Duration a b c d
15min 3 (2pkg) 0 9 (1pkg) 9 (1pkg)
1h 3 (2pkg) 0 9 (1pkg) 9 (1pkg)
8h 3 (2pkg) 0 9 (1pkg) 9 (1pkg)
12h 3 (2pkg) 0 9 (1pkg) 9 (1pkg)
24h 3 (2pkg) 0 9 (1pkg) 9 (1pkg)

パターン a 検出結果

f:id:htnosm:20161127172220p:plain

Severity が High で3つの CVE(2つのパッケージ) が検出されました。
opensslとkernelのバージョンを上げなさいという結果です。

パターン b 検出結果

yum でのパッケージ最新化を行った状態では検出結果 0 となりました。
導入しているパッケージが少なく、且つ、最新状態なので当然の結果です。

パターン c 検出結果

f:id:htnosm:20161127172225p:plain

Severity = High で 8つ、 Medium が1つ検出されました。 パッケージは全て nginx です。
通常だと外部リポジトリのパッケージについては検査してくれないようです。

パターン d 検出結果

changelog の CVE No を見て判断しているのかもしれないと思い、試してみました。
Nginx 公式のパッケージの changelog に CVE No を追記しています。 結果、changelog 書き換えで検知結果が変わる事はありませんでした。(パターン c と同じ結果でした)

CVE No が含まれています。

[ec2-user@ip-172-30-0-95 ~]$ rpm -qa | grep nginx
nginx-1.10.1-1.28.amzn1.x86_64
[ec2-user@ip-172-30-0-95 ~]$ rpm -q --changelog nginx | grep CVE
- CVE-2016-0747: Insufficient limits of CNAME resolution in resolver
- CVE-2016-0746: Use-after-free during CNAME response processing in resolver
- CVE-2016-0742: Invalid pointer dereference in resolver
- CVE-2014-3616 nginx: virtual host confusion (#1142573)
- (#1126891) CVE-2014-3556: SMTP STARTTLS plaintext injection flaw
- add patch for CVE-2013-4547
  CVE-2013-2028 stack-based buffer overflow when handling certain chunked
- Add security patch to fix CVE-2011-4315
  • Nginx 公式から導入

CVE No が含まれていません。

[ec2-user@ip-172-30-0-7 ~]$ rpm -qa | grep nginx
nginx-1.11.6-1.el6.ngx.x86_64
[ec2-user@ip-172-30-0-7 ~]$ rpm -q --changelog nginx | head
* 火 11月 15 2016 Konstantin Pavlov <thresh@nginx.com>
- 1.11.6

* 月 10月 10 2016 Andrei Belov <defan@nginx.com>
- 1.11.5

* 火  9月 13 2016 Konstantin Pavlov <thresh@nginx.com>
- 1.11.4.
- njs updated to 0.1.2.
[ec2-user@ip-172-30-0-7 ~]$ rpm -q --changelog nginx | grep -c CVE
0
  • Nginx 公式からソースパッケージを取得し、changelogに CVE No を追加して rebuild

無理矢理 CVE No を追加してみました。この状態で Inspector での検査を行いました。

[ec2-user@ip-172-30-0-248 ~]$ rpm -qa | grep nginx
nginx-1.11.6-1.amzn1.ngx.x86_64
[ec2-user@ip-172-30-0-248 ~]$ rpm -q --changelog nginx | head
* 火  1月 26 2016 Jamie Nguyen <jamielinux@fedoraproject.org> - 1:1.8.1-1
- update to upstream release 1.8.1
- CVE-2016-0747: Insufficient limits of CNAME resolution in resolver
- CVE-2016-0746: Use-after-free during CNAME response processing in resolver
- CVE-2016-0742: Invalid pointer dereference in resolver

* 水  9月 17 2014 Jamie Nguyen <jamielinux@fedoraproject.org> - 1:1.6.2-1
- update to upstream release 1.6.2
- CVE-2014-3616 nginx: virtual host confusion (#1142573)

EC2 EBS縮小 (というより CentOS ディスク縮小) の流れ

AWS EC2(Linux) のディスクサイズ縮小を行う機会があったので、備忘として整理します。 復旧や作り直しと同意になるので極力行いたくない作業です。

流れは以下のようになります。
各 Volume、Snapshot には判別しやすい名称を付けておくと混乱しないと思います。

01. 縮小対象 EC2 インスタンスの Volume(vol-A) から Snapshot(snap-A) を作成
02. Snapshot から Volume(vol-B) を作成
03. 縮小後のサイズを指定して、空の Volume(vol-C) を作成
04. 作業用 EC2 インスタンスを起動
05. 作業用 EC2 インスタンスに Volume(vol-B、vol-C) をアタッチ
06. データコピー
07. 作業用 EC2 インスタンスから Volume(vol-C) をデタッチ
08. Volume(vol-C) から Snapshot(snap-C) を作成
09. Snapshot(snap-C) から AMI を作成
    - マネジメントコンソールでの操作はデフォルトで Virtualization type  が PV 指定になるようなので、 HVM の場合は注意
10. AMI から縮小後サイズの EC2 インスタンスを起動





肝は 05 のデータコピー部分になるかと思いますので、以下、05部分の手順(一例)です。
ファイルシステムによりコマンドが多少違いますし、環境によっても異なるのであくまで例です。
起動に失敗する場合は大抵 fstab と grub の設定部分誤りなので、その辺りに目星を付けて修正すると起動できると思います。

また、SELINUX は無効にしておいた方がトラブルは少ないと思います。(ssh接続不可等が発生する可能性があります)

$ grep '^SELINUX' /etc/selinux/config
SELINUX=disabled
SELINUXTYPE=targeted

環境

ext4 と xfs で 30GB -> 10GB への縮小を行います。
作業用インスタンスのOSは、コマンド有無があるので対象OSと合わせると良いかと思います。 また、Marketplace のAMIだと stop しないと attach/detach が行えないようなので、 Amazon Linux 等の公式AMIを使用するのが良いのかもしれません。

vol-xxxxxxxx : Unable to detach volume 'vol-xxxxxxxx' with Marketplace codes from instance 'i-xxxxxxxx' as the instance is not in the 'stopped' state.

今回は AWS Marketplace にある CentOS 標準の AMI を対象に実施しました。

縮小元インスタンス情報

Apacheは起動後の確認に使用しただけですが、一応載せてます。

ext4

[root@ip-172-30-0-241 /]# cat /etc/redhat-release
CentOS release 6.8 (Final)
[root@ip-172-30-0-241 /]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       30G  1.1G   27G   4% /
tmpfs           498M     0  498M   0% /dev/shm
[root@ip-172-30-0-241 /]# httpd -v
Server version: Apache/2.2.15 (Unix)
Server built:   Jul 18 2016 15:24:00

xfs

[root@ip-172-30-0-149 /]# cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
[root@ip-172-30-0-149 /]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       30G  1.4G   29G   5% /
devtmpfs        478M     0  478M   0% /dev
tmpfs           496M     0  496M   0% /dev/shm
tmpfs           496M   13M  484M   3% /run
tmpfs           496M     0  496M   0% /sys/fs/cgroup
tmpfs           100M     0  100M   0% /run/user/1000
[root@ip-172-30-0-149 /]# httpd -v
Server version: Apache/2.4.6 (CentOS)
Server built:   Jul 18 2016 15:30:14

データコピー手順

ほぼ同様の流れなので特記しない限りは ext4 の実行結果を載せます。

1) アタッチ状態確認

Volume(vol-B、vol-C) がアタッチされている事を確認します。 vol-Bを xvdf、vol-C(空ボリューム)を xvdg としています。

[root@ip-172-30-0-241 /]# lsblk
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvda    202:0    0  30G  0 disk
└─xvda1 202:1    0  30G  0 part
xvdf    202:80   0  30G  0 disk
└─xvdf1 202:81   0  30G  0 part /
xvdg    202:96   0  10G  0 disk

2) パーティション設定

縮小前(xvdf)の設定に合わせて縮小後(xvdg)のパーティション設定を行います。

[root@ip-172-30-0-241 /]# fdisk /dev/xvdg
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x714a83d2.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
         switch off the mode (command 'c') and change display units to
         sectors (command 'u').

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-1305, default 1):
Using default value 1
Last cylinder, +cylinders or +size{K,M,G} (1-1305, default 1305):
Using default value 1305

Command (m for help): a
Partition number (1-4): 1

Command (m for help): p

Disk /dev/xvdg: 10.7 GB, 10737418240 bytes
255 heads, 63 sectors/track, 1305 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x714a83d2

    Device Boot      Start         End      Blocks   Id  System
/dev/xvdg1   *           1        1305    10482381   83  Linux

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

縮小前後(xvdf/xvdg)で同様の設定になっている事を確認します。

[root@ip-172-30-0-241 /]# fdisk -l

Disk /dev/xvda: 32.2 GB, 32212254720 bytes
255 heads, 63 sectors/track, 3916 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00057cbb

    Device Boot      Start         End      Blocks   Id  System
/dev/xvda1   *           1        3916    31454246   83  Linux

Disk /dev/xvdf: 32.2 GB, 32212254720 bytes
255 heads, 63 sectors/track, 3916 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00057cbb

    Device Boot      Start         End      Blocks   Id  System
/dev/xvdf1   *           1        3916    31454246   83  Linux

Disk /dev/xvdg: 10.7 GB, 10737418240 bytes
255 heads, 63 sectors/track, 1305 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x714a83d2

    Device Boot      Start         End      Blocks   Id  System
/dev/xvdg1   *           1        1305    10482381   83  Linux

3) マウント

ファイルシステムを作成後、マウントします。

[root@ip-172-30-0-241 /]# mkfs.ext4 /dev/xvdg1
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
655360 inodes, 2620595 blocks
131029 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=2684354560
80 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 21 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.
[root@ip-172-30-0-241 /]# mkdir -p /mnt/old /mnt/new/boot
[root@ip-172-30-0-241 /]# mount -t ext4 /dev/xvdf1 /mnt/old
[root@ip-172-30-0-241 /]# mount -t ext4 /dev/xvdg1 /mnt/new
[root@ip-172-30-0-241 /]# mount -l
/dev/xvdf1 on / type ext4 (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
devpts on /dev/pts type devpts (rw,gid=5,mode=620)
tmpfs on /dev/shm type tmpfs (rw,rootcontext="system_u:object_r:tmpfs_t:s0")
none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
/dev/xvdf1 on /mnt/old type ext4 (rw)
/dev/xvdg1 on /mnt/new type ext4 (rw)
  • xfs

xfs を扱うためのパッケージをインストールしておきます。

yum install xfsprogs xfsdump
[root@ip-172-30-0-149 /]# mkfs.xfs /dev/xvdg1
meta-data=/dev/xvdg1             isize=256    agcount=4, agsize=655296 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0        finobt=0
data     =                       bsize=4096   blocks=2621184, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
[root@ip-172-30-0-149 /]# mkdir -p /mnt/old /mnt/new/boot
[root@ip-172-30-0-149 /]# mount -t xfs /dev/xvdf1 /mnt/old
[root@ip-172-30-0-149 /]# mount -t xfs /dev/xvdg1 /mnt/new
[root@ip-172-30-0-149 /]# mount -l
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
devtmpfs on /dev type devtmpfs (rw,nosuid,seclabel,size=489108k,nr_inodes=122277,mode=755)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,seclabel)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,seclabel,mode=755)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,seclabel,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
pstore on /sys/fs/pstore type pstore (rw,nosuid,nodev,noexec,relatime)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/net_cls type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
configfs on /sys/kernel/config type configfs (rw,relatime)
/dev/xvdf1 on / type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
rpc_pipefs on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw,relatime)
selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime)
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=27,pgrp=1,timeout=300,minproto=5,maxproto=5,direct)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime,seclabel)
mqueue on /dev/mqueue type mqueue (rw,relatime,seclabel)
nfsd on /proc/fs/nfsd type nfsd (rw,relatime)
tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,seclabel,size=101536k,mode=700,uid=1000,gid=1000)
/dev/xvdf1 on /mnt/old type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
/dev/xvdg1 on /mnt/new type xfs (rw,relatime,seclabel,attr2,inode64,noquota)

その他にラベル付与やスワップ領域作成等が必要な場合は実施しておきます。

### ext4
# ラベル
e2label /dev/xvdg1 /
blkid
# スワップ
mkswap /dev/xvdg2

### xfs
# ラベル
xfs_admin -L "/boot" /dev/xvdg1
xfs_admin -L "/" /dev/xvdg3
blkid
# スワップ
mkswap /dev/xvdg2

4) ファイルコピー

容量により時間が掛かるのでバックグラウンド実行しておきます。複数パーティションが対象となる場合は、それぞれ実行します。

cd /mnt/old/
( LANG=C date; nohup rsync -avxH \
  --exclude ""proc/*"" \
  --exclude ""sys/*"" \
  --exclude ""dev/*"" \
  /mnt/old/ /mnt/new/; date \
) > /tmp/disk-sync.log 2>&1 < /dev/null &
  • xfs
cd /mnt/old/
( LANG=C date; nohup xfsdump -J - /mnt/old \
  | xfsrestore -J -p 60 - /mnt/new ; date \
) > /tmp/disk-sync.log 2>&1 < /dev/null &

5) grubインストール

chroot

OS起動時に作成されるディレクトリ群をマウントした後、 /mnt/new/ に対して chroot します。 (chroot した事を確認するためにログファイルコピーを行っていますが、必須ではありません。)

cp -ip /tmp/disk-sync.log /mnt/new/var/log/
gzip /mnt/new/var/log/disk-sync.log
ls -l /mnt/new/var/log/disk-sync.log*

mount -t proc /proc /mnt/new/proc
mount -t sysfs /sys /mnt/new/sys
mount --bind /dev /mnt/new/dev
chroot /mnt/new/
ls -l /var/log/disk-sync.log.gz

grub

[root@ip-172-30-0-241 /]# grub
Probing devices to guess BIOS drives. This may take a long time.


    GNU GRUB  version 0.97  (640K lower / 3072K upper memory)

 [ Minimal BASH-like line editing is supported.  For the first word, TAB
   lists possible command completions.  Anywhere else TAB lists the possible
   completions of a device/filename.]
grub> device (hd0) /dev/xvdg
device (hd0) /dev/xvdg
grub> root (hd0,0)
root (hd0,0)
 Filesystem type is ext2fs, partition type 0x83
grub> setup (hd0)
setup (hd0)
 Checking if "/boot/grub/stage1" exists... yes
 Checking if "/boot/grub/stage2" exists... yes
 Checking if "/boot/grub/e2fs_stage1_5" exists... yes
 Running "embed /boot/grub/e2fs_stage1_5 (hd0)"...  27 sectors are embedded.
succeeded
 Running "install /boot/grub/stage1 (hd0) (hd0)1+27 p (hd0,0)/boot/grub/stage2 /boot/grub/grub.conf"... succeeded
Done.
grub> quit
quit
  • xfs
[root@ip-172-30-0-149 /]# grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-327.36.3.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-327.36.3.el7.x86_64.img
Found linux image: /boot/vmlinuz-3.10.0-327.10.1.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-327.10.1.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-f32e0af35637b5dfcbedcb0a1de8dca1
Found initrd image: /boot/initramfs-0-rescue-f32e0af35637b5dfcbedcb0a1de8dca1.img
done
[root@ip-172-30-0-149 /]# grub2-install /dev/xvdg
Installing for i386-pc platform.
Installation finished. No error reported.

6) fstab/grub.conf 書き換え

fstab 、grub.conf に UUID 指定がある場合は、書き換えを行います。 (CentOS6 には grub-mkconfig が無いようなので grub.conf は直接書き換えています。)

[root@ip-172-30-0-241 /]# blkid
/dev/xvda1: UUID="cdbab22a-45d6-4cce-95a3-681f42187a46" TYPE="ext4"
/dev/xvdg1: UUID="67a96f57-8e2a-4d6f-b47d-2128b558cc58" TYPE="ext4"
[root@ip-172-30-0-241 /]# cp -ip /etc/fstab /etc/fstab.org
[root@ip-172-30-0-241 /]# vi /etc/fstab
[root@ip-172-30-0-241 /]# diff /etc/fstab.org /etc/fstab
9c9
< UUID=cdbab22a-45d6-4cce-95a3-681f42187a46 /                       xfs     defaults        0 0
---
> UUID=67a96f57-8e2a-4d6f-b47d-2128b558cc58 /                       xfs     defaults        0 0
[root@ip-172-30-0-241 /]# cp -ip /boot/grub/grub.conf /boot/grub/grub.conf.org
[root@ip-172-30-0-241 /]# vi /boot/grub/grub.conf
[root@ip-172-30-0-241 /]# diff /boot/grub/grub.conf.org /boot/grub/grub.conf
17c17
<    kernel /boot/vmlinuz-2.6.32-573.18.1.el6.x86_64 ro root=UUID=cdbab22a-45d6-4cce-95a3-681f42187a46 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD console=ttyS0,115200 crashkernel=auto SYSFONT=latarcyrheb-sun16  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM
---
>    kernel /boot/vmlinuz-2.6.32-573.18.1.el6.x86_64 ro root=UUID=67a96f57-8e2a-4d6f-b47d-2128b558cc58 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD console=ttyS0,115200 crashkernel=auto SYSFONT=latarcyrheb-sun16  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM
  • xfs

UUID指定部分を書き換えます。 CentOS7 では grub2 が導入済みのようなので /etc/grub/ ではなく、 /etc/grub2/ が使用されます。

[root@ip-172-30-0-149 /]# blkid | grep xvdg
/dev/xvdg1: UUID="5a413a36-b3cd-4902-b18f-3887282d32b7" TYPE="xfs"
[root@ip-172-30-0-149 /]# cp -ip /etc/fstab /etc/fstab.org
[root@ip-172-30-0-149 /]# vi /etc/fstab
[root@ip-172-30-0-149 /]# diff /etc/fstab.org /etc/fstab
9c9
< UUID=ef6ba050-6cdc-416a-9380-c14304d0d206 /                       xfs     defaults        0 0
---
> UUID=5a413a36-b3cd-4902-b18f-3887282d32b7 /                       xfs     defaults        0 0

7) アンマウント

# chrootを終了
[root@ip-172-30-0-241 /]# exit
exit
# アンマウント
[root@ip-172-30-0-241 old]# cd /
[root@ip-172-30-0-241 /]# umount /mnt/old/
[root@ip-172-30-0-241 /]# umount /mnt/new/proc /mnt/new/sys /mnt/new/dev
[root@ip-172-30-0-241 /]# umount /mnt/new/
[root@ip-172-30-0-241 /]# mount -l | grep "old\|new"

ディスク内容の移行が完了したら、 作業用インスタンスから Volume をデタッチして後続作業を行います。

Nagios 通知有効/無効を curl で切替

f:id:htnosm:20161107012121p:plain

Nagios で通知(Notifications)の有効/無効切替を curl で実行します。

_NAGIOS="nagios.example.com"
_NAGIOS_USER="nagiosadmin"
_NAGIOS_PASS="nagiosadmin"
_HOST="localhost"

## 無効化
# Disable notifications for this host
curl -s -S http://${_NAGIOS}/nagios/cgi-bin/cmd.cgi -u ${_NAGIOS_USER}:${_NAGIOS_PASS} -d "cmd_mod=2&cmd_typ=25&host=${_HOST}" \
| grep 'Message'

# Disable notifications for all services on this host
curl -s -S http://${_NAGIOS}/nagios/cgi-bin/cmd.cgi -u ${_NAGIOS_USER}:${_NAGIOS_PASS} -d "cmd_mod=2&cmd_typ=29&host=${_HOST}" \
| grep 'Message'

## 有効化
# Enable notifications for this host
#curl -s -S http://${_NAGIOS}/nagios/cgi-bin/cmd.cgi -u ${_NAGIOS_USER}:${_NAGIOS_PASS} -d "cmd_mod=2&cmd_typ=24&host=${_HOST}" | grep 'Message'

# Enable notifications for all services on this host
#curl -s -S http://${_NAGIOS}/nagios/cgi-bin/cmd.cgi -u ${_NAGIOS_USER}:${_NAGIOS_PASS} -d "cmd_mod=2&cmd_typ=28&host=${_HOST}" | grep 'Message'

経緯

WebUI での設定は対象台数が増加すると少々厳しくなります。 また、コマンドファイルへコマンドを渡すことでも実行可能ですが、nagiosサーバへのログインを行わずに外部から切替を行いたいと思いました。
NagiosAPI は無いようですが、WebUI から実行できるのだから、curl でも実行できるだろうという所です。
実行内容は WebUI で Enable|Disable notifications 〜 のリンクをクリックした場合と同等です。

f:id:htnosm:20161107012122p:plain

環境

WebUI で同様の操作が実行できることが前提条件です。
外部コマンド で実現しており、その有効か設定が必要です。Version 4.0.8 ではインストール時点で有効化されていました。

設定値としては check_external_commands を有効にします。 command_check_interval は明記しない場合、デフォルト 60 秒です。

check_external_commands=1
command_file=/var/spool/nagios/cmd/nagios.cmd

パラメータ

cmd_mod

"2" を指定で WebUI 上の Commit をクリックした状態になります。 言い換えると指定しないと実行されません。

cmd_typ

コマンドです。 外部コマンドIDにそれぞれ番号が割り振りされており、その番号をしていします。 WebUI 上のそれぞれのコマンドのリンクから確認できます。
通知有効無効に関わる cmd_typ は以下になります。

cmd_typ Command ID Link Name
24 ENABLE_HOST_NOTIFICATIONS Enable notifications for this host
25 DISABLE_HOST_NOTIFICATIONS Disable notifications for this host
28 ENABLE_HOST_SVC_NOTIFICATIONS Enable notifications for all services on this host
29 DISABLE_HOST_SVC_NOTIFICATIONS Disable notifications for all services on this host

host

Nagios 上で定義済みの一意な host_name です。

返却値

WebUI での実行同様の HTML が返却されます。

f:id:htnosm:20161107012123p:plain

成功すると infoMessage として以下が返されます。

Your command request was successfully submitted to Nagios for processing.

失敗した場合 errorMessage として返されます。

例) 認証失敗
Sorry, but you are not authorized to commit the specified command.
例) nagios プロセス未起動
Error: Could not stat() command file


通常はダウンタイム設定で行いたい所ですが、メンテナンス作業等で再開時間が定まらない場合などで有用と思います。

Mackerel事始め AWSインテグレーション タグ絞り込み小ネタ

AWSインテグレーションのタグ絞り込み設定の小ネタです。
適切なタグを付与して使用していれば、いずれも引っ掛かる事は無いと思います。

: を含むタグ

CloudFormation でインスタンスを起動した場合や、 Auto Scaling Group 配下のインスタンスに自動的に付与されるタグに : が含まれています。

f:id:htnosm:20161105045853p:plain

そのタグを絞り込みに使用したい場合はダブルクォーテーションで囲みます。

f:id:htnosm:20161105045854p:plain

250文字数制限

タグ、除外タグともに250文字が上限です。 超過すると too long と怒られます。 上記の自動付与される長いタグ名などを使用しているとあっさり超えます。

f:id:htnosm:20161105045855p:plain

Mackerel事始め mkr(4) dashboards

f:id:htnosm:20161012181150p:plain

mkr v0.11.1 で dashboardsサブコマンドが追加されています。

公式に詳細説明があります。

が、どういう風に見えるのかは載っていないので、説明にある内容でのダッシュボード表示を試してみます。

dashboards

mkr v0.11.1 以上で dashboards コマンドを使用できます。

$ mkr help | grep -A 1 -e VERSION -e dashboards
VERSION:
   0.11.3
--
     dashboards
     help, h     Shows a list of commands or help for one command

dashboards help

機能は今の所 generate のみです。
-p 付与で標準出力へ、オプション無しだと Mackerel への反映となります。 同一名称(url_path)のダッシュボードが既に存在する場合でも、上書きされます。

$ mkr dashboards generate -h
NAME:
    generate - Generate custom dashboard

USAGE:
    mkr generate

DESCRIPTION:
    A custom dashboard is registered from a yaml file.
    Requests "POST /api/v0/dashboards". See https://mackerel.io/ja/api-docs/entry/dashboards#create.


OPTIONS:
    --print, -p  markdown is output in standard output.

ホストグラフ指定

ホストとメトリックを指定するホストグラフの一覧

ホストグラフの例を表示します。 複数ホスト・メトリックを縦横に並べたダッシュボードの生成になります。 f:id:htnosm:20161012175529p:plain

個別グラフ指定

サービスメトリックや式によるグラフなどを個別に指定するグラフの一覧
- service_name のみの指定でサービスグラフ
- service_name, role_name の指定でロールグラフ
- host_id の指定でホストグラフ
- query の指定で式によるグラフ

ここで言うサービスグラフは サービスメトリック であり、サービス名指定でロールを跨いでの表示ができるわけでは無いようです。
個別グラフの例を表示します。手頃なメトリックがなかったので指定しているメトリックは変えています。 f:id:htnosm:20161012175530p:plain


yamlを定義しておくことで履歴管理、ある程度の使い回しができるようになります。 WebのUIでURLコピー&ペーストで作成するよりは作成しやすいかなと思いました。

Mackerel事始め AWSインテグレーション(EC2)

Mackerel の AWS インテグレーションに EC2 が追加されました。

とある環境で mackerel-agent のバージョンアップの機会があったので導入してみました。
AWSインテグレーションの導入は公式の手順で特に躓くこと無く導入できました。

導入時の注意点

適用する際の注意点としてはこの辺りかと思います。

  • mackerel-agent 未導入でも EC2 の監視が可能
  • mackerel-agent 0.34.0 以上 導入済みの場合、ホスト情報は統合される(重複カウントされない)
    • mackerel-agent 0.34.0 未満 は統合されない(重複カウントされる)
  • Free プランでは利用不可

取得内容の確認

当方環境では下記項目のグラフが表示されました。 ()内はメトリック名です。

  • CPU (custom.ec2.cpu)
  • CPU Credit Balance/Usage (custom.ec2.cpu_credit.*)
  • Disk IO Read/Write (custom.ec2.disk_io.*)
  • Disk OPS Read/Write (custom.ec2.disk_ops.*)
  • Network Packets (custom.ec2.network_packets.*)
  • Network Traffic (custom.ec2.network.*)
  • Status Check Failed (custom.ec2.status_check_failed.*)

取得間隔は 5分と記載がありますが、 EC2側で Detailed Monitoring が有効となっている場合は 1分のグラフ表示となっていました。

mackerel-agent 無し

  • mackerel-agent 未導入、もしくはバージョンが 0.34.0 未満の場合
    • mackerel-agent 導入済みホストとは別のホストとして登録される

f:id:htnosm:20160831064933p:plain

mackerel-agent 有り

  • mackerel-agent バージョン 0.34.0 以上が導入済みの場合
    • 同一ホストとして登録される

f:id:htnosm:20160831064956p:plain

重複登録後に統合を行いたい場合

重複登録された後に mackerel-agent のアップデートを行いましたが、 EC2上で mackerel-agent をアップデート だけでは反映されませんでした。
アップデート時に mackerel-agent の再起動が掛かっており、 コマンドで確認しても正常に更新されている状態です。

  • EC2 上の mackerel-agent Version
    • 最新版(0.34.0) へ更新済み
$ /usr/bin/mackerel-agent version
mackerel-agent version 0.34.0 (rev 694915a) [linux 386 go1.6.2]
  • Mackerel 上のホスト情報
    • 未更新(0.32.2) のまま

f:id:htnosm:20160902210154p:plain

解消方法

ホストIDファイルを削除し新規登録することで、 ホスト情報のMackerelエージェントのバージョンが最新版になり、 AWSインテグレーションでの取得情報との統合が成されました。

# ホストID削除
$ sudo rm /var/lib/mackerel-agent/id
# mackerel-agent 再起動
$ sudo /etc/init.d/mackerel-agent restart

尚、ホストの新規登録のため、既存情報への影響があります。

  • 既存のメトリックスは引き継がれない
  • 既存のホストは Poweroff となる
    • 退役忘れに注意

これまで別の方法で監視していた Status Check Failed が取得できるようになったのは嬉しいです。
mackerel-agent の更新で新規ホスト登録となる点は改善して欲しいと思います。

AWS EC2 インスタンスの復旧(Auto Recovery)設定の落とし穴

AWS EC2 インスタンスには、 Status Checked Failed 発生時に自動的に復旧を試みる機能があります。
設定自体は正しく行えているように見えるのに、いざ異常発生時に復旧に失敗するケースに当たりました。

Action failed. Encountered error calling EC2 recover. (401: AWS was not able to validate the provided access credentials)

復旧に失敗した RecoveryAlarm は IAM Role を使用して CloudFormation で作成していましたが、作成(設定)自体は正常に行えていました。
結論としてはドキュメントに記載があるのですが、IAM Role で復旧アラームを作成している場合、復旧アクションは動作しません。

IAM ロール (たとえば、Amazon EC2 インスタンスプロファイル) を使用している場合は、アラームアクションを使用してインスタンスを停止、終了、または再起動することはできません。

尚、復旧(recover)アクションと同様に、 停止(stop)、終了(terminate)、再起動(reboot) を実行するアラームを作成できますが、 復旧(recover)とその他のアクションでは使用される実行権限が異なります。 (アラーム作成時の権限が使用されるのは 復旧(revocer) の場合のみ)

IAM ロールに基づいて、アラームアクションを使用してインスタンスを停止、終了、または再起動する場合は、EC2ActionsAccess ロールしか使用できません。他の IAM ロールはサポートされていません。別の IAM ロールを使用している場合は、インスタンスを停止、終了、または再起動できません。

AWS Security Token Service (AWS STS) を用いて許可された一時的な認証情報を使用している場合は、アラームアクションを用いて Amazon EC2 インスタンスを復旧することはできません。

ドキュメントの内容だけではわかり難かったので、実際に復旧アクションの挙動を確認してみました。

IAM 準備

IAM Role と IAM User での比較を行います。

IAM Role / IAM User

IAM Role と IAM User を準備します。今回はいずれも PowerUserAccess を付与しています。

  • IAM Role

f:id:htnosm:20160816230225p:plain

  • IAM User

f:id:htnosm:20160816230226p:plain

aws configure

デフォルトで IAM Role を使用し、profile=cfn で IAM User を使用できるよう設定します。

$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************EFEA         iam-role
secret_key     ****************dE0o         iam-role
    region           ap-northeast-1      config-file    ~/.aws/config
$ cat ~/.aws/credentials
[default]
region = ap-northeast-1

[cfn]
aws_access_key_id = ****************VO2A
aws_secret_access_key = ************************************QPgI
region = ap-northeast-1

Cloud Formation テンプレート準備

EC2 + RecoveryAlarm のテンプレートを用意します。

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Outputs": {
    "InstanceID" : {
      "Value" : { "Ref" : "Ec2Instance" }
    },
    "RecoveryAlarm" : {
      "Value" : { "Ref" : "RecoveryAlarm" }
    }
  },
  "Resources": {
    "Ec2Instance" : {
      "Type" : "AWS::EC2::Instance",
      "Properties" : {
        "ImageId" : "ami-374db956",
        "InstanceType" : "t2.micro",
        "BlockDeviceMappings" : [
          {
            "DeviceName": "/dev/xvda",
            "Ebs": {
              "VolumeType": "gp2",
              "VolumeSize": "8"
            }
          }
        ]
      }
    },
    "RecoveryAlarm": {
      "Type": "AWS::CloudWatch::Alarm",
      "Properties": {
        "Namespace": "AWS/EC2" ,
        "MetricName": "StatusCheckFailed",
        "Statistic": "Minimum",
        "Period": "60",
        "EvaluationPeriods": "5",
        "ComparisonOperator": "GreaterThanThreshold",
        "Threshold": "0",
        "AlarmActions": [ {"Fn::Join" : ["", ["arn:aws:automate:", { "Ref" : "AWS::Region" }, ":ec2:recover" ]]} ],
        "Dimensions": [{"Name": "InstanceId","Value": {"Ref": "Ec2Instance"}}]
      }
    }
  }
}

RecoveryAlarm の作成

IAM Role と IAM User それぞれで CreateStack を実行します。

# IAM Role
aws cloudformation create-stack \
  --stack-name ec2-recoveryalarm-role \
  --template-body file://ec2.json
# IAM User
aws cloudformation create-stack \
  --stack-name ec2-recoveryalarm-user \
  --template-body file://ec2.json \
  --profile cfn
  • IAM Role で作成したStack

f:id:htnosm:20160816230228p:plain

  • IAM User で作成したStack

f:id:htnosm:20160816230227p:plain

f:id:htnosm:20160816230229p:plain

  • 作成したRecoveryAlarm

f:id:htnosm:20160816230230p:plain

RecoveryAlarm の実行確認

作成した RecoveryAlarm の状態を ALARM に更新し、挙動を確認します。 (システムステータスチェックのエラーを意図的に起こすことはできません。)

IAM Role で作成した RecoveryAlarm

# IAM Role で作成したRecoveryAlarm
$ aws cloudwatch set-alarm-state \
  --alarm-name "ec2-recoveryalarm-role-RecoveryAlarm-1SXN4O9QLTKH" \
  --state-value ALARM \
  --state-reason "Manual Update to ALARM"

401 エラーが発生し、Action が失敗します。

f:id:htnosm:20160816230231p:plain

IAM User で作成した RecoveryAlarm

# IAM User で作成したRecoveryAlarm
$ aws cloudwatch set-alarm-state \
  --alarm-name "ec2-recoveryalarm-user-RecoveryAlarm-1HG4YDX2YZ90H" \
  --state-value ALARM \
  --state-reason "Manual Update to ALARM"

IAM User で作成した場合は問題無く、 Action が正常に終了します。

f:id:htnosm:20160816230232p:plain

RecoveryAlarm を再作成

IAM Role で作成し、401エラーとなった RecoveryAlarm を IAM User からの実行で作成し直します。

$ diff ec2.json ec2_update.json
30a31
>         "AlarmName": "ec2-recoveryalarm-role-RecoveryAlarm-renew",
$ aws cloudformation update-stack --stack-name ec2-recoveryalarm-role --template-body file://ec2_update.json --profile cfn
  • RecoveryAlarm の再作成(Delete/Update)

f:id:htnosm:20160816230233p:plain

IAM User で "再作成" した RecoveryAlarm

作成し直した RecoveryAlarm の実行確認をします。

$ aws cloudwatch set-alarm-state \
  --alarm-name "ec2-recoveryalarm-role-RecoveryAlarm-renew" \
  --state-value ALARM \
  --state-reason "Manual Update to ALARM"

IAM User で再作成した場合も、Action が正常に終了しました。

f:id:htnosm:20160816230234p:plain



マネジメントコンソール上と、 describe-alarms で RecoveryAlarm を確認してみましたが、どの権限(IAM)で作成されたかの情報は保持していませんでした。
RecoveryAlarm を作成した際は実行確認を行い、権限エラーが発生しない事を確認しておいた方が良さそうです。