The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
このページを編集

gRPCサービスの実装

CDI Beanとして公開されたgRPCサービスの実装は、quarkus-grpcによって自動的に登録、提供されます。

gRPC サービスを実装するには、gRPC クラスを生成する必要があります。 proto ファイルを src/main/proto に置き、 mvn compile を実行します。

生成されたコード

Quarkusは、 proto ファイルで宣言されたサービスに対して、いくつかの実装クラスを生成します。

  1. Mutiny APIを使用した サービスインターフェース

    • クラス名は ${JAVA_PACKAGE}.${NAME_OF_THE_SERVICE}

  2. gRPC APIを利用した 実装のベース のクラス

    • クラス名は以下のように構成されています。 ${JAVA_PACKAGE}.${NAME_OF_THE_SERVICE}Grpc.${NAME_OF_THE_SERVICE}ImplBase

例えば、以下の proto ファイルスニペットを使用した場合は、

option java_package = "hello"; (1)

service Greeter { (2)
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}
1 hello は、生成されたクラスのjavaパッケージです。
2 Greeter はサービス名です。

サービス・インターフェースは hello.Greeter であり、実装ベースは hello.GreeterGrpc.GreeterImplBase という抽象的な静的ネストクラスです。

以下のセクションで説明するように、 サービスインターフェース を実装するか、 ベースクラス をサービス実装Beanで拡張する必要があります。

Mutiny APIによるサービスの実装

Mutiny APIを使ってgRPCサービスを実装するには、サービスインターフェースを実装したクラスを作成します。そして、サービスインターフェースで定義されているメソッドを実装します。サービスメソッドを実装したくない場合は、メソッドボディから java.lang.UnsupportedOperationException を投げてください(例外は適切な gRPCの例外に自動的に変換されます)。最後に、サービスを実装し、 @GrpcService アノテーションを追加します。

import io.quarkus.grpc.GrpcService;
import hello.Greeter;

@GrpcService (1)
public class HelloService implements Greeter { (2)

    @Override
    public Uni<HelloReply> sayHello(HelloRequest request) {
        return Uni.createFrom().item(() ->
                HelloReply.newBuilder().setMessage("Hello " + request.getName()).build()
        );
    }
}
1 gRPCサービス実装Beanは、 @GrpcService アノテーションを付けなければならず、他のCDI修飾子を宣言してはいけません。すべてのgRPCサービスは、 jakarta.inject.Singleton のスコープを持ちます。さらに、サービス呼び出しの間、リクエストコンテキストが有効になります。
2 hello.Greeter は、生成されたサービスインターフェースです。
サービス実装Beanは、Mutinyの実装ベースを拡張することもでき、その場合、クラス名は以下のように構成されます。 Mutiny${NAME_OF_THE_SERVICE}Grpc.${NAME_OF_THE_SERVICE}ImplBase

デフォルトのgRPC APIでのサービス実装

デフォルトのgRPC APIを使ってgRPCサービスを実装するには、デフォルトの実装ベースを拡張したクラスを作成します。次に、サービス・インターフェースで定義されているメソッドを上書きします。最後に、サービスを実装し、 @GrpcService アノテーションを追加します。

import io.quarkus.grpc.GrpcService;

@GrpcService
public class HelloService extends GreeterGrpc.GreeterImplBase {

    @Override
    public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
        String name = request.getName();
        String message = "Hello " + name;
        responseObserver.onNext(HelloReply.newBuilder().setMessage(message).build());
        responseObserver.onCompleted();
    }
}

ブロッキングサービスの実装

デフォルトでは、gRPCサービスからのすべてのメソッドはイベントループ上で実行されます。そのため、ブロックしては いけません 。サービスロジックをブロックする必要がある場合は、メソッドに io.smallrye.common.annotation.Blocking アノテーションを追加します。

@Override
@Blocking
public Uni<HelloReply> sayHelloBlocking(HelloRequest request) {
    // Do something blocking before returning the Uni
}

ストリームの処理

