The Confidential database feature provides a dedicated client driver, Encrypted Java Database Connectivity (EncJDBC), to enable seamless integration with your Java applications without requiring code modifications. EncJDBC automatically decrypts ciphertext and returns plaintext data. This process is transparent to the application. Your application can connect to the Confidential database feature with just a few lines of configuration, and no changes to your existing business code are required.
Solution architecture
The Confidential database feature is a dynamic encryption and decryption solution based on a database proxy. The proxy layer encrypts pre-configured sensitive fields in query results before returning them to the client. The client application must use the dedicated EncJDBC driver to transparently decrypt the data upon receipt.
Workflow and role permissions:
Query request: The client application sends a standard SQL query to the PolarDB cluster endpoint through the EncJDBC driver.
Proxy processing: The database proxy receives the request and forwards it to the backend database kernel for execution.
On-the-fly encryption: As query results are returned, the proxy layer checks whether they match a predefined encryption policy. If a match is found, the sensitive fields in the result set are encrypted using a specified key from KMS or a self-managed key.
Data return: The encrypted result set is returned to the client.
Transparent decryption: The EncJDBC driver on the client automatically decrypts the ciphertext. The application receives plaintext data, and the entire process is transparent to your business code.
Query results vary based on the role of the database account:
Super administrator: Query results are always in plaintext and are not affected by encryption policies. This is useful for database management and auditing.
Regular user: Query results are returned as ciphertext. You must use the EncJDBC driver and the correct key to decrypt the data on the client.
Other users: Query results are returned as ciphertext and cannot be decrypted.
Limits
Before you implement this feature, review the following limits to assess whether the feature meets your business and technical architecture requirements.
Endpoint requirement: Encryption rules take effect only when you connect using a cluster endpoint or a custom endpoint. Connecting directly to the primary endpoint bypasses the proxy, which disables the encryption feature.
Key management: When you use a self-managed key, key rotation is not supported. You also risk key loss or leakage. If a key is lost, the corresponding encrypted data cannot be decrypted. You must establish strict security procedures to manage your keys.
JDK version: You must use JDK 1.8 or later.
Use a KMS key
Step 1: Configure KMS access permissions
Obtain an AccessKey pair: Obtain the
AccessKeyIdandAccessKeySecretof a RAM user. This allows the application to obtain the master encryption key (MEK) that is managed by KMS.If you already have a suitable RAM user to access KMS, you can use that user.
If you do not have a suitable RAM user, go to the RAM console. In the navigation pane on the left, choose . Click Create User and follow the on-screen instructions to create a user.
Grant permissions to the RAM user:
Go to the RAM console. In the navigation pane on the left, choose . Click Create Access Policy. Switch to the script editor, copy the following content, and click OK. Enter a policy name and complete the creation.
{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": "KMS:Decrypt", "Resource": "*" } ] }Return to the RAM console. In the navigation pane on the left, choose . Find the target RAM user. In the Actions column, click Add Permissions. Grant the newly created access policy to the user. This allows PolarDB to dynamically decrypt data.
Step 2: Install dependencies
Add the following dependency to the pom.xml file of your Maven project.
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-cls-jdbc</artifactId>
<version>1.0.10-1</version>
</dependency>When you add the Maven dependency, replace the value of version as needed. You can find the latest version of aliyun-cls-jdbc on the official website.
Step 3: Configure the MEK to connect to the database
You can configure the MEK using JDBC properties, a file, or a URL. If you configure your JDBC using two or more methods, the priority is as follows: JDBC properties configuration > File configuration > URL configuration.
In the following configuration and connection methods, the
MEKis processed locally on the client and sent to the server using a secure method (envelope encryption) to ensure that theMEKis not leaked.Do not hard-code the AccessKey pair (
AccessKeyIdandAccessKeySecret) in your business code. This example uses system environment variables to manage the AccessKey pair. For more information, see Configure environment variables on Linux, macOS, and Windows systems.To use a temporary access credential to obtain the KMS-managed MEK, you can use an STS SDK to obtain a temporary credential, the Security Token Service (STS) token. For STS SDK examples, see Overview of STS SDKs.
JDBC properties configuration
When a standard JDBC connection is established, you can set custom attributes using a Properties object.
Example
// Prepare connection information such as the endpoint (hostname), port, database instance name (dbname), username, and password.
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// Get the AccessKey ID and AccessKey secret from environment variables.
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// If you use a temporary STS access credential to read the KMS key, you also need to fill in the obtained Security Token Service token (SecurityToken).
// String stsToken= "yourSecurityToken";
// For the KMS instance endpoint, use the public endpoint for public network access. Use the instance VPC endpoint for access within a VPC.
String kmsEndpoint = "your-kms-endpoint";
Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("ALIBABA_CLOUD_ACCESS_KEY_ID", accessKeyId);
props.setProperty("ALIBABA_CLOUD_ACCESS_KEY_SECRET", accessKeySecret);
props.setProperty("ALIBABA_CLOUD_KMS_ENDPOINT", kmsEndpoint);
// props.setProperty("ALIBABA_CLOUD_STS_TOKEN","stsToken");
// The following is the connection URL format for a MySQL database: "jdbc:mysql:encdb://%s:%s/%s".
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
// The following loads the EncJDBC driver for a MySQL database.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, props);
// ... Initiate a query ...URL configuration
You can embed the parameters for obtaining the KMS key in the URL.
Example
// Prepare connection information such as the endpoint (hostname), port, database instance name (dbname), username, and password.
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// Get the AccessKey ID and AccessKey secret from environment variables.
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// If you use a temporary STS access credential to read the KMS key, you also need to fill in the obtained Security Token Service token (SecurityToken).
// String stsToken= "yourSecurityToken";
// For the KMS instance endpoint, use the public endpoint for public network access. Use the instance VPC endpoint for access within a VPC.
String kmsEndpoint = "your-kms-endpoint";
// The following is the connection URL format for a MySQL database.
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s?ALIBABA_CLOUD_ACCESS_KEY_ID=%s&ALIBABA_CLOUD_ACCESS_KEY_SECRET=%s&ALIBABA_CLOUD_KMS_ENDPOINT=%s", hostname, port, dbname, accessKeyId, accessKeySecret, kmsEndpoint);
// Use an STS token.
// String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s?ALIBABA_CLOUD_ACCESS_KEY_ID=%s&ALIBABA_CLOUD_ACCESS_KEY_SECRET=%s&ALIBABA_CLOUD_KMS_ENDPOINT=%s&ALIBABA_CLOUD_STS_TOKEN=%s", hostname, port, dbname, accessKeyId, accessKeySecret, kmsEndpoint, stsToken);
// The following loads the EncJDBC driver for a MySQL database.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, username, password);
// ... Initiate a query ...Step 4: Query plaintext data from encrypted columns
After you successfully connect to the database, you can perform database operations as you would with a regular JDBC query. EncJDBC automatically decrypts encrypted columns and returns plaintext data.
Example
// Create a query statement.
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM your_table_name");
// Traverse the result set.
while (resultSet.next()) {
for (int i = 0; i < resultSet.getMetaData().getColumnCount(); i++) {
System.out.print(resultSet.getString(i + 1));
System.out.print("\t");
}
System.out.print("\n");
}Appendix: Complete code example
This example uses Maven version 3.9.9 and the IntelliJ IDEA Community Edition 2024.1.2 development tool.
import java.sql.*;
import java.util.Properties;
public class EncryptedColumnAccess {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// Update the following connection information with your instance details, such as endpoint (hostname), port, database instance name (dbname), username, and password.
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// Get the AccessKey ID and AccessKey secret from environment variables.
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// If you use a temporary STS access credential to read the KMS key, you also need to fill in the obtained Security Token Service token (SecurityToken).
// String stsToken= "yourSecurityToken";
// For the KMS instance endpoint, use the public endpoint for public network access. Use the instance VPC endpoint for access within a VPC.
String kmsEndpoint = "your-kms-endpoint";
Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("ALIBABA_CLOUD_ACCESS_KEY_ID", accessKeyId);
props.setProperty("ALIBABA_CLOUD_ACCESS_KEY_SECRET", accessKeySecret);
props.setProperty("ALIBABA_CLOUD_KMS_ENDPOINT", kmsEndpoint);
// props.setProperty("ALIBABA_CLOUD_STS_TOKEN","stsToken");
// The connection URL format for a MySQL database is "jdbc:mysql:encdb://%s:%s/%s".
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
// Load the EncJDBC driver.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, props);
// Initiate a query.
try {
// Create a query statement.
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
// Traverse the result set.
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("username");
String phone = resultSet.getString("phone");
// Process other fields based on your table schema.
System.out.println("ID: " + id + ", Name: " + name + ", Phone: " + phone);
}
// Close resources.
resultSet.close();
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}Use a local key
Step 1: Generate an MEK
The MEK is the root credential that you use to authorize clients to access encrypted data. For security reasons, the encrypted database does not store or manage your MEK. It also does not provide MEK generation or backup services. You are responsible for generating the MEK. Storing and managing the MEK is critical to database security. Therefore, we recommend that you back up your MEK securely.
MEK: The MEK is transmitted from the client to the database server using a secure asymmetric key encryption protocol. This allows the server and client to share the same key for secure data transmission through symmetric encryption.
Valid value: a 16-byte hexadecimal string that is 32 characters in length. For example, 00112233445566778899aabbccddeeff.
Common generation methods: You can use password generation tools or the random function in a programming language.
Example
On Linux, you can use the built-in OpenSSL tool. Run
openssl rand -hex 16to generate a key.# Use OpenSSL to generate a secure random key openssl rand -hex 16 # Example output: 11ce9a9489fab7355cf710837cea5d5bOn Windows, you can install the OpenSSL package.
Step 2: Install dependencies
Add the following dependency to the pom.xml file of your Maven project.
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-cls-jdbc</artifactId>
<version>1.0.10-1</version>
</dependency>When you add the Maven dependency, replace the value of version as needed. You can find the latest version of aliyun-cls-jdbc on the official website.
Step 3: Configure the MEK to connect to the database
You can configure the MEK using JDBC properties, a file, or a URL. If you configure your JDBC using two or more methods, the priority is as follows: JDBC properties configuration > File configuration > URL configuration.
In the following configuration and connection methods, the MEK is processed locally on the client and sent to the server using a secure method (envelope encryption) to ensure that the MEK is not leaked.
JDBC properties configuration
When a standard JDBC connection is established, you can set custom attributes using a Properties object.
Example
// Prepare connection information such as the endpoint (hostname), port, database instance name (dbname), username, and password.
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// Customer master key.
String mek = "00112233445566778899aabbccddeeff";
Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);
// The connection URL format for a MySQL database is "jdbc:mysql:encdb://%s:%s/%s".
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
// Load the EncJDBC driver for a MySQL database.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, props);
// ... Initiate a query ...File configuration
The file configuration method is applicable only to configuring a local MEK.
You can import parameters, such as the required MEK, from a configuration file. In your project, set a property named encJdbcConfigFile and set its value to the path of the configuration file. If you do not specify a path, the system uses the encjdbc.conf file by default. The following code shows the content of the configuration file:
MEK=00112233445566778899aabbccddeeffExample
You can specify the location of the configuration file in one of the following two ways:
Place the file in the resources directory of your project, as shown in the following figure:

