🧗‍♀️

[Ansible] community.general.nmcliモジュールのv6アドレス生成方式問題

2023/04/06に公開

Ansible の NetworkManger モジュールについて

Ansibleはコミュニティモジュールとしてnmcli (NetworkManager) を通じたネットワーク設定をサポートしている。

RedHatはRHEL8以来、 /etc/sysconfig/network-scripts/*を直接修正することをオススメしていないため、RHEL系のOSでネットワーク設定自動化をしたいときには、community.general.nmcli モジュールを利用することになる. (もちろん、/etc/sysconfig/network-scripts/ifcfg-*を設定している現場以外の話ではある)

しかし、このモジュール、v6まわりのエラーメッセージにクセがあるような気がする。
以下、困った点についてレポートする。

実施環境

今回の事象に関わるソフトウェアとそのバージョンの組み合わせは以下の通り。他の環境でも再現するかも。

管理機

  • ansible: 2.14.4
  • python: 3.11.2

管理対象ノード (Rocky Linux 9.1)

  • python: 3.9.14
  • NetworkManager: 1.40.0-1.el9

ipv6.addr-gen-mode が不正?どゆこと

2本目のNICに対するv6無効化ネットワークの初期化に際して、SLAACのアドレス生成モード周りのエラーメッセージが発生して参った。

fatal: [o_bk2]: FAILED! => {"changed": false, "msg": "Error: Failed to add 'con-enp0s3' connection: ipv6.addr-gen-mode: property is invalid\n", "name": "con-enp0s3", "rc": 4}

このときのタスクは以下の通り。iifip_addrは、適当に外部から値を入れる。(インベントリに書いてあったりする。)

#.... 抜粋 ...
    - name: add ether net ipv4 connection
      community.general.nmcli:
        conn_name: 'System {{ iif }}'
        ifname: '{{ iif }}'
        type: ethernet
        ip4: '{{ ip_addr }}'
        method6: ignore
        state: present
        autoconnect: true

IPv6を明示的に無効化しているのに,v6で文句を言われるのは筋違いだと思った。

結論

デバッグ出力を特盛でオーダーすると、真相が見えてきた。Ansibleの nmcli モジュールでは、IPv6が無効として指定された場合にもv6のアドレス生成モードをデフォルトでdefaultとして設定しているようだ。

fatal: [o_bk_2]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "addr_gen_mode6": "default",
            "ageingtime": 300,
            "arp_interval": null,
            "arp_ip_target": null,
            "autoconnect": true,
            "conn_name": "System ens4",
            "dhcp_client_id": null,
            "dns4": null,
            "dns4_ignore_auto": false,
#...以下略

この仕様は、Ansibleのドキュメントに載っていない。

https://docs.ansible.com/ansible/latest/collections/community/general/nmcli_module.html#parameter-addr_gen_mode6

つまり、nmcliモジュールのタスクを addr_gen_mode6未指定で実行すると、デフォルトでdefaultが指定されてしまうため、eui64stable-privacy 以外のアドレス生成をサポートしない特有の環境では、ネットワークインターフェースの初期化に失敗する。(nmcli経由でIPv6を無効としても、net.ipv6.conf.all.disable_ipv6 = 1としても、この問題が発生する)

この問題を回避するための方法は以下の通り。
addr_gen_mode6 に eui64 もしくは stable-privacy を明示的に指定してIFを初期化する。

- name: change network configuration for VPC hosts (RHEL)
  hosts: backend
  become: true
  tasks:
    - name: Try nmcli add Ethernet - conn_name only & ip4 gw4
      community.general.nmcli:
        conn_name: 'System {{ iif }}'
        ifname: '{{ iif }}'
     addr_gen_mode6: eui64
        type: ethernet
        ip4: '{{ iip_addr }}'
        method6: ignore
        state: present
        autoconnect: true

ref

/etc/sysconfig/network-scripts on RHEL: もーすこし延命するはず...
https://www.redhat.com/en/blog/rhel-9-networking-say-goodbye-ifcfg-files-and-hello-keyfiles

SLAAC related:
https://www.rfc-editor.org/rfc/rfc4862.txt
https://en.wikipedia.org/wiki/IPv6_address#Stateless_address_autoconfiguration

Ansible
https://docs.ansible.com/ansible/latest/collections/community/general/nmcli_module.html#parameter-addr_gen_mode6

追補: ipv6.addr-gen-mode に関するNetworkManagerの内部仕様

この問題は国内某クラウドのRocky Linux 9.1で再現する。

ちなみに、最近のDebian Bullseyeの NetworkManager (0.13.6) では、デフォルトのアドレス生成方式はEUI64。つまりIPv6対応のISPをご契約のご家庭で、デフォルト設定のNetworkManagerを有効化したDebianをONU直下に接続すると、stable-privacyが適用されない。

あたらしめのNetworkManagerでは default-or-eui64 になっており、Rocky Linux 9.1で
も、デフォルトではこのアドレス生成方式が選択される。(これもダメみたい)。
AnsibleだけでもEUI64デフォにしたほうが保守的でインフラ屋っぽい選択な気がするけど...単に我々が追随できていないだけなのだろうか

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/libnm-core-impl/nm-setting-ip6-config.c#L924

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/1.30.6/libnm-core/nm-setting-ip6-config.c#L871
~

Discussion