客户端授权

网络后端使用 TLS 证书或 SASL 时,客户端证明身份即可访问。如果身份数据库 仅包含 QEMU 客户端,这可能足够。但数据库通常范围更广,仅认证不足以限制 访问,因此 QEMU 提供认证后执行细粒度授权的灵活机制。

身份提供者

目前两种认证框架会在完成时产生身份:

  • TLS X.509 证书的可分辨名称。

    TLS 服务器可使用不同凭据,最常见是 X.509。最简单配置只为服务器签发 证书,让客户端防范针对目标服务器的中间人攻击。

    也可要求客户端提供证书,实现双向验证。将 tls-creds-x509 的 verify-peer=yes 即可,这也是默认值。

    启用对端验证后,客户端证书需由与服务器相同的 CA 签发。如果仍不够 严格,可进一步用证书可分辨名称作为 QEMU 授权身份。

  • SASL 用户名。

    SASL 认证成功后会提供用户名,格式取决于机制。可能是普通 UNIX 风格的 joebloggs,也可能在 Kerberos/GSSAPI 中带领域,如 joebloggs@QEMU.ORG。 无论形式如何,都可交给授权框架。

授权驱动

通用授权框架支持用户可定制的驱动,以对象形式提供。启动时用 -object, 运行时用 object_add 创建。

简单匹配

此驱动通过与单个身份精确匹配授予访问,适合只允许一个客户端的情况。

例如接收热迁移时,预期来源 QEMU 已知,可匹配其 X.509 身份。或者虚拟机 专供某租户使用,VNC 启用 SASL 并仅列出该租户用户名。

通过 QMP 创建:

{
  "execute": "object-add",
  "arguments": {
    "qom-type": "authz-simple",
    "id": "authz0",
    "identity": "fred"
  }
}

或命令行:

-object authz-simple,id=authz0,identity=fred

列表

需要允许多个客户端时,可用列表规则匹配身份。每条规则有对应策略,无规则 命中时采用默认策略。支持精确字符串或 Shell 风格 glob 通配匹配。

通过 QMP 创建:

{
  "execute": "object-add",
  "arguments": {
    "qom-type": "authz-list",
    "id": "authz0",
    "rules": [
       { "match": "fred", "policy": "allow", "format": "exact" },
       { "match": "bob", "policy": "allow", "format": "exact" },
       { "match": "danb", "policy": "deny", "format": "exact" },
       { "match": "dan*", "policy": "allow", "format": "glob" }
    ],
    "policy": "deny"
  }
}

由于需要设置嵌套属性,命令行必须采用 -object 的 JSON 语法。不过,多数 情况下下一种驱动更适合。

列表文件

这是列表驱动的变体,将规则放在独立文件,变更后可自动重载,使策略更动态。

通过 QMP 创建:

{
  "execute": "object-add",
  "arguments": {
    "qom-type": "authz-list-file",
    "id": "authz0",
    "filename": "/etc/qemu/myvm-vnc.acl",
    "refresh": true
  }
}

refresh 为 yes 时,用 inotify 监视文件变化并自动重载。

myvm-vnc.acl 格式与前一驱动接近:

{
  "rules": [
    { "match": "fred", "policy": "allow", "format": "exact" },
    { "match": "bob", "policy": "allow", "format": "exact" },
    { "match": "danb", "policy": "deny", "format": "exact" },
    { "match": "dan*", "policy": "allow", "format": "glob" }
  ],
  "policy": "deny"
}

命令行创建:

-object authz-list-file,id=authz0,\
        filename=/etc/qemu/myvm-vnc.acl,refresh=on

PAM

需要接入 QEMU 外部授权机制时,可使用 PAM 驱动以获得最大灵活性。

通过 QMP 创建:

{
  "execute": "object-add",
  "arguments": {
    "qom-type": "authz-pam",
    "id": "authz0",
    "parameters": {
      "service": "qemu-vnc-tls"
    }
  }
}

驱动只使用 PAM account 验证子系统。上例需要 /etc/pam.d/qemu-vnc-tls。 简单的文件查找配置可以是:

account requisite  pam_listfile.so item=user sense=allow \
        file=/etc/qemu/vnc.allow

外部文件保存用户名列表。若以 X.509 证书作为用户名,条目应匹配可分辨名称:

CN=laptop.berrange.com,O=Berrange Home,L=London,ST=London,C=GB

命令行创建:

-object authz-pam,id=authz0,service=qemu-vnc-tls

还有许多未在此列出的 PAM 插件,也可以使用 PAM API 开发新插件。

连接后端

用 -object 创建授权驱动后,还需关联网络服务。对象有唯一 ID,服务引用此 ID。

设置的属性随身份类型不同而变化。按惯例,TLS 后端提供 tls-authz,SASL 后端提供 sasl-authz。

VNC 使用 SASL 和授权的示例:

$QEMU --object authz-simple,id=authz0,identity=fred \
      --vnc 0.0.0.0:1,sasl,sasl-authz=authz0

同时验证 X.509 证书和 SASL 用户名:

echo "CN=laptop.qemu.org,O=QEMU Project,L=London,ST=London,C=GB" >> tls.acl
$QEMU --object authz-simple,id=authz0,identity=fred \
      --object authz-list-file,id=authz1,filename=tls.acl \
      --object tls-creds-x509,id=tls0,dir=/etc/qemu/tls,verify-peer=yes \
      --vnc 0.0.0.0:1,sasl,sasl-authz=auth0,tls-creds=tls0,tls-authz=authz1