trinodb / trino

Official repository of Trino, the distributed SQL query engine for big data, formerly known as PrestoSQL (https://trino.io)
https://trino.io
Apache License 2.0
10.25k stars 2.95k forks source link

Introduce an authentication plugin interface to the Trino JDBC driver #22516

Open sugibuchi opened 3 months ago

sugibuchi commented 3 months ago

Proposal

Introduce an authentication plugin interface similar to the ones existing in the PostgreSQL JDBC driver and MySQL JDBC driver to the Trino JDBC driver.

Context

Many public clouds and PaaS platforms, including Kubernetes, have a kind of "service account" mechanism that allows hosted workloads to access protected resources without predefined security credentials.

Using such service accounts significantly simplifies application deployment and improves security by eliminating the need for tedious credential management. A question here is how we can utilize service accounts provided by each platform in the Trino JDBC driver.

The main difficulty of this problem is that each platform has a different mechanism for authentication with service accounts and provides its own SDK for this. Therefore, it is not realistic to implement service account support for various platforms directly in the JDBC driver.

Interestingly, Microsoft Azure integrates its authentication framework, including service account (managed identity) support, into JDBC drivers by using "authentication plugin" interfaces.

The PostgreSQL JDBC driver and MySQL JDBC driver have authentication plugin interfaces (PostgreSQL, MySQL), which allow JDBC clients to plug in third-party components for client authentication.

The authentication plugins (PostgreSQL, MySQL) provided by the Azure identity authentication extensions authenticate JDBC clients in various ways supported by the Azure Identity framework and send JWT access tokens issued by Entra ID for authenticated clients to Azure PostgreSQL and MySQL as security credentials.

The support of a similar plugin interface in the Trino JDBC driver will enable more seamless integration of the authentication mechanism provided by each platform into Trino user authentication.

Technical details (idea)

Plugin API

Conceptually, the minimum definition of the authentication plugin interface for Trino looks like:

public interface AuthenticationPlugin 
{
    Set<String> propertyNames();

    void validateProperties(Properties properties) throws SQLException;

    boolean requireSecureConnection();
}

public interface HttpInterceptorPlugin extends AuthenticationPlugin
{
    Interceptor getInterceptor(String host, Properties properties);
}

AuthenticationPlugin interface defines an API for validating connection properties for the plugin. We need to define interfaces for each of the authentication methods supported by Trino as an extension of this interface. HttpRequestInterceptorPlugin in the above code is an interface that can be used for basic authentication, JWT authentication, and headers authentication.

For example, we can implement a plugin for using Entra ID-based authentication like below:

public class EntraIdAuthenticationPlugin implements HttpInterceptorPlugin
{
    public static String API_ID_URI = "azure.apiIdUri";
    ...
    public Interceptor getInterceptor(String host, Properties properties)
    {
        TokenCredential credential = new DefaultAzureCredentialBuilder().build();
        TokenRequestContext request = new TokenRequestContext().addScopes(properties.getProperty(API_ID_URI));

        return chain -> chain.proceed(chain.request().newBuilder()
                .addHeader(AUTHORIZATION, "Bearer " + credential.getTokenSync(request).getToken())
                .build());
    }
}

Modification of the JDBC driver

We need to implement the following modifications in TrinoUri.

Usage

JDBC clients can use an authentication plugin by setting the plugin class name as authenticationPluginName with additional connection properties for the plugin.

Properties connectionProperties = new Properties();

connectionProperties.setProperty("SSL", "true");
connectionProperties.setProperty("authenticationPluginName", "io.trino.jdbc.plugin.azure.EntraIdAuthenticationPlugin");
connectionProperties.setProperty("azure.appIdUri", "api://xxxxx-.....");

Connection connection = DriverManager.getConnection("jdbc:trino://host:port", connectionProperties);

The above example code will automatically detect an available authentication method, including a service account (Managed Identity), thanks to DefaultAzuretokenCredential and send JWT access tokens issued by Entra ID to Trino.

On the Trino server side, we can use JWT authentication to authenticate clients.

Status

We are testing a custom version of the Trino JDBC driver with this plugin interface to use Entra ID-based authentication. It works well in Azure for now, but more details of the plugin API need to be discussed.

mosabua commented 3 months ago

fyi @electrum