PolarDB Always-confidential 機能は、Java アプリケーションのコードを変更することなくシームレスに統合できるよう、専用のクライアントドライバーとして Encrypted Java Database Connectivity (EncJDBC) を提供します。 EncJDBC は、暗号文を自動的に復号し、プレーンテキストデータを返します。 このプロセスはアプリケーションに対して透過的です。 アプリケーションは、ビジネスコードを変更することなく、わずか数行の設定で PolarDB Always-confidential に接続できます。
Solution architecture
PolarDB Always-confidential is a dynamic encryption and decryption solution based on a database proxy. The database proxy encrypts pre-configured sensitive fields when returning query results 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.
Dynamic encryption: As the query results are returned, the proxy layer checks whether the results match a preset encryption policy. If a match is found, it encrypts the sensitive fields in the result set using a key that you specify 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, making the process transparent to the 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 ciphertext. You must use the EncJDBC driver and the correct key to decrypt data on the client.
Other users: Query results are ciphertext and cannot be decrypted.
Limitations
Before you implement this feature, review the following limitations to ensure it meets your business and technical requirements.
Endpoint requirement: Encryption rules take effect only when you connect by 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, and you are responsible for preventing key loss or leakage. If a key is lost, the corresponding encrypted data cannot be decrypted. You must therefore establish strict key management procedures.
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
AccessKey IDandAccessKey secretof a RAM user. This allows your 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 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 script editor, copy the following content, and click [OK]. Enter a policy 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 [操作] column, and grant the newly created access policy to the user. This allows the client application to decrypt data by using KMS.
Step 2: Add 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 with the version you require. You can check for the latest version of aliyun-cls-jdbc in the Maven repository.
Step 3: Configure connection parameters
You can configure MEK by using JDBC properties, a file, or a URL. If your JDBC is configured with two or more methods, the priority order is as follows: JDBC properties configuration > File configuration > URL configuration.
For the following configurations and connection methods, the
MEKis processed locally on the client and sent to the server by using envelope encryption, which ensures that theMEKis not leaked.We recommend that you do not hard-code the AccessKey pair (
AccessKey IDandAccessKey secret) in your application code. The examples in this topic use 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 STS access credential to access KMS, you can use an STS SDK to obtain a temporary credential, which is an 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 connection information, such as the endpoint (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";
// 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 must also specify the obtained security token.
// String stsToken = "yourSecurityToken";
// Specify 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 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);
// 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);
// ... Execute a query ...URL
You can embed the parameters for obtaining the KMS key in the URL.
Example
// Prepare connection information, such as the endpoint (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";
// 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 must also specify the obtained security token.
// String stsToken = "yourSecurityToken";
// Specify 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";
// 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);
// 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);
// ... Execute a query ...Step 4: Query data
After you connect to the database, you can perform database operations as you would with a regular JDBC query. EncJDBC automatically decrypts data in encrypted columns and returns it as plaintext.
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 3.9.9 and IntelliJ IDEA Community Edition 2024.1.2.
import java.sql.*;
import java.util.Properties;
public class EncryptedColumnAccess {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// Replace the following connection details with your instance information, such as hostname, port, 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 must also specify the obtained security token.
// String stsToken = "yourSecurityToken";
// Specify 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);
// Execute 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 an MEK
The database does not store, manage, generate, or back up your Master Encryption Key (MEK). You are responsible for generating, managing, and securely backing up the MEK, as this is critical to your data security.
MEK: The client securely transmits the MEK to the database server using envelope encryption, ensuring the key is never exposed in plaintext during transit.
Value range: A 16-byte, 32-character hexadecimal string. Example: 00112233445566778899aabbccddeeff.
Common generation methods: Use a password generation tool or a random function in a programming language.
Example
On a Linux system, use the built-in OpenSSL tool. Run the
openssl rand -hex 16command to generate a key.# Use OpenSSL to generate a secure random key openssl rand -hex 16 # Example output: 11ce9a9489fab7355cf710837cea5d5bOn a Windows system, install the OpenSSL package.
Step 2: Add 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 with the version you require. You can check for the latest version of aliyun-cls-jdbc in the Maven repository.
Step 3: Configure the MEK database connection
You can configure the MEK by using JDBC properties, a file, or a URL. If you use two or more methods, the following priority order applies: JDBC properties > File > URL.
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). This ensures that the MEK is not leaked.
JDBC properties
When you establish a standard JDBC connection, you can set custom attributes using a Properties object.
Example
// Prepare connection information, such as the endpoint (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 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);
// ... Execute a query ...File
The file configuration method is applicable only to configuring a local MEK.
You can import parameters from a configuration file to configure the required MEK. Set the encJdbcConfigFile Java system property to the file's path. If this property is not set, the driver searches for an encjdbc.conf file in the application's classpath. The content of the configuration file is as follows:
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 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); // ... Execute a query ...
URL
You can embed parameters such as the MEK in the URL.
Example
// Prepare connection information, such as the endpoint (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 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);
// ... Execute a query ...Step 4: Query data
After you connect to the database, you can perform database operations as you would with a regular JDBC query. EncJDBC automatically decrypts data in encrypted columns and returns it as plaintext.
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 3.9.9 and IntelliJ IDEA Community Edition 2024.1.2.
import java.sql.*;
import java.util.Properties;
public class EncryptedColumnAccess {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// Replace the following connection details with your instance information, such as hostname, port, 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 an example key. We recommend that you use a more complex key in production.
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);
// Execute 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();
}
}
}