本文預覽一下gRPC認證,包含內置已支持的認證機制,如何添加自己的認證系統(tǒng)和如何在支持的語言里使用gRPC認證的例子。
簡介
gRPC設計可以和很多認證機制工作狞尔,可以很簡單安全的使用gRPC與其他系統(tǒng)溝通」簦可以使用我們已支持的機制 - SSL/TLS使用或者不適用Google基于token認證 - 或者可以添加你自己的認證系統(tǒng)通過擴展我們提供的代碼偏序。
gRPC同樣提供了簡單的認證API,讓你提供所有需要的認證信息作為憑證(Credentials)在創(chuàng)建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語言實現不會讓你在未加密的渠道上發(fā)送認證敬拓。
警告:谷歌認證只允許用于谷歌服務。如果發(fā)送一個谷歌的OAuth2 token到非谷歌服務會導致這個token被竊取然后濫用谷歌的服務乘凸。
認證API
gRPC提供了簡單的認證API,基于統(tǒng)一認證對象的概念营勤,可以用在創(chuàng)建整個gRPC管道或單個調用的時候。
憑證類型
兩種憑證類型:
- Channel憑證冀偶,當訪問到Channel時,比如SSL憑證渔嚷。
- Call憑證进鸠,當觸發(fā)一個調用時(或者C++里的ClientContext)。
也可以在CompositeChannelCredentials組合使用形病,允許你指定客年,比如SSL 憑證給channel,然后這個channel上的每個請求用call憑證漠吻。CompositeChannelCredentials結合ChannelCredentials和CallCredentials來創(chuàng)建一個新的ChannelCredentials量瓜。結果發(fā)送認證數據與channel上的每個請求CallCredentialswith組合。
比如途乃,你可以創(chuàng)建SslCredentials的ChannelCredentials和AccessTokenCredentials绍傲。結果就是在Channel上使用時將會為Channel上的每個請求發(fā)送合適的認證token。
單個CallCredentials同樣可以與CompositeCallCredentials組合耍共。這會當CallCredentials使用在請求上是將會觸發(fā)發(fā)送認證數據和兩個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創(chuàng)建認證铝量,用于和Google各種開發(fā)場景認證。同樣银亲,我們的例子是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)的應用.
在前一種情況下群凶,服務賬戶的私鑰會被環(huán)境變量里的GOOGLE_APPLICATION_CREDENTIALS文件加載插爹。密鑰用于生成無記名令牌附加到每個發(fā)送的RPC在相應的channel。
對于運行在GCE里的應用程序请梢,默認的服務賬戶和相應的OAuth2域可以在VM設置期間配置赠尾。在運行時,這個憑證處理和認證系統(tǒng)通信獲取OAuth2訪問tokens毅弧,然后加在相應的channel里的發(fā)送的RPC气嫁。
擴展gRPC支持其他認證機制
認證插件API允許開發(fā)者加入自己的認證類型。這包括:
- MetadataCredentialsPlugin抽象類够坐,包含純凈的虛擬GetMetadata方法寸宵,需要被開發(fā)者創(chuàng)建的子類實現。
- MetadataCredentialsFromPlugin方法,在MetadataCredentialsPlugin插件里創(chuàng)建一個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,以免需要系統(tǒng)的額外權限拄轻。
Server server = ServerBuilder.forPort(8443)
// Enable TLS
.useTransportSecurity(certChainFile, privateKeyFile)
.addService(TestServiceGrpc.bindService(serviceImplementation))
.build();
server.start();
如果客戶端不知道發(fā)行證書機構恨搓,那么正確的配置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弄抬。證書從已知的位置加載或者通過程序運行環(huán)境提供的自動發(fā)現宪郊,比如,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));