本教程展示了如何对由两个不同 SPIRE 服务器识别的两个 SPIFFE 标识的工作负载进行身份验证。

本文的第一部分演示了如何通过显示 SPIRE 配置文件更改和 spire-server 命令来配置 SPIFFE 联邦,以设置股票报价 web 应用的前端和服务后端为例。本文的第二部分列出了你可以在此教程目录中包含的 Docker Compose 文件中运行的步骤,以显示场景的实际操作。

在本教程中,你将学到如何:

  • 配置每个 SPIRE 服务器以使用 SPIFFE 身份验证和 Web PKI 身份验证公开其 SPIFFE 联邦捆绑点。
  • 配置 SPIRE 服务器以从彼此检索信任捆绑点。
  • 使用不同的信任域引导两个 SPIRE 服务器之间的联合。
  • 为工作负载创建注册条目,以便它们可以与其他信任域进行联合。

先决条件

SPIFFE 联邦的基线组件包括:

  • 运行版本为 1.5.1 的两个 SPIRE 服务器实例。
  • 运行版本为 1.5.1 的两个 SPIRE 代理。一个连接到一个 SPIRE 服务器,另一个连接到另一个 SPIRE 服务器。
  • 两个需要通过 mTLS 进行通信的工作负载,并使用工作负载 API 获取 SVID 和信任捆绑点。

场景

假设我们有一个股票 broker(经纪人)的 web 应用程序,它希望从股票 market web 服务提供商那里获取股票报价并显示。情景如下:

  1. 用户在浏览器中输入 broker web 应用的股票报价 URL。
  2. Web 应用的工作负载接收到请求并使用 mTLS 向股票 market 服务发出获取报价的 HTTP 请求。
  3. 股票 market 服务收到请求并在响应中发送报价。
  4. Web 应用呈现使用返回的报价的股票报价页面并将其发送到浏览器。
  5. 浏览器向用户显示报价。Web 应用包括一些 JavaScript 以便每隔 1 秒刷新页面,因此每秒都会执行这些步骤。

下图详细描绘了本场景。

image
联邦场景

除了上述内容,本教程的其余部分中,我们将假设以下 信任域 名称用于这些示例 SPIRE 安装:broker.examplestockmarket.example。请注意,信任域不需要对应实际的 DNS 域名。此外,应用程序直接访问 WorkloadAPI 以获取 SVID 和信任捆绑点,这意味着在所描述的情景中没有代理。

配置 SPIFFE 联邦捆绑点

为了使联邦工作,并且因为 web 应用程序和报价服务将使用 mTLS,两个 SPIRE 服务器都需要彼此的信任捆绑点。在某种程度上,这是通过在每个 SPIRE 服务器上配置所谓的联邦捆绑点来完成的,该捆绑点提供了由其他信任域中的 SPIRE 服务器使用的 API,以获取他们要与之联合的信任域的信任捆绑点。

由 SPIRE 服务器公开的联邦捆绑点可以配置为使用两种身份验证方法之一:SPIFFE 身份验证或 Web PKI 身份验证。

使用 SPIFFE 身份验证配置联邦捆绑点

要配置 broker 的 SPIRE 服务器捆绑点端点,我们在 broker 的 SPIRE 服务器配置文件中使用了 federation 部分(默认为 server.conf):

 server {
     .
     .
     trust_domain = "broker.example"
     .
     .
 
     federation {
         bundle_endpoint {
             address = "0.0.0.0"
             port = 8443
         }
     }
 }

这将在运行 SPIRE 服务器的主机中的任何 IP 地址上的端口 8443 上发布联邦捆绑点。

另一方面,股票 market 服务提供商的 SPIRE 服务器配置类似:

 server {
     .
     .
     trust_domain = "stockmarket.example"
     .
     .
 
     federation {
         bundle_endpoint {
             address = "0.0.0.0"
             port = 8443
         }
     }
 }

