Linux | Network Manager中的Secret Agent

2021 01 15, Fri

K8S那边昨晚上刚刚搞清楚怎么写Controller,整理一下了我周末再写博客。今天休息一下写点别的。

之前在坚果云的时候我们就注意到过NetworkManager在图形化环境中配置密码,配置文件没有密码的情况。当时注意到一个参数可能影响了存储过程。最近做的工作一部分和这里有关系,稍微记录一下。

NetworkManager

Network Manager是什么

我抄录一下Arch Wiki对NM的描述

网络管理器(NetworManager)是检测网络、自动连接网络的程序。无论是无线还是有线连接,它都可以令您轻松管理。对于无线网络,网络管理器优先连接已知的网络并可以自动切换到最可靠的无线网络。利用网络管理器的程序可以自由切换在线和离线模式。网络管理器会相对无线网络优先选择有线网络,支持 VPN。网络管理器最初由 Redhat 公司开发,现在由 GNOME 管理。

警告: 请注意, Wi-Fi 的密码默认情况下是明文保存的。参见 #加密的Wi-Fi密码

NM其实就是管理网络状态的工具,比如说有线连接状态啊、无线连接状态啊、连接密码啊、VPN配置啊这些都可以管。我们就不需要一个个工具单独学着配置了。这玩意儿也是RedHat认证要考的东西。

比较有意思的是后面这句警告,Wifi密码默认情况下是明文保存的。今天说的东西和这里有关。

Network Manager交互

Network Manager有很多客户端,比如说自带的nmcli、nmtui,是两个NetworkManager自己的命令行客户端。

Gnome桌面环境中自带NetworkManager的客户端,会把网络信息在App Indicator的位置和用户之类的信息一起展示出来。Deepin似乎也是内嵌到桌面环境里面。

其他桌面中一般也都有NetworkManager的applet作为图形化客户端,比如说plasma-nm、nm-applet、networkmanager-dmenu之类的。

NetworkManager的使用教程太多了,而且客户端工具经常更新,有问题可以自己查阅资料学习怎么配置。

除了命令行和图形化客户端,NetworkManager也可以通过DBus来交互,一般是在SystemBus的org.freedesktop.NetworkManager这个端点上。上面说的大部分的客户端,理论上也是利用DBus来和NM交互的。

Network Manager基本交互流程

既然NM是管理连接状态的,那么就要维护这些连接的状态。

一般来说Network Manager从零到启动一个连接,有这么几步

  • 建立Connection Profile
  • 一个连接的生命周期
    • (初始)未连接
    • 激活
    • 尝试连接
      • 从配置文件读取信息
      • 调用各种工具建立连接
      • 失败后回到未连接
    • 连接
    • 取消激活
    • 断开

Network Manager存储

上面提到Wi-Fi 的密码默认情况下是明文保存的是因为,Network Manager的所有信息,在NM自己作为独立的网络管理工具的时候,都在/etc/下明文保存。比如说,通过nmtui配置的一个Wifi连接,那么Wifi的SSID和密码都会明文保存在配置文件里面,文件只能由root或者有权限的用户读到。这部分配置在DBus中都是由org.freedesktop.NetworkManager/org/freedesktop/NetworkManager/Settings对象的org.freedesktop.NetworkManager.Settings接口管理的。

这种情况在密码只有管理员的情况下是非常理想的,因为只有管理员有这个权限管理密码,而且文本文件非常好管理。在老东家的时候作为运维我是希望这么管理配置的。但是不是所有人的需求都如此。

设想一下有一台公共的机器,有几个人有多个用户,每个人都希望自己的密码只有自己知道,别人包括管理员都不应该知道这个密码。这种情况存到文本文件里面就不合适了。

针对这种情况,Network Manager设计了一个接口、由第三方实现,自己提供一个org.freedesktop.NetworkManager.AgentManager,管理这些第三方的实现。这个接口叫Secret Agent。

Secret Agent

是什么

Private D-Bus interface used by secret agents that store and provide secrets to NetworkManager. If an agent provides secrets to NetworkManager as part of connection creation, and the some of those secrets are “agent owned” the agent should store those secrets itself and should not expect its SaveSecrets() method to be called. SaveSecrets() will be called eg if some program other than the agent itself (like a connection editor) changes the secrets out of band. The agent should implement this D-Bus interface on an object with the path /org/freedesktop/NetworkManager/SecretAgent.

根据Gnome的定义,Secret Agent是用来储存和提供密码的一个私有接口,可以为一个connection提供一些秘密的信息。

交互流程

更新一下上面的流程。

加入Secret Agent后,上面的流程会稍微变化一些

  • 当前Session中的Secret Agent向Network Manager注册自己
  • 建立Connection Profile
  • 一个连接的生命周期
    • (初始)未连接
    • 激活
    • 尝试连接
      • 从配置文件读取信息
      • 调用各种工具建立连接
        • 如果需要从外部取回秘密
          • 向Secret Agent获取Secret
      • 失败后回到未连接
      • 需要时更新Secret
        • 向Secret Agent存储Secret
    • 连接
    • 取消激活
    • 断开

各个环境的实现

根据描述,我们实际上可以知道,Secret Agent就是一个独立于NM的程序,连接SystemBus后,向NM的Agent Manager注册了自己。在需要的时候NM会调用这个程序,获取信息。所以各个平台唯一不一样的就是两个事情,一个是怎么展示的图形界面,一个是用了什么存储后端。

nmcli可以作为secret agent运行,也可以作为polkit agent运行,或者二者一起,是用c实现的。作为Secret agent运行时用readline读取信息,似乎不存储信息。

Gnome和nm-applet都是C的,比较难读,但是逻辑都比较相近。Gnome是通过Gnome Shell直接展示一个模态框,nm-applet是通过glib打开了一个gtk的dialog。存储后端都是gnome-keyring。

KDE的plasma-nm是一个QML程序,由kded直接加载,逻辑是用C++实现的,交互是用QDialog,存储用了kwallet。

题外话1: 自己实现一个Agent

下次我们可以试着自己实现一个SecretAgent,用其他的keystore来存储密文。

题外话2:Polkit Agent

提到Polkit Agent,忽然想起来AgentManager - Agents这种方法管理信息的,还有一个PolicyKit。下次可以写写。