作業ログ源泉垂れ流し

しがないIT技術者の作業ログを垂れ流す

Fedora CoreOSのインストール練習 4 〜ネットワーク設定〜

前回までに引き続きFedora CoreOSで、ネットワークの設定をしてみる。

今回は、2個のネットワークインタフェースを持ち、1個目がDHCPでアドレスを取ってきてホスト名をcoreosに設定し、2個目は静的にIPアドレスを設定する構成にする。

Fedora CoreOSでインストール時にネットワークを設定するには、NetworkManagerのkeyfileを手動で配置してやる必要があるので、そのようなIgnition configを作成する。
まずはButaneファイルを書く。
Network Manager keyfileの書式はGnome公式ドキュメントを参照。
なお今回はコンソールでログインするようにpassword_hashを設定した。

variant: fcos
version: 1.3.0
passwd:
  users:
    - name: core
      password_hash: (mkpasswdで出力したハッシュ)
storage:
  files:
    - path: /etc/NetworkManager/system-connections/enp1s0.nmconnection
      mode: 0600
      contents:
        inline: |
          [connection]
          id=enp1s0
          type=ethernet
          interface-name=enp1s0
          [ipv4]
          method=auto
          dhcp-hostname=coreos
    - path: /etc/NetworkManager/system-connections/enp2s0.nmconnection
      mode: 0600
      contents:
        inline: |
          [connection]
          id=enp2s0
          type=ethernet
          interface-name=enp2s0
          [ipv4]
          address1=192.168.152.2/24
          method=manual

次に、Butane configをIgnition configに変換する。

$ docker run -i --rm quay.io/coreos/butane:release < netconfig.bu > netconfig.ign

そして、ネットワークインタフェースを2個指定してVMを作成してインストールする。

$ virt-install --connect qemu:///system --name coreos --vcpus 1 --memory 2048 --os-variant fedora31 --import --graphics=none --disk path=coreos.img,size=10,backing_store=$PWD/fedora-coreos-34.20210518.3.0-qemu.x86_64.qcow2 --network network=default --network network=private --qemu-commandline="-fw_cfg name=opt/com.coreos/config,file=$PWD/netconfig.ign"

インストールが終わったら、ログインして設定を確認する。

[core@coreos ~]$ nmcli con show
NAME    UUID                                  TYPE      DEVICE 
enp1s0  360d1330-11cf-3a91-ae05-590058fc3e82  ethernet  enp1s0 
enp2s0  08862f9c-09fb-396b-ba92-ff582dfe1839  ethernet  enp2s0 
[core@coreos ~]$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:44:6a:cb brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.159/24 brd 192.168.122.255 scope global dynamic noprefixroute enp1s0
       valid_lft 3224sec preferred_lft 3224sec
    inet6 fe80::1ce2:98a4:a6fa:2965/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:40:bd:8e brd ff:ff:ff:ff:ff:ff
    inet 192.168.152.2/24 brd 192.168.152.255 scope global noprefixroute enp2s0
       valid_lft forever preferred_lft forever
    inet6 fe80::767:ae67:5c75:d25a/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

enp2s0に指定したIPアドレスが設定されており、コマンドプロンプトからホスト名がcoreosに設定されていることがわかる。

Ignitionを使ってFedora CoreOSのネットワークが設定できた!

Fedora CoreOSのインストール練習 3 〜CDからのスタンドアロンインストール〜

前回の続き。

今回は、ISOイメージをカスタマイズして、スタンドアロンインストールを試してみる。

まずは、docker上でcoreos-installerを使ってisoイメージをダウンロードする。

$ docker run --rm -v $PWD:/data -w /data quay.io/coreos/coreos-installer:release download -s stable -p metal -f iso

次に、Live CDを構成するためのButane config liveiso.buを準備する。
インストール先用のIgnition configをLive CDシステム上に配置し、 coreos-installerのドキュメントを参考に、coreos-installerを自動実行するsystemdサービスを定義する。

