認證

本文預覽一下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));
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容