03-认证

本文档概述了gRPC认证机制,包括内置支持的身份验证机制,如何插入自己的身份验证系统,以及如何在支持的语言中使用gRPC认证机制的示例。

0.1. 概述

gRPC旨在与各种身份验证机制配合使用,可以轻松安全地使用gRPC与其他系统进行通信。可以使用我们支持的机制:

  • 带或不带基于Google令牌的身份验证的SSL/TLS
  • 通过扩展我们提供的代码来插入自己的身份验证系统

gRPC还提供了一个简单的身份验证API,允许在创建通道或发起调用时提供所有必要的身份验证信息作为凭据。

0.2. 支持的身份认证机制

gRPC内置了以下身份验证机制:

  • SSL/TLS:gRPC集成了SSL/TLS,并推荐使用SSL/TLS对服务进行身份验证,并且对客户端和服务端之间交换的所有数据进行加密。可选机制可供客户端提供相互身份验证的证书。
  • 基于Google令牌的认证:gRPC提供了一种通用机制(如下所述),用于将基于凭据的元数据附加到请求和响应中。此外,某些身份验证流程提供了通过gRPC访问Google API时获取访问令牌(例如,OAuth2令牌)的支持:可以在下面的代码示例中看到它的工作原理。通常,必须使用此机制就像必须在通道上使用SSL/TLS(Google不允许没有SSL/TLS的连接),并且大多数实现gRPC的编程语现都不允许在未加密的通道上发送凭据。

警告:Google凭据只能用于连接Google服务。将Google发布的OAuth2令牌发送到非Google服务可能会导致此令牌被盗并用于冒充客户端访问Google服务。

0.3. 认证API

gRPC提供基于凭据对象统一概念的简单认证API,可在创建整个gRPC通道或单个请求时使用。

0.3.1. 凭据类型