variant: fcos
version: 1.3.0
storage:
  files:
    - path: /var/tmp/simple.ign
      contents:
        local: simple.ign
systemd:
  units:
    - name: install.service
      enabled: true
      contents: |
        [Unit]
        Description=Run CoreOS Installer
        Requires=coreos-installer-pre.target
        After=coreos-installer-pre.target
        OnFailure=emergency.target
        OnFailureJobMode=replace-irreversibly

        [Service]
        Type=oneshot
        ExecStart=/usr/bin/coreos-installer install --ignition-file /var/tmp/simple.ign /dev/vda
        ExecStart=/usr/bin/systemctl --no-block reboot
        StandardOutput=kmsg+console
        StandardError=kmsg+console

        [Install]
        RequiredBy=default.target

そして、Ignition config liveiso.ignに変換する。

$ docker run -i -v $PWD:/data --rm quay.io/coreos/butane:release --files-dir /data < liveiso.bu > liveiso.ign

準備したliveiso.ignをLive CDのISOイメージに追加する。
ここでは、ダウンロードしたisoファイルをコピーして書き込んでいる。

$ cp fedora-coreos-34.20210518.3.0-live.x86_64.iso fedora-coreos-34.20210518.3.0-live-mod.x86_64.iso
$ docker run -i --rm -v $PWD:/data -w /data quay.io/coreos/coreos-installer:release iso ignition embed fedora-coreos-34.20210518.3.0-live-mod.x86_64.iso < liveiso.ign

今回はKVMにインストールするので、コンソールがシリアルに表示されるように、Live CDのkernel引数も変更しておく。

$ docker run --rm -v $PWD:/data -w /data quay.io/coreos/coreos-installer:release iso kargs modify fedora-coreos-34.20210518.3.0-live-mod.x86_64.iso --append "console=ttyS0,115200n8"

出来上がったISOイメージを使ってKVMにインストールする。

$ virt-install --name coreos --vcpus 1 --memory 2048 --os-variant fedora31 --cdrom fedora-coreos-34.20210518.3.0-live-mod.x86_64.iso --disk path=coreos.img,size=10 --network network=default --graphics none --console pty,target_type=serial

無事インストールが完了。

Ignitionファイルを格納したISOイメージを作って、スタンドアロンでインストールできた!

Fedora CoreOSのインストール練習 2 〜自動アップデートの設定〜

前回の続き。

現在のFedora CoreOSでは、Zincatiを使って自動アップデートするように設定されていて、そのデフォルト設定では、アップデートの準備が出来ると自動でリブートするようになっている。
そこで、特定の曜日・時間にだけリブートするように設定してみる。

公式ドキュメントを参考にして、Zincatiの設定ファイルの内容を決める。
今回は、土日の朝4時〜6時の間だけリブートするように設定してみる。

[updates]
strategy = "periodic"

[updates.periodic]
time_zone = "Asia/Tokyo"

[[updates.periodic.window]]
days = [ "Sat", "Sun" ]
start_time = "4:00"
length_minutes = 120

まず、strategyperiodic を選ぶ。 time_zone を日本に設定して、days に曜日 Sat, Sun を指定し、リブート可能区間 (window) を 4:00 から 120分に設定している。

この設定ファイルを /etc/zincati/config.d/ の下に適当なファイル名で置けば良い。

Fedora CoreOSなので、Ignitionで配置するようにする。
Butan configを前回のものに書き足して作る。

variant: fcos
version: 1.3.0
passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - (ssh公開鍵)
storage:
  files:
    - path: /etc/zincati/config.d/55-updates-strategy.toml
      contents:
        inline: |
          [updates]
          strategy = "periodic"
          [[updates.periodic.window]]
          days = [ "Sat", "Sun" ]
          start_time = "4:00"
          length_minutes = 120

前回同様にVMを作成する。

sshでログインして確認してみる。