此时,两个 SPIRE 服务器都暴露了它们的联邦捆绑点以提供它们的信任捆绑点,但它们都不知道如何到达彼此的联邦捆绑点。

使用 Web PKI 身份验证配置联邦捆绑点

我们将假设仅 broker 的 SPIRE 服务器将使用 Web PKI 身份验证来配置其联邦捆绑点。股票 market SPIRE 服务器仍将使用 SPIFFE 身份验证。因此,股票 market SPIRE 服务器配置与前一节中所见相同。

然后,要配置 broker 的 SPIRE 服务器捆绑点端点,我们将 federation 部分配置如下:

 server {
     .
     .
     trust_domain = "broker.example"
     .
     .
 
     federation {
         bundle_endpoint {
             address = "0.0.0.0"
             port = 443
             acme {
                 domain_name = "broker.example"
                 email = "[email protected]"
                 tos_accepted = true
             }
         }
     }
 }

这将在任何 IP 地址上的端口 443 上发布联邦捆绑点。我们使用端口 443,因为我们演示了使用 Let’s Encrypt 作为我们的 ACME 提供商(如果你要使用其他提供商,则必须设置 directory_url 可配置)。请注意,tos_accepted 设置为 true,这意味着我们接受了我们的 ACME 提供商的服务条款,这在使用 Let’s Encrypt 时是必要的。

要使使用 Web PKI 的 SPIFFE 联邦正常工作,你必须拥有为 domain_name(在我们的示例中为 broker.example)指定的 DNS 域名,并且该域名必须解析到公开联邦捆绑点的 SPIRE 服务器 IP 地址。

配置 SPIRE 服务器以从彼此检索信任捆绑点

在配置联邦端点后,启用 SPIFFE 联邦的下一步是配置 SPIRE 服务器以查找其他信任域的信任捆绑点。在 server.conf 中的 federates_with 配置选项是你指定另一个信任域的端点的地方。在使用不同的身份验证方法时,该部分的配置有一些细微的差异,根据每个端点配置文件的要求。

使用 SPIFFE 身份验证配置信任捆绑点位置(https_spiffe)

如前所述,股票 market 服务提供商的 SPIRE 服务器将其联邦端点监听在任何 IP 地址的端口 8443 上。我们还假设 spire-server-stock 是一个解析为股票 market 服务的 SPIRE 服务器 IP 地址的 DNS 名称。 (这里的 Docker Compose 演示使用主机名 spire-server-stock,但在典型的使用中,你会指定一个 FQDN。)然后,broker 的 SPIRE 服务器必须配置以下 federates_with 部分:

 server {
     .
     .
     trust_domain = "broker.example"
     .
     .
 
     federation {
         bundle_endpoint {
             address = "0.0.0.0"
             port = 8443
         }
         federates_with "stockmarket.example" {
             bundle_endpoint_url = "https://spire-server-stock:8443"
             bundle_endpoint_profile "https_spiffe" {
                 endpoint_spiffe_id = "spiffe://stockmarket.example/spire/server"
             }
         }
     }
 }

现在,broker 的 SPIRE 服务器知道在哪里找到可以用于验证包含来自 stockmarket.example 信任域的身份的信任捆绑点。

另一方面,股票 market 服务提供商的 SPIRE 服务器必须以类似的方式进行配置:

 server {
     .
     .
     trust_domain = "stockmarket.example"
     .
     .
 
     federation {
         bundle_endpoint {
             address = "0.0.0.0"
             port = 8443
         }
         federates_with "broker.example" {
             bundle_endpoint_url = "https://spire-server-broker:8443"
             bundle_endpoint_profile "https_spiffe" {
                 endpoint_spiffe_id = "spiffe://broker.example/spire/server"
             }
         }
     }
 }

请注意,指定了 “https_spiffe” 配置文件,指示了联邦捆绑点的预期 SPIFFE ID。指定 server.conffederation 部分和 federates_with 子部分是配置 SPIFFE 联邦所需的全部内容。要完成启用 SPIFFE 联邦,我们需要使用下面描述的 spire-server 命令来引导信任捆绑点和注册工作负载。

