This topic describes how to use the Always confidential database feature for an ApsaraDB RDS for PostgreSQL instance from a client.
Prerequisites
The Always confidential database feature is enabled. For more information, see Enable the Always confidential database feature.
Sensitive data is defined. For more information, see Define sensitive data.
The information that is used to connect to the Always confidential database is obtained. Before you use the Always confidential database feature from your client, you must obtain the connection information about the Always confidential database, such as the domain name (host), port number (port), database name (dbname), username (username), and password (password). For more information about how to obtain the internal and public endpoints of an RDS instance, see View and change the endpoints and port numbers of an ApsaraDB RDS for PostgreSQL instance.
In this topic, a Java application is used as an example. Make sure that a Java development environment is installed. We recommend that you use Java
1.8
or later, Maven3.9.2
, andIntelliJ IDEA Community Edition 2022.3.2
.
Usage notes
You must store your master encryption key (MEK)
and keep it confidential.
Examples
The feature encrypts the sensitive data in the query results. To use the feature for your application, you can use the feature from the following types of clients.
Connection method | Description | Business code modification required | |
Application | EncJDBC | EncJDBC automatically identifies data types for encryption and encrypts or decrypts data. | No. This method is recommended. |
EncDB SDK | You must call the encryption or decryption function that is provided by the EncDB SDK to encrypt or decrypt data on the client. | Yes. | |
psql | The psql tool is a command line tool that allows you to query data in databases. psql obtains only ciphertext data. | No. You do not need to modify the business code because psql is used only for queries. | |
Visual and interactive tools such as the Data Management (DMS) console |
EncJDBC
Download drivers and configure dependencies
Download the EncJDBC driver.
EncJDBC
depends on community-provided PostgreSQL drivers.Minor engine version of the RDS instance
Version of EncDB on the RDS instance
EncDB dependency package on the client
20230830 or later
1.1.13 or later
Configure Maven dependencies.
NoteIn this section, Maven is used to configure the client.
Run the following command to install the
EncJDBC
dependency package to your on-premises repository:mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=<Name of the installed JAR package> -Dversion=<Version of the installed JAR package> -Dpackaging=jar -Dfile=<File name of the installed JAR package>
Example:
mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=encjdbc -Dversion=1.0.6 -Dpackaging=jar -Dfile=D:\encdb\libs\encjdbc-1.0.6.jar
NoteIn the example, the EncDB dependency package is stored in the
D:\encdb\libs
path.In this example, Maven
3.9.2
is used. If you use other Maven versions, upgrade the Maven version and try again.
After you install the
EncJDBC
dependency package in your on-premises repository, you must add the following dependencies to the pom.xml configuration file of your Maven project:<dependencies> ... <dependency> <groupId>com.alibaba.encdb</groupId> <artifactId>encjdbc</artifactId> <version>1.0.6</version> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.62</version> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.62</version> </dependency> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql --> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.23</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>24.1.1-jre</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>org.jgrapht</groupId> <artifactId>jgrapht-core</artifactId> <!-- jgrapht does not support java 1.8 since 1.5.0 --> <version>1.4.0</version> </dependency> ... </dependencies>
Query data from the client (sample code)
This section provides the sample code for demonstration purposes. In the actual business code, do not set the password
and mek
parameters to values in plaintext. We recommend that you configure the parameters by using methods such as external configuration files and environment variables before you reference the parameters in the code.
URL configuration description
You can use
EncJDBC
in the same manner as Java Database Connectivity (JDBC). Before you useEncJDBC
, you must perform the following configuration to ensure data security:// The connection information such as the domain name (hostname), port number (port), database name (dbname), username (username), and password (password). // For more information, see the "Data security-related parameters" section. String mek=...; String encAlgo=...; String dbUrl = String.format("encjdbc:postgresql://%s:%s/%s?mek=%s&enc_algo=%s", hostname, port, dbname, mek, encAlgo); Class.forName("com.alibaba.encdb.encjdbc.EncDriver"); Connection dbConnection = DriverManager.getConnection(dbUrl, username, password); // ... Initiate a query. ...
NoteYou can use ampersands (
&
) to concatenate multiple parameters.mek
and other parameters are configured on the client side and transmitted to the server side by using envelope encryption. In the process, the confidentiality of the value ofmek
is ensured.
Complete sample code
// The connection information such as the domain name (hostname), port number (port), database name (dbname), username (username), and password (password). Specify the parameters based on your business requirements. String hostname = "hostname"; String port = "port"; String dbname = "db"; String username = "user"; String password = "password"; String mek="00112233445566778899aabbccddeeff"; // This is an example value. We recommend that you use a more complex MEK. String encAlgo="SM4_128_CBC"; String dbUrl = String.format("encjdbc:postgresql://%s:%d/%s?mek=%s&enc_algo=%s", hostname, port, dbname, mek, encAlgo); Class.forName("com.alibaba.encdb.encjdbc.EncDriver"); Connection dbConnection = DriverManager.getConnection(dbUrl, username, password); // create table dbConnection.createStatement().executeUpdate("DROP TABLE IF EXISTS example"); dbConnection.createStatement().executeUpdate("CREATE TABLE example (id INTEGER, name VARCHAR, price enc_int4, miles enc_float4, secret enc_text, PRIMARY KEY (id))"); // insert data PreparedStatement stmt = dbConnection.prepareStatement("INSERT INTO example (id, name, price, miles, secret) VALUES(?,?,?,?,?)"); int price = 1234; float miles = 12.34f; String secret = "aliyun"; stmt.setInt(1, 1); stmt.setString(2, "name"); stmt.setInt(3, price); stmt.setFloat(4, miles); stmt.setString(5, secret); stmt.execute(); // check plaintext data String sqlCmd = "SELECT * FROM example WHERE price > ?"; PreparedStatement stmt = dbConnection.prepareStatement(sqlCmd); stmt.setInt(1, 100); ResultSet rs = stmt.executeQuery(); while (rs.next()){ int id = rs.getInt(1); String name = rs.getString(2); int price = rs.getInt(3); float miles = rs.getFloat(4); String secret = rs.getString(5); System.out.println(id + ", " + name + ", " + price + ", " + miles + ", " + secret); }
Sample output:
1, name, 1234, 12.34, aliyun
In the preceding example for EncJDBC
, only the driver loading and URL configuration are modified. Other data operations can be performed in the same way as common database operations. You do not need to modify any business code.
EncDB SDK
Download drivers and configure dependencies
Download the EncDB SDK driver.
The
EncDB SDK
depends on community-provided PostgreSQL drivers.Minor engine version of the RDS instance
Version of EncDB on the RDS instance
EncDB dependency package on the client
20230830 or later
1.1.13 or later
Configure Maven dependencies.
NoteIn this section, Maven is used to configure the client.
Run the following command to install the
EncDB SDK
dependency package to your on-premises repository:mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=<Name of the installed JAR package> -Dversion=<Version of the installed JAR package> -Dpackaging=jar -Dfile=<File name of the installed JAR package>
Example:
mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=libencdb -Dversion=1.2.12 -Dpackaging=jar -Dfile=D:\encdb\libs\libencdb-1.2.12.jar
NoteIn the example, the EncDB dependency package is stored in the
D:\encdb\libs
path.In this example, Maven
3.9.2
is used. If you use other Maven versions, upgrade the Maven version and try again.
After you install the
EncDB SDK
dependency package in your on-premises repository, you must add the following dependencies to the pom.xml configuration file of your Maven project:<dependencies> ... <dependency> <groupId>com.alibaba.encdb</groupId> <artifactId>libencdb</artifactId> <version>1.2.12</version> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.70</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency> <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql --> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.23</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.1-jre</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.4</version> </dependency> ... </dependencies>
Query data from the client (sample code)
This section provides the sample code for demonstration purposes. In the actual business code, do not set the password
and mek
parameters to values in plaintext. We recommend that you configure the parameters by using methods such as external configuration files and environment variables before you reference the parameters in the code.
SDK configuration description
Before you manage ciphertext data that you receive or send, you must use the
EncDB SDK
to encrypt or decrypt the data.The
EncDB SDK
provides the required API operations for you to configure parameters related to data security when you initialize SDK objects. In most cases, you only need to configure the MEK specified by setMek and the required encryption algorithm specified by setEncAlgo. We recommend that you use the default settings for other parameters.// Obtain the connection information such as the domain name (hostname), port number (port), database name (dbname), username (username), and password (password). // Establish a database connection. All JDBC versions are supported. String dbUrl = String.format("jdbc:postgresql://%s:%s/%s?binaryTransfer=true", hostname, port, dbname); Class.forName("org.postgresql.Driver"); Connection dbConnection = DriverManager.getConnection(dbUrl, username, password); // Initialize the SDK. String mek=...; Constants.EncAlgo encAlgo=...; EncdbSDK sdk = EncdbSDKBuilder.newInstance() .setDbConnection(dbConnection) .setMek(mek) .setEncAlgo(encAlgo) .build(); Cryptor cryptor = sdk.getCryptor(); // Call the API operation for data encryption or decryption. // byte[] cipherBytes = cryptor.encrypt(...); // XXX value = cryptor.decryptXXX(...): // ... Initiate a query. ...
Notemek
and other parameters are configured on the client side and transmitted to the server side by using envelope encryption. In the process, the confidentiality of the value ofmek
is ensured.Complete sample code
// Update the connection information such as the domain name (hostname), port number (port), database name (dbname), username (username), and password (password) to your instance information. String hostname = "hostname"; String port = "port"; String dbname = "db"; String username = "user"; String password = "password"; // Establish a database connection. String dbUrl = String.format("jdbc:postgresql://%s:%s/%s?binaryTransfer=true", hostname, port, dbname); Class.forName("org.postgresql.Driver"); Connection dbConnection = DriverManager.getConnection(dbUrl, username, password); // Initialize the SDK. String mek="00112233445566778899aabbccddeeff"; // This is an example value. We recommend that you use a more complex MEK. Constants.EncAlgo encAlgo=Constants.EncAlgo.SM4_128_CBC; EncdbSDK sdk = EncdbSDKBuilder.newInstance() .setDbConnection(dbConnection) .setMek(mek) .setEncAlgo(encAlgo) .build(); Cryptor cryptor = sdk.getCryptor(); // create table dbConnection.createStatement().executeUpdate("DROP TABLE IF EXISTS example"); dbConnection.createStatement().executeUpdate("CREATE TABLE example (id INTEGER, name VARCHAR, price enc_int4, miles enc_float4, secret enc_text, PRIMARY KEY (id))"); // insert data PreparedStatement stmt = dbConnection.prepareStatement("INSERT INTO example (id, name, price, miles, secret) VALUES(?,?,?,?,?)"); int price = 1234; float miles = 12.34f; String secret = "aliyun"; stmt.setInt(1, 1); stmt.setString(2, "name"); stmt.setBytes(3, cryptor.encrypt("example", "price", price)); stmt.setBytes(4, cryptor.encrypt("example", "miles", miles)); stmt.setBytes(5, cryptor.encrypt("example", "secret", secret)); stmt.execute(); // check plaintext data String sqlCmd = "SELECT * FROM example WHERE price > ?"; stmt = dbConnection.prepareStatement(sqlCmd); stmt.setBytes(1, cryptor.encrypt("example", "price", 100)); ResultSet rs = stmt.executeQuery(); while (rs.next()) { int id = rs.getInt(1); String name = rs.getString(2); price = cryptor.decryptInt(rs.getBytes(3)); miles = cryptor.decryptFloat(rs.getBytes(4)); String text = cryptor.decryptString(rs.getBytes(5)); System.out.println(id +", " + name + ", " + price + ", " + miles + ", " + text); }
Sample output:
1, name, 1234, 12.34, aliyun
References
Introduction to the Java SDK module
The EncDB SDK
contains the following Java feature modules:
psql
You can use psql to query data in Always confidential databases. For example, you can execute the SELECT * FROM example;
statement by using psql.
In the preceding output, id
and name
are plaintext columns, and price
, miles
, and secret
are ciphertext columns. Encrypted data cannot be viewed on the RDS instance. This helps protect your data from security threats inside and outside the cloud at all times.
DMS console
You can use visual and interactive tools such as the DMS console to query data in Always confidential databases.
In the preceding figure, id
and name
are plaintext columns, and price
, miles
, and secret
are ciphertext columns.
FAQ
What do I do if the
org.postgresql.util.PSQLException: ERROR: db_process_msg_api: process message failure - returned 0xf7070000
error message is displayed when I connect to my database?The error code 0xf7070000 indicates that your MEK cannot be imported. The data that is encrypted by using one MEK cannot be accessed by using another MEK. If you use the same account but different MEKs to connect to the same Always confidential database, this error may occur. When you connect to a Always confidential database, we recommend that you use the same MEK at all times.
What do I do if the
Exception in thread "main" java.lang.IllegalAccessError: class com.alibaba.encdb.common.SymCrypto (in unnamed module @0x5c0369c4) cannot access class com.sun.crypto.provider.SunJCE (in module java.base) because module java.base does not export com.sun.crypto.provider to unnamed module @0x5c0369c4
error message is displayed when I run a program?This error message may be displayed due to the inter-module permission issues that occur when the JDK version is later than the required version. To resolve the error, you must add the VM option
--add-exports=java.base/com.sun.crypto.provider=ALL-UNNAMED
when you run the program to export com.sun.crypto.provider to the Unnamed module.