AWSにFreeBSDなインスタンスを作る

AWS EC2 に FreeBSD のインスタンスを作るメモ。 毎回 google で検索してページを再発見したりしてるので、自分用にメモ。 だいたい 2015 年 7 月初旬の状況。

AMI探し

EC2 でインスタンスを作るときにインストールメディアとして使うのが AMI で、 奇特な方が FreeBSD の各バージョンのものを公開してくれている。多謝。 その一覧ページがここ→ FreeBSD_on_EC2_status

例えば Oregon に FreeBSD 10.1-RELEASE amd64 を作るなら、表から ami-bbfcb78b を読み取って、これを EC2_Management_Console からインスタ ンスを作成するときに使えば良い。

AMI を選択しているところ

あとは普通にインスタンスを作成すれば良い。ここでは t2.micro を選択しているが、 もっと大きなインスタンスも選べる。

初期アクセス

インスタンス作成直後の ssh アクセスは

1
ssh -v -p 22 -l ec2-user -i .ssh/EC2.pem 52.26.x.x

でできる。もちろん、AWS EC2 側のファイアウォールで許可しておく必要がある。 ec2-user も root もパスワードが付いてないので、すかさず強いパスワードを 付けておく。

初期状態

最初にログインすると、

1
2
$ uname -a
FreeBSD ip-172-31-x-x 10.1-RELEASE-p10 FreeBSD 10.1-RELEASE-p10 #0: Wed May 13 06:54:13 UTC 2015     root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC  amd64

すでに 公式パッチ が当たっていたり して大変ありがたい。

uname が主張するように GENERIC kernel が入っているようで、これは /usr/src/sys/amd64/conf/GENERIC を他のシステムと比べて見ても本当に普通の GENERIC kernel であるようだ。 これなら、freebsd-update で更新できるので楽ができるけど、EC2 ってたしか xen じゃなかったっけ。最近は xen でも HVM のほうが良いってやつか。

ちょっと長いけれど、dmesg を付けておく。POPCNT が見えているので bhyve も動くんじゃないかな。 AESNI があるから運が良ければ openssl から使えるかもしれない。 (参考: AES-NIという加速装置のお話 とか) xn0 や xbd0 が見えているのは、やっぱり xen な環境ですな。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
$ dmesg
Copyright (c) 1992-2014 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
The Regents of the University of California. All rights reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 10.1-RELEASE-p10 #0: Wed May 13 06:54:13 UTC 2015
    root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC amd64
FreeBSD clang version 3.4.1 (tags/RELEASE_34/dot1-final 208032) 20140512
XEN: Hypervisor version 4.2 detected.
CPU: Intel(R) Xeon(R) CPU E5-2676 v3 @ 2.40GHz (2400.05-MHz K8-class CPU)
  Origin = "GenuineIntel"  Id = 0x306f2  Family = 0x6  Model = 0x3f  Stepping = 2
  Features=0x1783fbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,MMX,FXSR,SSE,SSE2,HTT>
  Features2=0xfffa3203<SSE3,PCLMULQDQ,SSSE3,FMA,CX16,PCID,SSE4.1,SSE4.2,x2APIC,MOVBE,POPCNT,TSCDLT,AESNI,XSAVE,OSXSAVE,AVX,F16C,RDRAND,HV>
  AMD Features=0x20100800<SYSCALL,NX,LM>
  AMD Features2=0x21<LAHF,ABM>
  Structured Extended Features=0x728<BMI1,AVX2,BMI2,ERMS,INVPCID>