使用 Web PKI 身份验证配置信任捆绑点位置(https_web)

如前所述,在这种备选方案中,我们假设只有 broker 的 SPIRE 服务器将使用 Web PKI 身份验证来配置其联邦端点,因此 broker 服务器的 federates_with 配置与前一节中所见相同。然而,股票 market 服务提供商的 SPIRE 服务器需要一个不同的配置,它使用 “https_web” 配置文件而不是 “https_spiffe”:

 server {
     .
     .
     trust_domain = "stockmarket.example"
     .
     .
 
     federation {
         bundle_endpoint {
             address = "0.0.0.0"
             port = 8443
         }
         federates_with "broker.example" {
             bundle_endpoint_url = "https://spire-server-broker:8443"
             bundle_endpoint_profile "https_web" {}
         }
     }
 }

可以注意到 “https_web” 配置文件不需要额外的配置设置。端点使用安装在操作系统中的相同公共 CA 证书进行身份验证。

引导联邦

我们已经配置了 SPIRE 服务器的联邦端点地址,但这并不足以使联邦正常工作。为了使 SPIRE 服务器能够从彼此获取信任捆绑点,它们首先需要彼此的信任捆绑点,因为它们必须对试图访问联邦端点的联合服务器的 SPIFFE 身份进行身份验证。一旦联邦被引导,就可以使用当前信任捆绑点通过联邦端点 API 获取信任捆绑点更新。

引导工作是通过使用 SPIRE Server 命令 bundle showbundle set 来完成的。

获取引导信任捆绑点

假设我们想要获取 broker 的 SPIRE 服务器信任捆绑点。在运行 broker 的 SPIRE 服务器的节点上运行:

broker> spire-server bundle show -format spiffe > broker.example.bundle

这会将信任捆绑点保存在 broker.example.bundle 文件中。然后,broker 必须将此文件的副本提供给股票 market 服务人员,以便他们可以将此信任捆绑点存储在他们的 SPIRE 服务器上,并将其与 broker.example 信任域关联起来。要做到这一点,股票 market 服务人员必须在他们运行 SPIRE 服务器的节点上运行以下命令:

stock-market> spire-server bundle set -format spiffe -id spiffe://broker.example -path /some/path/broker.example.bundle

此时,股票 market 服务的 SPIRE 服务器可以验证具有 broker.example 信任域的 SPIFFE ID 的 SVID。但是,broker 的 SPIRE 服务器尚无法验证具有 stockmarket.example 信任域的 SPIFFE ID 的 SVID。要使此成为可能,股票 market 人员必须在他们运行 SPIRE 服务器的节点上运行以下命令:

stock-market> spire-server bundle show -format spiffe > stockmarket.example.bundle

然后,股票 market 人员必须将此文件的副本提供给 broker,以便他们可以将此信任捆绑点存储在他们的 SPIRE 服务器上,并将其与 stockmarket.example 信任域关联起来。要做到这一点,broker 必须在他们运行 SPIRE 服务器的节点上运行以下命令:

broker> spire-server bundle set -format spiffe -id spiffe://stockmarket.example -path /some/path/stockmarket.example.bundle

现在,两台 SPIRE 服务器都可以验证具有彼此信任域的 SPIFFE ID 的 SVID,因此两者可以开始从彼此的联邦端点获取信任捆绑点更新。此外,从现在起,他们可以创建用于联合的注册条目,如下一节所示。

请注意,在 broker 的 SPIRE 服务器为其联邦捆绑点使用 Web PKI 身份验证时,不需要创建 broker.example.bundle 文件(后来由股票 market 服务导入)。

为联邦创建注册条目

现在,SPIRE 服务器具有了彼此的信任捆绑点,让我们看看它们如何创建用于联合的注册条目。