Place the file in the root directory of the project, which is the runtime directory of the program.
After you configure the file, you do not need to make additional configurations in your program, as shown in the following code:
// Prepare connection information such as the endpoint (hostname), port, database instance name (dbname), username, and password. String hostname = "your-hostname"; String port = "your-port"; String dbname = "your-database-name"; String username = "your-username"; String password = "your-password"; // The connection URL format for a MySQL database is "jdbc:mysql:encdb://%s:%s/%s". String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname); // Load the EncJDBC driver for a MySQL database. Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver"); // Get the database connection. Connection connection = DriverManager.getConnection(dbUrl, username, password); // ... Initiate a query ...
URL configuration
You can embed parameters, such as the MEK, in the URL.
Example
// Prepare connection information such as the endpoint (hostname), port, database instance name (dbname), username, and password.
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// Customer master key.
String mek = "00112233445566778899aabbccddeeff";
// The connection URL format for a MySQL database is "jdbc:mysql:encdb://%s:%s/%s?MEK=%s".
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s?MEK=%s", hostname, port, dbname, mek);
// Load the EncJDBC driver for a MySQL database.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, username, password);
// ... Initiate a query ...Step 4: Query plaintext data from encrypted columns
After you successfully connect to the database, you can perform database operations as you would with a regular JDBC query. EncJDBC automatically decrypts encrypted columns and returns plaintext data.
Example
// Create a query statement.
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM your_table_name");
// Traverse the result set.
while (resultSet.next()) {
for (int i = 0; i < resultSet.getMetaData().getColumnCount(); i++) {
System.out.print(resultSet.getString(i + 1));
System.out.print("\t");
}
System.out.print("\n");
}Appendix: Complete code example
This example uses Maven version 3.9.9 and the IntelliJ IDEA Community Edition 2024.1.2 development tool.
import java.sql.*;
import java.util.Properties;
public class EncryptedColumnAccess {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// Update the following connection information with your instance details, such as endpoint (hostname), port, database instance name (dbname), username, and password.
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// This is just an example. Use a more complex key.
String mek="00112233445566778899aabbccddeeff";
Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);
// The connection URL format for a MySQL database is "jdbc:mysql:encdb://%s:%s/%s".
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
// Load the EncJDBC driver.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, props);
// Initiate a query.
try {
// Create a query statement.
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
// Traverse the result set.
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("username");
String phone = resultSet.getString("phone");
// Process other fields based on your table schema.
System.out.println("ID: " + id + ", Name: " + name + ", Phone: " + phone);
}
// Close resources.
resultSet.close();
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}