gRPCでは、ストリームを受信して返すことができます。

service Streaming {
    rpc Source(Empty) returns (stream Item) {} // Returns a stream
    rpc Sink(stream Item) returns (Empty) {}   // Reads a stream
    rpc Pipe(stream Item) returns (stream Item) {}  // Reads a streams and return a streams
}

Mutinyを使うと、以下のように実装できます。

import io.quarkus.grpc.GrpcService;

@GrpcService
public class StreamingService implements Streaming {

    @Override
    public Multi<Item> source(Empty request) {
        // Just returns a stream emitting an item every 2ms and stopping after 10 items.
        return Multi.createFrom().ticks().every(Duration.ofMillis(2))
                .select().first(10)
                .map(l -> Item.newBuilder().setValue(Long.toString(l)).build());
    }

    @Override
    public Uni<Empty> sink(Multi<Item> request) {
        // Reads the incoming streams, consume all the items.
        return request
                .map(Item::getValue)
                .map(Long::parseLong)
                .collect().last()
                .map(l -> Empty.newBuilder().build());
    }

    @Override
    public Multi<Item> pipe(Multi<Item> request) {
        // Reads the incoming stream, compute a sum and return the cumulative results
        // in the outbound stream.
        return request
                .map(Item::getValue)
                .map(Long::parseLong)
                .onItem().scan(() -> 0L, Long::sum)
                .onItem().transform(l -> Item.newBuilder().setValue(Long.toString(l)).build());
    }
}

ヘルスチェック

実装されたサービスでは、Quarkus gRPCは以下の形式でヘルスチェックを公開しています。

syntax = "proto3";

package grpc.health.v1;

message HealthCheckRequest {
  string service = 1;
}

message HealthCheckResponse {
  enum ServingStatus {
    UNKNOWN = 0;
    SERVING = 1;
    NOT_SERVING = 2;
  }
  ServingStatus status = 1;
}

service Health {
  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);

  rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}

クライアントは、特定のサービスのヘルス状態を取得するために完全修飾されたサービス名を指定したり、gRPCサーバーの一般的な状態を取得するためにサービス名の指定を省略することができます。

詳細については、 gRPCのドキュメント を確認してください。

さらに、Quarkus SmallRye Healthがアプリケーションに追加された場合、gRPCサービスの状態に関するレディネスチェックがMicroProfile Healthエンドポイントレスポンスに追加されます( /q/health )。

リフレクションサービス

Quarkus gRPC Serverは、 リフレクションサービス を実装しています。このサービスを使用すると、 grpcurlgrpcox などのツールがサービスと対話できるようになります。

リフレクションサービスは、 開発 モードではデフォルトで有効になっています。テストモードやプロダクションモードでは、 quarkus.grpc.server.enable-reflection-servicetrue に設定して明示的に有効にする必要があります。

Quarkusは、リフレクションサービス v1v1alpha の両方を公開しています。

スケーリング

デフォルトでは、quarkus-grpcは単一のイベントループ上で動作する単一のgRPCサーバーを起動します。

サーバーをスケールさせたい場合は、 quarkus.grpc.server.instances を設定することで、サーバーのインスタンス数をセットできます。

サーバー構成

ビルド時に固定される設定プロパティ - その他の設定プロパティは実行時にオーバーライド可能です。

Configuration property

タイプ

デフォルト

Do we use separate HTTP server to serve gRPC requests. Set this to false if you want to use new Vert.x gRPC support, which uses existing Vert.x HTTP server.

Environment variable: QUARKUS_GRPC_SERVER_USE_SEPARATE_SERVER

Show more

ブーリアン

true

Configure XDS usage, if enabled

タイプ

デフォルト

Explicitly enable use of XDS.

Environment variable: QUARKUS_GRPC_SERVER_XDS_ENABLED

Show more

ブーリアン

false

Use secure credentials.

Environment variable: QUARKUS_GRPC_SERVER_XDS_SECURE

Show more

ブーリアン

false

Explicitly enable use of in-process.