host$ ssh core@coreos_ip_address
coreos$ cat /etc/zincati/config.d/55-updates-strategy.toml
[updates]
strategy = "periodic"
[updates.periodic]
time_zone = "Asia/Tokyo"
[[updates.periodic.window]]
days = [ "Sat", "Sun" ]
start_time = "4:00"
length_minutes = 120

Zincatiのログでも確認する。

$ sudo journalctl -b 0 -e -u zincati.service | grep strategy
Jun 09 08:53:49 localhost zincati[925]: [INFO ] update strategy: periodic, total schedule length 240 minutes; next window at 4:0 on Sat (Asia/Tokyo), subject to time zone caveats.

特定の曜日・時間にだけリブートするようにZincatiが設定できた!

Fedora CoreOSのインストール練習 1

KVM上にFedora CoreOSをインストールしてみる。

公式ドキュメントを参考に作業を進める。

最初に、公式ダウンロードページから、QEMU用のイメージファイルをダウンロードして展開する。

$ curl -O 'https://builds.coreos.fedoraproject.org/prod/streams/stable/builds/34.20210518.3.0/x86_64/fedora-coreos-34.20210518.3.0-qemu.x86_64.qcow2.xz'
$ unxz fedora-coreos-34.20210518.3.0-qemu.x86_64.qcow2.xz

次に、公式ドキュメントを参考に、Ignitionファイルを準備する。

まずはButaneのDockerイメージを取得する。

$ docker pull quay.io/coreos/butane:release

次に、YAML形式のButan configファイル simple.bu を作成する。
ここではユーザcoreを作るだけの設定にする。

variant: fcos
version: 1.3.0
passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - (ssh公開鍵)

ここで(ssh公開鍵)は実際のSSH公開鍵を入力する。

Butan configファイル simple.bu からJSON形式のIgnition configファイル simple.ign に変換する。

$ docker run -i --rm quay.io/coreos/butane:release < simple.bu > simple.ign

出力されたsimple.ignの中身はこれ。

{"ignition":{"version":"3.2.0"},"passwd":{"users":[{"name":"core","sshAuthorizedKeys":["(ssh公開鍵)"]}]}}

ここまででFedora CoreOSのインストールに必要なものは準備できたが、 Debian系ではAppArmorが有効になっており、そのままvirt-installすると

can't load /path/to/simple.ign: Failed to open file “/path/to/simple.ign”: Permission denied

といって怒られる。
そこで、libvirtsimple.ignファイルを読めるように、AppArmorの設定を変更する。

$ sudo vi /etc/apparmor.d/libvirt/TEMPLATE.qemu
 profile LIBVIRT_TEMPLATE flags=(attach_disconnected) {
   #include <abstractions/libvirt-qemu>
+  /path/to/simple.ign rk,
 }

準備が整ったので、VMを作成する。
手元のホストでは、os-variantでfedora-coreos-stableが認識してもらえなかったので、fedora31を指定している。

$ virt-install --name coreos --vcpus 1 --memory 2048 --os-variant fedora31 --import --graphics=none --disk path=coreos.img,size=10,backing_store=$PWD/fedora-coreos-34.20210518.3.0-qemu.x86_64.qcow2 --network network=default --qemu-commandline="-fw_cfg name=opt/com.coreos/config,file=$PWD/simple.ign"

インストールが終了したら、sshで接続してみる。
IPアドレスはインストール時のコンソールの最後の方に次のように表示されている。

enp1s0: 192.168.122.22 fe80::ba1b:5f86:aa42:280f

coreユーザでssh接続できることを確認する。

$ ssh core@192.168.122.22

無事Fedora CoreOSがKVM上にインストールできた!

nftablesでブリッジにフィルタ設定

前回はVMごとにネットワークフィルタを設定したが、共通のフィルタはホスト環境で設定した方が間違いがない。
そこで、ホスト環境のネットワークインタフェースに接続したブリッジに対してnftablesでフィルタを設定してみる。

