Restreindre l'accès à l'API avec des clés API

Les clés API vous permettent de restreindre l'accès à certaines méthodes d'une API ou à l'ensemble de ses méthodes. Cette page explique comment restreindre l'accès à une API aux seuls clients disposant de la clé API correspondante, ainsi que comment créer une clé API. Le proxy Extensible Service Proxy (ESP) utilise l'API Service Control pour valider une clé API et son association avec une API active d'un projet.

Le proxy Extensible Service Proxy (ESP) utilise l'API Service Control pour valider une clé API et son association avec une API active d'un projet. Si vous configurez une exigence de clé API dans votre API, toute requête concernant la méthode, la classe ou l'API ainsi protégées est rejetée, sauf si elle est assortie d'une clé générée au sein de votre projet ou dans un autre projet appartenant à un développeur auquel vous avez donné l'autorisation d'activer cette API. Le projet dans lequel la clé API a été créée n'est pas enregistré et n'est pas ajouté à l'en-tête de requête. Pour savoir dans quel projet une clé API doit être créée, consultez Partager des API protégées par une clé API. Google Cloud

Pour savoir dans quel Google Cloud projet une clé API doit être créée, consultez Partage d'API protégées par une clé API.

Par défaut dans les services gRPC, toutes les méthodes d'API nécessitent une clé API pour y accéder . Vous pouvez désactiver l'exigence de clé API pour l'ensemble de l'API ou pour des méthodes spécifiques. Pour ce faire, vous devez ajouter une section usage à votre configuration de service et configurer des règles et des sélecteurs, comme décrit dans les procédures suivantes.

Restreindre ou autoriser l'accès à toutes les méthodes d'API

Pour spécifier qu'une clé API n'est pas requise pour accéder à votre API :

  1. Ouvrez le fichier de configuration du service gRPC de votre projet dans un éditeur de texte et recherchez ou ajoutez une section usage.

  2. Dans votre section usage, spécifiez une règle allow_unregistered_calls comme suit. Le caractère générique "*" dans l'élément selector signifie que la règle s'applique à toutes les méthodes de l'API.

    usage:
      rules:
      # All methods can be called without an API Key.
      - selector: "*"
        allow_unregistered_calls: true
    

Supprimer la restriction de clé API pour une méthode

Pour désactiver la validation de clé API pour une méthode particulière même lorsque vous avez restreint l'accès à l'API pour l'API :

  1. Dans votre section usage, spécifiez une règle gRPC service configuration comme suit.

  2. Dans votre section usage, spécifiez une règle allow_unregistered_calls comme suit. La valeur de l'élément selector signifie que la règle s'applique uniquement à la méthode spécifiée, dans ce cas, ListShelves.

    usage:
      rules:
      # ListShelves method can be called without an API Key.
      - selector: endpoints.examples.bookstore.Bookstore.ListShelves
        allow_unregistered_calls: true
    

Appeler une API à l'aide d'une clé API

L'appel d'une API varie selon que vous appelez depuis un client gRPC ou un client HTTP.

Clients gRPC

Si une méthode nécessite une clé API, les clients gRPC doivent transmettre la valeur de la clé sous forme de métadonnées x-api-key avec leur appel de méthode.

**Dogfood** : cet exemple de code contient des liens générés de manière dynamique vers la documentation de référence sur la source.

def run(
    host, port, api_key, auth_token, timeout, use_tls, servername_override, ca_path

Java

private static final class Interceptor implements ClientInterceptor {
  private final String apiKey;
  private final String authToken;

  private static Logger LOGGER = Logger.getLogger("InfoLogging");

  private static Metadata.Key<String> API_KEY_HEADER =
      Metadata.Key.of("x-api-key", Metadata.ASCII_STRING_MARSHALLER);
  private static Metadata.Key<String> AUTHORIZATION_HEADER =
      Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);

  public Interceptor(String apiKey, String authToken) {
    this.apiKey = apiKey;
    this.authToken = authToken;
  }

  @Override
  public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
      MethodDescriptor<ReqT,RespT> method, CallOptions callOptions, Channel next) {
    LOGGER.info("Intercepted " + method.getFullMethodName());
    ClientCall<ReqT, RespT> call = next.newCall(method, callOptions);

    call = new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(call) {
      @Override
      public void start(Listener<RespT> responseListener, Metadata headers) {
        if (apiKey != null && !apiKey.isEmpty()) {
          LOGGER.info("Attaching API Key: " + apiKey);
          headers.put(API_KEY_HEADER, apiKey);
        }
        if (authToken != null && !authToken.isEmpty()) {
          System.out.println("Attaching auth token");
          headers.put(AUTHORIZATION_HEADER, "Bearer " + authToken);
        }
        super.start(responseListener, headers);
      }
    };
    return call;
  }
}