为简化起见,我们假设股票 market Web 应用程序和行情服务都在运行在 Linux 主机上,一个属于股票 market 组织,另一个属于 broker。由于它们使用 SPIRE,每个 Linux 主机上还安装了一个 SPIRE 代理。除此之外,Web 应用程序是使用 webapp 用户运行的,行情服务是使用 quotes-service 用户运行的。

在 broker 的 SPIRE Server 节点上,broker 必须创建一个注册条目。-federatesWith 标志是必需的,以启用 SPIFFE 联邦:

broker> spire-server entry create \
   -parentID <SPIRE 代理的 SPIFFE ID> \
   -spiffeID spiffe://broker.example/webapp \
   -selector unix:user:webapp \
   -federatesWith "spiffe://stockmarket.example"

通过指定 -federatesWith 标志,创建了此注册条目后,当 Web 应用程序的 SPIRE 服务器请求 SVID 时,它将从 broker 的 SPIRE 服务器获取一个具有 spiffe://broker.example/webapp 身份的 SVID,并附带与 stockmarket.example 信任域关联的信任捆绑点。

在股票 market 服务的一侧,他们必须创建一个注册条目,如下所示:

stock-market> spire-server entry create \
   -parentID <SPIRE 代理的 SPIFFE ID> \
   -spiffeID spiffe://stockmarket.example/quotes-service \
   -selector unix:user:quotes-service \
   -federatesWith "spiffe://broker.example"

类似地,创建了此注册条目后,当行情服务请求 SVID 时,它将获得一个具有 spiffe://stockmarket.example/quotes-service 身份的 SVID,并附带与 broker.example 信任域关联的信任捆绑点。

以上就是全部内容。现在,所有的组件都已就绪,可以使联邦正常工作,并演示 Web 应用程序如何在具有不同信任域的身份的情况下与行情服务通信。

使用 SPIFFE 身份验证的联邦示例

本节将解释如何使用 Docker Compose 尝试此教程中描述的 SPIFFE 身份验证场景的示例实现。

尽管此处没有显示出来,但你可以对 Web PKI 身份验证部分中显示的更改进行更改以尝试 Web PKI 场景。请记住,要配置 Web PKI,domain_name 指定的 FQDN 必须由你拥有,并且可以通过 DNS 通过互联网进行解析。

要求

本教程的所需文件可以在 https://github.com/spiffe/spire-tutorialsdocker-compose/federation 目录中找到。如果你尚未克隆该存储库,请立即执行此操作。

在继续之前,请查看以下系统要求:

  • 64 位 Linux 或 macOS 环境
  • 安装了 DockerDocker Compose(Docker Compose 包含在 macOS Docker Desktop 中)
  • 安装了 Go 1.14.4 或更高版本

构建

确保当前工作目录是 .../spire-tutorials/docker-compose/federation,并运行以下命令以创建 Docker Compose 所需的文件:

$ ./build.sh

运行

运行以下命令以启动 SPIRE 服务器和应用程序:

$ docker-compose up -d

启动 SPIRE Agents

运行以下命令以启动 SPIRE Agents:

$ ./1-start-spire-agents.sh

引导联邦

运行以下命令以引导联邦:

$ ./2-bootstrap-federation.sh

创建工作负载注册条目

运行以下命令以创建工作负载注册条目:

$ ./3-create-registration-entries.sh

运行此脚本后,应用程序可能需要几秒钟才能收到其 SVID(SPIFFE 身份验证信息)和信任捆绑包。

在浏览器中查看场景工作

在浏览器中打开 http://localhost:8080/quotes,你应该看到一个显示每秒更新的随机生成的虚假股票报价的网格。

查看配置

要查看经纪人的 SPIRE 服务器配置,可以运行以下命令:

$ docker-compose exec spire-server-broker cat conf/server/server.conf