ここでは、ホスト環境のネットワークインタフェースenp1s0に接続されたブリッジに対してフィルタを設定する。

まずはnftで手動で設定してみる。
bridge filterテーブルとfowardチェインを(なければ)作る。

# nft add table bridge filter
# nft add chain bridge filter forward '{type filter hook forward priority filter; policy accept; }'

次にルールを設定する。
ここでは、VMから x.y.z.0/24 への通信を禁止してみる。

# nft add rule bridge filter ct state established,related accept
# nft add rule bridge filter oif "enp1s0" ip daddr x.y.z.0/24 counter drop

VM内部からx.y.z.0/24にpingを打っても返ってこない。 なお、先に x.y.z.0/24 のどこかにpingを打って返ってくることを確認してある。

nftでも確認する。

# nft list ruleset bridge
table bridge filter {
    chain forward {
        type filter hook forward priority filter; policy accept;
        ct state established,related accept
        oif "enp1s0" ip daddr x.y.z.0/24 counter packets 3 bytes 252 drop
    }
}

確かにdropルールに引っ掛かっている。

手動で設定したフィルタを永続化する。

# cat <<EOF >> /etc/nftables.conf
table bridge filter {
    chain forward {
        type filter hook forward priority filter; policy accept;
        ct state established,related accept
        oif "enp1s0" ip daddr x.y.z.0/24 counter drop
    }
}

なお/etc/nftables.confDebian系の場合。

設定を反映する。

# systemctl restart nftables
# nft list ruleset bridge
table bridge filter {
    chain forward {
        type filter hook forward priority filter; policy accept;
        ct state established,related accept
        oif "enp1s0" ip daddr x.y.z.0/24 counter packets 0 bytes 0 drop
    }
}

nftablesを使ってホストブリッジにフィルタを設定できた!

KVMのネットワークフィルタ設定

libvirtに備わっているネットワークフィルタ機能 (nwfilter) をVMに適用してみる。

libvirtの公式ドキュメントを参考に作業を進める。

nwfilterは(バックエンドがnftablesであっても)iptablesを使ってフィルタリングを行うので、まずはnwfilter未設定時のiptables設定を確認する。

# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  161 14807 LIBVIRT_INP  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 LIBVIRT_FWX  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 LIBVIRT_FWI  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 LIBVIRT_FWO  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  122 11453 LIBVIRT_OUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain LIBVIRT_FWI (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  *      virbr0  0.0.0.0/0            192.168.122.0/24     ctstate RELATED,ESTABLISHED
    0     0 REJECT     all  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            reject-with icmp-port-unreachable

