Настройка шифрования для подключений хранилища BLOB-объектов Azure
В этом разделе поясняется настройка шифрования для сохранения содержимого в зашифрованном формате в хранилище BLOB-объектов Azure. По умолчанию содержимое, сохраняемое в хранилище BLOB-объектов Azure, шифруется с использованием типа шифрования serverSideEncryption. Содержимое, находящееся в хранилищах на основе файловой системы, имеет текстовый формат.
Windchill поддерживает следующие типы шифрования.
1. Сторона сервера - для выбора доступны две опции:
a. Ключ, управляемый системой Azure - это тип шифрования по умолчанию, автоматически задается системой Azure.
b. Управляемый хранилищем ключей Azure ключ - можно задать ключ хранилища ключей для контейнера на портале Azure.
2. Сторона клиента - для выбора доступны две опции:
a. clientSideEncryption-keyvault - этот тип шифрования использует ключи, управляемые хранилищем ключей Azure.
b. clientSideEncryption - этот тип шифрования использует пользовательские управляемые ключи.
Подробные сведения о реализациях делегатов для шифрования на стороне клиента см. в подразделе "Написание реализаций делегатов для шифрования на стороне клиента".
|
Пользователь несет ответственность за управление опциями шифрования. Необходимо убедиться, что содержимое будет доступно в случае изменений опций шифрования.
|
Написание реализаций делегатов для шифрования на стороне клиента
Чтобы настроить шифрование содержимого в хранилище BLOB-объектов Azure, напишите реализации делегатов следующим образом.
1. Делегат конфигуратора шифрования Blob-объекта - делегат по умолчанию:
com.ptc.windchill.objectstorage.azureblob.encryption.DefaultBlobEncryptConfigurator. Делегат по умолчанию возвращает тип шифрования
serverSideEncryption. Если нужно использовать другой тип шифрования, напишите делегат, который возвращает нужный тип шифрования, разверните файлы класса и выполните конфигурирование с помощью инструмента командной строки. Дополнительные сведения о конфигурировании см. в разделе
Конфигурирование файловых архивов Windchill для использования хранилища BLOB-объектов Azure.
Ниже приведен пример делегата.
SampleBlobEncryptConfigurator.java:
package com.abc.windchill.objectstorage.azureblob.encryption;
import com.ptc.windchill.objectstorage.azureblob.exception.BlobException;
public class SampleBlobEncryptConfigurator implements BlobEncryptConfigurator {
private static final String CSE_KEYVAULT_FOLDER = "keyvault";
private static final String CSE_FOLDER = "cse";
@Override
public String getBlobEncryptionType(String storageAccountName, String containerName, String blobName) throws BlobException {
if (blobName != null && blobName.contains(CSE_KEYVAULT_FOLDER)) {
return BlobEncryptionType.CSE_KEYVAULT;
} else if (blobName != null && blobName.contains(CSE_FOLDER)) {
return BlobEncryptionType.CSE;
} else {
return BlobEncryptionType.SSE;
}
}
}
В зависимости от пути подключения (наименования Blob-объекта) SampleBlobEncryptConfigurator возвращает в качестве типа шифрования serverSideEncryption, clientSideEncryption или clientSideEncryption-keyvault. Содержимое, сохраненное в хранилище BLOB-объектов Azure, шифруется с использованием следующих типов шифрования. Интерфейс API getBlobEncryptionType получает в виде аргументов наименование учетной записи хранилища, наименование контейнера и наименование Blob-объекта. Тип шифрования можно программировать, используя наименование учетной записи хранилища, наименование контейнера и наименование Blob-объекта. Например, для контейнера c1 возвратите тип шифрования serverSideEncryption, а для контейнера c2 возвратите тип шифрования clientSideEncryption-keyvault.
Допустимые значения типа шифрования:
a. serverSideEncryption - содержимое сохраняется с помощью шифрования с помощью управляемых ключей Azure на стороне сервера.
b. clientSideEncryption-keyvault - содержимое сохраняется путем шифрования с помощью управляемых ключей Azure на стороне клиента.
c. clientSideEncryption - содержимое сохраняется путем шифрования с помощью предоставляемых заказчиком ключей на стороне клиента.
2. CSEKeyVaultKeyProvider Delegate - этот делегат применим, если тип шифрования сконфигурирован как
clientSideEncryption-keyvault. Для этого делегата отсутствует стандартная реализация по умолчанию. Необходимо написать делегат, возвращающий ожидаемые параметры соединения с хранилищем ключей Azure, развернуть файлы класса и выполнить настройку с помощью инструмента командной строки. Дополнительные сведения о конфигурировании см. в разделе
Конфигурирование файловых архивов Windchill для использования хранилища Blob-объектов Azure.
|
Не используйте следующие примеры реализаций "как есть" в производственной среде.
|
Ниже приведен пример делегата.
package com.abc.windchill.objectstorage.azureblob.encryption.csekeyvault;
import com.ptc.windchill.objectstorage.azureblob.encryption.csekeyvault.CSEKeyVaultKeyProvider;
import com.ptc.windchill.objectstorage.azureblob.encryption.csekeyvault.KeyVaultConnectionParams;
import com.ptc.windchill.objectstorage.azureblob.exception.BlobException;
/**
* Sample implementation of CSEKeyVaultKeyProvider.
*/
public class SampleCSEKeyVaultKeyProvider implements CSEKeyVaultKeyProvider {
@Override
public KeyVaultConnectionParams getKeyVaultConnectionDetails(String containerName, String blobName)
throws BlobException {
String keyVaultKeyIdUrl = "https://mykeyvault.vault.azure.net/keys/MyKeyVaultKey";
String appId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
String appAuthKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
KeyVaultConnectionParams connectionParams = new KeyVaultConnectionParams(keyVaultKeyIdUrl, appId,
appAuthKey);
return connectionParams;
}
}
3. CSESecKeyGenerator Delegate - при конфигурировании типа шифрования как
clientSideEncryption необходимо написать реализацию для этого делегата и выполнить конфигурирование делегата. Этот делегат применим, только если тип шифрования сконфигурирован как
clientSideEncryption. Для этого делегата отсутствует стандартная реализация по умолчанию. Напишите делегат, управляющий
KeyPair и
KeyId, разверните файлы класса и выполните настройку с помощью инструмента командной строки. Дополнительные сведения о конфигурировании см. в разделе
Конфигурирование файловых архивов Windchill для использования хранилища BLOB-объектов Azure.
Ниже приведен пример делегата.
SampleCSESecKeyGenerator.java: этот пример реализации демонстрирует способ генерации KeyPair и KeyId. В этом примере реализации выполняется поиск существующего параметра KeyPair. Будет возвращен параметр KeyPair, если он будет найден. В противном случае будет создан, сохранен в файле на диске и возвращен новый параметр KeyPair. Можно выбрать стратегию безопасного хранения KeyPair. Кроме того, в этом примере реализации используется один параметр KeyPair для всех файлов в архиве. Можно написать собственный алгоритм управления несколькими парами ключей для контейнеров или для Blob-объектов, сохраненных в Azure.
package com.abc.windchill.objectstorage.azureblob.encryption.cse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import com.ptc.windchill.objectstorage.azureblob.encryption.cse.CSESecKeyGenerator;
import com.ptc.windchill.objectstorage.azureblob.exception.BlobException;
import wt.util.WTException;
import wt.util.WTProperties;
import wt.wrmf.delivery.ObjectIS;
import wt.wrmf.delivery.PayloadShippingItem;
import wt.wrmf.delivery.ShippingHelper;
/**
* Sample implementation of CSESecKeyGenerator.
*/
public class SampleCSESecKeyGenerator implements CSESecKeyGenerator {
private File keyPairFile;
public static String keyPairFileName;
static {
try {
WTProperties props = WTProperties.getLocalProperties();
String windchillHome = props.getProperty("wt.home");
keyPairFileName = windchillHome + File.separator + "RsaKey";
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
@Override
public KeyPair getKeyPair(String storageAccountName, String containerName, String blobName) throws BlobException {
try{
KeyPair wrapKey = getKeyPairFromFileStore();
if(wrapKey == null){
// Create the IKey used for encryption.
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
wrapKey = keyGen.generateKeyPair();
storeKeyPairInFileStore(containerName, blobName, wrapKey);
storeKeyPairInFileStoreOnReplica(containerName, blobName, wrapKey);
}
return wrapKey;
}
catch(Exception e){
throw new BlobException(e);
}
}
@Override
public String getKeyId(String storageAccountName, String containerName, String blobName) throws BlobException {
return containerName;//using container name as key id
}
private KeyPair getKeyPairFromFileStore()throws IOException, ClassNotFoundException{
KeyPair keyPair = null;
File keyPairFile = getKeyPairFile();
try(
FileInputStream fis = new FileInputStream(keyPairFile);
ObjectInputStream ois = new ObjectInputStream(fis);){
keyPair = (KeyPair)ois.readObject();
}catch (IOException ignore){
ignore.printStackTrace();
}
return keyPair;
}
public synchronized void storeKeyPairInFileStore(String containerName, String blobName, KeyPair keyPair)throws IOException{
File keyPairFile = getKeyPairFile();
try(FileOutputStream fos = new FileOutputStream(keyPairFile, true);
ObjectOutputStream oos = new ObjectOutputStream(fos);){
oos.writeObject(keyPair);
oos.flush();
}
}
private synchronized void storeKeyPairInFileStoreOnReplica(String containerName, String blobName, KeyPair keyPair)
throws Exception {
//this is a private method that invokes method call on replica site
invokeMethodOnReplica(getReplicaSite(),
SampleCSESecKeyGenerator.class.getName(), "setKeyPairOnReplica",
new String[] { String.class.getName(), String.class.getName(), KeyPair.class.getName() },
new Serializable[] { containerName, blobName, keyPair });
}
private synchronized File getKeyPairFile() throws IOException {
if (keyPairFile == null) {
keyPairFile = new File(keyPairFileName);
if (!keyPairFile.exists()) {
keyPairFile.createNewFile();
}
}
return keyPairFile;
}
@Override
public boolean removeKeyPair(String storageAccountName, String containerName, String blobName) {
return true;//do not remove the KeyPair, since sample code uses single KeyPair for all files in vault.
}
public static PayloadShippingItem setKeyPairOnReplica(String storageAccountName,
String containerName, String blobName, KeyPair keyPair) throws WTException {
PayloadShippingItem psi = ShippingHelper.service.createPayloadShippingItem();
try {
File keyPairFile = new File(keyPairFileName);
if (!keyPairFile.exists()) {
keyPairFile.createNewFile();
}
try (FileOutputStream fos = new FileOutputStream(keyPairFile, false);
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(keyPair);
oos.flush();
}
Object[] valuesToReturn = new Object[] {};
ObjectIS retValsIS = new ObjectIS(valuesToReturn);
psi.setPayload(retValsIS);
} catch (Exception e) {
throw new WTException(e);
}
return psi;
}
}
Управление типом шифрования
Если нужно изменить тип шифрования для файлового архива, выполните следующие шаги.
1. Создайте новое хранилище и сконфигурируйте его для нужного типа шифрования, используя реализацию делегата. Дополнительные сведения см. в разделе "Написание реализаций делегатов для шифрования на стороне клиента".
2. Обновите правило помещения в файловые хранилища, чтобы направить содержимое в новое хранилище.
3. Выполните график повторного помещения в файловые хранилища.