Go

func main() {
	flag.Parse()

	// Set up a connection to the server.
	conn, err := grpc.Dial(*addr, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	if *keyfile != "" {
		log.Printf("Authenticating using Google service account key in %s", *keyfile)
		keyBytes, err := ioutil.ReadFile(*keyfile)
		if err != nil {
			log.Fatalf("Unable to read service account key file %s: %v", *keyfile, err)
		}

		tokenSource, err := google.JWTAccessTokenSourceFromJSON(keyBytes, *audience)
		if err != nil {
			log.Fatalf("Error building JWT access token source: %v", err)
		}
		jwt, err := tokenSource.Token()
		if err != nil {
			log.Fatalf("Unable to generate JWT token: %v", err)
		}
		*token = jwt.AccessToken
		// NOTE: the generated JWT token has a 1h TTL.
		// Make sure to refresh the token before it expires by calling TokenSource.Token() for each outgoing requests.
		// Calls to this particular implementation of TokenSource.Token() are cheap.
	}

	ctx := context.Background()
	if *key != "" {
		log.Printf("Using API key: %s", *key)
		ctx = metadata.AppendToOutgoingContext(ctx, "x-api-key", *key)
	}
	if *token != "" {
		log.Printf("Using authentication token: %s", *token)
		ctx = metadata.AppendToOutgoingContext(ctx, "Authorization", fmt.Sprintf("Bearer %s", *token))
	}

	// Contact the server and print out its response.
	name := defaultName
	if len(flag.Args()) > 0 {
		name = flag.Arg(0)
	}
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.Message)
}

Node.js

const makeGrpcRequest = (JWT_AUTH_TOKEN, API_KEY, HOST, GREETEE) => {
  // Uncomment these lines to set their values
  // const JWT_AUTH_TOKEN = 'YOUR_JWT_AUTH_TOKEN';
  // const API_KEY = 'YOUR_API_KEY';
  // const HOST = 'localhost:50051'; // The IP address of your endpoints host
  // const GREETEE = 'world';

  // Import required libraries
  const grpc = require('@grpc/grpc-js');
  const protoLoader = require('@grpc/proto-loader');
  const path = require('path');

  // Load protobuf spec for an example API
  const PROTO_PATH = path.join(__dirname, '/protos/helloworld.proto');

  const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true,
  });

  const protoObj = grpc.loadPackageDefinition(packageDefinition).helloworld;

  // Create a client for the protobuf spec
  const client = new protoObj.Greeter(HOST, grpc.credentials.createInsecure());

  // Build gRPC request
  const metadata = new grpc.Metadata();
  if (API_KEY) {
    metadata.add('x-api-key', API_KEY);
  } else if (JWT_AUTH_TOKEN) {
    metadata.add('authorization', `Bearer ${JWT_AUTH_TOKEN}`);
  }

  // Execute gRPC request
  client.sayHello({name: GREETEE}, metadata, (err, response) => {
    if (err) {
      console.error(err);
    }

    if (response) {
      console.log(response.message);
    }
  });
};

Si vous utilisez la fonctionnalité de transcodage HTTP de Cloud Endpoints pour gRPC, les clients HTTP peuvent envoyer la clé en tant que paramètre de requête de la même manière que pour les services OpenAPI.

Si vous utilisez la fonctionnalité de transcodage HTTP de Cloud Endpoints pour gRPC, les clients HTTP peuvent envoyer la clé en tant que paramètre de requête de la même manière que pour les services OpenAPI.

Les clés API sont associées au projet dans lequel elles ont été créées.

Si vous avez décidé d'exiger une clé API pour votre API, le projet dans lequel la clé API est créée dépend des réponses aux questions suivantes : Google Cloud Si vous avez décidé d'exiger une clé API pour votre API, le Google Cloud projet dans lequel la clé API est créée dépend des réponses aux questions suivantes :

  • Tous les appelants de votre API ont-ils leur propre projet pour que vous puissiez utiliser les fonctionnalités d'Endpoints telles que les quotas ?
  • Avez-vous besoin de configurer différentes restrictions de clés API ? Google Cloud
  • Avez-vous besoin de configurer différentes restrictions de clé API ?