凭据有两种类型:

  • 通道凭据(ChannelCredentials:附加到一个通道上,例如SSL凭据
  • 调用凭据(CallCredentials:附加到一个调用上(或者是C++中的ClientContext

还可以在综合通道凭据(CompositeChannelCredentials)中组合使用这两种凭据。

例如,可以指定通道的SSL以及在通道中进行的每个调用的调用凭据。

综合通道凭据将通道凭据与调用凭据相关联,以创建新的通道凭据。结果就是将发送与在通道上进行的每次调用相关联的调用凭据组合而成的认证数据。

例如,可以从SslCredentialsAccessTokenCredentials创建通道凭据。结果就是当应用在一个通道时将为此通道上的每个调用发送相应的访问令牌(token)。

单个调用凭据也可以使用综合调用凭据(CompositeCallCredentials)组成。在一个调用中使用综合调用凭据生成的调用凭据时,将触发发送与两个调用凭据关联的认证数据。

0.3.2. 使用客户端SSL/TLS

现在让我们看看凭据如何与我们支持的认证机制一起工作。这是最简单的身份验证方案,客户端只想验证服务端并加密所有数据。该示例使用的是C++,所有编程语言的API都类似:可以在下面的示例部分中看到如何在更多语言中启用SSL/TLS。

// Create a default SSL ChannelCredentials object.

 channel_creds = grpc::SslCredentials(grpc::SslCredentialsOptions());
// Create a channel using the credentials created in the previous step.

 channel = grpc::CreateChannel(server_name, channel_creds);
// Create a stub on the channel.
std::unique_ptr<Greeter::Stub> stub(Greeter::NewStub(channel));
// Make actual RPC calls on the stub.
grpc::Status s = stub->sayHello(&context, *request, response);

对于高级用例,例如修改根CA或使用客户端证书,可以在传递给工厂模式的SslCredentialsOptions参数中设置相应的选项。

0.3.3. 使用基于Google令牌的认证

gRPC应用程序可以使用简单的API创建凭据,该凭据可用于在各种部署方案中与Google进行身份验证。同样,我们的示例是在C++中,但可以在我们的示例部分中找到其他语言的示例。

 creds = grpc::GoogleDefaultCredentials();
// Create a channel, stub and make RPC calls (same as in the previous example)

 channel = grpc::CreateChannel(server_name, creds);
std::unique_ptr<Greeter::Stub> stub(Greeter::NewStub(channel));
grpc::Status s = stub->sayHello(&context, *request, response);

此通道凭据对象适用于使用Service Account的应用程序或者在Google Compute Engine(GCE)中运行的应用程序。

  • 前一种情况下,Service Account的私钥是从环境变量GOOGLE_APPLICATION_CREDENTIALS中指定的文件加载的。密钥用于生成承载令牌,该令牌附加到相应通道的每个传出RPC上。

  • 对于在GCE中运行的应用程序,可以在VM启动期间配置默认的Service Account和对应的OAuth2作用域。在运行时,此凭据处理与身份验证系统的通信来获得OAuth2访问令牌,并将获得的访问令牌附加到相应通道的每个传出RPC上。

0.3.4. 扩展gRPC以支持其他认证机制

凭据插件API允许开发人员插入自己的凭据类型,包括:

  • MetadataCredentialsPlugin抽象类,它包含需要由开发人员创建的子类实现的纯虚拟GetMetadata方法。
  • MetadataCredentialsFromPlugin函数,它从MetadataCredentialsPlugin创建调用凭据。

下面是一个简单凭的据插件的示例,该插件在自定义标头中设置认证票据。

class MyCustomAuthenticator : public grpc::MetadataCredentialsPlugin {
 public:
  MyCustomAuthenticator(const grpc::string& ticket) : ticket_(ticket) {}

  grpc::Status GetMetadata(
      grpc::string_ref service_url, grpc::string_ref method_name,
      const grpc::AuthContext& channel_auth_context,
      std::multimap<grpc::string, grpc::string>* metadata) override {
    metadata->insert(std::make_pair("x-custom-auth-ticket", ticket_));
    return grpc::Status::OK;
  }

 private:
  grpc::string ticket_;
};


 call_creds = grpc::MetadataCredentialsFromPlugin(
    std::unique_ptr<grpc::MetadataCredentialsPlugin>(
        new MyCustomAuthenticator("super-secret-ticket")));

通过在核心级别插入gRPC凭证可以实现更深入的集成。gRPC内部还允许使用其他加密机制切换SSL/TLS。

0.4. 样例

所有gRPC支持的编程语言都可以提供这样的身份认证机制。以下部分演示了如何在每种编程语言中使用上述身份验证和授权功能:即将推出更多语言。

0.4.1. Golang

0.4.1.1. 基础例子,没有加密和认证

// 客户端
conn, _ := grpc.Dial("localhost:50051", grpc.WithInsecure())
// error handling omitted
client := pb.NewGreeterClient(conn)
// ...

// 服务端
s := grpc.NewServer()
lis, _ := net.Listen("tcp", "localhost:50051")
// error handling omitted
s.Serve(lis)

0.4.1.2. 带有SSL/TLS认证的服务

// 客户端
creds, _ := credentials.NewClientTLSFromFile(certFile, "")
conn, _ := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(creds))
// error handling omitted
client := pb.NewGreeterClient(conn)
// ...

// 服务端
creds, _ := credentials.NewServerTLSFromFile(certFile, keyFile)
s := grpc.NewServer(grpc.Creds(creds))
lis, _ := net.Listen("tcp", "localhost:50051")
// error handling omitted
s.Serve(lis)

0.4.1.3. 基于Google令牌的认证

pool, _ := x509.SystemCertPool()
// error handling omitted
creds := credentials.NewClientTLSFromCert(pool, "")
perRPC, _ := oauth.NewServiceAccountFromFile("service-account.json", scope)
conn, _ := grpc.Dial(
    "greeter.googleapis.com",
    grpc.WithTransportCredentials(creds),
    grpc.WithPerRPCCredentials(perRPC),
)
// error handling omitted
client := pb.NewGreeterClient(conn)
// ...
上次修改: 14 April 2020