Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions conf/springConfigXml/encrypt.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@
</zstack:plugin>
</bean>

<bean id="ZbsVolumeEncryptionMaterialFactory" class="org.zstack.storage.encrypt.ZbsVolumeEncryptionMaterialFactory"/>
<bean id="ZbsVolumeEncryptionKvmCaller" class="org.zstack.storage.encrypt.ZbsVolumeEncryptionKvmCaller"/>
<bean id="ZbsVolumeEncryptionCleanup" class="org.zstack.storage.encrypt.ZbsVolumeEncryptionCleanup"/>
<bean id="ZbsEncryptedEmptyVolumeCreator" class="org.zstack.storage.encrypt.ZbsEncryptedEmptyVolumeCreator"/>
<bean id="ZbsEncryptedVolumeCloner" class="org.zstack.storage.encrypt.ZbsEncryptedVolumeCloner"/>
<bean id="ZbsEncryptedSnapshotVolumeCopier" class="org.zstack.storage.encrypt.ZbsEncryptedSnapshotVolumeCopier"/>
<bean id="ZbsVolumeEncryptInPlaceHandler" class="org.zstack.storage.encrypt.ZbsVolumeEncryptInPlaceHandler"/>
<bean id="ZbsEncryptedVolumeResizer" class="org.zstack.storage.encrypt.ZbsEncryptedVolumeResizer"/>
<bean id="ZbsVolumeEncryptionExtension" class="org.zstack.storage.encrypt.ZbsVolumeEncryptionExtension">
<zstack:plugin>
<zstack:extension interface="org.zstack.header.storage.addon.primary.ZbsVolumeEncryptionExtensionPoint"/>
</zstack:plugin>
</bean>

