mirror of https://github.com/grpc/grpc.git
The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
290 lines
11 KiB
290 lines
11 KiB
10 years ago
|
#gRPC Authentication support
|
||
|
|
||
10 years ago
|
gRPC is designed to plug-in a number of authentication mechanisms. This document
|
||
|
provides a quick overview of the various auth mechanisms supported, discusses
|
||
|
the API with some examples, and concludes with a discussion of extensibility.
|
||
|
More documentation and examples are coming soon!
|
||
10 years ago
|
|
||
|
## Supported auth mechanisms
|
||
10 years ago
|
|
||
|
###SSL/TLS
|
||
10 years ago
|
gRPC has SSL/TLS integration and promotes the use of SSL/TLS to authenticate the
|
||
|
server, and encrypt all the data exchanged between the client and the server.
|
||
|
Optional mechanisms are available for clients to provide certificates to
|
||
|
accomplish mutual authentication.
|
||
10 years ago
|
|
||
|
###OAuth 2.0
|
||
10 years ago
|
gRPC provides a generic mechanism (described below) to attach metadata to
|
||
|
requests and responses. This mechanism can be used to attach OAuth 2.0 Access
|
||
|
Tokens to RPCs being made at a client. Additional support for acquiring Access
|
||
|
Tokens while accessing Google APIs through gRPC is provided for certain auth
|
||
|
flows, demonstrated through code examples below.
|
||
10 years ago
|
|
||
10 years ago
|
## API
|
||
10 years ago
|
To reduce complexity and minimize API clutter, gRPC works with a unified concept
|
||
|
of a Credentials object. Users construct gRPC credentials using corresponding
|
||
|
bootstrap credentials (e.g., SSL client certs or Service Account Keys), and use
|
||
|
the credentials while creating a gRPC channel to any server. Depending on the
|
||
|
type of credential supplied, the channel uses the credentials during the initial
|
||
|
SSL/TLS handshake with the server, or uses the credential to generate and
|
||
|
attach Access Tokens to each request being made on the channel.
|
||
10 years ago
|
|
||
10 years ago
|
###SSL/TLS for server authentication and encryption
|
||
10 years ago
|
This is the simplest authentication scenario, where a client just wants to
|
||
|
authenticate the server and encrypt all data.
|
||
|
|
||
10 years ago
|
```cpp
|
||
10 years ago
|
SslCredentialsOptions ssl_opts; // Options to override SSL params, empty by default
|
||
10 years ago
|
// Create the credentials object by providing service account key in constructor
|
||
|
std::unique_ptr<Credentials> creds = CredentialsFactory::SslCredentials(ssl_opts);
|
||
|
// Create a channel using the credentials created in the previous step
|
||
|
std::shared_ptr<ChannelInterface> channel = CreateChannel(server_name, creds, channel_args);
|
||
|
// Create a stub on the channel
|
||
|
std::unique_ptr<Greeter::Stub> stub(Greeter::NewStub(channel));
|
||
10 years ago
|
// Make actual RPC calls on the stub.
|
||
10 years ago
|
grpc::Status s = stub->sayHello(&context, *request, response);
|
||
|
```
|
||
|
|
||
10 years ago
|
For advanced use cases such as modifying the root CA or using client certs,
|
||
|
the corresponding options can be set in the SslCredentialsOptions parameter
|
||
10 years ago
|
passed to the factory method.
|
||
|
|
||
|
|
||
|
###Authenticating with Google
|
||
|
|
||
|
gRPC applications can use a simple API to create a credential that works in various deployment scenarios.
|
||
|
|
||
10 years ago
|
```cpp
|
||
10 years ago
|
std::unique_ptr<Credentials> creds = CredentialsFactory::GoogleDefaultCredentials();
|
||
10 years ago
|
// Create a channel, stub and make RPC calls (same as in the previous example)
|
||
|
std::shared_ptr<ChannelInterface> channel = CreateChannel(server_name, creds, channel_args);
|
||
|
std::unique_ptr<Greeter::Stub> stub(Greeter::NewStub(channel));
|
||
|
grpc::Status s = stub->sayHello(&context, *request, response);
|
||
|
```
|
||
|
|
||
10 years ago
|
This credential works for applications using Service Accounts as well as for
|
||
10 years ago
|
applications running in [Google Compute Engine (GCE)](https://cloud.google.com/compute/). In the former case, the
|
||
10 years ago
|
service account’s private keys are loaded from the file named in the environment
|
||
10 years ago
|
variable `GOOGLE_APPLICATION_CREDENTIALS`. The
|
||
10 years ago
|
keys are used to generate bearer tokens that are attached to each outgoing RPC
|
||
10 years ago
|
on the corresponding channel.
|
||
10 years ago
|
|
||
|
For applications running in GCE, a default service account and corresponding
|
||
|
OAuth scopes can be configured during VM setup. At run-time, this credential
|
||
|
handles communication with the authentication systems to obtain OAuth2 access
|
||
|
tokens and attaches them to each outgoing RPC on the corresponding channel.
|
||
|
Extending gRPC to support other authentication mechanisms
|
||
|
The gRPC protocol is designed with a general mechanism for sending metadata
|
||
|
associated with RPC. Clients can send metadata at the beginning of an RPC and
|
||
10 years ago
|
servers can send back metadata at the beginning and end of the RPC. This
|
||
|
provides a natural mechanism to support OAuth2 and other authentication
|
||
|
mechanisms that need attach bearer tokens to individual request.
|
||
10 years ago
|
|
||
|
In the simplest case, there is a single line of code required on the client
|
||
10 years ago
|
to add a specific token as metadata to an RPC and a corresponding access on
|
||
|
the server to retrieve this piece of metadata. The generation of the token
|
||
10 years ago
|
on the client side and its verification at the server can be done separately.
|
||
|
|
||
10 years ago
|
A deeper integration can be achieved by plugging in a gRPC credentials implementation for any custom authentication mechanism that needs to attach per-request tokens. gRPC internals also allow switching out SSL/TLS with other encryption mechanisms.
|
||
10 years ago
|
|
||
10 years ago
|
## Examples
|
||
|
|
||
10 years ago
|
These authentication mechanisms will be available in all gRPC's supported languages.
|
||
10 years ago
|
The following sections demonstrate how authentication and authorization features described above appear in each language: more languages are coming soon.
|
||
10 years ago
|
|
||
10 years ago
|
###SSL/TLS for server authentication and encryption (Ruby)
|
||
10 years ago
|
```ruby
|
||
10 years ago
|
# Base case - No encryption
|
||
10 years ago
|
stub = Helloworld::Greeter::Stub.new('localhost:50051')
|
||
|
...
|
||
|
|
||
10 years ago
|
# With server authentication SSL/TLS
|
||
10 years ago
|
creds = GRPC::Core::Credentials.new(load_certs) # load_certs typically loads a CA roots file
|
||
|
stub = Helloworld::Greeter::Stub.new('localhost:50051', creds: creds)
|
||
|
```
|
||
|
|
||
10 years ago
|
###SSL/TLS for server authentication and encryption (C#)
|
||
|
```csharp
|
||
|
// Base case - No encryption
|
||
|
var channel = new Channel("localhost:50051");
|
||
|
var client = new Greeter.GreeterClient(channel);
|
||
|
...
|
||
|
|
||
|
// With server authentication SSL/TLS
|
||
|
var credentials = new SslCredentials(File.ReadAllText("ca.pem")); // Load a CA file
|
||
|
var channel = new Channel("localhost:50051", credentials);
|
||
|
var client = new Greeter.GreeterClient(channel);
|
||
|
```
|
||
|
|
||
10 years ago
|
###SSL/TLS for server authentication and encryption (Objective-C)
|
||
|
|
||
|
The default for Objective-C is to use SSL/TLS, as that's the most common use case when accessing
|
||
|
remote APIs.
|
||
|
|
||
|
```objective-c
|
||
|
// Base case - With server authentication SSL/TLS
|
||
|
HLWGreeter *client = [[HLWGreeter alloc] initWithHost:@"localhost:50051"];
|
||
|
// Same as using @"https://localhost:50051".
|
||
|
...
|
||
|
|
||
|
// No encryption
|
||
|
HLWGreeter *client = [[HLWGreeter alloc] initWithHost:@"http://localhost:50051"];
|
||
|
// Specifying the HTTP scheme explicitly forces no encryption.
|
||
|
```
|
||
|
|
||
10 years ago
|
###SSL/TLS for server authentication and encryption (Python)
|
||
|
```python
|
||
|
# Base case - No encryption
|
||
|
stub = early_adopter_create_GreeterService_stub('localhost', 50051)
|
||
|
...
|
||
|
|
||
|
# With server authentication SSL/TLS
|
||
|
stub = early_adopter_create_GreeterService_stub(
|
||
|
'localhost', 50051, secure=True, root_certificates=open('ca.pem').read())
|
||
|
...
|
||
|
```
|
||
|
n.b.: the beta API will look different
|
||
|
|
||
10 years ago
|
###Authenticating with Google (Ruby)
|
||
|
```ruby
|
||
10 years ago
|
# Base case - No encryption/authorization
|
||
10 years ago
|
stub = Helloworld::Greeter::Stub.new('localhost:50051')
|
||
|
...
|
||
|
|
||
10 years ago
|
# Authenticating with Google
|
||
10 years ago
|
require 'googleauth' # from http://www.rubydoc.info/gems/googleauth/0.1.0
|
||
10 years ago
|
...
|
||
|
creds = GRPC::Core::Credentials.new(load_certs) # load_certs typically loads a CA roots file
|
||
|
scope = 'https://www.googleapis.com/auth/grpc-testing'
|
||
|
authorization = Google::Auth.get_application_default(scope)
|
||
|
stub = Helloworld::Greeter::Stub.new('localhost:50051',
|
||
|
creds: creds,
|
||
|
update_metadata: authorization.updater_proc)
|
||
|
```
|
||
10 years ago
|
|
||
|
###Authenticating with Google (Node.js)
|
||
|
|
||
|
```node
|
||
|
// Base case - No encryption/authorization
|
||
|
var stub = new helloworld.Greeter('localhost:50051');
|
||
|
...
|
||
|
// Authenticating with Google
|
||
|
var GoogleAuth = require('google-auth-library'); // from https://www.npmjs.com/package/google-auth-library
|
||
|
...
|
||
|
var creds = grpc.Credentials.createSsl(load_certs); // load_certs typically loads a CA roots file
|
||
|
var scope = 'https://www.googleapis.com/auth/grpc-testing';
|
||
|
(new GoogleAuth()).getApplicationDefault(function(err, auth) {
|
||
|
if (auth.createScopeRequired()) {
|
||
|
auth = auth.createScoped(scope);
|
||
|
}
|
||
|
var stub = new helloworld.Greeter('localhost:50051',
|
||
|
{credentials: creds},
|
||
|
grpc.getGoogleAuthDelegate(auth));
|
||
|
});
|
||
|
```
|
||
10 years ago
|
|
||
|
###Authenticating with Google (C#)
|
||
|
```csharp
|
||
|
// Base case - No encryption/authorization
|
||
|
var channel = new Channel("localhost:50051");
|
||
|
var client = new Greeter.GreeterClient(channel);
|
||
|
...
|
||
|
|
||
|
// Authenticating with Google
|
||
|
using Grpc.Auth; // from Grpc.Auth NuGet package
|
||
|
...
|
||
|
var credentials = new SslCredentials(File.ReadAllText("ca.pem")); // Load a CA file
|
||
|
var channel = new Channel("localhost:50051", credentials);
|
||
|
|
||
|
string scope = "https://www.googleapis.com/auth/grpc-testing";
|
||
|
var authorization = GoogleCredential.GetApplicationDefault();
|
||
|
if (authorization.IsCreateScopedRequired)
|
||
|
{
|
||
|
authorization = credential.CreateScoped(new[] { scope });
|
||
|
}
|
||
|
var client = new Greeter.GreeterClient(channel,
|
||
|
new StubConfiguration(OAuth2InterceptorFactory.Create(credential)));
|
||
|
```
|
||
10 years ago
|
|
||
10 years ago
|
###Authenticating with Google (PHP)
|
||
|
```php
|
||
|
// Base case - No encryption/authorization
|
||
|
$client = new helloworld\GreeterClient(
|
||
|
new Grpc\BaseStub('localhost:50051', []));
|
||
|
...
|
||
|
|
||
|
// Authenticating with Google
|
||
|
// the environment variable "GOOGLE_APPLICATION_CREDENTIALS" needs to be set
|
||
|
$scope = "https://www.googleapis.com/auth/grpc-testing";
|
||
|
$auth = Google\Auth\ApplicationDefaultCredentials::getCredentials($scope);
|
||
|
$opts = [
|
||
|
'credentials' => Grpc\Credentials::createSsl(file_get_contents('ca.pem'));
|
||
|
'update_metadata' => $auth->getUpdateMetadataFunc(),
|
||
|
];
|
||
|
|
||
|
$client = new helloworld\GreeterClient(
|
||
|
new Grpc\BaseStub('localhost:50051', $opts));
|
||
|
|
||
|
```
|
||
10 years ago
|
|
||
10 years ago
|
###Authenticating with Google (Objective-C)
|
||
|
|
||
|
This example uses the [Google iOS Sign-In library](https://developers.google.com/identity/sign-in/ios/),
|
||
|
but it's easily extrapolated to any other OAuth2 library.
|
||
|
|
||
|
```objective-c
|
||
|
// Base case - No authentication
|
||
|
[client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) {
|
||
|
...
|
||
|
}];
|
||
|
|
||
|
...
|
||
|
|
||
|
// Authenticating with Google
|
||
|
|
||
|
// When signing the user in, ask her for the relevant scopes.
|
||
|
GIDSignIn.sharedInstance.scopes = @[@"https://www.googleapis.com/auth/grpc-testing"];
|
||
|
|
||
|
...
|
||
|
|
||
10 years ago
|
#import <ProtoRPC/ProtoRPC.h>
|
||
10 years ago
|
|
||
|
// Create a not-yet-started RPC. We want to set the request headers on this object before starting
|
||
|
// it.
|
||
|
ProtoRPC *call =
|
||
|
[client RPCToSayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) {
|
||
|
...
|
||
|
}];
|
||
|
|
||
|
// Set the access token to be used.
|
||
|
NSString *accessToken = GIDSignIn.sharedInstance.currentUser.authentication.accessToken;
|
||
10 years ago
|
call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken]}];
|
||
10 years ago
|
|
||
|
// Start the RPC.
|
||
|
[call start];
|
||
|
```
|
||
|
|
||
|
You can see a working example app, with a more detailed explanation, [here](https://github.com/grpc/grpc-common/tree/master/objective-c/auth_sample).
|
||
10 years ago
|
|
||
|
### Authenticating with Google (Python)
|
||
|
```python
|
||
|
# Base case - No encryption
|
||
|
stub = early_adopter_create_GreeterService_stub('localhost', 50051)
|
||
|
...
|
||
|
|
||
|
# With server authentication SSL/TLS
|
||
|
import oauth2client.client
|
||
|
credentials = oauth2client.GoogleCredentials.get_application_default()
|
||
|
scope = 'https://www.googleapis.com/auth/grpc-testing'
|
||
|
scoped_credentials = credentials.create_scoped([scope])
|
||
|
access_token = scoped_credentials.get_access_token().access_token
|
||
|
metadata_transformer = (
|
||
|
lambda x: [('Authorization', 'Bearer {}'.format(access_token))])
|
||
|
|
||
|
stub = early_adopter_create_GreeterService_stub(
|
||
|
'localhost', 50051, secure=True, root_certificates=open('ca.pem').read(),
|
||
|
metadata_transformer=metadata_transformer)
|
||
|
...
|
||
|
```
|
||
|
n.b.: the beta API will look different
|