Documentation

17. 项目签名和验证

项目签名和验证提供了在项目目录中为文件签名的功能,然后可以验证内容是否有任何形式的改变,或者文件被意外地从项目中删除或添加到项目。这需要使用一个私有进行签名并使用与它匹配的公钥进行验证。

对于项目维护者,对内容进行签名的方式是,通过命令行界面 (CLI) 提供的一个名为 ansible-sign 的工具程序进行。

CLI 旨在方便地使用加密技术,如 GNU Privacy Guard (GPG) 等技术来验证项目中的文件是否已被改变或破坏。当前,GPG 是唯一支持的签名和验证方法。

Ansible Automation 控制器用于验证签名的内容。当匹配的公钥与已签名项目相关联后,控制器会验证被签名的文件是否被改变,以及文件是否被意外添加或删除。如果签名无效或文件被改变,项目将无法更新,使用这个项目的作业将无法启动。通过项目的验证状态,可以确保只有安全的、没有被修改的内容才会在作业中运行。

假设已配置了仓库签名和验证(请参阅以下),更改项目的常见工作流将变成:

  1. 用户设置了一个项目仓库,并希望对一个文件进行修改。

  2. 用户进行更改,运行 ansible-sign project gpg-sign /path/to/project,它将更新校验和清单并进行签名。

  3. 用户将向仓库提交进行的更改以及更新的校验和清单,以及签名。

  4. 当用户同步项目时,控制器(在这个情况中已配置)会拉取新的更改,检查与控制器中项目关联的公钥是否与校验和清单签名的私钥匹配(防止对校验和清单本身进行了修改),然后重新计算清单中每个文件的校验和,以确保校验和匹配(确保文件没有被修改)。 它还会确保所有文件都被考虑:文件包括或排除了以下讨论的 MANIFEST.in 文件中指定的文件 ; 如果有文件已被意外添加或删除,验证将失败。

_images/content-sign-diagram.png

17.1. 前提条件

  • RHEL 节点必须正确订阅:

    • RHEL 订阅并启用了 baseosappstream 软件仓库启

    • Ansible Automation Platform 订阅并启用了正确的 Ansible Automation Platform 频道:

    ansible-automation-platform-2.3-for-rhel-8-x86_64-rpms for RHEL 8
    ansible-automation-platform-2.3-for-rhel-9-x86_64-rpms for RHEL 9
    
  • 对内容进行签名需要一个有效的 GPG 公钥/私钥。详情请参阅 How to create GPG keypairs

请参阅 GnuPG documentation 以了解有关 GPG 密钥的更多信息。

您可以使用以下命令验证您是否具有有效的 GPG 密钥对和默认 GnuPG 密钥环:

$ gpg --list-secret-keys

如果上述命令没有输出,或只输出了一行 trustdb was created,则代表在您的默认密钥环中没有 secret 密钥。在这种情况下,请先参考 How to create GPG keypairs 以了解如何创建新密钥对。如果命令的输出超出以上内容,代表您已有一个有效的 secret 密钥,您可以使用 ansible-sign 继续。

17.2. 在 Ansible Automation Controller 中添加 GPG 密钥

要将 GPG 密钥用于控制器中的内容并验证,您必须在 CLI 中运行以下命令:

$ gpg --list-keys
$ gpg --export --armour <key fingerprint> > my_public_key.asc
  1. 在控制器用户界面中,点左侧导航栏中的 Credentials,然后点 Add 按钮。

  2. 提供有意义的名称(例如:“Infrastructure team public GPG key”)

  3. 在 Credential Type 字段中,选择 GPG Public Key

  4. Browse 找到并选择公钥文件(例如 my_public_key.asc

  5. 完成后请点击 Save

_images/credentials-gpg-details.png

现在,这个凭证可以在 projects 中选择,内容验证将会在将来的项目同步时自动进行。

_images/project-create-with-gpg-creds.png

注解

使用项目缓存 SCM 超时来控制您希望控制器重新验证已签名的内容的频率。当项目配置为在启动时更新时(任何配置了该项目的作业模板),您可以启用缓存超时设置,这告诉它在自上次更新后 N 秒后更新。如果验证太频繁,则可以通过在项目的 Option Details 框中的 Cache Timeout 字段中指定一个超时时间来进行调整。

_images/project-update-launch-cache-timeout.png

17.3. 访问 ansible-sign CLI 工具

ansible-sign 工具为用户提供了签名和验证项目是否已签名的选项。

  1. 运行以下命令来安装 ansible-sign

$ dnf install ansible-sign
  1. 验证 ansible-sign 已成功安装:

$ ansible-sign --version

输出类似以下内容(可能具有不同的版本号):

ansible-sign 0.1

这表明您已成功安装了 ansible-sign

17.4. 对您的项目进行签名

顾名思义,为项目签名涉及一个 Ansible 项目目录。如需更复杂的项目目录结构的示例,请参阅 Ansible documentation

以下示例项目有一个非常简单的结构。它包括一个清单文件,以及 playbook 目录下的两个简单的 playbook:

$ cd sample-project/
$ tree -a .
.
├── inventory
└── playbooks
    └── get_uptime.yml
    └── hello.yml

1 directory, 3 files

注解

本节中使用的命令假设您的工作目录是您的项目的根目录。作为一个规则,ansible-sign project 命令始终将项目根目录视为其最后一个参数,因此我们可以使用 . 表示当前工作目录。

ansible-sign 保护内容不受篡改的方式是,对项目中所有安全的文件进行校验和(SHA256),将它们编译到校验和清单文件中,最后再对该清单文件进行签名。

对内容进行签名的第一步是,创建一个文件,该文件为 ansible-sign 指定要保护的文件。该文件应称为 MANIFEST.in,并位于项目根目录中。

在内部,ansible-sign 使用 Python distlib 库的 distlib.manifest 模块,因此 MANIFEST.in 必须遵循这个库指定的语法。有关 MANIFEST.in 文件指令的说明,请参阅 Python Packaging User Guide

在示例项目中,包含两个指令,MANIFEST.in 文件类似如下:

include inventory
recursive-include playbooks *.yml

使用这个文件,生成您的验证和清单文件并对其进行签名。这些步骤通过一个 ansible-sign 命令实现:

$ ansible-sign project gpg-sign .
[OK   ] GPG signing successful!
[NOTE ] Checksum manifest: ./.ansible-sign/sha256sum.txt
[NOTE ] GPG summary: signature created

现在,该项目已被签名。

请注意,gpg-sign 子命令位于 project 子命令下。对于签名项目内容,每个命令都将以 ansible-sign project 开头。如上所述,作为一个规则,每个 ansible-sign project 命令都会将项目根目录作为其最终参数。

如前所述,ansible-sign 默认会使用您的默认密钥环,并使用第一个可用的 secret 密钥为项目签名。您可以使用 --fingerprint 选项指定一个特定的 secret 密钥进行签名,甚至可以使用 --gnupg-home 选项进行完全独立的 GPG 主目录。

注解

如果您使用一个桌面环境,则 GnuPG 会自动提示您输入 secret 密钥的密码短语。如果此功能无法正常工作,或者在没有桌面环境的情况下工作(例如,通过 SSH),您可以在以上命令的 gpg-sign 后使用 -p/--prompt-passphrase 标志,这会使 ansible-sign 提示输入密码。

查看项目目录的结构后,请注意创建了一个新的 .ansible-sign 目录。该目录包含校验和清单,以及一个独立的 GPG 签名。

$ tree -a .
.
├── .ansible-sign
│   ├── sha256sum.txt
│   └── sha256sum.txt.sig
├── inventory
├── MANIFEST.in
└── playbooks
    ├── get_uptime.yml
    └── hello.yml

17.5. 验证您的项目

如果要验证已签名的 Ansible 项目没有被更改,您可以使用 ansible-sign 检查签名是否有效,以及文件的校验和是否与正确的值匹配。特别是,可以使用 ansible-sign project gpg-verify 命令自动验证这两个条件。

$ ansible-sign project gpg-verify .
[OK   ] GPG signature verification succeeded.
[OK   ] Checksum validation succeeded.

注解

默认情况下,ansible-sign 使用默认 GPG 密钥环查找匹配的公钥。您可以使用 --keyring 选项指定一个密钥环文件,或使用 --gnugpg-home 选项指定不同的 GPG 主目录。

如果因为任何原因验证失败,则会显示信息以帮助您进行调试。通过在命令 ansible-sign 后使用全局 --debug 标志来输出更多信息。

注解

在项目中使用 GPG 凭据时,内容验证将会在未来的项目同步上自动进行。

17.6. 自动签名

在具有高度可信的 CI 环境(如 OpenShift、Jenkins 等)中,可以自动化签名的流程。例如,您可以将使用的 CI 平台中将您的 GPG 私钥存储为一个 secret,并在 CI 环境中将其导入到 GnuPG 中。然后,您可以在一般的 CI 工作流/容器/环境中运行签名工作流。

当使用 GPG 对项目进行签名时,ANSIBLE_SIGN_GPG_PASSPHRASE 环境变量 可以设置为签名密钥的密码短语。这可以在 CI 管道中注入(masked/secured)。

根据具体情况,在签名和验证期间,ansible-sign 将以不同的退出代码返回。这在 CI 和自动化上下文中也很有用,因为 CI 环境根据故障进行不同的操作(例如,对于一些错误会发送警报,但对其他错误会静默)。

以下是 ansible-sign 当前使用的退出代码,它们被视为稳定:

退出代码

大约含义

示例情境

0

成功

  • 签名成功

  • 验证成功

1

常规故障

  • 验证和清单文件在验证过程中包含语法错误

  • 验证过程中不存在签名文件

  • 在签名过程中 MANIFEST.in 不存在

2

验证和验证失败

  • 在验证过程中计算的校验和哈希值与签名校验和清单中的内容不同(例如,项目文件已更改,但签署过程并没有重新完成)

3

签名验证失败

  • 签名人的公钥没有在用户的 GPG 密钥环中

  • 指定了错误的 GnuPG 主目录或密钥环文件

  • 签名的验证和清单文件被修改

4

签名进程失败

  • 签名人的私钥没有在 GPG 密钥环中找到

  • 指定了错误的 GnuPG 主目录或密钥环文件