Skip to content

Commit

Permalink
Provide an option to configure trusted Azure Key Vault endpoints (#1285)
Browse files Browse the repository at this point in the history
  • Loading branch information
ulvii committed Mar 19, 2020
1 parent f53b3bf commit f739431
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,21 @@

import static java.nio.charset.StandardCharsets.UTF_16LE;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.logging.Level;

import com.microsoft.azure.AzureResponseBuilder;
import com.microsoft.azure.keyvault.KeyVaultClient;
Expand Down Expand Up @@ -43,22 +49,21 @@
*/
public class SQLServerColumnEncryptionAzureKeyVaultProvider extends SQLServerColumnEncryptionKeyStoreProvider {

private final static java.util.logging.Logger akvLogger = java.util.logging.Logger
.getLogger("com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionAzureKeyVaultProvider");
/**
* Column Encryption Key Store Provider string
*/
String name = "AZURE_KEY_VAULT";

private final String baseUrl = "https://{vaultBaseUrl}";

/**
* List of Azure trusted endpoints https://docs.microsoft.com/en-us/azure/key-vault/key-vault-secure-your-key-vault
*/
private final String azureTrustedEndpoints[] = {"vault.azure.net", // default
"vault.azure.cn", // Azure China
"vault.usgovcloudapi.net", // US Government
"vault.microsoftazure.de" // Azure Germany
};

private static final String MSSQL_JDBC_PROPERTIES = "mssql-jdbc.properties";
private static final String AKV_TRUSTED_ENDPOINTS_KEYWORD = "AKVTrustedEndpoints";
private static final List<String> akvTrustedEndpoints;
static {
akvTrustedEndpoints = getTrustedEndpoints();
}
private final String rsaEncryptionAlgorithmWithOAEPForAKV = "RSA-OAEP";

/**
Expand Down Expand Up @@ -455,7 +460,7 @@ private void ValidateNonEmptyAKVPath(String masterKeyPath) throws SQLServerExcep
if (null != host) {
host = host.toLowerCase(Locale.ENGLISH);
}
for (final String endpoint : azureTrustedEndpoints) {
for (final String endpoint : akvTrustedEndpoints) {
if (null != host && host.endsWith(endpoint)) {
return;
}
Expand Down Expand Up @@ -628,4 +633,57 @@ public boolean verifyColumnMasterKeyMetadata(String masterKeyPath, boolean allow
throw new SQLServerException(SQLServerException.getErrString("R_NoSHA256Algorithm"), e);
}
}

private static List<String> getTrustedEndpoints() {
Properties mssqlJdbcProperties = getMssqlJdbcProperties();
List<String> trustedEndpoints = new ArrayList<String>();
boolean append = true;
if (null != mssqlJdbcProperties) {
String endpoints = mssqlJdbcProperties.getProperty(AKV_TRUSTED_ENDPOINTS_KEYWORD);
if (null != endpoints && !endpoints.isBlank()) {
endpoints = endpoints.trim();
// Append if the list starts with a semicolon.
if (';' != endpoints.charAt(0)) {
append = false;
} else {
endpoints = endpoints.substring(1);
}
String[] entries = endpoints.split(";");
for (String entry : entries) {
if (null != entry && !entry.isBlank()) {
trustedEndpoints.add(entry.trim());
}
}
}
}
/*
* List of Azure trusted endpoints
* https://docs.microsoft.com/en-us/azure/key-vault/key-vault-secure-your-key-vault
*/
if (append) {
trustedEndpoints.add("vault.azure.net");
trustedEndpoints.add("vault.azure.cn");
trustedEndpoints.add("vault.usgovcloudapi.net");
trustedEndpoints.add("vault.microsoftazure.de");
}
return trustedEndpoints;
}

/**
* Attempt to read MSSQL_JDBC_PROPERTIES.
*
* @return corresponding Properties object or null if failed to read the file.
*/
private static Properties getMssqlJdbcProperties() {
Properties props = null;
try (FileInputStream in = new FileInputStream(MSSQL_JDBC_PROPERTIES)) {
props = new Properties();
props.load(in);
} catch (IOException e) {
if (akvLogger.isLoggable(Level.FINER)) {
akvLogger.finer("Unable to load the mssql-jdbc.properties file: " + e);
}
}
return (null != props && !props.isEmpty()) ? props : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
package com.microsoft.sqlserver.testframework;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.ResultSet;
Expand Down Expand Up @@ -145,8 +148,22 @@ public static void setup() throws Exception {
}

if (null == akvProvider) {
akvProvider = new SQLServerColumnEncryptionAzureKeyVaultProvider(applicationClientID, applicationKey);
map.put(Constants.AZURE_KEY_VAULT_NAME, akvProvider);
File file = null;
try {
file = new File(Constants.MSSQL_JDBC_PROPERTIES);
try (OutputStream os = new FileOutputStream(file);) {
Properties props = new Properties();
// Append to the list of hardcoded endpoints.
props.setProperty(Constants.AKV_TRUSTED_ENDPOINTS_KEYWORD, ";vault.azure.net");
props.store(os, "");
}
akvProvider = new SQLServerColumnEncryptionAzureKeyVaultProvider(applicationClientID, applicationKey);
map.put(Constants.AZURE_KEY_VAULT_NAME, akvProvider);
} finally {
if (null != file) {
file.delete();
}
}
}

if (!isKspRegistered) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ private Constants() {}
public static final String JDBC_PREFIX = "jdbc:sqlserver://";
public static final String DEFAULT_DRIVER_LOG = "Driver.log";
public static final String MSSQL_JDBC_PACKAGE = "com.microsoft.sqlserver.jdbc";
public static final String MSSQL_JDBC_PROPERTIES = "mssql-jdbc.properties";
public static final String AKV_TRUSTED_ENDPOINTS_KEYWORD = "AKVTrustedEndpoints";

public static final String DEFAULT_WRAP_IDENTIFIER = "\'";
public static final String CREATE_TABLE = "CREATE TABLE";
Expand Down

0 comments on commit f739431

Please sign in to comment.