<bean id="PasswordConvert" class="org.zstack.core.convert.PasswordConverter" />
<bean id="SpecialDataConverter" class="org.zstack.core.convert.SpecialDataConverter" />
</beans>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ public class CreateVolumeSpec {
private String uuid;
private long size;
private VolumeQos qos;
private boolean encrypted;
private String hostUuid;
private String encryptedDek;

private String allocatedUrl;
private boolean dryRun;
Expand Down Expand Up @@ -58,4 +61,28 @@ public String getName() {
public void setName(String name) {
this.name = name;
}

public boolean isEncrypted() {
return encrypted;
}

public void setEncrypted(boolean encrypted) {
this.encrypted = encrypted;
}

public String getHostUuid() {
return hostUuid;
}

public void setHostUuid(String hostUuid) {
this.hostUuid = hostUuid;
}

public String getEncryptedDek() {
return encryptedDek;
}

public void setEncryptedDek(String encryptedDek) {
this.encryptedDek = encryptedDek;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import org.zstack.header.core.ReturnValueCompletion;
import org.zstack.header.host.HostInventory;
import org.zstack.header.storage.addon.*;
import org.zstack.header.storage.primary.EncryptVolumeBitsOnPrimaryStorageMsg;
import org.zstack.header.storage.primary.EncryptVolumeBitsOnPrimaryStorageReply;
import org.zstack.header.storage.snapshot.VolumeSnapshotStats;
import org.zstack.header.volume.VolumeInventory;
import org.zstack.header.volume.VolumeProtocol;
import org.zstack.header.volume.VolumeStats;

Expand All @@ -30,14 +33,15 @@ public interface PrimaryStorageControllerSvc {
void trashVolume(String installPath, Completion comp);
void cloneVolume(String srcInstallPath, CreateVolumeSpec dst, ReturnValueCompletion<VolumeStats>comp);
void copyVolume(String srcInstallPath, CreateVolumeSpec dst, ReturnValueCompletion<VolumeStats>comp);
void encryptVolumeBits(EncryptVolumeBitsOnPrimaryStorageMsg msg, ReturnValueCompletion<EncryptVolumeBitsOnPrimaryStorageReply> comp);
void flattenVolume(String installPath, ReturnValueCompletion<VolumeStats>comp);

// support uri or path
void stats(String installPath, ReturnValueCompletion<VolumeStats> comp);

void batchStats(Collection<String> installPath, ReturnValueCompletion<List<VolumeStats>> comp);

void expandVolume(String installPath, long size, ReturnValueCompletion<VolumeStats> comp);
void expandVolume(VolumeInventory volume, long size, ReturnValueCompletion<VolumeStats> comp);
void setVolumeQos(BaseVolumeInfo v, Completion comp);
void deleteVolumeQos(BaseVolumeInfo v, Completion comp);
void export(ExportSpec espec, VolumeProtocol protocol, ReturnValueCompletion<RemoteTarget> comp);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.zstack.header.storage.addon.primary;

import org.zstack.header.core.Completion;
import org.zstack.header.core.ReturnValueCompletion;
import org.zstack.header.volume.VolumeStats;

public interface ZbsVolumeEncryptionBackend {
String getPrimaryStorageUuid();

String buildConfiguredVolumePath(String volumeName);

String buildEncryptedTargetPath(String installPath);

void createLuksBackingVolume(String installPath, long virtualSize, ReturnValueCompletion<String> completion);

void deleteLuksBackingVolume(String installPath);

void cloneVolumeAsBacking(String srcInstallPath, CreateVolumeSpec dst, ReturnValueCompletion<VolumeStats> completion);

void resolveSnapshotPathForQemu(String installPath, ReturnValueCompletion<String> completion);

void checkNoSnapshots(String installPath, Completion completion);

void stats(String installPath, ReturnValueCompletion<VolumeStats> completion);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.zstack.header.storage.addon.primary;

import org.zstack.header.core.ReturnValueCompletion;
import org.zstack.header.storage.primary.EncryptVolumeBitsOnPrimaryStorageMsg;
import org.zstack.header.storage.primary.EncryptVolumeBitsOnPrimaryStorageReply;
import org.zstack.header.storage.snapshot.VolumeSnapshotInventory;
import org.zstack.header.volume.VolumeInventory;
import org.zstack.header.volume.VolumeStats;
import org.zstack.header.volume.VolumeVO;

public interface ZbsVolumeEncryptionExtensionPoint {
String PRIMARY_STORAGE_IDENTITY = "zbs";

void createEncryptedEmptyVolume(ZbsVolumeEncryptionBackend backend, CreateVolumeSpec spec,
ReturnValueCompletion<VolumeStats> completion);

void cloneEncryptedVolumeFromImage(ZbsVolumeEncryptionBackend backend, String srcInstallPath, CreateVolumeSpec dst,
ReturnValueCompletion<VolumeStats> completion);

void copyEncryptedVolumeFromSnapshot(ZbsVolumeEncryptionBackend backend, String srcInstallPath, CreateVolumeSpec dst,
ReturnValueCompletion<VolumeStats> completion);

void encryptVolumeBits(ZbsVolumeEncryptionBackend backend, EncryptVolumeBitsOnPrimaryStorageMsg msg,
ReturnValueCompletion<EncryptVolumeBitsOnPrimaryStorageReply> completion);

void resizeEncryptedVolume(String primaryStorageUuid, VolumeInventory volume, long size,
ReturnValueCompletion<VolumeStats> completion);

void beforeTakeSnapshot(String primaryStorageUuid, VolumeVO volume, VolumeSnapshotInventory snapshot);

void afterTakeSnapshot(String primaryStorageUuid, VolumeVO volume, VolumeSnapshotInventory snapshot);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,12 @@
import org.zstack.header.log.NoLogging;
import org.zstack.header.message.NeedReplyMessage;

/**
* Triggers an in-place LUKS encryption of an existing volume file on primary storage.
* Used after downloading a data-volume template's plain bits to LocalStorage when the
* volume is marked encrypted: the agent converts the plain qcow2/raw at {@link #installPath}
* into a LUKS-encrypted qcow2 (overwriting in place).
*
* The DEK is passed as a host-enveloped encryptedDek. The kvmagent unwraps it and
* creates any single-use secret material file locally as needed.
*/
public class EncryptVolumeBitsOnPrimaryStorageMsg extends NeedReplyMessage implements PrimaryStorageMessage {
private String primaryStorageUuid;
private String hostUuid;
private String volumeUuid;
private String installPath;
private String targetInstallPath;
@NoLogging
private String encryptedDek;

Expand Down Expand Up @@ -53,6 +45,14 @@ public void setInstallPath(String installPath) {
this.installPath = installPath;
}

public String getTargetInstallPath() {
return targetInstallPath;
}

public void setTargetInstallPath(String targetInstallPath) {
this.targetInstallPath = targetInstallPath;
}

public String getEncryptedDek() {
return encryptedDek;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,13 @@
import org.zstack.header.message.MessageReply;

public class EncryptVolumeBitsOnPrimaryStorageReply extends MessageReply {
private String installPath;

public String getInstallPath() {
return installPath;
}

public void setInstallPath(String installPath) {
this.installPath = installPath;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@
import org.zstack.header.core.ReturnValueCompletion;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.errorcode.OperationFailureException;
import org.zstack.header.errorcode.SysErrors;
import org.zstack.header.expon.HealthStatus;
import org.zstack.header.host.HostInventory;
import org.zstack.header.host.HostVO;
import org.zstack.header.host.HostVO_;
import org.zstack.header.image.ImageConstant;
import org.zstack.header.storage.addon.*;
import org.zstack.header.storage.addon.primary.*;
import org.zstack.header.storage.primary.EncryptVolumeBitsOnPrimaryStorageMsg;
import org.zstack.header.storage.primary.EncryptVolumeBitsOnPrimaryStorageReply;
import org.zstack.header.storage.primary.ImageCacheInventory;
import org.zstack.header.storage.primary.VolumeSnapshotCapability;
import org.zstack.header.storage.snapshot.VolumeSnapshotStats;
Expand Down Expand Up @@ -1093,6 +1096,12 @@ public void fail(ErrorCode errorCode) {
});
}

@Override
public void encryptVolumeBits(EncryptVolumeBitsOnPrimaryStorageMsg msg, ReturnValueCompletion<EncryptVolumeBitsOnPrimaryStorageReply> comp) {
String details = String.format("primary storage controller[%s] does not support encrypting volume bits in place", getIdentity());
comp.fail(new ErrorCode(SysErrors.UNIMPLEMENTED_OPERATION_ERROR.toString(), "unimplemented operation", details));
}

@Override
public void flattenVolume(String installPath, ReturnValueCompletion<VolumeStats> comp) {
// TODO flatten snapshot
Expand Down Expand Up @@ -1125,7 +1134,8 @@ public void batchStats(Collection<String> installPath, ReturnValueCompletion<Lis
}

@Override
public void expandVolume(String installPath, long size, ReturnValueCompletion<VolumeStats> comp) {
public void expandVolume(VolumeInventory volume, long size, ReturnValueCompletion<VolumeStats> comp) {
String installPath = volume.getInstallPath();
VolumeModule vol = apiHelper.expandVolume(getVolIdFromPath(installPath), size);
VolumeStats stats = new VolumeStats();
stats.setInstallPath(installPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.zstack.core.asyncbatch.While;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.SQL;
import org.zstack.core.workflow.FlowChainBuilder;
Expand All @@ -36,6 +37,7 @@
import org.zstack.header.storage.primary.*;
import org.zstack.header.storage.snapshot.VolumeSnapshotStats;
import org.zstack.header.volume.VolumeConstant;
import org.zstack.header.volume.VolumeInventory;
import org.zstack.header.volume.VolumeProtocol;
import org.zstack.header.volume.VolumeStats;
import org.zstack.kvm.KVMHostAsyncHttpCallMsg;
Expand Down Expand Up @@ -77,6 +79,8 @@ public class ZbsStorageController implements PrimaryStorageControllerSvc, Primar
private ResourceConfigFacade rcf;
@Autowired
private CloudBus bus;
@Autowired
private PluginRegistry pluginRgty;

private ExternalPrimaryStorageVO self;
private AddonInfo addonInfo;
Expand Down Expand Up @@ -581,10 +585,34 @@ private List<LogicalPoolInfo> getSelfPools() {
return logicalPoolInfos;
}

private ZbsVolumeEncryptionExtensionPoint getVolumeEncryptionExtension() {
List<ZbsVolumeEncryptionExtensionPoint> exts = pluginRgty.getExtensionList(ZbsVolumeEncryptionExtensionPoint.class);
if (exts.isEmpty()) {
throw new OperationFailureException(operr("cannot find ZBS volume encryption extension"));
}
return exts.get(0);
}

private ZbsVolumeEncryptionBackend encryptionBackend() {
if (config == null || addonInfo == null) {
reloadDbInfo();
}
return new ZbsVolumeEncryptionBackendImpl(this, self.getUuid(), addonInfo, config);
}

@Override
public void createVolume(CreateVolumeSpec v, ReturnValueCompletion<VolumeStats> comp) {
reloadDbInfo();

if (v.isEncrypted()) {
try {
getVolumeEncryptionExtension().createEncryptedEmptyVolume(encryptionBackend(), v, comp);
} catch (OperationFailureException e) {
comp.fail(e.getErrorCode());
}
return;
}

CreateVolumeCmd cmd = new CreateVolumeCmd();
cmd.setLogicalPool(config.getLogicalPoolName());
cmd.setVolume(v.getName());
Expand Down Expand Up @@ -627,6 +655,15 @@ public void trashVolume(String installPath, Completion comp) {

@Override
public void cloneVolume(String srcInstallPath, CreateVolumeSpec dst, ReturnValueCompletion<VolumeStats> comp) {
if (dst.isEncrypted()) {
try {
getVolumeEncryptionExtension().cloneEncryptedVolumeFromImage(encryptionBackend(), srcInstallPath, dst, comp);
} catch (OperationFailureException e) {
comp.fail(e.getErrorCode());
}
return;
}

VolumeStats stats = new VolumeStats();

FlowChain chain = FlowChainBuilder.newShareFlowChain();
Expand Down Expand Up @@ -711,6 +748,15 @@ public void handle(ErrorCode errCode, Map data) {

@Override
public void copyVolume(String srcInstallPath, CreateVolumeSpec dst, ReturnValueCompletion<VolumeStats> comp) {
if (dst.isEncrypted()) {
try {
getVolumeEncryptionExtension().copyEncryptedVolumeFromSnapshot(encryptionBackend(), srcInstallPath, dst, comp);
} catch (OperationFailureException e) {
comp.fail(e.getErrorCode());
}
return;
}

CopyCmd cmd = new CopyCmd();
cmd.setPath(srcInstallPath);
cmd.setDstVolume(dst.getName());
Expand All @@ -734,6 +780,15 @@ public void fail(ErrorCode errorCode) {
});
}

@Override
public void encryptVolumeBits(EncryptVolumeBitsOnPrimaryStorageMsg msg, ReturnValueCompletion<EncryptVolumeBitsOnPrimaryStorageReply> comp) {
try {
getVolumeEncryptionExtension().encryptVolumeBits(encryptionBackend(), msg, comp);
} catch (OperationFailureException e) {
comp.fail(e.getErrorCode());
}
}

@Override
public void flattenVolume(String installPath, ReturnValueCompletion<VolumeStats> comp) {
FlattenVolumeCmd cmd = new FlattenVolumeCmd();
Expand Down Expand Up @@ -808,7 +863,18 @@ public void fail(ErrorCode errorCode) {
}

@Override
public void expandVolume(String installPath, long size, ReturnValueCompletion<VolumeStats> comp) {
public void expandVolume(VolumeInventory volume, long size, ReturnValueCompletion<VolumeStats> comp) {
if (Boolean.TRUE.equals(volume.getEncrypted())) {
List<ZbsVolumeEncryptionExtensionPoint> exts = pluginRgty.getExtensionList(ZbsVolumeEncryptionExtensionPoint.class);
if (exts.isEmpty()) {
comp.fail(operr("cannot find ZBS volume encryption extension"));
return;
}
exts.get(0).resizeEncryptedVolume(self.getUuid(), volume, size, comp);
return;
}

String installPath = volume.getInstallPath();
ExpandVolumeCmd cmd = new ExpandVolumeCmd();
cmd.setPath(installPath);
cmd.setUnit(getSizeUnit(addonInfo.getClusterInfo().getVersion()));
Expand Down
Loading