你应该会看到:

 server {
     bind_address = "0.0.0.0"
     bind_port = "8081"
     socket_path = "/tmp/spire-server/private/api.sock"
     trust_domain = "broker.example"
     data_dir = "/opt/spire/data/server"
     log_level = "DEBUG"
     log_file = "/opt/spire/server.log"
     default_svid_ttl = "1h"
     ca_subject = {
         country = ["US"],
         organization = ["SPIFFE"],
         common_name = "",
     }

     federation {
         bundle_endpoint {
             address = "0.0.0.0"
             port = 8443
         }
         federates_with "stockmarket.example" {
             bundle_endpoint_url = "https://spire-server-stock:8443"
             bundle_endpoint_profile "https_spiffe" {
                 endpoint_spiffe_id = "spiffe://stockmarket.example/spire/server"
             }
         }
     }
 }

 plugins {
     DataStore "sql" {
         plugin_data {
             database_type = "sqlite3"
             connection_string = "/opt/spire/data/server/datastore.sqlite3"
         }
     }

   NodeAttestor "x509pop" {
     plugin_data {
       ca_bundle_path = "/opt/spire/conf/server/agent-cacert.pem"
     }
   }

     KeyManager "memory" {
         plugin_data = {}
     }
 }

要查看股票 market 的 SPIRE 服务器配置,可以运行以下命令:

$ docker-compose exec spire-server-stock cat conf/server/server.conf

你应该会看到:

 server {
     bind_address = "0.0.0.0"
     bind_port = "8081"
     socket_path = "/tmp/spire-server/private/api.sock"
     trust_domain = "stockmarket.example"
     data_dir = "/opt/spire/data/server"
     log_level = "DEBUG"
     log_file = "/opt/spire/server.log"
     default_svid_ttl = "1h"
     ca_subject = {
         country = ["US"],
         organization = ["SPIFFE"],
         common_name = "",
     }

     federation {
         bundle_endpoint {
             address = "0.0.0.0"
             port = 8443
         }
         federates_with "broker.example" {
             bundle_endpoint_url = "https://spire-server-broker:8443"
             bundle_endpoint_profile "https_spiffe" {
                 endpoint_spiffe_id = "spiffe://broker.example/spire/server"
             }
         }
     }
 }

 plugins {
     DataStore "sql" {
         plugin_data {
             database_type = "sqlite3"
             connection_string = "/opt/spire/data/server/datastore.sqlite3"
         }
     }

   NodeAttestor "x509pop" {
     plugin_data {
       ca_bundle_path = "/opt/spire/conf/server/agent-cacert.pem"
     }
   }

     KeyManager "memory" {
         plugin_data = {}
     }
 }

查看注册条目

要查看经纪人的 SPIRE 服务器注册条目,可以运行以下命令:

$ docker-compose exec spire-server-broker bin/spire-server entry show

你应该会看到类似以下内容:

 Found 1 entry
 Entry ID      : 2d799235-ddca-4088-ba6f-bf54d2af918f
 SPIFFE ID     : spiffe://broker.example/webapp
 Parent ID     : spiffe://broker.example/spire/agent/x509pop/4f9238aaa7a93cf96ca3d6060abe27bc51a267e7
 Revision      : 0
 TTL           : 3600
 Selector      : unix:user:root
 FederatesWith : spiffe://stockmarket.example

要查看股票 market 的 SPIRE 服务器注册条目,可以运行以下命令:

$ docker-compose exec spire-server-stock bin/spire-server entry show

你应该会看到类似以下内容:

 Found 1 entry
 Entry ID      : e42e8d6b-0a0a-4e38-b544-08510c35cbbe
 SPIFFE ID     : spiffe://stockmarket.example/quotes-service
 Parent ID     : spiffe://stockmarket.example/spire/agent/x509pop/50686366996ece3ca8e528765af685fe81f81435
 Revision      : 0
 TTL           : 3600
 Selector      : unix:user:root
 FederatesWith : spiffe://broker.example

清理

 $ docker-compose down