20190211のLinuxに関する記事は5件です。

VXLAN/EVPN on Linux の検証

モチベーション

データセンタ内のVXLAN/EVPN環境において、VXLAN終端をleafスイッチでなく配下の物理サーバ(Linux)でやりたい.

メリット

  • サーバとスイッチ間の接続がL2からL3になる
    • bondingやMLAGが不要
  • leafスイッチの設定が簡素化される
    • スイッチはMP-BGPの通信に徹する
    • ネットワークデザインがシンプル化
  • leafスイッチのメンテナンスが楽になる
    • BGP graceful shutdown community (使ったことないけど)
    • スイッチのアップグレードを人知れず実施したい

デメリット

  • ネットワーク性能の低下?(本記事では未検証)
    • leafスイッチのASICで高速処理されていたVXLANのカプセル処理が物理サーバに委譲されるため
      • サーバ用のVXLANオフロードNICがあったような...

前回の記事で Cumulus-VX を使用して VXLAN/EVPNのルーティングを検証し、CumulusはDebianとFRRを使っていることがわかった。ということはノーマルなlinuxでも、設定を適切に投入すればVXLAN/EVPNを動作させられるはずである. 結論として動作を確認できた. 

背景

データセンタネットワークの歴史的な経緯はこちらの資料を参照.
(JANOG41) データセンターでのルーティングプロトコル

IP-fabric デザインにするとスケーラビリティを得る代わりにToR内でVLANが閉じるため、L2-fabricと異なり他のラックに同じVLANをもつマシンを分散配置できない. ラック内のネットワーク設計によるがネットワーク設定と物理ラックが密結合になるため、管理が必要だったりリソースを有効活用しにくくなる.
これを解決するためにオーバレイネットワークやルーティングプロトコルを駆使してラックを越境するわけだがVXLAN以外にも様々なアプローチがとられている.

サーバエンドでVXLANを終端させるアプローチ自体は既に考えられている.

Network 概要

今回構築するネットワークはこちら. VMが2台あれば容易に検証できるようにした.
host-vtep-internal.png

Linux Networkの詳細な設定は実際の Cumulus-VX の内部設定を参考にした. NCLUは無いので、L2やVNIの設定はipコマンド、L3の設定はFRRを直接叩く必要がある.
Cumulus だとVLAN-aware BridgeというひとつのbridgeにすべてのVNIを接続させてVLANでサブネットを分離していた。今回はLXCとの親和性からサブネットごとにbridgeを作成してL2分離した.
Cumulus本家も、本検証とは異なるアプローチ(vlan-aware Bridge + nodeはnamespaceで代用)でサーバVTEPを検証している.

VTEPの構築

Ubuntu18.04-LTS(bionic)を2台用意する. 互いにping疎通可であるとする.
ネットワークの設定方法がnetplanを使う方法になっているので注意する.

Netplan の使い方

Linux Kernel のアップグレード

ipコマンドのVRF機能やFRRの要件より、デフォルトより新しめのカーネルにする必要がある.

sudo su -
#-------------------------------------------------------
# Update repository
#-------------------------------------------------------
cat > /etc/apt/sources.list <<EOF
deb http://ftp.jaist.ac.jp/pub/Linux/ubuntu/ bionic main restricted
deb http://ftp.jaist.ac.jp/pub/Linux/ubuntu/ bionic-updates main restricted
deb http://ftp.jaist.ac.jp/pub/Linux/ubuntu/ bionic universe
deb http://ftp.jaist.ac.jp/pub/Linux/ubuntu/ bionic-updates universe
deb http://ftp.jaist.ac.jp/pub/Linux/ubuntu/ bionic multiverse
deb http://ftp.jaist.ac.jp/pub/Linux/ubuntu/ bionic-updates multiverse
deb http://ftp.jaist.ac.jp/pub/Linux/ubuntu/ bionic-backports main restricted universe multiverse
deb http://ftp.jaist.ac.jp/pub/Linux/ubuntu/ bionic-security main restricted
deb http://ftp.jaist.ac.jp/pub/Linux/ubuntu/ bionic-security universe
deb http://ftp.jaist.ac.jp/pub/Linux/ubuntu/ bionic-security multiverse
EOF
apt-get -y update

#-------------------------------------------------------
# Upgrade linux kernel to 4.19
#-------------------------------------------------------
mkdir linux4.19/ && cd $_
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.19/linux-headers-4.19.0-041900_4.19.0-041900.201810221809_all.deb
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.19/linux-headers-4.19.0-041900-generic_4.19.0-041900.201810221809_amd64.deb
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.19/linux-image-unsigned-4.19.0-041900-generic_4.19.0-041900.201810221809_amd64.deb
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.19/linux-modules-4.19.0-041900-generic_4.19.0-041900.201810221809_amd64.deb
dpkg -i *.deb
reboot

# Check > 4.19.0-041900-generic
uname -r

sysctl の調整

linux内のbridge間でパケットを転送し合ったりVRFを有効にするためにsysctlの設定も入れておく. 新しいことをやろうとするとよく嵌まるポイント.

CumulusからLinuxをルータ/スイッチとして使うにあたり、ARPの挙動をどのように変更したかの解説記事が出ている. 本記事ではLinuxのデフォルトの設定を利用しているが、いつか設定を見直すかもしれない.

#-------------------------------------------------------
# sysctl
#-------------------------------------------------------
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.tcp_l3mdev_accept=1
sysctl -w net.ipv4.udp_l3mdev_accept=1
sysctl -p

FRR のインストール

インストールの仕方は色々あるようだ. 今回はdpkgでインストール.

# Install
wget https://github.com/FRRouting/frr/releases/download/frr-6.0.2/frr_6.0.2-0.ubuntu18.04.1_amd64.deb
dpkg -i dpkg -i frr_6.0.2-0.ubuntu18.04.1_amd64.deb

# Enable routing daemons
sed -i -e "s/zebra=no/zebra=yes/g" /etc/frr/daemons
sed -i -e "s/bgpd=no/bgpd=yes/g" /etc/frr/daemons
cat /etc/frr/daemons | grep yes

# Restart
systemctl enable frr
systemctl restart frr
systemctl status frr

# Check version
vtysh -c "show version"

LXD の設定

Bridge接続ができればいいのでKVMでも問題ないが取り回しが重いのと、UbuntuなのでLXDを使う.

#-------------------------------------------------------
# LXD 3.0
#-------------------------------------------------------
# Install LXD
apt-get install -y lxd
lxc --version # > 3.0.3

# Initialization
lxd init
# Would you like to use LXD clustering? (yes/no) [default=no]:
# Do you want to configure a new storage pool? (yes/no) [default=yes]:
# Name of the new storage pool [default=default]:
# Name of the storage backend to use (btrfs, ceph, dir, lvm) [default=btrfs]: dir
# Would you like to connect to a MAAS server? (yes/no) [default=no]:
# Would you like to create a new local network bridge? (yes/no) [default=yes]: no
# Would you like to configure LXD to use an existing bridge or host interface? (yes/no) [default=no]:
# Would you like LXD to be available over the network? (yes/no) [default=no]:
# Would you like stale cached images to be updated automatically? (yes/no) [default=yes]
# Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]: yes
# config: {}
# networks: []
# storage_pools:
# - config: {}
#   description: ""
#   name: default
#   driver: dir
# profiles:
# - config: {}
#   description: ""
#   devices:
#     root:
#       path: /
#       pool: default
#       type: disk
#   name: default
# cluster: null

# Get new container image
lxc init ubuntu:18.04 ubuntu
FINGER_PRINT=$(lxc image list --format json | jq -r .[].fingerprint)
lxc image alias create ubuntu1804 $FINGER_PRINT
lxc image list

#-------------------------------------------------------
# Create original container image for PoC
#-------------------------------------------------------
# Deploy a container
lxc launch ubuntu1804 test
lxc exec test bash

# SSH
sed -i -e "s/PasswordAuthentication no/PasswordAuthentication yes/g" /etc/ssh/sshd_config
sed -i -e "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
systemctl restart ssh
systemctl status ssh

# Change default root password
echo root:ubuntu | chpasswd

# Stop DHCP DISCOVER traffic
# 今回は静的に各コンテナにIPアドレスを設定する
sed -i -e "s/dhcp4: true/dhcp4: false/g" /etc/netplan/50-cloud-init.yaml

# Generate new container image
lxc stop test
lxc publish test --alias demo
lxc list
lxc remove test

Linux Network の設定

bridge や VNIを作る. ここから混乱しやすくなるので上図を見ながら設定を投入していく.

各VRFのルーティングテーブルに宛先エントリがない場合、unreachableにしてルックアップを終了する設定を入れる必要がある. この設定がないとip rule showにしたがって物理サーバのルーティングテーブルを使って、オーバレイネットワークのパケットがVRFから漏れ出してしまうので蓋をしておく.

Linux VRF の公式マニュアル

#-------------------------------------------------------
# Underlay IF MTU (+50 due to VXLAN overhead) 
#-------------------------------------------------------
NETWORK_IF=ens38
ip link set $NETWORK_IF mtu 1550