Vous pouvez utiliser l'arbre de décision suivant comme guide pour décider dans quel Google Cloud projet créer la clé API.

Arbre de décision relatif aux clés API

Autoriser l'activation de l'API

De cette manière, les utilisateurs de votre API peuvent créer leur propre clé API à utiliser avec votre API. Google Cloud Google Cloud Par exemple, supposons que votre équipe ait créé une API à usage interne pour différents programmes clients de votre entreprise et que chaque programme client possède son propre projet.

Pour distinguer les appelants de votre API, la clé API de chaque appelant doit être créée dans un projet différent. Google CloudPour distinguer les appelants de votre API, la clé API pour chaque appelant doit être créée dans un Google Cloud projet différent. Vous pouvez accorder à vos collègues l'autorisation d'activer l'API dans le Google Cloud projet auquel le programme client est associé.

Dans le projet dans lequel votre API est configurée, accordez à chaque utilisateur l'autorisation d'activer votre API.

  1. Contactez les utilisateurs et informez-les qu'ils peuvent activer votre API dans leur propre Google Cloud projet et créer une clé API.
  2. Contacter les utilisateurs et leur faire savoir qu'ils peuvent activer votre API dans leur propre Google Cloud projet et créer une clé API.

Lorsque vous devez faire la distinction entre les appelants de votre API et que tous les appelants n'ont pas de projet, vous pouvez créer un projet et une clé API distincts pour chaque appelant. Google Cloud

Avant de créer ces projets, réfléchissez aux noms que vous allez leur donner, afin d'être en mesure d'identifier facilement l'appelant associé à chaque projet. Google Cloud Google Cloud Par exemple, supposons que vous ayez des clients externes pour votre API, et que vous ne sachiez pas comment les programmes clients qui appellent celle-ci ont été créés.

Certains clients utilisent peut-être des services et possèdent donc un projet, alors que d'autres non. Pour distinguer les appelants, vous devez créer un projet et une clé API distincts pour chaque appelant. Google Cloud Google Cloud Pour créer un projet et une clé API distincts pour chaque appelant : Google Cloud

Créez un projet distinct pour chaque appelant. Google Cloud

  1. Dans chaque projet, activez votre API et créez une clé API.
  2. Dans chaque projet, activez votre API et créez une clé API.
  3. Donnez la clé API à chaque appelant.

Créer une clé API pour chaque appelant

Lorsque vous n'avez pas besoin de distinguer les appelants de votre API, mais que vous souhaitez ajouter des restrictions de clé API, vous pouvez créer une clé API distincte pour chaque appelant du même projet.

Pour créer une clé API pour chaque appelant dans le même projet :

  1. Soit dans le projet dans lequel votre API est configurée, soit dans un projet dans lequel votre API est activée, créez pour chaque client une clé API disposant des restrictions de clés API dont vous avez besoin.
  2. Donnez la clé API à chaque appelant.

Créer une clé API pour tous les appelants

Lorsque vous n'avez pas besoin de distinguer les appelants de votre API ni d'ajouter de restrictions d'API, mais que vous souhaitez quand même qu'une clé API soit exigée (pour empêcher l'accès anonyme, par exemple), vous pouvez créer une clé API que tous les appelants peuvent utiliser.

Soit dans le projet dans lequel votre API est configurée, soit dans un projet dans lequel votre API est activée, créez pour tous les appelants une clé API disposant des restrictions de clés API dont vous avez besoin.
  1. Donnez la même clé API à chaque appelant.
  2. Restrictions liées aux applications

Les restrictions liées aux applications spécifient les sites Web, adresses IP ou applications qui peuvent utiliser votre clé API.

Pour en savoir plus, consultez Ajouter des restrictions d'application. **Remarque** : Si vous utilisez des **référents HTTP (sites Web)** comme restriction d'application, vous devez inclure un schéma (par exemple, `https://`) lorsque vous ajoutez la restriction de site Web. Pour plus d'informations, consultez Ajouter des restrictions d'application.

Remarque : Si vous utilisez les référents HTTP (sites Web) comme restriction d'application, vous devez inclure un schéma (par exemple, https://) lorsque vous ajoutez la restriction de site Web. Par exemple, https://example.com/* est une restriction valide, mais example.com/* ne l'est pas.

Quand et pourquoi utiliser les clés API