Environment variable: QUARKUS_GRPC_SERVER_IN_PROCESS_ENABLED

Show more

ブーリアン

false

Set in-process name.

Environment variable: QUARKUS_GRPC_SERVER_IN_PROCESS_NAME

Show more

string

quarkus-grpc

The gRPC Server port.

Environment variable: QUARKUS_GRPC_SERVER_PORT

Show more

int

9000

The gRPC Server port used for tests.

Environment variable: QUARKUS_GRPC_SERVER_TEST_PORT

Show more

int

9001

The gRPC server host.

Environment variable: QUARKUS_GRPC_SERVER_HOST

Show more

string

0.0.0.0

The gRPC handshake timeout.

Environment variable: QUARKUS_GRPC_SERVER_HANDSHAKE_TIMEOUT

Show more

Duration 

The max inbound message size in bytes.

When using a single server (using quarkus.grpc.server.use-separate-server=false), the default value is 256KB. When using a separate server (using quarkus.grpc.server.use-separate-server=true), the default value is 4MB.

Environment variable: QUARKUS_GRPC_SERVER_MAX_INBOUND_MESSAGE_SIZE

Show more

int

The max inbound metadata size in bytes

Environment variable: QUARKUS_GRPC_SERVER_MAX_INBOUND_METADATA_SIZE

Show more

int

The classpath path or file path to a server certificate or certificate chain in PEM format.

Environment variable: QUARKUS_GRPC_SERVER_SSL_CERTIFICATE

Show more

path

The classpath path or file path to the corresponding certificate private key file in PEM format.

Environment variable: QUARKUS_GRPC_SERVER_SSL_KEY

Show more

path

An optional keystore that holds the certificate information instead of specifying separate files. The keystore can be either on classpath or an external file.

Environment variable: QUARKUS_GRPC_SERVER_SSL_KEY_STORE

Show more

path

An optional parameter to specify the type of the keystore file. If not given, the type is automatically detected based on the file name.

Environment variable: QUARKUS_GRPC_SERVER_SSL_KEY_STORE_TYPE

Show more

string

A parameter to specify the password of the keystore file.

Environment variable: QUARKUS_GRPC_SERVER_SSL_KEY_STORE_PASSWORD

Show more

string

A parameter to specify the alias of the keystore file.

Environment variable: QUARKUS_GRPC_SERVER_SSL_KEY_STORE_ALIAS

Show more

string

A parameter to specify the alias password of the keystore file.

Environment variable: QUARKUS_GRPC_SERVER_SSL_KEY_STORE_ALIAS_PASSWORD

Show more

string

An optional trust store which holds the certificate information of the certificates to trust

The trust store can be either on classpath or an external file.

Environment variable: QUARKUS_GRPC_SERVER_SSL_TRUST_STORE

Show more

path

An optional parameter to specify type of the trust store file. If not given, the type is automatically detected based on the file name.

Environment variable: QUARKUS_GRPC_SERVER_SSL_TRUST_STORE_TYPE

Show more

string

A parameter to specify the password of the trust store file.

Environment variable: QUARKUS_GRPC_SERVER_SSL_TRUST_STORE_PASSWORD

Show more

string

The cipher suites to use. If none is given, a reasonable default is selected.

Environment variable: QUARKUS_GRPC_SERVER_SSL_CIPHER_SUITES

Show more

list of string

Sets the ordered list of enabled SSL/TLS protocols.

If not set, it defaults to "TLSv1.3, TLSv1.2". The following list of protocols are supported: TLSv1, TLSv1.1, TLSv1.2, TLSv1.3. To only enable TLSv1.3, set the value to to "TLSv1.3".

Note that setting an empty list, and enabling SSL/TLS is invalid. You must at least have one protocol.

Environment variable: QUARKUS_GRPC_SERVER_SSL_PROTOCOLS

Show more

list of string

TLSv1.3,TLSv1.2

Configures the engine to require/request client authentication. NONE, REQUEST, REQUIRED

Environment variable: QUARKUS_GRPC_SERVER_SSL_CLIENT_AUTH