#-------------------------------------------------------
# VRF
#-------------------------------------------------------
# Create VRF
ip link add vrf-1 type vrf table 101000
ip link add vrf-2 type vrf table 102000

# Up VRF IF
ip link set dev vrf-1 up
ip link set dev vrf-2 up

# Check (state UP / vrf table 10XXXX)
ip -d link show vrf-1
ip -d link show vrf-2

# Check Lookup table
ip rule show
# > 0:       from all lookup local
# > 1000:    from all lookup [l3mdev-table] <--- Check
# > 32766:   from all lookup main
# > 32767:   from all lookup default

# Tenant Isolation
ip route add table 101000 unreachable default metric 4278198272
ip route add table 102000 unreachable default metric 4278198272

# Check
ip route show vrf vrf-1
ip route show vrf vrf-2
# > unreachable default metric 4278198272

# VRF: rp_filter
# ここを設定しないとVRFを跨ぐ時にL3VNIからbridgeにパケットが転送されない
sysctl -w net.ipv4.conf.vrf-1.rp_filter=0
sysctl -w net.ipv4.conf.vrf-2.rp_filter=0
sysctl -p

Subnet と L2VNI の設定

NETWORK_IF=ens38
VTEP_IPADDR=$(ip -4 addr show $NETWORK_IF | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
echo $VTEP_IPADDR

#--------------------------------------------
# L2VNI (vrf-1/subnet1-1)
#--------------------------------------------
L2VNI=101001
SUBNET=10.1.1.0/24
SUBNET_GATEWAY=10.1.1.254
SUBNET_GATEWAY_PREFIX=${SUBNET_GATEWAY}/24
VRF=vrf-1

ip link add L2VNI${L2VNI} type vxlan id ${L2VNI} local $VTEP_IPADDR dstport 4789 nolearning
ip link set L2VNI${L2VNI} mtu 9000
ip link set L2VNI${L2VNI} up
bridge link set dev L2VNI${L2VNI} neigh_suppress on
brctl addbr br${L2VNI}
brctl stp br${L2VNI} off
brctl addif br${L2VNI} L2VNI${L2VNI}
ip addr add dev br${L2VNI} ${SUBNET_GATEWAY_PREFIX}
ip link set br${L2VNI} up
ip link set br${L2VNI} master $VRF
ip route add ${SUBNET} via ${SUBNET_GATEWAY} dev br${L2VNI}

# Check
brctl show
ip -d link show L2VNI${L2VNI}
vtysh -c "show interface L2VNI${L2VNI}"
ip addr show vrf $VRF
ip route show vrf $VRF

#--------------------------------------------
# L2VNI (vrf-1/subnet1-2)
#--------------------------------------------
L2VNI=101002
SUBNET=10.1.2.0/24
SUBNET_GATEWAY=10.1.2.254
SUBNET_GATEWAY_PREFIX=${SUBNET_GATEWAY}/24
VRF=vrf-1

ip link add L2VNI${L2VNI} type vxlan id ${L2VNI} local $VTEP_IPADDR dstport 4789 nolearning
ip link set L2VNI${L2VNI} mtu 9000
ip link set L2VNI${L2VNI} up
bridge link set dev L2VNI${L2VNI} neigh_suppress on
brctl addbr br${L2VNI}
brctl stp br${L2VNI} off
brctl addif br${L2VNI} L2VNI${L2VNI}
ip addr add dev br${L2VNI} ${SUBNET_GATEWAY_PREFIX}
ip link set br${L2VNI} up
ip link set br${L2VNI} master $VRF
ip route add ${SUBNET} via ${SUBNET_GATEWAY} dev br${L2VNI}

# Check
brctl show
ip -d link show L2VNI${L2VNI}
vtysh -c "show interface L2VNI${L2VNI}"
ip addr show vrf $VRF
ip route show vrf $VRF

#--------------------------------------------
# L2VNI (vrf-2/subnet2-1)
#--------------------------------------------
L2VNI=102001
SUBNET=10.2.1.0/24
SUBNET_GATEWAY=10.2.1.254
SUBNET_GATEWAY_PREFIX=${SUBNET_GATEWAY}/24
VRF=vrf-2

ip link add L2VNI${L2VNI} type vxlan id ${L2VNI} local $VTEP_IPADDR dstport 4789 nolearning
ip link set L2VNI${L2VNI} mtu 9000
ip link set L2VNI${L2VNI} up
bridge link set dev L2VNI${L2VNI} neigh_suppress on
brctl addbr br${L2VNI}
brctl stp br${L2VNI} off
brctl addif br${L2VNI} L2VNI${L2VNI}
ip addr add dev br${L2VNI} ${SUBNET_GATEWAY_PREFIX}
ip link set br${L2VNI} up
ip link set br${L2VNI} master $VRF
ip route add ${SUBNET} via ${SUBNET_GATEWAY} dev br${L2VNI}

# Check
brctl show
ip -d link show L2VNI${L2VNI}
vtysh -c "show interface L2VNI${L2VNI}"
ip addr show vrf $VRF
ip route show vrf $VRF

#--------------------------------------------
# Sample output
#--------------------------------------------
# root@vtep-1:~# ip route show vrf vrf-1
# unreachable default metric 4278198272
# 10.1.1.0/24 dev br101001 proto kernel scope link src 10.1.1.254
# 10.1.2.0/24 dev br101002 proto kernel scope link src 10.1.2.254

# root@vtep-1:~# ip route show vrf vrf-2
# unreachable default metric 4278198272
# 10.2.1.0/24 dev br102001 proto kernel scope link src 10.2.1.254

# root@vtep-1:~# brctl show
# bridge name   bridge id       STP enabled interfaces
# br101001      8000.e2a8f93a7056   no      L2VNI101001
# br101002      8000.ea09e6adfcce   no      L2VNI101002
# br102001      8000.6e4881804f2b   no      L2VNI102001

# Check VXLAN IF are UP
# root@vtep-1:~# ip link show type vxlan | grep L2VNI
# 13: L2VNI102001: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master br102001 state UNKNOWN mode DEFAULT group default qlen 1000
# 19: L2VNI101001: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master br101001 state UNKNOWN mode DEFAULT group default qlen 1000
# 21: L2VNI101002: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master br101002 state UNKNOWN mode DEFAULT group default qlen 1000

# Check bridge are UP
# root@vtep-1:~# ip link show type bridge | grep mtu
# 34: br101001: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master vrf-1 state UP mode DEFAULT group default qlen 1000
# 36: br101002: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master vrf-1 state UP mode DEFAULT group default qlen 1000
# 38: br102001: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master vrf-2 state UP mode DEFAULT group default qlen 1000

L3VNI の設定

NETWORK_IF=ens38
VTEP_IPADDR=$(ip -4 addr show $NETWORK_IF | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
echo $VTEP_IPADDR

#-------------------------------------------------------
# L3VNI (vrf-1)
#-------------------------------------------------------
L3VNI=101000
VRF=vrf-1

ip link add L3VNI${L3VNI} type vxlan id ${L3VNI} local $VTEP_IPADDR dstport 4789 nolearning
ip link set L3VNI${L3VNI} mtu 9000
ip link set L3VNI${L3VNI} up
bridge link set dev L3VNI${L3VNI} neigh_suppress on
ip -d link show L3VNI${L3VNI}

brctl addbr br${L3VNI}
brctl stp br${L3VNI} off
brctl addif br${L3VNI} L3VNI${L3VNI}
ip link set br${L3VNI} up
ip link set br${L3VNI} master $VRF

brctl show
ip -d link show L3VNI${L3VNI}
vtysh -c "show interface L3VNI${L3VNI}"
ip addr show vrf $VRF

#-------------------------------------------------------
# L3VNI (vrf-2)
#-------------------------------------------------------
L3VNI=102000
VRF=vrf-2

ip link add L3VNI${L3VNI} type vxlan id ${L3VNI} local $VTEP_IPADDR dstport 4789 nolearning
ip link set L3VNI${L3VNI} mtu 9000
ip link set L3VNI${L3VNI} up
bridge link set dev L3VNI${L3VNI} neigh_suppress on
ip -d link show L3VNI${L3VNI}

brctl addbr br${L3VNI}
brctl stp br${L3VNI} off
brctl addif br${L3VNI} L3VNI${L3VNI}
ip link set br${L3VNI} up
ip link set br${L3VNI} master $VRF

brctl show
ip -d link show L3VNI${L3VNI}
vtysh -c "show interface L3VNI${L3VNI}"
ip addr show vrf $VRF

#-------------------------------------------------------
# Sample output
#-------------------------------------------------------
# root@vtep-1:~# ip addr show vrf vrf-1
# 16: br101000: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master vrf-1 state UP group default qlen 1000
#     link/ether 92:7c:04:3f:38:8f brd ff:ff:ff:ff:ff:ff
#     inet6 fe80::907c:4ff:fe3f:388f/64 scope link
#        valid_lft forever preferred_lft forever
# 20: br101001: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master vrf-1 state UP group default qlen 1000
#     link/ether e2:a8:f9:3a:70:56 brd ff:ff:ff:ff:ff:ff
#     inet 10.1.1.254/24 scope global br101001
#        valid_lft forever preferred_lft forever
#     inet6 fe80::e0a8:f9ff:fe3a:7056/64 scope link
#        valid_lft forever preferred_lft forever
# 22: br101002: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master vrf-1 state UP group default qlen 1000
#     link/ether ea:09:e6:ad:fc:ce brd ff:ff:ff:ff:ff:ff
#     inet 10.1.2.254/24 scope global br101002
#        valid_lft forever preferred_lft forever
#     inet6 fe80::e809:e6ff:fead:fcce/64 scope link
#        valid_lft forever preferred_lft forever

# root@vtep-1:~# ip addr show vrf vrf-2
# 14: br102001: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master vrf-2 state UP group default qlen 1000
#     link/ether 6e:48:81:80:4f:2b brd ff:ff:ff:ff:ff:ff
#     inet 10.2.1.254/24 scope global br102001
#        valid_lft forever preferred_lft forever
#     inet6 fe80::6c48:81ff:fe80:4f2b/64 scope link
#        valid_lft forever preferred_lft forever
# 18: br102000: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master vrf-2 state UP group default qlen 1000
#     link/ether 02:ed:fb:0d:81:e0 brd ff:ff:ff:ff:ff:ff
#     inet6 fe80::ed:fbff:fe0d:81e0/64 scope link
#        valid_lft forever preferred_lft forever

# root@vtep-1:~# ip link show type vxlan | grep L3VNI
# 15: L3VNI101000: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master br101000 state UNKNOWN mode DEFAULT group default qlen 1000
# 17: L3VNI102000: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue master br102000 state UNKNOWN mode DEFAULT group default qlen 1000

# root@vtep-1:~# brctl show
# bridge name     bridge id               STP enabled     interfaces
# br101000        8000.d202cf1bf95f       no              L3VNI101000 # <-- NEW
# br101001        8000.bef545052a7c       no              L2VNI101001
# br101002        8000.7678fc174cb3       no              L2VNI101002
# br102000        8000.365d009e5a9f       no              L3VNI102000 # <-- NEW
# br102001        8000.ae8e8ac6fba4       no              L2VNI102001

FRR の設定

FRRにBGPとEVPNの設定を投入する.
FRRでBGPピアを設定する際、対向への接続がeBGPマルチホップだとスタティックルートを設定していないとBGP OPENを送信しようとしない(BIRDだと静的ルートなしでピアを張れた). したがってデフォルトルートでping疎通できるのにBGPピアが張れない場合はスタティックルートを入れるようにする.

FRR VTEP-1 の設定

# Static route for eBGP multi-hop
# ポイントツー接続なら不要
UNDERLAY_GATEWAY=$(ip -4 route show | grep default | cut -d ' ' -f3)
echo $UNDERLAY_GATEWAY
BGP_PEER_IP_ADDRESS=192.168.0.2
ip route add $BGP_PEER_IP_ADDRESS via $UNDERLAY_GATEWAY
ip route show

# Underlay eBGP Neighbor
vtysh
conf t
router bgp 65001
bgp router-id 1.1.1.1
neighbor 192.168.0.2 remote-as external
neighbor 192.168.0.2 ebgp-multihop
address-family ipv4 unicast
redistribute connected
end
write memory
exit

# Enable EVPN
vtysh
conf t
router bgp 65001
address-family l2vpn evpn
neighbor 192.168.0.2 activate
advertise-all-vni
end
write memory
exit

# Overlay BGP (vrf-1)
vtysh
conf t
router bgp 65001 vrf vrf-1
bgp router-id 1.1.1.1
neighbor 192.168.0.2 remote-as external
neighbor 192.168.0.2 ebgp-multihop
address-family ipv4 unicast
redistribute connected
address-family l2vpn evpn
advertise ipv4 unicast
end
write memory
exit

# Overlay BGP (vrf-2)
vtysh
conf t
router bgp 65001 vrf vrf-2
bgp router-id 1.1.1.1
neighbor 192.168.0.2 remote-as external
neighbor 192.168.0.2 ebgp-multihop
address-family ipv4 unicast
redistribute connected
address-family l2vpn evpn
advertise ipv4 unicast
end
write memory
exit

#-------------------------------------------------------
# Mapping VRF and L3VNI for vrf-1 and vrf-2
#-------------------------------------------------------
vtysh
conf t
vrf vrf-1
vni 101000
vrf vrf-2
vni 102000
end
write memory
exit

FRR VTEP-2 の設定

# Static route for eBGP multi-hop
UNDERLAY_GATEWAY=$(ip -4 route show | grep default | cut -d ' ' -f3)
echo $UNDERLAY_GATEWAY
BGP_PEER_IP_ADDRESS=192.168.0.1
ip route add $BGP_PEER_IP_ADDRESS via $UNDERLAY_GATEWAY
ip route show

# Underlay eBGP Neighbor
vtysh
conf t
router bgp 65002
bgp router-id 2.2.2.2
neighbor 192.168.0.1 remote-as external
neighbor 192.168.0.1 ebgp-multihop
address-family ipv4 unicast
redistribute connected
end
write memory
exit

# Enable EVPN
vtysh
conf t
router bgp 65002
address-family l2vpn evpn
neighbor 192.168.0.1 activate
advertise-all-vni
end
write memory
exit

# Overlay BGP (vrf-1)
vtysh
conf t
router bgp 65002 vrf vrf-1
bgp router-id 2.2.2.2
neighbor 192.168.0.1 remote-as external
neighbor 192.168.0.1 ebgp-multihop
address-family ipv4 unicast
redistribute connected
address-family l2vpn evpn
advertise ipv4 unicast
end
write memory
exit

# Overlay BGP (vrf-2)
vtysh
conf t
router bgp 65002 vrf vrf-2
bgp router-id 2.2.2.2
neighbor 192.168.0.1 remote-as external
neighbor 192.168.0.1 ebgp-multihop
address-family ipv4 unicast
redistribute connected
address-family l2vpn evpn
advertise ipv4 unicast
end
write memory
exit

#-------------------------------------------------------
# Mapping VRF and L3VNI for vrf-1 and vrf-2
#-------------------------------------------------------
vtysh
conf t
vrf vrf-1
vni 101000
vrf vrf-2
vni 102000
end
write memory
exit

FRR コマンド出力結果

# Check
vtysh -c "show running-config"
vtysh -c "show bgp summary"
vtysh -c "show bgp l2vpn evpn route"
vtysh -c "show evpn mac vni all"
vtysh -c "show evpn vni"
vtysh -c "show evpn vni 101001"
vtysh -c "show evpn vni 101002"
vtysh -c "show evpn vni 102001"
vtysh -c "show evpn vni 101000"
vtysh -c "show evpn vni 102000"

# Sample output
# root@vtep-1:~# vtysh -c "show bgp summary"
# 
# IPv4 Unicast Summary:
# BGP router identifier 1.1.1.1, local AS number 65001 vrf-id 0
# BGP table version 3
# RIB entries 5, using 800 bytes of memory
# Peers 1, using 21 KiB of memory
# 
# Neighbor        V         AS MsgRcvd MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd
# 192.168.0.2     4      65002      23      23        0    0    0 00:05:27            2
# 
# Total number of neighbors 1
# 
# L2VPN EVPN Summary:
# BGP router identifier 1.1.1.1, local AS number 65001 vrf-id 0
# BGP table version 0
# RIB entries 19, using 3040 bytes of memory
# Peers 1, using 21 KiB of memory
# 
# Neighbor        V         AS MsgRcvd MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd
# 192.168.0.2     4      65002      23      23        0    0    0 00:05:27            6
# 
# Total number of neighbors 1

# root@vtep-1:~# vtysh -c "show evpn vni"
# VNI        Type VxLAN IF              # MACs   # ARPs   # Remote VTEPs  Tenant VRF
# 102001     L2   L2VNI102001           1        1        1               vrf-2
# 101001     L2   L2VNI101001           1        1        1               vrf-1
# 101002     L2   L2VNI101002           1        1        1               vrf-1
# 101000     L3   L3VNI101000           1        1        n/a             vrf-1
# 102000     L3   L3VNI102000           1        1        n/a             vrf-2


# root@vtep-1:~# vtysh -c "show evpn vni 101001"
# VNI: 101001
#  Type: L2
#  Tenant VRF: vrf-1
#  VxLAN interface: L2VNI101001
#  VxLAN ifIndex: 7
#  Local VTEP IP: 192.168.0.1
#  Remote VTEPs for this VNI:
#   192.168.0.2
#  Number of MACs (local and remote) known for this VNI: 1
#  Number of ARPs (IPv4 and IPv6, local and remote) known for this VNI: 2
#  Advertise-gw-macip: No

# root@vtep-1:~# vtysh -c "show evpn vni 101000"
# VNI: 101000
#   Type: L3
#   Tenant VRF: vrf-1
#   Local Vtep Ip: 192.168.0.1
#   Vxlan-Intf: L3VNI101000
#   SVI-If: br101000
#   State: Up
#   VNI Filter: none
#   Router MAC: f6:b1:a7:d6:84:f6
#   L2 VNIs: 101001 101002

# root@vtep-1:~# vtysh -c "show evpn vni 102000"
# VNI: 102000
#   Type: L3
#   Tenant VRF: vrf-2
#   Local Vtep Ip: 192.168.0.1
#   Vxlan-Intf: L3VNI102000
#   SVI-If: br102000
#   State: Up
#   VNI Filter: none
#   Router MAC: b2:e2:2d:18:e5:9b
#   L2 VNIs: 102001

LXD の起動

# Network Profile
lxc profile create subnet1-1
lxc profile create subnet1-2
lxc profile create subnet2-1

lxc profile device add subnet1-1 root disk path=/ pool=default
lxc profile device add subnet1-1 eth0 nic name=eth0 nictype=bridged parent=br101001

lxc profile device add subnet1-2 root disk path=/ pool=default
lxc profile device add subnet1-2 eth0 nic name=eth0 nictype=bridged parent=br101002

lxc profile device add subnet2-1 root disk path=/ pool=default
lxc profile device add subnet2-1 eth0 nic name=eth0 nictype=bridged parent=br102001

lxc profile list

LXC の起動 (VTEP1)

cat > boot_lxc.sh <<EOF
# Boot Container
lxc list
lxc launch ubuntu1804 lxc-1 -p subnet1-1
lxc launch ubuntu1804 lxc-3 -p subnet1-1
lxc launch ubuntu1804 lxc-5 -p subnet1-2
lxc launch ubuntu1804 lxc-7 -p subnet1-2
lxc launch ubuntu1804 lxc-9 -p subnet2-1
lxc launch ubuntu1804 lxc-11 -p subnet2-1
lxc list

# IP address setting
lxc exec lxc-1 -- ip link set eth0 up
lxc exec lxc-1 -- ip addr add 10.1.1.1/24 dev eth0
lxc exec lxc-1 -- ip route add default via 10.1.1.254 dev eth0
lxc exec lxc-3 -- ip link set eth0 up
lxc exec lxc-3 -- ip addr add 10.1.1.3/24 dev eth0
lxc exec lxc-3 -- ip route add default via 10.1.1.254 dev eth0

lxc exec lxc-5 -- ip link set eth0 up
lxc exec lxc-5 -- ip addr add 10.1.2.5/24 dev eth0
lxc exec lxc-5 -- ip route add default via 10.1.2.254 dev eth0
lxc exec lxc-7 -- ip link set eth0 up
lxc exec lxc-7 -- ip addr add 10.1.2.7/24 dev eth0
lxc exec lxc-7 -- ip route add default via 10.1.2.254 dev eth0

lxc exec lxc-9 -- ip link set eth0 up
lxc exec lxc-9 -- ip addr add 10.2.1.9/24 dev eth0
lxc exec lxc-9 -- ip route add default via 10.2.1.254 dev eth0
lxc exec lxc-11 -- ip link set eth0 up
lxc exec lxc-11 -- ip addr add 10.2.1.11/24 dev eth0
lxc exec lxc-11 -- ip route add default via 10.2.1.254 dev eth0
lxc list
EOF

cat > delete_lxc.sh <<EOF
# Delete container
lxc delete -f lxc-1
lxc delete -f lxc-3
lxc delete -f lxc-5
lxc delete -f lxc-7
lxc delete -f lxc-9
lxc delete -f lxc-11
EOF

chmod 755 boot_lxc.sh delete_lxc.sh
sh -x boot_lxc.sh

# root@vtep-1:~# lxc list
# +--------+---------+------------------+------+------------+-----------+
# |  NAME  |  STATE  |       IPV4       | IPV6 |    TYPE    | SNAPSHOTS |
# +--------+---------+------------------+------+------------+-----------+
# | lxc-1  | RUNNING | 10.1.1.1 (eth0)  |      | PERSISTENT | 0         |
# +--------+---------+------------------+------+------------+-----------+
# | lxc-11 | RUNNING | 10.2.1.11 (eth0) |      | PERSISTENT | 0         |
# +--------+---------+------------------+------+------------+-----------+
# | lxc-3  | RUNNING | 10.1.1.3 (eth0)  |      | PERSISTENT | 0         |
# +--------+---------+------------------+------+------------+-----------+
# | lxc-5  | RUNNING | 10.1.2.5 (eth0)  |      | PERSISTENT | 0         |
# +--------+---------+------------------+------+------------+-----------+
# | lxc-7  | RUNNING | 10.1.2.7 (eth0)  |      | PERSISTENT | 0         |
# +--------+---------+------------------+------+------------+-----------+
# | lxc-9  | RUNNING | 10.2.1.9 (eth0)  |      | PERSISTENT | 0         |
# +--------+---------+------------------+------+------------+-----------+

# Enter lxc
lxc exec lxc-1 bash
ifconfig
ping 10.1.1.254
exit

LXC の起動 (VTEP2)

cat > boot_lxc.sh <<EOF
#!/bin/bash

# Boot Container
lxc list
lxc launch ubuntu1804 lxc-2 -p subnet1-1
lxc launch ubuntu1804 lxc-4 -p subnet1-1
lxc launch ubuntu1804 lxc-6 -p subnet1-2
lxc launch ubuntu1804 lxc-8 -p subnet1-2
lxc launch ubuntu1804 lxc-10 -p subnet2-1
lxc launch ubuntu1804 lxc-12 -p subnet2-1
lxc list

# IP address setting
lxc exec lxc-2 -- ip link set eth0 up
lxc exec lxc-2 -- ip addr add 10.1.1.2/24 dev eth0
lxc exec lxc-2 -- ip route add default via 10.1.1.254 dev eth0
lxc exec lxc-4 -- ip link set eth0 up
lxc exec lxc-4 -- ip addr add 10.1.1.4/24 dev eth0
lxc exec lxc-4 -- ip route add default via 10.1.1.254 dev eth0

lxc exec lxc-6 -- ip link set eth0 up
lxc exec lxc-6 -- ip addr add 10.1.2.6/24 dev eth0
lxc exec lxc-6 -- ip route add default via 10.1.2.254 dev eth0
lxc exec lxc-8 -- ip link set eth0 up
lxc exec lxc-8 -- ip addr add 10.1.2.8/24 dev eth0
lxc exec lxc-8 -- ip route add default via 10.1.2.254 dev eth0

lxc exec lxc-10 -- ip link set eth0 up
lxc exec lxc-10 -- ip addr add 10.2.1.10/24 dev eth0
lxc exec lxc-10 -- ip route add default via 10.2.1.254 dev eth0 
lxc exec lxc-12 -- ip link set eth0 up
lxc exec lxc-12 -- ip addr add 10.2.1.12/24 dev eth0
lxc exec lxc-12 -- ip route add default via 10.2.1.254 dev eth0
lxc list

cat > delete_lxc.sh <<EOF
# Delete container
#!/bin/bash
lxc delete -f lxc-2
lxc delete -f lxc-4
lxc delete -f lxc-6
lxc delete -f lxc-8
lxc delete -f lxc-10
lxc delete -f lxc-12
EOF

chmod 755 boot_lxc.sh delete_lxc.sh
sh -x boot_lxc.sh

# root@vtep-2:~# lxc list
# +--------+---------+------------------+------+------------+-----------+
# |  NAME  |  STATE  |       IPV4       | IPV6 |    TYPE    | SNAPSHOTS |
# +--------+---------+------------------+------+------------+-----------+
# | lxc-10 | RUNNING | 10.2.1.10 (eth0) |      | PERSISTENT | 0         |
# +--------+---------+------------------+------+------------+-----------+
# | lxc-12 | RUNNING | 10.2.1.12 (eth0) |      | PERSISTENT | 0         |
# +--------+---------+------------------+------+------------+-----------+
# | lxc-2  | RUNNING | 10.1.1.2 (eth0)  |      | PERSISTENT | 0         |
# +--------+---------+------------------+------+------------+-----------+
# | lxc-4  | RUNNING | 10.1.1.4 (eth0)  |      | PERSISTENT | 0         |
# +--------+---------+------------------+------+------------+-----------+
# | lxc-6  | RUNNING | 10.1.2.6 (eth0)  |      | PERSISTENT | 0         |
# +--------+---------+------------------+------+------------+-----------+
# | lxc-8  | RUNNING | 10.1.2.8 (eth0)  |      | PERSISTENT | 0         |
# +--------+---------+------------------+------+------------+-----------+

# Check Ping
lxc exec lxc-2 bash
ifconfig
ping 10.1.1.254
exit

動作検証

今回はRoute Leaking設定をしていないので異なるVRF配下のネットワーク(Case-3)には到達できない.

# VTEP-1
lxc exec lxc-1 bash
ping 10.1.1.2  # Case-1: 同じsubnet --> OK
ping 10.1.2.6  # Case-2: 異なるsubnet --> OK
ping 10.2.1.10 # Case-3: 異なるVRF --> Destination Unreachable
exit

確認コマンド

#-----------------------------------------
# common
#-----------------------------------------
tcpdump -i any port 4789 # VXLAN のパケット監視
tcpdump -i any port 179  # BGP/EVPN のパケット監視

#-----------------------------------------
# L2
#-----------------------------------------
bridge fdb show        # bridge の Forwarding DB の確認
bridge monitor link    # bridge のイベント監視
bridge monitor fdb
ip neighbor            # ARPテーブル確認
ip neighbor show dev br101001
ip -s neigh flush all  # ARPテーブル初期化

#-----------------------------------------
# L3
#-----------------------------------------
ip route show vrf vrf-1        # ルーティングテーブルの確認
vtysh -c "show running-config" # FRR の設定
vtysh -c "show bgp summary"    # BGP 情報
vtysh -c "show bgp evpn route" # EVPN 情報

考察: EVPN で Type-2 ルートが広報される条件

cumulus がleafスイッチの場合、配下のコンテナやVMで通信を発生させれば自動的に送信元と宛先のType-2ルート(/32)がルーティングテーブルに載ってくるのだが今回は挙動が異なる.
例えば上記動作検証のCase-1において、対向のVTEP配下のノードに通信を発生させても、送信元と宛先両方ともEVPNで経路広報の対象にならない. Case-2の場合は送信元10.1.1.1@VTEP1のType-2がVTEP-2に広報され、10.1.2.6@VTEP-2の経路はVTEP-1に広報されていない.

# Case-2 実施後のルーティングテーブル
root@vtep-1:~# ip route show vrf vrf-1
unreachable default metric 4278198272
10.1.1.0/24 dev br101001 proto kernel scope link src 10.1.1.254
10.1.2.0/24 dev br101002 proto kernel scope link src 10.1.2.254
# 10.1.2.6/32 のエントリが存在しない

root@vtep-2:~# ip route show vrf vrf-1
unreachable default metric 4278198272
10.1.1.0/24 dev br101001 proto kernel scope link src 10.1.1.254
10.1.1.1 via 192.168.0.1 dev br101000 proto bgp metric 20 onlink # <-- ホストルート
10.1.2.0/24 dev br101002 proto kernel scope link src 10.1.2.254

結論から言うと、FRRが稼働する物理サーバ側のip neighbor(ARPテーブル)にREACHABLEで一度エントリが載らないとEVPNで経路が広報されないということがわかった.

root@vtep-1:~# ip neighbor show dev br101001
10.1.1.1 lladdr 00:16:3e:c9:30:44 STALE # <-- エントリが存在
root@vtep-1:~# ip neighbor show dev br101002
10.1.2.6 lladdr 00:16:3e:e0:59:6b STALE

# エントリが存在しない
root@vtep-2:~# ip neighbor show dev br101001
root@vtep-2:~# ip neighbor show dev br101002

ip neighborにエントリを載せるにはそのサブネットのgatewayに対してARP Request/Replyの通信を発生させる必要があるようだ. Case-1の場合、同サブネット間の通信の通信はgatewayを経由しないので物理ホスト側のARPテーブルにはエントリが載らない. Case-2の場合、10.1.1.1から10.1.1.254へARPリクエストが発生するためARPテーブルにエントリが載る.これによりEVPN Type-2で対向VTEPに10.1.1.1/32の経路が載るようだ. しかしこの理屈だと、戻りの通信(10.1.2.6@VTEP2 --> 10.1.1.1@VTEP1)でも10.1.2.254へのARPリクエストが発生するので10.1.2.6/32の経路もEVPN Type2でVTEP1に広報されてもいい気がするのだが、なぜそうならないのかはコードをよく読まないとわからない.

このEVPN Type2がスムーズに広報されない問題を回避する最も簡単な方法は、コンテナ起動時に物理ホストから各コンテナに対して通信を意図的に発生させることである. Cumulus本家のPoC ではハイパーバイザ側からVMにpingしてEVPN Type2を強制的に広報させているように見える. 別のアプローチでこの問題をスマートに解決する有効なオプションや設定を現時点では見つけることができなかった(ので知ってる方いたらおしえてほしい).

LXCコンテナを削除した際には、BGP UPDATE(Withdrawn Routes)が広報されることにより、該当コンテナのホストルートはルーティングテーブルから削除される.この辺りの実装を見ると bridge fdb showip neighborを監視することでコンテナやVMの削除を検知していることがわかる.

Source NAT

VXLAN/EVPN に関係ないが GitLab: evpn-to-the-host の Future work にあった NAT もついでに検証する. LinuxでVRFを前提にNATするのは初ケースなので動作する設定を見つけ出すのに苦労した. 説明しづらいので図も添付する.

host-vtep-snat.png

まず物理ホストにて外部との接続を持つインターフェースをブリッジ(br0)に所属させる. 次にOverlay NetworkのパケットをどうにかしてUnderlay Networkに持っていくために、UnderlayのVRF(VRF-PUBLIC)を作成し仮のインターフェースを作成する(vrf_br0). FRRでRoute Leakingを設定し、デフォルトルートをVRF-PUBLICに向ける. あとはiptablesでSource NATをしてやれば、物理ホストのインターフェースを使用して外に出ることができる.
デフォルトルートでRoute LeakingをするのはCumulus のマニュアルによると非推奨だがとりあえず動作はした. デフォルトルートで無闇にリークしてしまうとVRFによる隔離が弱くなる可能性があるため、実際に使う際はよく考えてから設定する必要がある.

#----------------------------------------------------
# br0
#----------------------------------------------------
# Create a bridge
brctl addbr br0
brctl stp br0 off
ip link set dev br0 up
ip addr add 172.16.25.100/24 dev br0
sysctl -w net.ipv4.conf.br0.rp_filter=0
sysctl -p

# 管理インターフェースの ens33 を br0 に参加させる
# ens33 で接続していた通信は切れるので注意
ip addr flush dev ens33
brctl addif br0 ens33
ip link set dev ens33 up
ip route add default via 172.16.25.254 dev br0

#----------------------------------------------------
# VRF-PUBLIC
#----------------------------------------------------
# Set value
VRF_TABLE_ID=103000
PUBLIC_GATEWAY=172.16.25.254
VETH_PUBLIC_IP=172.16.25.101/24

# Create VRF
ip link add vrf-public type vrf table $VRF_TABLE_ID
ip link set vrf-public up

# Check (VRF status is UP)
ip -d link show vrf-public
ip route show vrf vrf-public
ip vrf show

# Create a Virtual cable (veth)
ip link add name vrf_br0 type veth peer name br0_vrf

# Connect (br0)*<-- (br0_vrf)
brctl addif br0 br0_vrf
ip link set br0_vrf up

# Connect (vrf_br0) -->*(VRF)
ip addr add $VETH_PUBLIC_IP dev vrf_br0
ip link set dev vrf_br0 master vrf-public
ip link set vrf_br0 up

# Set default route in VRF
ip route add table $VRF_TABLE_ID default via $PUBLIC_GATEWAY dev vrf_br0

# Check
brctl show
ip addr show vrf_br0
ip addr show vrf vrf-public
ip link show br0_vrf
ip route show vrf vrf-public
ping -I vrf_br0 $PUBLIC_GATEWAY


#-------------------------------------------------------
# (FRR) RouteLeaking
# vrf-1 && vrf-2 --> vrf-public
#-------------------------------------------------------
vtysh
conf t
vrf vrf-1
ip route 0.0.0.0/0 vrf-public nexthop-vrf vrf-public
vrf vrf-2
ip route 0.0.0.0/0 vrf-public nexthop-vrf vrf-public
end
write memory
exit

# Check
vtysh -c "show ip route vrf vrf-1"
vtysh -c "show ip route vrf vrf-2"
ip route show vrf vrf-1
ip route show vrf vrf-2

#--------------------------------------------------------
# SNAT (overlay --> public)
#--------------------------------------------------------
SNAT_IPADDR=$(ip -4 addr show br0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
echo $SNAT_IPADDR
iptables -t nat -A POSTROUTING -p all -s 10.1.1.0/24 -j SNAT --to-source $SNAT_IP_ADDR
iptables -t nat -A POSTROUTING -p all -s 10.1.2.0/24 -j SNAT --to-source $SNAT_IP_ADDR
iptables -t nat -A POSTROUTING -p all -s 10.2.1.0/24 -j SNAT --to-source $SNAT_IP_ADDR
iptables -t nat -L

# ping check
lxc list
lxc exec lxc-1 bash
ping 8.8.8.8
exit

物理サーバでルーティングできるので、任意のVRFをBGPでサーバまで伝搬させれば分散NATが可能となる.

おわり

結論として、ただのLinuxにFRRをインストールすることで、従来leafスイッチでやっていたEVPN+VXLANの処理をサーバエンドにオフロードすることができた. 数年前にOpenStack NeutronとNamespaceを駆使して実現できたことをBGPやVRFで置き換えているだけなのだが、SPOFが存在しないのでより洗練されたアーキテクチャになった. VXLANのオーバヘッドに懸念があるのでネットワーク性能は試験する必要がある. またセキュリティ(ACL)や細かい動作などを考慮していないので実用にはまだ遠い.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

アリババCloudを使って見ました。(hello worldまで)

image.png

環境:

・OS:Linux Ubuntu  14.04 64位
・Nginx
・Gunicorn
・supervisor

アリババcloudでECSを購入して、ssh接続方法でウェブサーバに接続できます。
ssh root@[IPアドレス]

 パースワードを入力すれば、こんな画面表示されます。
image.png

step1: pythonの環境の用意

・ウェブサーバの方は、python2があ李ますが、python3ないので、必要な場合はダウンロードするべき。
・自分のプロジェクトをFTP ソフトとか scpでコマンドでウェブサーバーアプロードします。
$ scp -r [localのpath] root@abc.com:[サーバーのpath]

step2: Gunicornのインストール

Gunicornは仮想環境を使うべき(virtualenv)

(venv) $ pip install gunicorn

Gunicornを実行する
gunicorn -w 4 -b 127.0.0.1:8000 「ファイル名」:app

ここでは簡単なhello.pyを実行してみます。

hello.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
    return 'hello world'
if __name__ == '__main__':
    from werkzeug.contrib.fixers import ProxyFix
    app.wsgi_app = ProxyFix(app.wsgi_app)
    app.run()

実行成功したら、 webサーバで訪問できます。
curl http://127.0.0.1:8000/

上のコマンドで、terminalで確かめることができます。

step3: nginxのインストール&環境設定

・nginxをインストール

$ sudo apt-get update
$ sudo apt-get install nginx
$ sudo chmod 777

・ngixnの環境設定

sudo cp /etc/nginx/site-avalidable/default /etc/nginx/site-avalidable/default.bak
sudo vim /etc/nginx/sites-avalidable/default

・相応な部分を編集します。

server {
    listen 80;
    server_name example.org; # ドメインまたは、IPアドレス

    location / {
        proxy_pass http://127.0.0.1:8080; # ここは gunicorn hostアドレス
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  }

設定した後、再実行します。
sudo service nginx restart

これで、OK。
ドメインとかIPアドレスで、自分のホームページを訪問できます。image.png

備考

・nginxコマンド

起動: sudo service nginx start
restart: sudo service nginx restart
stop: sudo service nginx stop
テスト: sudo service nginx configtest
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

wpa_supplicantのコード解説 ①起動

はじめに

LinuxのWi-Fi機能はwpa_supplicantを使用します。このwpa_supplicantはユーザー空間上で動作するデーモンプロセスであり、アプリケーションからのコマンドを受け付けたり、ドライバを制御したりします。その内部構造を知りたいと思い、ソースコードを調べてみました。今後もし余力があればスキャン、接続などの動作について調べようと思いますが、まずはwpa_supplicantの起動処理について記述します。

wpa_supplicantの起動方法

私のRaspberry Piではデフォルトでwpa_supplicantが起動しているので、一旦プロセスを落としてから起動しています。手順とコマンドは以下です。

  1. LinuxのWiFiをOFFにする
  2. wpa_supplicantを再起動し、CLIツールを起動
# sudo kill PID #wpa_supplicantのPIDを指定
# sudo wpa_supplicant -i wlan0 -c ./wpa_supplicant.conf &
# sudo wpa_cli -i wlan0 -p /var/run/wpa_supplicant

主に以下の起動オプションを設定します。

オプション 内容
-B バックグラウンドで起動(&を付けるのと同じ)
-c 設定ファイルのパス
-i インターフェース(wlan0等)
-d デバッグ出力を増やす(-ddでさらに増える)
-D ドライバを指定(nl80211等)
-N 複数の-i,-cを指定してConcurrent動作をするときに使う

設定ファイルであるwpa_supplicant.confは以下のものを使っています。

wpa_supplicant.conf
ctrl_interface=/var/run/wpa_supplicant
update_config=1

起動処理の一連の流れ

起動処理は以下のように進みます。各々は以降で説明していきます。

  1. コマンドラインオプションの読み取り・設定
  2. 共通部分の初期化(イベントループ、乱数生成、制御I/Fの初期化)
  3. 各Network I/Fの初期化(ドライバの設定、ステートマシンの初期化、制御I/Fの初期化)
  4. 動作開始(アプリとの接続、イベントループの開始)

コマンドラインオプションの読み取り・設定

main()の中で各オプションを読み取っています。
共通の設定はparamsを経由してwpa_supplicant_init()で行われます。インターフェースごとの設定はifaceを経由してwpa_supplicant_add_iface()で行われます。
-Nで二つ目のインターフェースがあることを指定すると、ifacesをreallocして、ifaceに二つ目のポインタを設定してオプションを読み取ります。paramsに代入するオプションはインターフェースごとに指定できません。

wpa_supplicant/main.c
int main(int argc, char *argv[])
{
//
    struct wpa_interface *ifaces, *iface; // intarfaceの設定
//
    struct wpa_params params; // 共通設定(一時変数)
    struct wpa_global *global; // 共通設定(グローバル変数)
//
    for (;;) {
        c = getopt(argc, argv,
               "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
        if (c < 0)
            break;
        switch (c) {
//
        case 'c':
            iface->confname = optarg; // 設定ファイルのパス
            break;
//
        case 'D':
            iface->driver = optarg; // ドライバ名(nl80211など)
            break;
        case 'd':
//
            params.wpa_debug_level--; // デバッグレベル
            break;
//
        case 'i':
            iface->ifname = optarg; // Network I/F名
            break;
//
        case 'N':
            iface_count++;
            iface = os_realloc_array(ifaces, iface_count,
                         sizeof(struct wpa_interface)); // 追加するinterface分のメモリを拡張
            if (iface == NULL)
                goto out;
            ifaces = iface; // ifacesは最初のinterfaceを指す
            iface = &ifaces[iface_count - 1]; // ifaceは追加したinterfaceを指す(この後、-i,-d等で設定)
            os_memset(iface, 0, sizeof(*iface));
            break;
//
    global = wpa_supplicant_init(&params); // paramsの内容をglobalにコピー。共通部分の初期化(後述)
//
    for (i = 0; exitcode == 0 && i < iface_count; i++) { // 各Network I/Fごとにループ
//
        wpa_s = wpa_supplicant_add_iface(global, &ifaces[i], NULL); // 各Network I/Fの初期化(後述)
//
    }
//
    if (exitcode == 0)
        exitcode = wpa_supplicant_run(global); // イベントループを起動

共通部分の初期化

共通部分の初期化はmain()から呼ばれるwpa_supplicant_init()で行います。
イベント処理、乱数生成、制御I/F(イベントを送受信するためのソケット)の初期化などを行います。

wpa_supplicant/wpa_supplicant.c
struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
{
//
    if (eloop_init()) { // イベントループの初期化
//
    random_init(params->entropy_file); // 乱数生成の初期化
//
    global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global); // 制御I/Fの初期化
//
}

wpa_supplicant_global_ctrl_iface_init()ではアプリと通信するために、ソケットを取得して接続しています。
ctrlにソケットのパスが入っています。

wpa_supplicant/ctrl_iface_unix.c
static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global,
                        struct ctrl_iface_global_priv *priv)
{
//
    priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); // ソケットの取得
//
    os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path)); // パス設定
    if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { // 接続
//

各Network I/Fの初期化

次はwlan0などのNetwork I/Fごとの設定を見ていきます。
Network I/Fの状態変数を取得して、DISCONNECTED状態として初期化します。

wpa_supplicant/wpa_supplicant.c
struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
                         struct wpa_interface *iface,
                         struct wpa_supplicant *parent)
{
    struct wpa_supplicant *wpa_s; // I/Fごとの状態変数
    struct wpa_interface t_iface;
//
    wpa_s = wpa_supplicant_alloc(parent);
//
    t_iface = *iface;
//
    if (wpa_supplicant_init_iface(wpa_s, &t_iface)) { // I/Fの初期化(後述)
//
    wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); // 未接続状態にして追加完了
//
    return wpa_s;
}

次はwpa_supplicant_init_iface()の中身です。
-cで指定した設定ファイルの読み込み、-Dで指定したドライバの設定、状態の初期化などをしています。

wpa_supplicant/wpa_supplicant.c
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                     const struct wpa_interface *iface)
{
//
        wpa_s->conf = wpa_config_read(wpa_s->confname, NULL); // -cで指定した設定ファイルの読み込み
//
    if (wpas_init_driver(wpa_s, iface) < 0) // ドライバの設定(後述)
//
    if (wpa_supplicant_init_wpa(wpa_s) < 0) // WPAステートマシン、コールバック(ctx)の設定
//
    if (wpa_supplicant_driver_init(wpa_s) < 0) // 初期状態を設定
//
    wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s); // Network I/Fごとのソケットの初期化
//
}

ドライバの設定についてもう少し詳しく見ていきます。
wpa_driver[]にwpa_driver_xxx_ops(各ドライバのコールバック関数)の一覧があり、各opsの中身はdriverフォルダ以下のソースコードで実装されています。-Dオプションの内容から適切なopsを探し出して設定しています。

wpa_supplicant/wpa_supplicant.c
static int wpas_init_driver(struct wpa_supplicant *wpa_s,
                struct wpa_interface *iface)
{
//
    if (wpa_supplicant_set_driver(wpa_s, driver) < 0) // driverは-Dで指定した内容(nl80211など)
//
    wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname); // wpa_s->driver->init2を呼び出す(後述)
//
}

static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
                     const char *name)
{
//
        for (i = 0; wpa_drivers[i]; i++) {
            if (os_strlen(wpa_drivers[i]->name) == len &&
                os_strncmp(driver, wpa_drivers[i]->name, len) == // wpa_driversとdriver(nl80211等)を照合
                0) {
                /* First driver that succeeds wins */
                if (select_driver(wpa_s, i) == 0) // 見つかれば関数を登録
                    return 0;
            }
        }
//
}

static int select_driver(struct wpa_supplicant *wpa_s, int i)
{
//
    wpa_s->driver = wpa_drivers[i]; // 関数を登録
//
}

wpa_driver[]は以下で定義されています。
デフォルトだと一番上のwpa_driver_nl80211_opsが指定されます。
前述したwpas_init_driver()でwpa_s->driver->init2()が呼ばれていますが、このinit2()もopsで定義されています。

src/drivers/drivers.c
const struct wpa_driver_ops *const wpa_drivers[] =
{
#ifdef CONFIG_DRIVER_NL80211
    &wpa_driver_nl80211_ops,
#endif /* CONFIG_DRIVER_NL80211 */
//
};

動作開始

最後にアプリと結合(ATTACH)して、イベントループを開始します。
main()から呼ばれるwpa_supplicant_run()で処理を行います。
wpa_cliなどのアプリからの結合が終わればイベントループを開始します。

wpa_supplicant/wpa_supplicant.c
int wpa_supplicant_run(struct wpa_global *global)
{
//
    if (global->params.daemonize &&
        (wpa_supplicant_daemon(global->params.pid_file) || // -Bオプションがあればデーモンとする
//
    if (global->params.wait_for_monitor) {
        for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
            if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
                wpa_supplicant_ctrl_iface_wait( // アプリとの結合待ち(後述)
                    wpa_s->ctrl_iface);
    }
//
    eloop_run(); // イベントループの開始
//
}

以下のwpa_supplicant_ctrl_iface_wait()にてアプリからのATTACHコマンドを待ちます。ソケットから最初のコマンドを受け取り、ATTACHであればアプリと結合します。

wpa_supplicant/ctrl_iface_unix.c
void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
{
//
    for (;;) {
//
        eloop_wait_for_read_sock(priv->sock);

        res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0, // ソケットからコマンドを受け取る
                   (struct sockaddr *) &from, &fromlen);
//
        if (os_strcmp(buf, "ATTACH") == 0) { // ATTACH以外受け付けない
            /* handle ATTACH signal of first monitor interface */
            if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
                                  &from, fromlen,
                                  0)) {
                if (sendto(priv->sock, "OK\n", 3, 0, // ATTACH成功ならOKを返す
                       (struct sockaddr *) &from, fromlen) <
//
}

まとめ

基本的にwpa_supplicantはアプリ又はドライバからのイベント駆動のプロセスなので、起動中にイベントループの初期化、アプリ・ドライバとの結合部分の初期化をするものだと思えば良いかもしれません。起動の処理中で出てきたイベントループ、wpa_sといった状態変数はスキャン、接続などの動作でも今後出てくるかと思います。

以上がwpa_supplicantの起動処理の説明となります。
記事をお読み頂きありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Linux(Ubuntu18.04.1)でGitBucketを実行してみる(Linux初心者)(その①)

Gitでプルリクエストを使いたいのでLinux初心者が順に環境構築してみた。

プルリクエストをするにはGitHubを使えるようにしたい。

  • 社内で使えるか確認したところ、部課長を納得させる説明が必要とのこと。(ソースを社外に置くリスクやら、社内ポリシーに沿った運用方法等…)
  • Gitすら知らないステークホルダーたちに対して利点とリスク、はたまた運用方法まで縛られるのは時間の無駄と判断
  • ほかにやりようがないか調査すると、社内LAN内で動かせるタイプもあるのを確認。

社内に環境構築できるタイプにしよう

  • 候補はGitLab,GitBucket
  • 両方ともLinux上で動くソフトウェア
  • Linux触ったことないな、GitLabは何やら構築が難しい?GitBucketはJavaがあれば簡単に動く?なるほど。教育コストが少ないLinux-GitBucketでやってみよう。

Linuxの選定

  • CentOS?RedHat??
  • Ubuntu?
  • Windows10のHyper-Vのクイック作成機能にUbuntuってのがある
  • UbuntuはデスクトップPCとしてLinuxを使う場合にオススメ
  • CentOSはサーバとしてLinuxを立てる場合にオススメ
  • よし、Ubuntuってのにしてみよう

Hyper-Vクイック作成でUbuntuをセットアップ

  • 全部英語...
  • 日本語にするには...パッチをインストールして...
    ⇒なぜか知らないがコマンドを見様見真似してるうちにUbuntuが動かなくなる。
  • 日本のチームが作ったUbuntuがある!?
    「Ubuntu Desktop 日本語 Remix」「ubuntu Japanese Team」
  • https://www.ubuntulinux.jp/home

GitBucketを見様見真似でインストールしてみる


Javaをインストールする必要がある。以下のコマンドを実行する。

add-apt-repository ppa:webupd8team/java

apt-get update

apt-get install oracle-java8-installer

いきなりわからないので調べながら実施。

  • [add-apt-repository]
    ubuntuはaptitude(apt)を使ってパッケージ管理している。その公式リポジトリは「etc/apt/sources.list」   非公式なリポジトリは「add-apt-repository」を使って追加することができる。   追加したリポジトリは「etc/apt/sources.list.d」にある。
  • [apt-get update]
    apt-get で パッケージを取得してインストール/アップデートすること。
    update で サーバからパッケージリストを入手する。
  • [apt-get install oracle-java8-installer]
    install で パッケージをインストールする。

じゃあ、実行。

  • エラー: root で実行する必要があります

    管理者ってことかと思ってみると

    ubuntuはrootを初期構築時に作らないとのこと。

    CentOS等だと[su rootのパスワード]でrootに昇格できるとか。(rootになってると $ が # になるとか)
    ubuntuの場合はsudoを使って毎回実行するという記載を発見。試しに以下構文を実行

    [sudo add-apt-repository]

    ユーザのパスワードを聞かれたのでうまくいってると判断。続行する。

  • apt-get install oracle-java8-installerが途中で止まって焦った
    72%で10分くらい停止。あああああ。って思って対処法を調べまくってたらいつの間にか失敗を検知して再ダウンロードを始めてた。すごい。

次はGitBucketをダウンロードする。以下のコマンドを実行する。

wget https://github.com/gitbucket/gitbucket/releases/download/4.30.1/gitbucket.war

※releasesのページに飛んでバージョンがいくつになってるか確認してから実行すること。

わからないので調べながら実施。

  • [wget]
    HTTP/HTTPSなどを介してデータをまとめて取得するコマンド。windowsにもあるみたい。
    もしかしてこれ使えば自動ダウンロードのソフトウェアとか作れるのかな?
    面白そう。後で調べてみよう。
  • 好きなフォルダに配置するのだがフォルダが作れない。
    権限がないのだとわかりsudo mkdirする。
    そのフォルダにも権限がない。
    よくわからないので少し調査。
    (今回はダウンロードフォルダにダウンロード)

次はGitBucketを単体で実行する。以下のコマンドを実行する。

java -jar gitbucket.war

起動を確認するためにhttpで接続する。

http://localhost:8080.gitbucket

今回はここまで。

とりあえず動くところまで行ったので一旦終了。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Elasticsreachのデータ暗号化

はじめに

Elasticsearchのデータ暗号化について、検討する機会があったので、記事にまとめてみました^^:

利用した環境

product version
cryptsetup 1.7.4
Elasticsearch 6.6.0
OS Amazon Linux2 (4.14.88)
Instance Type m5.2xlarge
EBS ルート(8GB)、追加(30GB)
AMI ami-04677bdaa3c2b6e24

【ディスクの状態】
nvme0n1が8GBのルートボリューム、nvme1n1が追加の30GBボリュームです。
※m5はNitro世代のEC2インスタンスでEBS NVMeボリュームのため、/dev/nvmeXnXという名称

[root@ip-172-31-34-49 ~]# lsblk
NAME          MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nvme1n1       259:0    0  30G  0 disk 
nvme0n1       259:1    0   8G  0 disk 
├─nvme0n1p1   259:2    0   8G  0 part /
└─nvme0n1p128 259:3    0   1M  0 part 

[root@ip-172-31-34-49 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs         16G     0   16G   0% /dev
tmpfs            16G     0   16G   0% /dev/shm
tmpfs            16G  388K   16G   1% /run
tmpfs            16G     0   16G   0% /sys/fs/cgroup
/dev/nvme0n1p1  8.0G  1.2G  6.9G  15% /
tmpfs           3.1G     0  3.1G   0% /run/user/1000

基本的な考え方

Elasticsearchのデータ(=Index)暗号化では、日立ソリューションズ社のCredeon Secure Full-text Searchがありますが、あくまで全文検索のためのIndex暗号化であって、Kibanaが利用するaggregation機能には対応していません。

ElasticStackでは5.3.0から保存データの暗号化に対応しています。
サブスクリプションのPlatinum Editionで対応していますが、あくまでdm-cryptを用いたボリュームの暗号化を利用した場合でもElasticsreachとしてサポートするというものです。暗号化機能が付いている訳ではありません。

dm-cryptとは

Device-Mapperの機能の1つでLinuxにおけるブロックデバイス暗号の仕組みです。
Kernel 2.6以降のdevice-mapperモジュールに標準で組み込まれていて、cyptsetupという暗号化管理ツールを使ってストレージデバイスの暗号化を行います。
dmcrypt.PNG

【参考】
LUKSとは?

設定手順

  1. Java 1.8.0 インストール
  2. Elasticsearch 6.6.0 インストール
  3. JVMヒープサイズ設定
  4. Elasticsreach設定
  5. 暗号化ボリュームの設定
  6. Index保存領域の作成
  7. 設定確認

1. Java 1.8.0 インストール

Javaがインストールされていないことを確認した上でJava 1.8.0をインストールします。

[root@ip-172-31-34-49 ~]# java -version
-bash: java: command not found

[root@ip-172-31-34-49 ~]# yum install -y java-1.8.0-openjdk
<インストールの経過は省略>

[root@ip-172-31-34-49 ~]# java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)

2. Elasticsearch 6.6.0 インストール

Elastic社公式のリポジトリを登録し、Elasticsearch 6.6.0をインストールします。

[root@ip-172-31-34-49 ~]# vi /etc/yum.repos.d/elastic.repo
[root@ip-172-31-34-49 ~]# cat /etc/yum.repos.d/elastic.repo
[elasticsearch-6.x]
name=Elasticsearch repository for 6.x packages
baseurl=https://artifacts.elastic.co/packages/6.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

[root@ip-172-31-34-49 ~]# yum install -y elasticsearch
<インストールの経過は省略>

[root@ip-172-31-34-49 ~]# systemctl status elasticsearch
● elasticsearch.service - Elasticsearch
   Loaded: loaded (/usr/lib/systemd/system/elasticsearch.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
     Docs: http://www.elastic.co

3. JVMヒープサイズ設定

Elasticsreachには物理メモリの半分を上限にJVMヒープを割り当てます。
m5.2xlargeのメモリは32GBなので、今回は15GBのメモリを割り当てます。

[root@ip-172-31-34-49 ~]# vi /etc/elasticsearch/jvm.options
-Xms15g
-Xmx15g
# 以下、設定の確認です。
[root@ip-172-31-34-49 ~]# cat /etc/elasticsearch/jvm.options | grep 15

4. Elasticsreach設定

ElasticsearchのIndex保存領域をpath.dataで指定します。今回は/mnt/es/elasticsearchとします。

[root@ip-172-31-34-49 ~]# vi /etc/elasticsearch/elasticsearch.yml
path.data: /mnt/es/elasticsearch
# 以下、設定の確認です。
[root@ip-172-31-34-49 ~]# cat /etc/elasticsearch/elasticsearch.yml | grep path.data

5. 暗号化ボリュームの設定

cryptsetupコマンドで/dev/nvme1n1にAES256/SHA1暗号化ボリューム(esvol)を作成し、/mnt/esにマウントします。

[root@ip-172-31-34-49 ~]# cryptsetup --key-size 512 --hash sha512 luksFormat /dev/nvme1n1

WARNING!
========
This will overwrite data on /dev/nvme1n1 irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase: #パスワードを設定
Verify passphrase: #パスワードの確認

[root@ip-172-31-34-49 ~]# cryptsetup luksOpen /dev/nvme1n1 esvol
Enter passphrase for /dev/nvme1n1: #上記で設定したパスワードを入力

[root@ip-172-31-34-49 ~]# ls /dev/mapper
control  esvol

[root@ip-172-31-34-49 ~]# mkfs.ext4 /dev/mapper/esvol
mke2fs 1.42.9 (28-Dec-2013)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
1966080 inodes, 7863808 blocks
393190 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=2155872256
240 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, 2654208, 
        4096000

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

[root@ip-172-31-34-49 ~]# mount /dev/mapper/esvol /mnt/es
[root@ip-172-31-34-49 ~]# ll /mnt
total 4
drwxr-xr-x 3 root root 4096 Feb 10 18:29 es

暗号化ボリュームが作成されていることを確認します。

[root@ip-172-31-34-49 ~]# lsblk
NAME          MAJ:MIN RM SIZE RO TYPE  MOUNTPOINT
nvme1n1       259:0    0  30G  0 disk  
└─esvol       253:0    0  30G  0 crypt /mnt/es
nvme0n1       259:1    0   8G  0 disk  
├─nvme0n1p1   259:2    0   8G  0 part  /
└─nvme0n1p128 259:3    0   1M  0 part

[root@ip-172-31-34-49 ~]# df -h
Filesystem         Size  Used Avail Use% Mounted on
devtmpfs            16G     0   16G   0% /dev
tmpfs               16G     0   16G   0% /dev/shm
tmpfs               16G  392K   16G   1% /run
tmpfs               16G     0   16G   0% /sys/fs/cgroup
/dev/nvme0n1p1     8.0G  1.5G  6.6G  19% /
/dev/mapper/esvol   30G   45M   28G   1% /mnt/es
tmpfs              3.1G     0  3.1G   0% /run/user/1000

6. Index保存領域の作成

/mnt/es配下にelasticsearchディレクトリを作成し、適切な権限を付与します。

[root@ip-172-31-34-49 elasticsearch]# cd /mnt/es
[root@ip-172-31-34-49 es]# mkdir elasticsearch
[root@ip-172-31-34-49 es]# chown elasticsearch:elasticsearch elasticsearch/
[root@ip-172-31-34-49 es]# chmod 750 elasticsearch/
[root@ip-172-31-34-49 es]# ll
total 20
drwxr-x--- 2 elasticsearch elasticsearch  4096 Feb 10 21:47 elasticsearch
drwx------ 2 root          root          16384 Feb 10 18:29 lost+found

Elasticsearchをサービス起動し、path.data配下にNodeIDファイル(node-0.st)が生成されていることを確認します。

[root@ip-172-31-34-49 es]# systemctl start elasticsearch
[root@ip-172-31-34-49 es]# cat elasticsearch/nodes/0/_state/node-0.st
?lstate:)
node_idUWTgg6zqmS2Cq72YdCOdCpA(

7. 設定確認

  • 暗号化した30GBの追加EBSボリュームのSnapshotを作成します。
  • 作成したSnapshotから別途EBSボリュームを作成し、別EC2にアタッチします。

EBSをアタッチしたEC2にログインし、追加EBSとしてnvme1n1が存在していることを確認します。

[root@ip-172-31-6-22 ~]# lsblk
NAME          MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
nvme0n1       259:0    0  100G  0 disk 
├─nvme0n1p1   259:1    0  100G  0 part /
└─nvme0n1p128 259:2    0    1M  0 part 
nvme1n1       259:3    0   30G  0 disk 

[root@ip-172-31-6-22 ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        3.8G     0  3.8G   0% /dev
tmpfs           3.8G     0  3.8G   0% /dev/shm
tmpfs           3.8G  380K  3.8G   1% /run
tmpfs           3.8G     0  3.8G   0% /sys/fs/cgroup
/dev/nvme0n1p1  100G  2.2G   98G   3% /
tmpfs           763M     0  763M   0% /run/user/1000

/mnt/esにマウントし、内容を確認してみます。

[root@ip-172-31-6-22 ~]# mkdir /mnt/es
[root@ip-172-31-6-22 ~]# mount -o discard /dev/nvme1n1 /mnt/es
mount: /mnt/es: unknown filesystem type 'crypto_LUKS'.

まとめ

LUKSで暗号化したボリュームを他マシンにマウントしても認識しませんでした。
これでElasticsreachノードにログインされない限り、OSレベルでのIndexデータの機密性は確保できました。

ElasticsreachのData Nodeをi3系インスタンスで構築し、NVMe SSDにIndexを配置することで暗号化することも可能です。

NVMe インスタンスストレージのデータは、インスタンスのハードウェアモジュールに実装されている XTS-AES-256 ブロック暗号を使用して暗号化されます。暗号化キーは、ハードウェアモジュールで作成され、NVMe インスタンスストレージデバイスごとに固有です。すべての暗号化キーは、インスタンスが停止または終了して復元できないときに破棄されます。この暗号化を無効にしたり、独自の暗号キーを指定したりすることはできません。

以上、いかがでしたでしょうか。
不明な点、誤植などありましたら、コメントをお願いします!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む