Chain LIBVIRT_FWO (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  virbr0 *       192.168.122.0/24     0.0.0.0/0           
    0     0 REJECT     all  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-port-unreachable

Chain LIBVIRT_FWX (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  virbr0 virbr0  0.0.0.0/0            0.0.0.0/0           

Chain LIBVIRT_INP (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     udp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            udp dpt:53
    0     0 ACCEPT     tcp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:53
    0     0 ACCEPT     udp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            udp dpt:67
    0     0 ACCEPT     tcp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:67

Chain LIBVIRT_OUT (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     udp  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            udp dpt:53
    0     0 ACCEPT     tcp  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            tcp dpt:53
    0     0 ACCEPT     udp  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            udp dpt:68
    0     0 ACCEPT     tcp  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            tcp dpt:68

既にlibvirtによってDNSDHCPを通すフィルタリングなどが設定されている。

まずはフィルタtest-filterを定義する。 ここではホスト環境のIPアドレス192.168.122.1へのsshをブロックするルールを書いてみる。
ルールの詳細は公式ドキュメントを参考にする。

$ virsh nwfilter-define <(cat <<EOF
<filter name='test-filter'>
  <rule action='drop' direction='out'>
    <tcp dstipaddr='192.168.122.1' dstportstart='22'/>
  </rule>
</filter>
EOF
)
$ virsh nwfilter-dumpxml test-filter
<filter name='test-filter' chain='root'>
  <uuid>49978302-912f-45b2-8298-af957757177e</uuid>
  <rule action='drop' direction='out' priority='500'>
    <tcp dstipaddr='192.168.122.1' dstportstart='22'/>
  </rule>
</filter>

いま定義したフィルタtest-filterVM kvmdomに設定する。

$ virsh edit kvmdom
     <interface type='network'>
       <mac address='52:54:00:fa:68:d9'/>
       <source network='default'/>
       <model type='virtio'/>
+      <filterref filter='test-filter'/>
       <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
     </interface>
Domain kvmdom XML configuration edited.

VM kvmdomを起動する。

$ virsh start kvmdom

iptables設定を確認してみる。

# iptables -nvL

追加された部分

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   21  2032 libvirt-host-in  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 libvirt-in  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 libvirt-out  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 libvirt-in-post  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain FI-vnet2 (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       tcp  --  *      *       0.0.0.0/0            192.168.122.1        tcp dpt:22

Chain FO-vnet2 (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       tcp  --  *      *       192.168.122.1        0.0.0.0/0            tcp spt:22

Chain HI-vnet2 (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       tcp  --  *      *       0.0.0.0/0            192.168.122.1        tcp dpt:22

Chain libvirt-host-in (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    2   656 HI-vnet2   all  --  *      *       0.0.0.0/0            0.0.0.0/0           [goto]  PHYSDEV match --physdev-in vnet2

Chain libvirt-in (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 FI-vnet2   all  --  *      *       0.0.0.0/0            0.0.0.0/0           [goto]  PHYSDEV match --physdev-in vnet2

Chain libvirt-in-post (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            PHYSDEV match --physdev-in vnet2

Chain libvirt-out (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 FO-vnet2   all  --  *      *       0.0.0.0/0            0.0.0.0/0           [goto]  PHYSDEV match --physdev-out vnet2 --physdev-is-bridged

先ほど定義したルールはChain FI-vnet2, FO-vnet2, HI-vnet2 に定義されている。
実際にVM kvmdomから192.168.122.1sshしてみても接続できない。

libvirtの機能を使ってVMにネットワークフィルタを設定できた!

KVMのデフォルトネットワークをブリッジへ変更

KVMのデフォルトネットワークは通常、ブリッジでプライベートアドレスのサブネットを作ってNATで外部に出ていくものになっているが、これをホスト環境のネットワークインタフェースに直接ブリッジするもの(ホストブリッジ)に変えてみる。

まずは現状の確認。

$ export LIBVIRT_DEFAULT_URI='qemu:///system'
$ virsh net-list --all
 Name      State      Autostart   Persistent
----------------------------------------------
 default   inactive   no          yes

デフォルトのネットワークが定義されている。

いったんdefaultネットワークの定義を削除する。

$ virsh net-undefine default
$ virsh net-list --all
 Name   State   Autostart   Persistent
----------------------------------------

続いて、ブリッジbr0を使うホストブリッジ用ネットワークを定義する。
ブリッジを作成する方法は各ディストリビューションのドキュメントを参照のこと。

defaultネットワークをXMLを使って定義する。
なお <( ... ) の部分はbashのprocess substitution(プロセス置換)という機能。

$ virsh net-define <(cat <<EOF
<network>
  <name>default</name>
  <forward mode="bridge"/>
  <bridge name="br0"/>
</network>
EOF
)
Network default defined from /tmp/br0.xml

$ virsh net-list --all
 Name      State      Autostart   Persistent
----------------------------------------------
 default   inactive   no          yes

最後に、defaultネットワークを開始し、自動開始を設定する。

$ virsh net-start default
Network default started

$ virsh net-autostart default
Network default marked as autostarted

$ virsh net-list --all
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

KVMのデフォルトネットワークをホストブリッジに変更できた!