Show more

none, request, required

none

Disables SSL, and uses plain text instead. If disabled, configure the ssl configuration.

Environment variable: QUARKUS_GRPC_SERVER_PLAIN_TEXT

Show more

ブーリアン

true

Whether ALPN should be used.

Environment variable: QUARKUS_GRPC_SERVER_ALPN

Show more

ブーリアン

true

The path to the certificate file.

Environment variable: QUARKUS_GRPC_SERVER_TRANSPORT_SECURITY_CERTIFICATE

Show more

string

The path to the private key file.

Environment variable: QUARKUS_GRPC_SERVER_TRANSPORT_SECURITY_KEY

Show more

string

Enables the gRPC Reflection Service. By default, the reflection service is only exposed in dev mode. This setting allows overriding this choice and enable the reflection service every time.

Environment variable: QUARKUS_GRPC_SERVER_ENABLE_REFLECTION_SERVICE

Show more

ブーリアン

false

Number of gRPC server verticle instances. This is useful for scaling easily across multiple cores. The number should not exceed the amount of event loops.

Environment variable: QUARKUS_GRPC_SERVER_INSTANCES

Show more

int

1

Sets a custom keep-alive duration. This configures the time before sending a keepalive ping when there is no read activity.

Environment variable: QUARKUS_GRPC_SERVER_NETTY_KEEP_ALIVE_TIME

Show more

Duration 

Sets a custom permit-keep-alive duration. This configures the most aggressive keep-alive time clients are permitted to configure. The server will try to detect clients exceeding this rate and when detected will forcefully close the connection.

Environment variable: QUARKUS_GRPC_SERVER_NETTY_PERMIT_KEEP_ALIVE_TIME

Show more

Duration 

Sets whether to allow clients to send keep-alive HTTP/2 PINGs even if there are no outstanding RPCs on the connection.

Environment variable: QUARKUS_GRPC_SERVER_NETTY_PERMIT_KEEP_ALIVE_WITHOUT_CALLS

Show more

ブーリアン

gRPC compression, e.g. "gzip"

Environment variable: QUARKUS_GRPC_SERVER_COMPRESSION

Show more

string

期間フォーマットについて

To write duration values, use the standard java.time.Duration format. See the Duration#parse() Java API documentation for more information.

数字で始まる簡略化した書式を使うこともできます:

  • 数値のみの場合は、秒単位の時間を表します。

  • 数値の後に ms が続く場合は、ミリ秒単位の時間を表します。

その他の場合は、簡略化されたフォーマットが解析のために java.time.Duration フォーマットに変換されます:

  • 数値の後に hms が続く場合は、その前に PT が付けられます。

  • 数値の後に d が続く場合は、その前に P が付けられます。

quarkus.grpc.server.use-separate-server を無効にすると、既存の HTTP サーバーを使用する新しい Vert.x gRPC サーバー実装が使用されます。つまり、サーバーのポートが 8080 (または quarkus.http.port で設定されたポート) になることを意味します。また、すでに適切に設定されているはずの HTTP サーバーであるため、他のほとんどの設定プロパティは適用されなくなります。
quarkus.grpc.server.xds.enabled を有効にすると、上記の設定のほとんどを処理するのはxDSになります。

構成の例

TLSを有効にする

TLSを有効にするには、以下の設定を使用します。

設定のすべてのパスは、クラスパス上のリソース (通常は src/main/resources やそのサブフォルダーから) か外部ファイルを指定することに注意してください。

quarkus.grpc.server.ssl.certificate=tls/server.pem
quarkus.grpc.server.ssl.key=tls/server.key
SSL/TLSを設定すると、 plain-text は自動的に無効になります。

相互認証付きTLS

相互認証付きのTLSを使用するには、以下の設定を使用します。

quarkus.grpc.server.ssl.certificate=tls/server.pem
quarkus.grpc.server.ssl.key=tls/server.key
quarkus.grpc.server.ssl.trust-store=tls/ca.jks
quarkus.grpc.server.ssl.trust-store-password=*****
quarkus.grpc.server.ssl.client-auth=REQUIRED

