Skip to content

Commit 075b458

Browse files
authored
feat: add client-side encryption samples for Postgres and SQL Server (GoogleCloudPlatform#4867)
* feat: add client-side encryption samples for Postgres and SQL Server * replace VARBINARY with BYTEA in postgres sample * Trim padding from team name * address review comments * add comment to CloudKMSEnvelopeAead.java * fix linting errors
1 parent c4c33ab commit 075b458

24 files changed

Lines changed: 1411 additions & 5 deletions

cloud-sql/mysql/client-side-encryption/example.envrc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
/*
2+
* Copyright 2021 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
117
GOOGLE_APPLICATION_CREDENTIALS='path/to/service-account-key.json'
218
DB_USER='your-database-username'
319
DB_PASS='your-database-password'

cloud-sql/mysql/client-side-encryption/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
<artifactId>HikariCP</artifactId>
8585
<version>4.0.2</version>
8686
</dependency>
87+
8788
<dependency>
8889
<groupId>junit</groupId>
8990
<artifactId>junit</artifactId>

cloud-sql/mysql/client-side-encryption/src/main/java/cloudsql/tink/CloudKmsEnvelopeAead.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ public static Aead get(String kmsUri) throws GeneralSecurityException {
3737
// Create an AEAD primitive using the Cloud KMS key
3838
Aead gcpAead = client.getAead(kmsUri);
3939

40-
// Create an envelope AEAD primitive
40+
// Create an envelope AEAD primitive.
41+
// This key should only be used for client-side encryption to ensure authenticity and integrity
42+
// of data.
4143
return new KmsEnvelopeAead(AeadKeyTemplates.AES128_GCM, gcpAead);
4244
}
4345
}

cloud-sql/mysql/client-side-encryption/src/main/java/cloudsql/tink/CloudSqlConnectionPool.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import com.zaxxer.hikari.HikariConfig;
2222
import com.zaxxer.hikari.HikariDataSource;
23-
import java.security.GeneralSecurityException;
2423
import java.sql.Connection;
2524
import java.sql.PreparedStatement;
2625
import java.sql.SQLException;
@@ -29,7 +28,7 @@
2928
public class CloudSqlConnectionPool {
3029

3130
public static DataSource createConnectionPool(String dbUser, String dbPass, String dbName,
32-
String cloudSqlConnectionName) throws GeneralSecurityException {
31+
String cloudSqlConnectionName) {
3332
HikariConfig config = new HikariConfig();
3433
config.setJdbcUrl(String.format("jdbc:mysql:///%s", dbName));
3534
config.setUsername(dbUser);

cloud-sql/mysql/client-side-encryption/src/main/java/cloudsql/tink/EncryptAndInsertData.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ public static void main(String[] args) throws GeneralSecurityException, SQLExcep
3838
String cloudSqlConnectionName =
3939
System.getenv("CLOUD_SQL_CONNECTION_NAME"); // e.g. "project-name:region:instance-name"
4040
String kmsUri = System.getenv("CLOUD_KMS_URI"); // e.g. "gcp-kms://projects/...path/to/key
41+
// Tink uses the "gcp-kms://" prefix for paths to keys stored in Google Cloud KMS. For more
42+
// info on creating a KMS key and getting its path, see
43+
// https://cloud.google.com/kms/docs/quickstart
4144

4245
String team = "TABS";
4346
String tableName = "votes";
@@ -68,7 +71,9 @@ public static void encryptAndInsertData(DataSource pool, Aead envAead, String ta
6871
voteStmt.setTimestamp(2, new Timestamp(new Date().getTime()));
6972

7073
// Use the envelope AEAD primitive to encrypt the email, using the team name as
71-
// associated data
74+
// associated data. Encryption with associated data ensures authenticity
75+
// (who the sender is) and integrity (the data has not been tampered with) of that
76+
// data, but not its secrecy. (see RFC 5116 for more info)
7277
byte[] encryptedEmail = envAead.encrypt(email.getBytes(), team.getBytes());
7378
voteStmt.setBytes(3, encryptedEmail);
7479

cloud-sql/mysql/client-side-encryption/src/main/java/cloudsql/tink/QueryAndDecryptData.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ public static void main(String[] args) throws GeneralSecurityException, SQLExcep
3838
String cloudSqlConnectionName =
3939
System.getenv("CLOUD_SQL_CONNECTION_NAME"); // e.g. "project-name:region:instance-name"
4040
String kmsUri = System.getenv("CLOUD_KMS_URI"); // e.g. "gcp-kms://projects/...path/to/key
41+
// Tink uses the "gcp-kms://" prefix for paths to keys stored in Google Cloud KMS. For more
42+
// info on creating a KMS key and getting its path, see
43+
// https://cloud.google.com/kms/docs/quickstart
4144

4245
String tableName = "votes123";
4346

@@ -74,7 +77,9 @@ public static void queryAndDecryptData(DataSource pool, Aead envAead, String tab
7477
Timestamp timeCast = voteResults.getTimestamp(2);
7578

7679
// Use the envelope AEAD primitive to decrypt the email, using the team name as
77-
// associated data
80+
// associated data. Encryption with associated data ensures authenticity
81+
// (who the sender is) and integrity (the data has not been tampered with) of that
82+
// data, but not its secrecy. (see RFC 5116 for more info)
7883
String email = new String(envAead.decrypt(voteResults.getBytes(3), team.getBytes()));
7984

8085
System.out.println(String.format("%s\t%s\t%s", team, timeCast, email));
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Encrypting fields in Cloud SQL - Postgres with Tink
2+
3+
## Before you begin
4+
5+
1. If you haven't already, set up a Java Development Environment (including google-cloud-sdk and
6+
maven utilities) by following the [java setup guide](https://cloud.google.com/java/docs/setup) and
7+
[create a project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project).
8+
9+
1. Create a 2nd Gen Cloud SQL Instance by following these
10+
[instructions](https://cloud.google.com/sql/docs/postgres/create-instance). Note the connection string,
11+
database user, and database password that you create.
12+
13+
1. Create a database for your application by following these
14+
[instructions](https://cloud.google.com/sql/docs/postgres/create-manage-databases). Note the database
15+
name.
16+
17+
1. Create a KMS key for your application by following these
18+
[instructions](https://cloud.google.com/kms/docs/creating-keys). Copy the resource name of your
19+
created key.
20+
21+
1. Create a service account with the 'Cloud SQL Client' permissions by following these
22+
[instructions](https://cloud.google.com/sql/docs/postgres/connect-external-app#4_if_required_by_your_authentication_method_create_a_service_account).
23+
Then, add the 'Cloud KMS CryptoKey Encrypter/Decrypter' permission for the key to your service account
24+
by following these [instructions](https://cloud.google.com/kms/docs/iam).
25+
26+
## Running Locally
27+
28+
Before running, copy the `example.envrc` file to `.envrc` and replace the values for
29+
`GOOGLE_APPLICATION_CREDENTIALS`, `DB_USER`, `DB_PASS`, `DB_NAME`, `CLOUD_SQL_CONNECTION_NAME`,
30+
and `CLOUD_KMS_URI` with the values from your project. Then run `source .envrc` or optionally use
31+
[direnv](https://direnv.net/).
32+
33+
Once the environment variables have been set, run:
34+
```
35+
mvn exec:java -Dexec.mainClass=cloudsql.tink.EncryptAndInsertData
36+
```
37+
and
38+
```
39+
mvn exec:java -Dexec.mainClass=cloudsql.tink.QueryAndDecryptData
40+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2021 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
GOOGLE_APPLICATION_CREDENTIALS='path/to/service-account-key.json'
18+
DB_USER='your-database-username'
19+
DB_PASS='your-database-password'
20+
DB_NAME='your_database_name'
21+
CLOUD_SQL_CONNECTION_NAME='project:region:instance-name'
22+
CLOUD_KMS_URI='gcp-kms://your-kms-uri`
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<!--
2+
Copyright 2021 Google LLC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
-->
16+
<project>
17+
<modelVersion>4.0.0</modelVersion>
18+
<packaging>jar</packaging>
19+
<version>1.0-SNAPSHOT</version>
20+
<groupId>com.google.cloud</groupId>
21+
<artifactId>cloud-sql-tink-postgres</artifactId>
22+
<name>Cloud SQL Client Side Encryption Samples</name>
23+
24+
<!--
25+
The parent pom defines common style checks and testing strategies for our samples.
26+
Removing or replacing it should not affect the execution of the samples in anyway.
27+
-->
28+
<parent>
29+
<groupId>com.google.cloud.samples</groupId>
30+
<artifactId>shared-configuration</artifactId>
31+
<version>1.0.21</version>
32+
</parent>
33+
34+
<properties>
35+
<maven.compiler.target>1.8</maven.compiler.target>
36+
<maven.compiler.source>1.8</maven.compiler.source>
37+
</properties>
38+
39+
<dependencyManagement>
40+
<dependencies>
41+
<dependency>
42+
<groupId>com.google.cloud</groupId>
43+
<artifactId>libraries-bom</artifactId>
44+
<version>18.0.0</version>
45+
<type>pom</type>
46+
<scope>import</scope>
47+
</dependency>
48+
<dependency>
49+
<groupId>com.google.api-client</groupId>
50+
<artifactId>google-api-client</artifactId>
51+
<version>1.31.3</version>
52+
</dependency>
53+
</dependencies>
54+
</dependencyManagement>
55+
56+
<dependencies>
57+
<dependency>
58+
<groupId>com.google.http-client</groupId>
59+
<artifactId>google-http-client-jackson2</artifactId>
60+
<version>1.39.0</version>
61+
</dependency>
62+
<dependency>
63+
<groupId>com.google.cloud.sql</groupId>
64+
<artifactId>postgres-socket-factory</artifactId>
65+
<version>1.2.1</version>
66+
</dependency>
67+
<dependency>
68+
<groupId>org.postgresql</groupId>
69+
<artifactId>postgresql</artifactId>
70+
<version>42.2.19</version>
71+
</dependency>
72+
<dependency>
73+
<groupId>com.google.crypto.tink</groupId>
74+
<artifactId>tink</artifactId>
75+
<version>1.5.0</version>
76+
</dependency>
77+
<dependency>
78+
<groupId>com.google.crypto.tink</groupId>
79+
<artifactId>tink-gcpkms</artifactId>
80+
<version>1.5.0</version>
81+
</dependency>
82+
<dependency>
83+
<groupId>com.zaxxer</groupId>
84+
<artifactId>HikariCP</artifactId>
85+
<version>4.0.2</version>
86+
</dependency>
87+
88+
<dependency>
89+
<groupId>junit</groupId>
90+
<artifactId>junit</artifactId>
91+
<version>4.13.2</version>
92+
<scope>test</scope>
93+
</dependency>
94+
<dependency>
95+
<groupId>com.google.truth</groupId>
96+
<artifactId>truth</artifactId>
97+
<version>1.1.2</version>
98+
<scope>test</scope>
99+
</dependency>
100+
</dependencies>
101+
102+
</project>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2021 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package cloudsql.tink;
18+
19+
// [START cloud_sql_postgres_cse_key]
20+
21+
import com.google.crypto.tink.Aead;
22+
import com.google.crypto.tink.KmsClient;
23+
import com.google.crypto.tink.aead.AeadConfig;
24+
import com.google.crypto.tink.aead.AeadKeyTemplates;
25+
import com.google.crypto.tink.aead.KmsEnvelopeAead;
26+
import com.google.crypto.tink.integration.gcpkms.GcpKmsClient;
27+
import java.security.GeneralSecurityException;
28+
29+
public class CloudKmsEnvelopeAead {
30+
31+
public static Aead get(String kmsUri) throws GeneralSecurityException {
32+
AeadConfig.register();
33+
34+
// Create a new KMS Client
35+
KmsClient client = new GcpKmsClient().withDefaultCredentials();
36+
37+
// Create an AEAD primitive using the Cloud KMS key
38+
Aead gcpAead = client.getAead(kmsUri);
39+
40+
// Create an envelope AEAD primitive.
41+
// This key should only be used for client-side encryption to ensure authenticity and integrity
42+
// of data.
43+
return new KmsEnvelopeAead(AeadKeyTemplates.AES128_GCM, gcpAead);
44+
}
45+
}
46+
// [END cloud_sql_postgres_cse_key]

0 commit comments

Comments
 (0)