To integrate your Java applications with no code changes, use the dedicated Encrypted JDBC (EncJDBC) driver provided with PolarDB Always-confidential. EncJDBC automatically decrypts ciphertext and returns plaintext data. This process is transparent to your application, allowing you to connect to PolarDB Always-confidential with only a few configuration changes.
Solution architecture
PolarDB Always-confidential is an on-the-fly encryption and decryption solution based on a database proxy. The proxy encrypts pre-configured sensitive fields when returning the query result set to the client. The client application must use the dedicated EncJDBC driver to transparently decrypt the received data.
Workflow and role permissions:
-
Query: A 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: When returning the query result, the proxy layer checks if it matches a preset encryption policy. If it matches, the proxy encrypts sensitive fields in the result set by using a key that you specify from Key Management Service (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 data on the client.
-
Other users: Query results are returned as ciphertext and cannot be decrypted.
Limitations
Before you proceed, review the following key limitations to determine if this solution meets your business and technical requirements.
-
Endpoint requirements: Encryption rules take effect only when you connect to 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, and you risk key loss or leakage. If a key is lost, you cannot decrypt the corresponding encrypted data. You must establish strict security procedures to manage the key.
-
JDK version: You must use JDK version 1.8 or later.
Use a key from KMS
Step 1: Configure KMS access permissions
-
Obtain an AccessKey pair: Obtain the
AccessKey IDandAccessKey secretof a RAM user. This allows your application to retrieve the master encryption key (MEK) managed by Key Management Service (KMS).-
If you already have a suitable RAM user with permissions to access KMS, you can use that user.
-
If you do not have a suitable RAM user, go to the RAM console. In the left-side navigation pane, choose Identity Management > Users. 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 left-side navigation pane, choose Permission Management > Policies. Click Create Policy. Switch to the JSON tab, copy the following content, and then click OK. Enter a name to create the policy.
{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": "KMS:Decrypt", "Resource": "*" } ] } -
Return to the RAM console. In the left-side navigation pane, choose Identity Management > Users. Find the target RAM user, click Add Permissions in the Actions column, and 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 in 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 version value based on your use case. You can find the latest version of aliyun-cls-jdbc in the Maven repository.
Step 3: Configure the MEK
You can configure the MEK by using JDBC properties, a file configuration, or a URL configuration. If you use multiple configuration methods, the priority is as follows: JDBC properties configuration > file configuration > URL configuration.
-
In the following configuration and connection methods, the
MEKis processed on the client and securely sent to the server using envelope encryption. This ensures theMEKdoes not leak. -
We recommend that you do not hard-code your AccessKey pair (
AccessKey IDandAccessKey secret) in your application code. This topic uses an environment variable to manage the AccessKey pair. For more information, see Configure environment variables on Linux, macOS, and Windows systems. -
If you need to use a temporary STS access credential to obtain the MEK managed by KMS, you can use an STS SDK to obtain a temporary STS token. For STS SDK examples, see Overview of STS SDKs.
JDBC properties
When you establish a standard JDBC connection, you can set custom attributes using a Properties object.
Example
// Prepare the connection information, such as the hostname, port, database 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";
// Obtain 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 must also provide the obtained STS token.
// String stsToken= "yourSecurityToken";
// For the KMS instance endpoint, use the public endpoint for internet access or the 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 for the MySQL database.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, props);
// ... Initiate a query ...
URL
You can embed the KMS key parameters in the connection URL.
Example
// Prepare the connection information, such as the hostname, port, database 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";
// Obtain 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 must also provide the obtained STS token.
// String stsToken= "yourSecurityToken";
// For the KMS instance endpoint, use the public endpoint for internet access or the VPC endpoint for access within a VPC.
String kmsEndpoint = "your-kms-endpoint";
// Embed the KMS key parameters in the connection URL.
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);
// Load the EncJDBC driver for the 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
After you connect to the database, you can perform database operations as you would with a standard 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");
// Iterate over 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: 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 {
// Replace the following connection information with your instance details, such as hostname, port, database 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";
// Obtain 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 must also provide the obtained STS token.
// String stsToken= "yourSecurityToken";
// For the KMS instance endpoint, use the public endpoint for internet access or the 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");
// Iterate over 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 the resources.
resultSet.close();
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Use a local key
Step 1: Generate MEK
The master encryption key (MEK) is the root credential that authorizes clients to access encrypted data. For security, the encrypted database does not store, manage, generate, or back up your MEK. You are solely responsible for generating, securely managing, and backing it up. The storage and management of the MEK are critical to database security. We strongly recommend that you back up your MEK.
MEK: The client sends the MEK to the database server over a secure asymmetric encryption protocol. This allows both the client and server to share the same key, enabling secure data transmission through symmetric encryption.
Value requirements: A 16-byte hexadecimal string (32 characters long). For example, 00112233445566778899aabbccddeeff.
Common generation methods: You can use password generation tools or a random function in a programming language.
Example
-
On Linux, 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: 11ce9a9489fab7355cf710837cea5d5b -
On Windows, install the OpenSSL package.
Step 2: Install dependencies
Add the following dependency to the pom.xml file in 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 version value based on your use case. You can find the latest version of aliyun-cls-jdbc in the Maven repository.
Step 3: Configure the MEK
You can configure the MEK by using JDBC properties, a file configuration, or a URL configuration. If you use multiple configuration methods, the priority is as follows: JDBC properties configuration > file configuration > URL configuration.
In the following configuration and connection methods, the MEK is processed on the client and securely sent to the server using envelope encryption. This ensures the MEK does not leak.
JDBC properties
When you establish a standard JDBC connection, you can set custom attributes using a Properties object.
Example
// Prepare the connection information, such as the hostname, port, database 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 master encryption 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 the MySQL database.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, props);
// ... Initiate a query ...
File
The file configuration method applies only to configuring a local key MEK.
You can import parameters from a configuration file to configure the required MEK. In your project, set the encJdbcConfigFile property to the path of the configuration file. If you do not specify a path, the system uses the encjdbc.conf file by default. The configuration file must contain the following content:
MEK=00112233445566778899aabbccddeeff
Example
-
You can specify the location of the configuration file in one of the following two ways:
-
Place the file in the
resourcesdirectory of your project, as shown in the following structure:src main java resources encjdbc.conf -
Place the file in the root directory of your 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 the connection information, such as the hostname, port, database 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 the 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
You can embed the MEK and other parameters in the connection URL.
Example
// Prepare the connection information, such as the hostname, port, database 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 master encryption 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 the 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
After you connect to the database, you can perform database operations as you would with a standard 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");
// Iterate over 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: 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 {
// Replace the following connection information with your instance details, such as hostname, port, database 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 only an example. We recommend that you 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");
// Iterate over 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 the resources.
resultSet.close();
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}