サーバーインターセプター

gRPCサーバーのインターセプターでは、サービスが呼び出される前に、認証などのロジックを実行することができるようになります。

io.grpc.ServerInterceptor を実装した @ApplicationScoped Beanを作成することで、gRPC サーバーのインターセプターを実装できます。

@ApplicationScoped
// add @GlobalInterceptor for interceptors meant to be invoked for every service
public class MyInterceptor implements ServerInterceptor {

    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall,
            Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) {
        // ...
    }
}

プロデューサー・メソッドをグローバル・インターセプターとしてアノテーションすることも可能です:

import io.quarkus.grpc.GlobalInterceptor;

import jakarta.enterprise.inject.Produces;

public class MyProducer {
    @GlobalInterceptor
    @Produces
    public MyInterceptor myInterceptor() {
        return new MyInterceptor();
    }
}
ServerInterceptor JavaDoc をチェックして、インターセプターを適切に実装してください。

公開されているすべてのサービスにインターセプターを適用するには、 @io.quarkus.grpc.GlobalInterceptor でアノテーションを付けます。インターセプターを単一のサービスに適用するには、 @io.quarkus.grpc.RegisterInterceptor でそのサービスに登録します。

import io.quarkus.grpc.GrpcService;
import io.quarkus.grpc.RegisterInterceptor;

@GrpcService
@RegisterInterceptor(MyInterceptor.class)
public class StreamingService implements Streaming {
    // ...
}

複数のサーバーインターセプターがある場合、 jakarta.enterprise.inject.spi.Prioritized インターフェースを実装することで、それらを順番に並べることができます。すべてのグローバルインターセプターは、サービス固有のインターセプターの前に起動されることに注意してください。

@ApplicationScoped
public class MyInterceptor implements ServerInterceptor, Prioritized {

    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall,
            Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) {
        // ...
    }

    @Override
    public int getPriority() {
        return 10;
    }
}

最高の優先度を持つインターセプターが最初に呼び出されます。インターセプターが Prioritized インターフェイスを実装していない場合に使用されるデフォルトの優先度は 0 です。

サービスのテスト

gRPCサービスをテストする最も簡単な方法は、 gRPCサービスの使用 で説明したように、gRPCクライアントを使用することです。

なお、TLS を使用していない公開サービスのテストにクライアントを使用する場合は、設定を行う必要はありませんのでご注意ください。例えば、上記で定義した HelloService をテストするには、次のようなテストを作成します。

public class HelloServiceTest implements Greeter {

    @GrpcClient
    Greeter client;

    @Test
    void shouldReturnHello() {
        CompletableFuture<String> message = new CompletableFuture<>();
        client.sayHello(HelloRequest.newBuilder().setName("Quarkus").build())
                .subscribe().with(reply -> message.complete(reply.getMessage()));
        assertThat(message.get(5, TimeUnit.SECONDS)).isEqualTo("Hello Quarkus");
    }
}

手動でサービスを試す

In the dev mode, you can try out your gRPC services in the Quarkus Dev UI. Just go to http://localhost:8080/q/dev-ui and click on Services under the gRPC tile.

Dev UIにアクセスするには、アプリケーションが ”通常の” HTTPポートを公開する必要があることに注意してください。アプリケーションがHTTPエンドポイントを公開していない場合は、 quarkus-vertx-http に依存する専用のプロファイルを作成することができます。

    <profiles>
        <profile>
            <id>development</id>
            <dependencies>
                <dependency>
                    <groupId>io.quarkus</groupId>
                    <artifactId>quarkus-vertx-http</artifactId>
                </dependency>
            </dependencies>
        </profile>
    </profiles>

これがあれば、次のようにしてDevモードを実行できます: mvn quarkus:dev -Pdevelopment

Gradleを使用している場合は、 quarkusDev タスクの依存関係を追加するだけです。

dependencies {
    quarkusDev 'io.quarkus:quarkus-vertx-http'
}

