认证

本文预览一下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));
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容