real memory  = 1073741824 (1024 MB)
avail memory = 1010733056 (963 MB)
Event timer "LAPIC" quality 400
ACPI APIC Table: <Xen HVM>
ioapic0: Changing APIC ID to 1
MADT: Forcing active-low polarity and level trigger for SCI
ioapic0 <Version 1.1> irqs 0-47 on motherboard
kbd1 at kbdmux0
random: <Software, Yarrow> initialized
xen_et0: <Xen PV Clock> on motherboard
Event timer "XENTIMER" frequency 1000000000 Hz quality 950
Timecounter "XENTIMER" frequency 1000000000 Hz quality 950
acpi0: <Xen> on motherboard
acpi0: Power Button (fixed)
acpi0: Sleep Button (fixed)
acpi0: reservation of 0, a0000 (3) failed
cpu0: <ACPI CPU> on acpi0
hpet0: <High Precision Event Timer> iomem 0xfed00000-0xfed003ff on acpi0
Timecounter "HPET" frequency 62500000 Hz quality 950
attimer0: <AT timer> port 0x40-0x43 irq 0 on acpi0
Timecounter "i8254" frequency 1193182 Hz quality 0
Event timer "i8254" frequency 1193182 Hz quality 100
atrtc0: <AT realtime clock> port 0x70-0x71 irq 8 on acpi0
Event timer "RTC" frequency 32768 Hz quality 0
Timecounter "ACPI-fast" frequency 3579545 Hz quality 900
acpi_timer0: <32-bit timer at 3.579545MHz> port 0xb008-0xb00b on acpi0
pcib0: <ACPI Host-PCI bridge> port 0xcf8-0xcff on acpi0
pci0: <ACPI PCI bus> on pcib0
isab0: <PCI-ISA bridge> at device 1.0 on pci0
isa0: <ISA bus> on isab0
atapci0: <Intel PIIX3 WDMA2 controller> port 0x1f0-0x1f7,0x3f6,0x170-0x177,0x376,0xc100-0xc10f at device 1.1 on pci0
ata0: <ATA channel> at channel 0 on atapci0
ata1: <ATA channel> at channel 1 on atapci0
pci0: <bridge> at device 1.3 (no driver attached)
vgapci0: <VGA-compatible display> mem 0xf0000000-0xf1ffffff,0xf3000000-0xf3000fff at device 2.0 on pci0
vgapci0: Boot video device
xenpci0: <Xen Platform Device> port 0xc000-0xc0ff mem 0xf2000000-0xf2ffffff irq 28 at device 3.0 on pci0
xenstore0: <XenStore> on xenpci0
atkbdc0: <Keyboard controller (i8042)> port 0x60,0x64 irq 1 on acpi0
atkbd0: <AT Keyboard> irq 1 on atkbdc0
kbd0 at atkbd0
atkbd0: [GIANT-LOCKED]
psm0: <PS/2 Mouse> irq 12 on atkbdc0
psm0: [GIANT-LOCKED]
psm0: model IntelliMouse Explorer, device ID 4
fdc0: <floppy drive controller> port 0x3f0-0x3f5,0x3f7 irq 6 drq 2 on acpi0
fdc0: does not respond
device_attach: fdc0 attach returned 6
uart0: <16550 or compatible> port 0x3f8-0x3ff irq 4 flags 0x10 on acpi0
uart0: console (9600,n,8,1)
sc0: <System console> at flags 0x100 on isa0
sc0: VGA <16 virtual consoles, flags=0x100>
vga0: <Generic ISA VGA> at port 0x3c0-0x3df iomem 0xa0000-0xbffff on isa0
fdc0: No FDOUT register!
ppc0: cannot reserve I/O port range
Timecounters tick every 10.000 msec
xctrl0: <Xen Control Device> on xenstore0
xenbusb_front0: <Xen Frontend Devices> on xenstore0
xn0: <Virtual Network Interface> at device/vif/0 on xenbusb_front0
xn0: Ethernet address: 06:89:9b:88:70:69
xenbusb_back0: <Xen Backend Devices> on xenstore0
xn0: backend features: feature-sg feature-gso-tcp4
xbd0: 10240MB <Virtual Block Device> at device/vbd/768 on xenbusb_front0
xbd0: attaching as ada0
random: unblocking device.
Timecounter "TSC-low" frequency 1200023715 Hz quality 800
Trying to mount root from ufs:/dev/ada0a [rw]...
$

/dev/ の下はこんな感じ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$ ls /dev
acpi       cuau0.init mdctl    ttyu0      ttyvb
ada0       cuau0.lock mem      ttyu0.init ttyvc
ada0a      devctl     midistat ttyu0.lock ttyvd
apm        devstat    nfslock  ttyv0      ttyve
apmctl     fd         null     ttyv1      ttyvf
atkbd0     fido       pci      ttyv2      ufssuspend
audit      geom.ctl   psm0     ttyv3      urandom
bpf        io         pts      ttyv4      usbctl
bpf0       kbd0       random   ttyv5      xen
bpsm0      kbd1       sndstat  ttyv6      xpt0
console    kbdmux0    stderr   ttyv7      zero
consolectl klog       stdin    ttyv8
ctty       kmem       stdout   ttyv9
cuau0      log        sysmouse ttyva

