Azure Blob Storage 마운트에 대한 암호화 사용자 정의
이 단원에서는 컨텐트를 암호화된 형식으로 Azure Blob Storage에 저장하는 암호화 사용자 정의에 대해 설명합니다. 기본적으로 Azure Blob Storage에 저장되는 컨텐트는 serverSideEncryption 암호화 유형을 사용하여 암호화됩니다. 파일 시스템 기반 보관소에 저장되는 컨텐트는 일반 형식으로 저장됩니다.
Windchill는 다음 암호화 유형을 지원합니다.
1. 서버측 - 두 가지 옵션 중에서 선택할 수 있습니다.
a. Azure 관리 키 - 기본 암호화 유형이며 Azure 시스템에서 자동으로 설정됩니다.
b. Azure Key Vault 관리 키 - Azure 포털에서 컨테이너의 키 보관소 키를 설정할 수 있습니다.
2. 클라이언트측 - 두 가지 옵션 중에서 선택할 수 있습니다.
a. clientSideEncryption-keyvault - 이 암호화 유형은 Azure Key Vault 관리 키를 사용합니다.
b. clientSideEncryption - 이 암호화 유형은 고객 관리 키를 사용합니다.
클라이언트측 암호화를 위한 위임 구현에 대한 자세한 내용은 "클라이언트측 암호화를 위한 위임 구현 작성" 단원을 참조하십시오.
* 
암호화 옵션은 사용자가 관리합니다. 암호화 옵션을 변경해도 컨텐트는 액세스 가능한 상태여야 합니다.
클라이언트측 암호화를 위한 위임 구현 작성
Azure Blob Storage의 컨텐트 암호화를 사용자 정의하려면 다음과 같이 위임 구현을 작성하십시오.
1. Blob 암호화 구성 위임 - 기본 위임은 com.ptc.windchill.objectstorage.azureblob.encryption.DefaultBlobEncryptConfigurator입니다. 기본 위임은 암호화 유형을 serverSideEncryption으로 반환합니다. 다른 암호화 유형을 사용하려면 예상 암호화 유형을 반환하는 위임을 작성하고 클래스 파일을 배포한 후 명령줄 도구를 사용하여 구성해야 합니다. 구성에 대한 자세한 내용은 Azure Blob Storage를 사용하도록 Windchill 파일 보관소 구성을 참조하십시오.
다음은 샘플 위임입니다.
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 이름)에 따라 SampleBlobEncryptConfiguratorserverSideEncryption, clientSideEncryption 또는 clientSideEncryption-keyvault를 암호화 유형으로 반환합니다. Azure Blob Storage에 저장된 컨텐트는 이러한 암호화 유형을 사용하여 암호화됩니다. API getBlobEncryptionType은 저장소 계정 이름, 컨테이너 이름 및 Blob 이름을 인수로 받습니다. 저장소 계정 이름, 컨테이너 이름 및 Blob 이름을 사용하여 암호화 유형을 프로그래밍할 수 있습니다. 예를 들어, 컨테이너 c1에 대해 암호화 유형으로 serverSideEncryption을 반환하고 컨테이너 c2에 대해 암호화 유형으로 clientSideEncryption-keyvault를 반환할 수 있습니다.
암호화 유형으로 적합한 값은 다음과 같습니다.
a. serverSideEncryption - 컨텐트가 Azure 관리 키와 함께 서버측 암호화를 사용하여 저장됩니다.
b. clientSideEncryption-keyvault - 컨텐트가 Azure Key Vault 관리 키가 있는 클라이언트측 암호화를 사용하여 저장됩니다.
c. clientSideEncryption - 컨텐트가 고객 제공 키와 함께 클라이언트측 암호화를 사용하여 저장됩니다.
2. CSEKeyVaultKeyProvider Delegate - 이 위임은 암호화 유형이 clientSideEncryption-keyvault로 구성된 경우 적용 가능합니다. 이 위임에 대한 기본 제공 구현은 없습니다. 예상 Azure Key Vault 연결 매개변수를 반환하는 위임을 작성하고 클래스 파일을 배포한 후 명령줄 도구를 사용하여 구성해야 합니다. 구성에 대한 자세한 내용은 Azure Blob Storage를 사용하도록 Windchill 파일 보관소 구성을 참조하십시오.
* 
생산 환경에서는 다음 샘플 구현을 사용하지 마십시오.
샘플 위임은 다음과 같습니다.
SampleCSEKeyVaultKeyProvider.java: 이 샘플 구현은 Azure Key Vault 연결 매개변수를 반환하는 방법을 보여줍니다. 키 보관소 및 응용 프로그램 등록에 대한 자세한 내용은 Azure Blob Storage를 사용하도록 Windchill 파일 보관소 구성의 "Azure Blob에서 키 보관소 암호화 설정"을 참조하십시오.
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";
String tenantId = “xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”;
KeyVaultConnectionParams connectionParams = new KeyVaultConnectionParams(keyVaultKeyIdUrl, appId,
appAuthKey, tenantId);
return connectionParams;
}
}
* 
Windchill 12.1.2.0 릴리즈부터 clientSideEncryption-keyvault 암호화 유형의 경우 테넌트(디렉터리) ID는 KeyVaultConnectionParams 생성자에 제공되어야 하는 필수 입력입니다.
테넌트(디렉터리) ID에 대한 코드 변경을 방지하려면 wt.property wt.objectStorage.blob.csekeyvault.appTenantId를 사용하여 테넌트(디렉터리) ID를 설정할 수 있습니다.
3. CSESecKeyGenerator Delegate - 암호화 유형을 clientSideEncryption으로 구성할 경우 이 위임에 대한 구현을 작성하고 위임을 구성해야 합니다. 이 위임은 암호화 유형이 clientSideEncryption으로 구성된 경우에만 적용 가능합니다. 이 위임에 대한 기본 제공 구현은 없습니다. KeyPairKeyId를 관리하는 위임을 작성하고 클래스 파일을 배포한 후 명령줄 도구를 사용하여 구성합니다. 구성에 대한 자세한 내용은 Azure Blob Storage를 사용하도록 Windchill 파일 보관소 구성을 참조하십시오.
샘플 위임은 다음과 같습니다.
SampleCSESecKeyGenerator.java: KeyPairKeyId 생성 방법을 보여주는 샘플 구현입니다. 이 샘플 구현은 기존 KeyPair를 검색합니다. KeyPair를 찾으면 반환됩니다. 그렇지 않으면 새로운 KeyPair를 생성하여 디스크의 파일에 저장하고 반환합니다. KeyPair를 안전하게 저장할 전략을 결정할 수 있습니다. 또한 이 샘플 구현에서는 보관소의 모든 파일에 단일 KeyPair를 사용합니다. 자체 알고리즘을 작성하여 Azure에 저장된 컨테이너 또는 Blob에 대한 여러 KeyPair를 관리할 수 있습니다.
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. 재보관 스케줄을 실행합니다.
도움이 되셨나요?