认证

作者: 竹天亮 | 来源:发表于2017-09-12 17:57 被阅读557次

    本文预览一下gRPC认证,包含内置已支持的认证机制,如何添加自己的认证系统和如何在支持的语言里使用gRPC认证的例子。

    简介

    gRPC设计可以和很多认证机制工作,可以很简单安全的使用gRPC与其他系统沟通。可以使用我们已支持的机制 - SSL/TLS使用或者不适用Google基于token认证 - 或者可以添加你自己的认证系统通过扩展我们提供的代码。

    gRPC同样提供了简单的认证API,让你提供所有需要的认证信息作为凭证(Credentials)在创建channel或者请求时。

    已支持的认证机制

    下面的认证机制是gRPC内置的:

    • SSL/TLS: gRPC继承了SSL/TLS,并且提升了SSL/TLS认证服务器的使用,加密所有客户端和服务端的数据交换。为客户端提供相互认证的证书机制是可选的。

    • 基于Google的Token认证:gRPC提供了通用的机制(下面介绍)对请求和响应附加metadata。另外支持使用tokens(一般是OAuth2 tokens)在通过gRPC使用Google API提供确认的认证流程:可以在下面代码例子里查看如何使用。一般这种机制必须是SSL/TLS的 - 没有SSL/TLS Google不允许连接,并且大多数gRPC语言实现不会让你在未加密的渠道上发送认证。

    警告:谷歌认证只允许用于谷歌服务。如果发送一个谷歌的OAuth2 token到非谷歌服务会导致这个token被窃取然后滥用谷歌的服务。

    认证API

    gRPC提供了简单的认证API,基于统一认证对象的概念,可以用在创建整个gRPC管道或单个调用的时候。

    凭证类型

    两种凭证类型:

    • Channel凭证,当访问到Channel时,比如SSL凭证。
    • Call凭证,当触发一个调用时(或者C++里的ClientContext)。

    也可以在CompositeChannelCredentials组合使用,允许你指定,比如SSL 凭证给channel,然后这个channel上的每个请求用call凭证。CompositeChannelCredentials结合ChannelCredentialsCallCredentials来创建一个新的ChannelCredentials。结果发送认证数据与channel上的每个请求CallCredentialswith组合。

    比如,你可以创建SslCredentials的ChannelCredentialsAccessTokenCredentials。结果就是在Channel上使用时将会为Channel上的每个请求发送合适的认证token。

    单个CallCredentials同样可以与CompositeCallCredentials组合。这会当CallCredentials使用在请求上是将会触发发送认证数据和两个CallCredentials

    使用客户端SSL/TLS

    现在我们看一下Credentials如何与我们支持的认证机制合作。这是最简单的认证场景:客户端指向认证服务器并加密所有的数据。例子是用C++,但是API对所有的语言都相同:你可以在我们下面的例子里看到很多语言里如何启用SSL/TLS:

    // Create a default SSL ChannelCredentials object.
    auto channel_creds = grpc::SslCredentials(grpc::SslCredentialsOptions());
    // Create a channel using the credentials created in the previous step.
    auto 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参数里设置传递给工厂方法。

    基于谷歌token认证

    gRPC应用可以使用简单的API创建认证,用于和Google各种开发场景认证。同样,我们的例子是C++,但是你可以找到其他语言的例子:

    auto creds = grpc::GoogleDefaultCredentials();
    // Create a channel, stub and make RPC calls (same as in the previous example)
    auto channel = grpc::CreateChannel(server_name, creds);
    std::unique_ptr<Greeter::Stub> stub(Greeter::NewStub(channel));
    grpc::Status s = stub->sayHello(&context, *request, response);
    

    这个channel认证对象用于使用Service Accounts的应用,以及运行在Google Compute Engine (GCE)的应用.
    在前一种情况下,服务账户的私钥会被环境变量里的GOOGLE_APPLICATION_CREDENTIALS文件加载。密钥用于生成无记名令牌附加到每个发送的RPC在相应的channel。

    对于运行在GCE里的应用程序,默认的服务账户和相应的OAuth2域可以在VM设置期间配置。在运行时,这个凭证处理和认证系统通信获取OAuth2访问tokens,然后加在相应的channel里的发送的RPC。

    扩展gRPC支持其他认证机制

    认证插件API允许开发者加入自己的认证类型。这包括:

    • MetadataCredentialsPlugin抽象类,包含纯净的虚拟GetMetadata方法,需要被开发者创建的子类实现。
    • MetadataCredentialsFromPlugin方法,在MetadataCredentialsPlugin插件里创建一个CallCredentials

    下面是一个简单认证插件例子,在自定义header里设置凭证ticket:

    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_;
    };
    
    auto call_creds = grpc::MetadataCredentialsFromPlugin(
        std::unique_ptr<grpc::MetadataCredentialsPlugin>(
            new MyCustomAuthenticator("super-secret-ticket")));
    

    更深层次的插件集成实现gRPC凭证实现是在源代码等级。gRPC内部同样可以与其他加密实现交换SSL/TLS。

    示例

    这些认证机制可以在gRPC支持的所有语言里可用。下面会演示如何认证和在每个语言里上面讲述的认证特性:更多语言准备中。

    Java

    基础案例 - 无需加密或认证

    ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50051)
        .usePlaintext(true)
        .build();
    GreeterGrpc.GreeterStub stub = GreeterGrpc.newStub(channel);
    

    使用服务端认证SSL/TLS
    如果gRPC是TLS的,我们建议在Java里使用OpenSSL。可以在Security文档里查看如何安装和使用OpenSSL和其他必须的库。

    在服务端启用TLS,证书链和密钥需要制定为PEM格式。标准的TLS端口是443,但是下面我们使用8443,以免需要系统的额外权限。

    Server server = ServerBuilder.forPort(8443)
        // Enable TLS
        .useTransportSecurity(certChainFile, privateKeyFile)
        .addService(TestServiceGrpc.bindService(serviceImplementation))
        .build();
    server.start();
    

    如果客户端不知道发行证书机构,那么正确的配置SslContext或者SSLSocketFactory应该提供给NettyChannelBuilder或者OkHttpChannelBuilder

    在客户端,服务端的SSL/TLS认证看起来像:

    // With server authentication SSL/TLS
    ManagedChannel channel = ManagedChannelBuilder.forAddress("myservice.example.com", 443)
        .build();
    GreeterGrpc.GreeterStub stub = GreeterGrpc.newStub(channel);
    
    // With server authentication SSL/TLS; custom CA root certificates; not on Android
    ManagedChannel channel = NettyChannelBuilder.forAddress("myservice.example.com", 443)
        .sslContext(GrpcSslContexts.forClient().trustManager(new File("roots.pem")).build())
        .build();
    GreeterGrpc.GreeterStub stub = GreeterGrpc.newStub(channel);
    
    谷歌认证

    下面的代码片段演示如何使用服务账户和gRPC调用Google Cloud PubSub API。证书从已知的位置加载或者通过程序运行环境提供的自动发现,比如,Google Compute Engine。这个例子是指定谷歌和他的服务的,其他服务提供者可以使用相同的模式。

    GoogleCredentials creds = GoogleCredentials.getApplicationDefault();
    ManagedChannel channel = ManagedChannelBuilder.forTarget("greeter.googleapis.com")
        .build();
    GreeterGrpc.GreeterStub stub = GreeterGrpc.newStub(channel)
        .withCallCredentials(MoreCallCredentials.from(creds));
    

    相关文章

      网友评论

          本文标题:认证

          本文链接:https://www.haomeiwen.com/subject/ktzqjxtx.html