ディスクの mount 状況はこれ。dmesg にあるように xbd0 が ada0 として 認識されているので、ada0a が / (root) になってる。

1
2
3
$ mount
/dev/ada0a on / (ufs, local, soft-updates)
devfs on /dev (devfs, local, multilabel)
1
2
3
4
$ df -m
Filesystem 1M-blocks Used Avail Capacity  Mounted on
/dev/ada0a      9905 2158  6955    24%    /
devfs              0    0     0   100%    /dev

ネットワークインタフェイス。xn0 に private address が割り当てられている。 ということは、インスタンスとインターネットの間に Amazon の firewall/NAT 機能が入ってるってことね。 RXCSUM/TXCSUM/TSO4/LRO などの off load 機構が有効になってるけど、xen 世界では これは無効にしておくほうが良いんじゃなかったっけ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
  options=600003<RXCSUM,TXCSUM,RXCSUM_IPV6,TXCSUM_IPV6>
  inet6 ::1 prefixlen 128
  inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
  inet 127.0.0.1 netmask 0xff000000
  nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
xn0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
  options=503<RXCSUM,TXCSUM,TSO4,LRO>
  ether 06:89:9b:x:x:x
  inet 172.31.x.x netmask 0xfffff000 broadcast 172.31.x.255
  nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
  media: Ethernet manual
  status: active

初期設定

主要な設定ファイルを見ておく。

/boot.config は存在しないので、まずは /boot/loader.conf。FreeBSD の console をシリアルポートへ向けているが、これによって AWS EC2 のインスタンスコンソール 出力に表示ができるってことかな。 (参考: インスタンスコンソール出力 ) どうも EC2 では FreeBSD のコンソールへの入力はできないみたいなのだが、 kernel patch 当てる時なんかの安心感がぐっと下がる(コンソールを取れれば 最悪でも loader や single user mode が使えるのに ;_;)。なんとかならんもんか。 ところで、カーネルモジュールをロードしているわけではないこともわかる。 本当に GENERIC kernel に xen 関係を入れちゃったんだなぁ、と。

1
2
3
4
5
6
7
8
$ cat /boot/loader.conf
# Make booting fast
autoboot_delay="-1"
beastie_disable="YES"

# Make the EC2 console work
console="comconsole"
hw.broken_txfifo=1

実際、kldstat で見ても kernel 一発の清々しい状態である。そして、xen 関係の デバイスがすでに入っている。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$ kldstat
Id Refs Address            Size     Name
 1    1 0xffffffff80200000 1756638  kernel

$ kldstat -v | grep xen
            411 xenpci/xenstore
            410 xenstore/xenbusb_back
            409 xenstore/xenbusb_front
            336 nexus/xentimer
            335 pci/xenpci
            334 xenbusb_front/xe
            333 xenbusb_back/xnb
            332 xenstore/xctrl
            331 xenbusb_back/xbbd
            330 xenbusb_front/xbd

次は /etc/sysctl.conf。ここでも特に変わったことはしていないが、panic 時に backtrace はするけれども debugger へは落とさない設定になっている(らしい)。 曰く、EC2 のコンソールが一方通行なので云々。僕と同じ発想 :-)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ cat /etc/sysctl.conf
# $FreeBSD: head/etc/sysctl.conf 112200 2003-03-13 18:43:50Z mux $
#
#  This file is read when going to multi-user and its contents piped thru
#  ``sysctl'' to adjust kernel values.  ``man 5 sysctl.conf'' for details.
#

# Uncomment this to prevent users from seeing information about processes that
# are being run under another UID.
#security.bsd.see_other_uids=0

# The EC2 console is one-way; backtraces are useful, the debugger isn't.
debug.trace_on_panic=1
debug.debugger_on_panic=0

# There's no point lingering after a panic, since we have no console input.
kern.panic_reboot_wait_time=0

続いて /etc/rc.conf。これはちょっといろいろやっている。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
$ cat /etc/rc.conf
### EC2-specific configuration
# On first instance boot, download and process user-data.
ec2_configinit_enable="YES"