gRPCサーバーのメトリクス

メトリクス収集の有効化

アプリケーションが quarkus-micrometer エクステンションも使用している場合、gRPCサーバーのメトリクスは自動的に有効になります。 Micrometerは、アプリケーションが実装するすべてのgRPCサービスのメトリクスを収集します。

例えば、メトリクスをPrometheusにエクスポートすると、以下のように取得できます。

# HELP grpc_server_responses_sent_messages_total The total number of responses sent
# TYPE grpc_server_responses_sent_messages_total counter
grpc_server_responses_sent_messages_total{method="SayHello",methodType="UNARY",service="helloworld.Greeter",} 6.0
# HELP grpc_server_processing_duration_seconds The total time taken for the server to complete the call
# TYPE grpc_server_processing_duration_seconds summary
grpc_server_processing_duration_seconds_count{method="SayHello",methodType="UNARY",service="helloworld.Greeter",statusCode="OK",} 6.0
grpc_server_processing_duration_seconds_sum{method="SayHello",methodType="UNARY",service="helloworld.Greeter",statusCode="OK",} 0.016216771
# HELP grpc_server_processing_duration_seconds_max The total time taken for the server to complete the call
# TYPE grpc_server_processing_duration_seconds_max gauge
grpc_server_processing_duration_seconds_max{method="SayHello",methodType="UNARY",service="helloworld.Greeter",statusCode="OK",} 0.007985236
# HELP grpc_server_requests_received_messages_total The total number of requests received
# TYPE grpc_server_requests_received_messages_total counter
grpc_server_requests_received_messages_total{method="SayHello",methodType="UNARY",service="helloworld.Greeter",} 6.0

サービス名、メソッド、タイプは tags で確認できます。

メトリクス収集の無効化

quarkus-micrometer を使用しているときに gRPC サーバーメトリクスを無効にするには、アプリケーションの設定に以下のプロパティを追加します。

quarkus.micrometer.binder.grpc-server.enabled=false

仮想スレッドの使用

gRPCサービスの実装で仮想スレッドを使用するには、専用の ガイド を参照してください。

gRPC Server authorization

Quarkus includes built-in security to allow authorization using annotations when the Vert.x gRPC support, which uses existing Vert.x HTTP server, is enabled.

Add the Quarkus Security extension

Security capabilities are provided by the Quarkus Security extension, therefore make sure your pom.xml file contains following dependency:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-security</artifactId>
</dependency>

To add the Quarkus Security extension to an existing Maven project, run the following command from your project base directory:

コマンドラインインタフェース
quarkus extension add security
Maven
./mvnw quarkus:add-extension -Dextensions='security'
Gradle
./gradlew addExtension --extensions='security'

サポートされる認証メカニズムの概要

Some supported authentication mechanisms are built into Quarkus, while others require you to add an extension. The following table maps specific authentication requirements to a supported mechanism that you can use in Quarkus:

Table 1. 認証要件とメカニズム
認証要件 認証メカニズム

ユーザー名とパスワード

Basic認証

クライアント証明書

相互TLS認証

Custom requirements

Custom authentication

ベアラーアクセストークン

OIDCベアラートークン認証JWTOAuth2

Do not forget to install at least one extension that provides an IdentityProvider based on selected authentication requirements. Please refer to the Basic authentication guide for example how to provide the IdentityProvider based on username and password.

If you use separate HTTP server to serve gRPC requests, Custom authentication is your only option. Set the quarkus.grpc.server.use-separate-server configuration property to false so that you can use other mechanisms.

Secure gRPC service

The gRPC services can be secured with the standard security annotations like in the example below:

package org.acme.grpc.auth;

import hello.Greeter;
import io.quarkus.grpc.GrpcService;
import jakarta.annotation.security.RolesAllowed;

@GrpcService
public class HelloService implements Greeter {

    @RolesAllowed("admin")
    @Override
    public Uni<HelloReply> sayHello(HelloRequest request) {
        return Uni.createFrom().item(() ->
                HelloReply.newBuilder().setMessage("Hello " + request.getName()).build()
        );
    }
}

