Server Security

<- Back to Index

This section describes how you secure your application using transport layer security and authentication. We strongly recommend enabling at least transport layer security.

Table of Contents

Additional Topics

Enable Transport Layer Security

You can configure transport level security using spring’s configuration mechanisms. For non security related configuration options refer to the Configuration page.

If you are behind a reverse proxy that handles TLS for you, you might not need to set up TLS. Please consult with security experts, if you are not familiar with security. Don’t forget to check the setup for security issues. ^^

Note: Please refer to the official documentation for additional information!

Prerequisites

Generating Self Signed Certificates

If you don’t have certificates (e.g. for your internal test server) you can generate them using openssl:

openssl req -x509 -nodes -subj "//CN=localhost" -newkey rsa:4096 -sha256 -keyout server.key -out server.crt -days 3650

Please note that these certificates aren’t trusted by any application without additional configuration. We recommend that you either use certificates that are trusted by a global CA or your company’s CA.

Configuring the Server

In order to allow the grpc-server to use TLS you have to configure it using the following options:

grpc.server.security.enabled=true
grpc.server.security.certificateChain=file:certificates/server.crt
grpc.server.security.privateKey=file:certificates/server.key
#grpc.server.security.privateKeyPassword=MyStrongPassword

If you want to know what options are supported here, read Spring’s Resource docs.

For the corresponding client configuration read the Client Security page.

Mutual Certificate Authentication

If you want to make sure that only trustworthy clients can connect to the server you can enable mutual certificate authentication. This either allows or forces the client to authenticate itself using a x509 certificate.

To enable mutual authentication simply add the following properties to your configuration:

grpc.server.security.trustCertCollection=file:certificates/trusted-clients.crt.collection
grpc.server.security.clientAuth=REQUIRE

You can create the trusted-clients.crt.collection file by simply concatenating the clients certificates:

cat client*.crt > trusted-clients.crt.collection

The clientAuth mode defines how the server will behave:

You can use OPTIONAL if you want to secure only some important services or methods.

Especially in the later case, it is important to configure the authentication appropriately.

Authentication and Authorization

grpc-spring-boot-starter supports spring-security natively, so you can just use the well-known annotations to secure your application.

server-request-security

Configure Authentication

In order to support authentication from grpc-clients, you have to define how the clients are allowed to authenticate. You can do so by defining a GrpcAuthenticationReader.

grpc-spring-boot-starter comes with a number of build-in implementations:

Your bean definition will look similar to this example:

@Bean
public GrpcAuthenticationReader grpcAuthenticationReader() {
    return new BasicGrpcAuthenticationReader();
}

If you want to force users to authenticate use the CompositeGrpcAuthenticationReader and append a GrpcAuthenticationReader that throws a AuthenticationException. This marks the authentication as failed and will stop the processing of the request. If the GrpcAuthenticationReader returns null, then the user will continue unauthenticated. If the reader was able to extract the credentials/authentication, then they will be validated by spring’s AuthenticationManager. That instance will then decide, whether the user has sent valid credentials and may proceed or not.

Example setups

The following sections contain example configurations for different authentication setups:

Note: It is not necessary to wrap the reader in a CompositeGrpcAuthenticationReader it should just demonstrate, that you could add multiple mechanisms.

BasicAuth
@Bean
AuthenticationManager authenticationManager() {
    final List<AuthenticationProvider> providers = new ArrayList<>();
    providers.add(...); // Possibly DaoAuthenticationProvider
    return new ProviderManager(providers);
}

@Bean
GrpcAuthenticationReader authenticationReader() {
    final List<GrpcAuthenticationReader> readers = new ArrayList<>();
    readers.add(new BasicGrpcAuthenticationReader());
    return new CompositeGrpcAuthenticationReader(readers);
}
Bearer Authentication (OAuth2/OpenID-Connect)
@Bean
AuthenticationManager authenticationManager() {
    final List<AuthenticationProvider> providers = new ArrayList<>();
    providers.add(...); // Possibly JwtAuthenticationProvider
    return new ProviderManager(providers);
}

@Bean
GrpcAuthenticationReader authenticationReader() {
    final List<GrpcAuthenticationReader> readers = new ArrayList<>();
    // The actual token class is dependent on your spring-security library (OAuth2/JWT/...)
    readers.add(new BearerAuthenticationReader(accessToken -> new BearerTokenAuthenticationToken(accessToken)));
    return new CompositeGrpcAuthenticationReader(readers);
}

You might also want to define your own GrantedAuthoritiesConverter to map the permissions/roles in the bearer token to Spring Security’s GrantedAuthoritys.

Certificate Authentication
@Bean
AuthenticationManager authenticationManager() {
    final List<AuthenticationProvider> providers = new ArrayList<>();
    providers.add(new X509CertificateAuthenticationProvider(userDetailsService()));
    return new ProviderManager(providers);
}

@Bean
GrpcAuthenticationReader authenticationReader() {
    final List<GrpcAuthenticationReader> readers = new ArrayList<>();
    readers.add(new SSLContextGrpcAuthenticationReader());
    return new CompositeGrpcAuthenticationReader(readers);
}

See also Mutual Certificate Authentication.

Configure Authorization

This step is very important as it actually secures your application against unwanted access. You can secure your grpc-server in two ways.

gRPC security checks

One way to secure your application is adding GrpcSecurityMetadataSource bean to your application context. It allows you to return the security conditions on a per grpc method level.

An example bean definition (using hard coded rules) might look like this:

import net.devh.boot.grpc.server.security.check.AccessPredicate;
import net.devh.boot.grpc.server.security.check.ManualGrpcSecurityMetadataSource;

@Bean
GrpcSecurityMetadataSource grpcSecurityMetadataSource() {
    final ManualGrpcSecurityMetadataSource source = new ManualGrpcSecurityMetadataSource();
    source.set(MyServiceGrpc.getMethodA(), AccessPredicate.authenticated());
    source.set(MyServiceGrpc.getMethodB(), AccessPredicate.hasRole("ROLE_USER"));
    source.set(MyServiceGrpc.getMethodC(), AccessPredicate.hasAllRole("ROLE_FOO", "ROLE_BAR"));
    source.set(MyServiceGrpc.getMethodD(), auth -> "admin".equals(auth.getName()));
    source.setDefault(AccessPredicate.denyAll());
    return source;
}

@Bean
AccessDecisionManager accessDecisionManager() {
    final List<AccessDecisionVoter<?>> voters = new ArrayList<>();
    voters.add(new AccessPredicateVoter());
    return new UnanimousBased(voters);
}

You have to configure the AccessDecisionManager otherwise it doesn’t know how to deal with the AccessPredicates.

This approach has the benefit that you are able to move the configuration to an external file or database. You have to implement that yourself though.

Spring annotation security checks

Of course, it is also possible to just use spring-security’s annotations. For this use case you have to add the following annotation to one of your @Configuration classes:

@EnableGlobalMethodSecurity(___Enabled = true, proxyTargetClass = true)

Please note that proxyTargetClass = true is required! If you forget to add it, you will get a lot of UNIMPLEMENTED responses. However, you will receive a warning that MyServiceImpl#bindService() method is final. Do NOT try to un-final that method as that would bypass security.

Then you can simply annotate the grpc method implementation:

@Override
@Secured("ROLE_ADMIN")
// MyServiceGrpc.methodX
public void methodX(Request request, StreamObserver<Response> responseObserver) {
    [...]
}

This library assumes that you extend the ImplBase (generated by grpc) in order to implement the service. Not doing so might result in bypassing spring-security.

Additional Topics


<- Back to Index