# On first instance boot, fetch the EC2 SSH keypair so that the user
# can log in.  Note that if ec2_fetchkey_user is root, sshd_config
# must contain a PermitRootLogin option in order for this to be useful.
ec2_fetchkey_enable="YES"

# On first instance boot, send the AMI author an email.  This (together
# with panicmail) allows him to get some idea of how stable the platform
# is; and it also gives him a Warm Fuzzy Feeling when he sees that his
# work is being used.
ec2_bootmail_enable="YES"
ec2_bootmail_addr="cperciva-ec2launch@daemonology.net"

# Use part of any attached EC2 ephemeral disks for swap.
ec2_ephemeralswap_enable="YES"

# Log the SSH host keys to the EC2 console.
ec2_loghostkey_enable="YES"

# EC2 uses DHCP; the network interface appears as xn0.
ifconfig_xn0="DHCP"

### Configuration for some pre-installed packages
# Fetch security updates the first time the image boots.
firstboot_freebsd_update_enable="YES"

# Install packages the first time the image boots.  Install the awscli port by
# default, since it's a very useful tool to have when doing anything with AWS.
firstboot_pkgs_enable="YES"
firstboot_pkgs_list="awscli"

# Automatically submit panic reports.  Depending on your level of paranoia,
# you may wish to unset panicmail_autosubmit; in that case panic reports will
# be emailed to root with instructions to forward them (but make sure that you
# read or forward root's email).
dumpdev="AUTO"
panicmail_enable="YES"
panicmail_autosubmit="YES"

# The freebsd.org mail servers don't accept email directly from EC2, so send
# panic reports in via this address (which simply forwards them).
panicmail_sendto="FreeBSD Panic Reporting <cperciva-panicmail@daemonology.net>"

### Standard FreeBSD configuration from here onwards.
sshd_enable="YES"

まず、ec2_configinit_enable だが、/usr/local/etc/rc.d/ec2_config_init が呼ばれることになるわけだが、EC2 独自の仕様で「ユーザデータ」を EC2 側から渡せるようだ。ここ のユーザデータの 項に説明がある模様。

rc スクリプト中には、「最初の boot 時のみ動作する」云々とあるが、それ らしい制御は入っていないので、毎回 boot 時に動いちゃうんじゃないかなあ。 ひょっとして、KEYWORD: firstboot があるから初回 boot 時のみ動くことに なるのかな。もしそうなら、これは FreeBSD 側の機能ってわけやね。

動作としては、http://169.254.169.254/latest/user-data から「ユーザデー タ」をダウンロードして、/usr/local/sbin/configinit で処理をすることに なっている。他にも出てくるけど、この URL は EC2 インスタンスからでない とアクセスできないようだ。

configinit では、

  • ユーザデータの先頭2文字が #! ならば、実行ファイルとみなして実行する。
  • 同じく >/ ならば、ファイルのパスを指定しているとみなして、そのファイ ルを作成し、2行目以降をそのファイルに書き込む。
  • 先頭3文字が >>/ ならば、上書きせずに後ろに追加する。
  • いずれでもなければ tar アーカイブだと期待して tar xf して、出てきた ファイルを順次 /bin/sh で実行する

という動きをしている。

続いて ec2_fetchkey_enable だが、/usr/local/etc/rc.d/ec2_fetchkey が呼 ばれて、上と似た感じで EC2 側から ssh 公開鍵をもらってくるらしい。 同じく「初回 boot 時に」とあるが KEYWORD: firstboot はあるが、それっぽ い制御は入っていない。

/etc/rc.conf (僕の好みでは rc.conf.local だが) に ec2_fetchkey_user=hoge と書いておけば、デフォルトのユーザ名 ec2-user の代わりに hoge を使える。 初回 boot 時にどうやってそんなエントリを書いておくのかっていうと、多分、 すぐ上の ec2_configinit_enable で /etc/rc.conf に追記させるんだろう。

指定されたユーザ名が存在しない場合は、この rc スクリプトの中でアカウン トを作成しているので、カスタマイズした場合でも大丈夫な模様。