Most of the examples of the supported mechanisms sends authentication headers, please refer to the gRPC Headers section of the Consuming a gRPC Service guide for more information about the gRPC headers.

Basic認証

Quarkus Security provides built-in authentication support for the Basic authentication.

quarkus.grpc.server.use-separate-server=false
quarkus.http.auth.basic=true (1)
1 Enable the Basic authentication.
package org.acme.grpc.auth;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

import org.acme.proto.Greeter;
import org.acme.proto.HelloRequest;
import io.grpc.Metadata;
import io.quarkus.grpc.GrpcClient;
import io.quarkus.grpc.GrpcClientUtils;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

@QuarkusTest
public class GreeterServiceTest {

    private static final Metadata.Key<String> AUTHORIZATION = Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER);

    @GrpcClient
    Greeter greeterClient;

    @Test
    void shouldReturnHello() throws ExecutionException, InterruptedException, TimeoutException {
        Metadata headers = new Metadata();

        // Set the headers - Basic auth for testing
        headers.put(AUTHORIZATION, "Basic YWxpY2U6YWxpY2U="); // alice:alice with "admin" role
        var client = GrpcClientUtils.attachHeaders(greeterClient, headers);

        // Call the client
        CompletableFuture<String> message = new CompletableFuture<>();
        client.sayHello(HelloRequest.newBuilder().setName("Quarkus").build())
                .subscribe().with(reply -> message.complete(reply.getMessage()));

        // Get the values
        String theValue = message.get(5, TimeUnit.SECONDS);

        // Assert
        assertThat(theValue, is("Hello Quarkus"));
    }
}

相互TLS認証

Quarkus provides mutual TLS (mTLS) authentication so that you can authenticate users based on their X.509 certificates. The simplest way to enforce authentication for all your gRPC services is described in the 相互認証付きTLS section of this guide. However, the Quarkus Security supports role mapping that you can use to perform even more fine-grained access control.

quarkus.grpc.server.use-separate-server=false
quarkus.http.insecure-requests=disabled
quarkus.http.ssl.certificate.files=tls/server.pem
quarkus.http.ssl.certificate.key-files=tls/server.key
quarkus.http.ssl.certificate.trust-store-file=tls/ca.jks
quarkus.http.ssl.certificate.trust-store-password=**********
quarkus.http.ssl.client-auth=required
quarkus.http.auth.certificate-role-properties=role-mappings.txt     (1)
quarkus.native.additional-build-args=-H:IncludeResources=.*\\.txt
1 Adds certificate role mapping.
Example of the role mapping file
testclient=admin (1)
1 Map the testclient certificate CN (Common Name) to the SecurityIdentity role admin.

Custom authentication

You can always implement one or more GrpcSecurityMechanism bean if above-mentioned mechanisms provided by Quarkus do no meet your needs.

Example of custom GrpcSecurityMechanism
package org.acme.grpc.auth;

import jakarta.inject.Singleton;

import io.grpc.Metadata;
import io.quarkus.security.credential.PasswordCredential;
import io.quarkus.security.identity.request.AuthenticationRequest;
import io.quarkus.security.identity.request.UsernamePasswordAuthenticationRequest;

@Singleton
public class CustomGrpcSecurityMechanism implements GrpcSecurityMechanism {

    private static final Metadata.Key<String> AUTHORIZATION = Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER);

    @Override
    public boolean handles(Metadata metadata) {
        String authString = metadata.get(AUTHORIZATION);
        return authString != null && authString.startsWith("Custom ");
    }

    @Override
    public AuthenticationRequest createAuthenticationRequest(Metadata metadata) {
        final String authString = metadata.get(AUTHORIZATION);
        final String userName;
        final String password;
        // here comes your application logic that transforms 'authString' to user name and password
        return new UsernamePasswordAuthenticationRequest(userName, new PasswordCredential(password));
    }
}

関連コンテンツ