次。ec2_bootmail_enable と ec2_bootmail_addr だけど、これは初回 boot 時に ec2_bootmail_addr に書かれたアドレス (AMI 作者の cperciva さん) 宛にメールを送っている。

メールの内容は http://169.254.169.254/latest/meta-data/instance-type から取ってきたインスタンスタイプだけ。t2.micro とかそういうやつね。 ただ、こういうメールを飛ばすよってことを FreeBSD_on_EC2_status に書い てないみたいなのよね。気にする人は気にすると思うんだけどな。 まあ、rc.conf 読めばコメントしてあるし、そこを読みに行かないような人は 気にしないだろうし、オイラ的にはおっけーというかフィードバックするから 引き続き AMI のメンテ頼んます、って感じなんですが。

ちょっと順序が前後するが、後ろに出てくる panicmail_enable, panicmail_autosubmit, panicmail_sendto も同様で、FreeBSD がパニックし た時にメールを送出する。 panicmail_sendto は、パニック時に送出するメールの宛先でデフォルトでは さっきの cperciva さん。

panicmail_autosubmit=YES なので、直接にメールを送る。NO の場合には、パ ニック時のメールを root に送るので、レビューしてから報告するなりなんな りせよという動きになる。

また、panicmail_key はデフォルトで cperciva さんの公開鍵を収めてあるそ うで、パニック時のメールの内容は暗号化されて送られるようだ。

じゃあ、そのメールの中身は何になるのか。 rc スクリプトを見ると、${dumpdir} (/etc/defaults/rc.conf で /var/crash と定義されている) の下の info.* とか vmcore などのファイルから情報を集 めている。

次。ec2_ephemeralswap_enable は、EC2 でいうところの Ephemeral_Disk を swap に使おうというものらしい。 このディスクは、日本語ではインスタンスストアボリュームと呼ぶようで、イ ンスタンスから見てローカルにあるディスクで、インスタンスタイプ毎にサイ ズと本数上限が決まっていて、インスタンス終了時などには揮発するが、無料 で使えるディスクということらしい。 あるタイミングで揮発しちゃうので swap か一過性の計算などの揮発しても問 題の内容と以外には使いにくいが、逆にそういう用途ならお得かもしれない。

rc スクリプト中で理想的なスワップサイズとして

  • RAM が 4GB 以下なら RAM の2倍
  • 4GB 超 8GB 以下なら 8GB
  • 8GB 超なら RAM と同じ

と言っている。 core を吐かせるために RAM サイズ以上で、最低でも 4GB といった考え方で あるようだ。

次は、やっと見慣れたエントリである。 ifconfig_xn0=”DHCP” なので、xennet な NIC でDHCP を使ってアドレスなど を設定せよという設定になっている。

次。firstboot_freebsd_update_enable であるが、これを YES にしておくこ とで初回 boot 時に freebsd-update {fetch, install} を実行してくれる。 ということは、出来上がったインスタンスは常にその時点の最新のパッチが当 たっていることになる。 素晴らしい。

次。firstboot_pkgs_enable と firstboot_pkgs_list。 前者が YES なら、後者に空白区切りで列挙された ports package を初回 boot 時にインストールしてくれる。インストールには pkg コマンドを使って バイナリパッケージを持ってくるようだ。

この AMI では後者に awscli が与えられているが、これは devel/awscli の ことで、種々の AWS 側サービスを利用するためのツール類であるようだ。 上に出てきた ec2_* もこのパッケージにふくまれているのだろう。

最後。sshd_enable で sshd を立ち上げる設定になっている。 EC2 はコンソールから入力できないので、sshd が上がっていないとログイン できなくなってしまう。 最初の設定だと 22/tcp で待ち受けるが、blute force を避ける意味で high port に変えておくほうがいいだろう。(AWS 側の ACL 設定やインスタンス上 の ipfw などのルールをよく理解してポート変更されたし。)

というわけで、FreeBSD を AWS EC2 で使うための AMI 選定から各種起動設定 を見てきた。 初回 boot 時に動く rc スクリプトというアイデアは、今回のようなことがな ければ勉強できなかっただろう。 ここまでくれば、あとは hardening と tuning だが、それはまた別の話題で ある。

参考までに、この状態での sysctl -a の出力 を付けておく。

備考

執筆時期: 2015/Jul/03, 14