Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IGNITE-21013 Support encryption of cache dumps #11078

Merged
merged 9 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from 7 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
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteExperimental;
import org.apache.ignite.spi.IgniteSpiAdapter;
import org.apache.ignite.spi.encryption.EncryptionSpi;

import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.apache.ignite.configuration.DataStorageConfiguration.DFLT_MARSHALLER_PATH;
Expand Down Expand Up @@ -75,7 +77,7 @@ public DumpReader(DumpReaderConfiguration cfg, IgniteLogger log) {
@Override public void run() {
ackAsciiLogo();

try (Dump dump = new Dump(cfg.dumpRoot(), cfg.keepBinary(), false, log)) {
try (Dump dump = new Dump(cfg.dumpRoot(), null, cfg.keepBinary(), false, encryptionSpi(), log)) {
DumpConsumer cnsmr = cfg.consumer();

cnsmr.start();
Expand Down Expand Up @@ -231,4 +233,19 @@ private void ackAsciiLogo() {
"");
}
}

/** */
private EncryptionSpi encryptionSpi() {
EncryptionSpi encSpi = cfg.encryptionSpi();

if (encSpi == null)
return null;

if (encSpi instanceof IgniteSpiAdapter)
((IgniteSpiAdapter)encSpi).onBeforeStart();

encSpi.spiStart("dump-reader");

return encSpi;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.apache.ignite.internal.processors.cache.CacheObject;
import org.apache.ignite.internal.processors.cache.KeyCacheObject;
import org.apache.ignite.lang.IgniteExperimental;
import org.apache.ignite.spi.encryption.EncryptionSpi;

/**
* Configuration class of {@link DumpReader}.
Expand Down Expand Up @@ -61,12 +62,15 @@ public class DumpReaderConfiguration {
/** Skip copies. */
private final boolean skipCopies;

/** Encryption SPI. */
private final EncryptionSpi encSpi;

/**
* @param dir Root dump directory.
* @param cnsmr Dump consumer.
*/
public DumpReaderConfiguration(File dir, DumpConsumer cnsmr) {
this(dir, cnsmr, DFLT_THREAD_CNT, DFLT_TIMEOUT, true, true, null, false);
this(dir, cnsmr, DFLT_THREAD_CNT, DFLT_TIMEOUT, true, true, null, false, null);
}

/**
Expand All @@ -78,15 +82,18 @@ public DumpReaderConfiguration(File dir, DumpConsumer cnsmr) {
* @param keepBinary If {@code true} then don't deserialize {@link KeyCacheObject} and {@link CacheObject}.
* @param cacheGroupNames Cache group names.
* @param skipCopies Skip copies.
* @param encSpi Encryption SPI.
*/
public DumpReaderConfiguration(File dir,
public DumpReaderConfiguration(
File dir,
DumpConsumer cnsmr,
int thCnt,
Duration timeout,
boolean failFast,
boolean keepBinary,
String[] cacheGroupNames,
boolean skipCopies
boolean skipCopies,
EncryptionSpi encSpi
) {
this.dir = dir;
this.cnsmr = cnsmr;
Expand All @@ -96,6 +103,7 @@ public DumpReaderConfiguration(File dir,
this.keepBinary = keepBinary;
this.cacheGroupNames = cacheGroupNames;
this.skipCopies = skipCopies;
this.encSpi = encSpi;
}

/** @return Root dump directiory. */
Expand Down Expand Up @@ -137,4 +145,9 @@ public String[] cacheGroupNames() {
public boolean skipCopies() {
return skipCopies;
}

/** @return Encryption SPI */
public EncryptionSpi encryptionSpi() {
return encSpi;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,7 @@ private IgniteInternalFuture<SnapshotOperationResponse> initLocalFullSnapshot(
withMetaStorage,
req.dump(),
req.compress(),
req.encrypt(),
locSndrFactory.apply(req.snapshotName(), req.snapshotPath())
);

Expand All @@ -1218,6 +1219,10 @@ private IgniteInternalFuture<SnapshotOperationResponse> initLocalFullSnapshot(

SnapshotFutureTaskResult res = (SnapshotFutureTaskResult)task0.result();

Serializable encKey = req.encrypt() ? ((CreateDumpFutureTask)task0).encryptionKey() : null;

EncryptionSpi encSpi = cctx.gridConfig().getEncryptionSpi();

SnapshotMetadata meta = new SnapshotMetadata(req.requestId(),
req.snapshotName(),
cctx.localNode().consistentId().toString(),
Expand All @@ -1229,9 +1234,10 @@ private IgniteInternalFuture<SnapshotOperationResponse> initLocalFullSnapshot(
blts,
res.parts(),
res.snapshotPointer(),
cctx.gridConfig().getEncryptionSpi().masterKeyDigest(),
encSpi.masterKeyDigest(),
req.onlyPrimary(),
req.dump()
req.dump(),
encKey == null ? null : encSpi.encryptKey(encKey)
);

SnapshotHandlerContext ctx = new SnapshotHandlerContext(meta, req.groups(), cctx.localNode(), snpDir,
Expand Down Expand Up @@ -1808,7 +1814,7 @@ private boolean cancelLocalSnapshotTask0(Function<AbstractSnapshotFutureTask<?>,

/** {@inheritDoc} */
@Override public IgniteFuture<Void> createDump(String name, @Nullable Collection<String> cacheGroupNames) {
return createSnapshot(name, null, cacheGroupNames, false, false, true, false);
return createSnapshot(name, null, cacheGroupNames, false, false, true, false, false);
}

/**
Expand Down Expand Up @@ -2196,7 +2202,7 @@ public IgniteFutureImpl<Void> createSnapshot(
boolean incremental,
boolean onlyPrimary
) {
return createSnapshot(name, snpPath, null, incremental, onlyPrimary, false, false);
return createSnapshot(name, snpPath, null, incremental, onlyPrimary, false, false, false);
}

/**
Expand All @@ -2209,6 +2215,7 @@ public IgniteFutureImpl<Void> createSnapshot(
* @param onlyPrimary If {@code true} snapshot only primary copies of partitions.
* @param dump If {@code true} cache dump must be created.
* @param compress If {@code true} then compress partition files.
* @param encrypt If {@code true} then content of dump encrypted.
* @return Future which will be completed when a process ends.
*/
public IgniteFutureImpl<Void> createSnapshot(
Expand All @@ -2218,7 +2225,8 @@ public IgniteFutureImpl<Void> createSnapshot(
boolean incremental,
boolean onlyPrimary,
boolean dump,
boolean compress
boolean compress,
boolean encrypt
) {
A.notNullOrEmpty(name, "Snapshot name cannot be null or empty.");
A.ensure(U.alphanumericUnderscore(name), "Snapshot name must satisfy the following name pattern: a-zA-Z0-9_");
Expand Down Expand Up @@ -2250,11 +2258,17 @@ public IgniteFutureImpl<Void> createSnapshot(
return new IgniteSnapshotFutureImpl(cctx.kernalContext().closure()
.callAsync(
BALANCE,
new CreateSnapshotCallable(name, cacheGroupNames, incremental, onlyPrimary, dump, compress),
new CreateSnapshotCallable(name, cacheGroupNames, incremental, onlyPrimary, dump, compress, encrypt),
options(Collections.singletonList(crd)).withFailoverDisabled()
));
}

A.ensure(!encrypt || dump, "Encryption key is supported only for dumps");
A.ensure(
!encrypt || cctx.gridConfig().getEncryptionSpi() != null,
"Encryption SPI must be set to encrypt dump"
);

if (!CU.isPersistenceEnabled(cctx.gridConfig()) && !dump) {
throw new IgniteException("Create snapshot request has been rejected. " +
"Snapshots on an in-memory clusters are not allowed.");
Expand Down Expand Up @@ -2353,7 +2367,8 @@ else if (grps.isEmpty())
incIdx,
onlyPrimary,
dump,
compress
compress,
encrypt
));

String msg =
Expand Down Expand Up @@ -2733,6 +2748,7 @@ public GridCloseableIterator<CacheDataRow> partitionRowIterator(String snpName,
* @param withMetaStorage {@code true} if all metastorage data must be also included into snapshot.
* @param dump {@code true} if cache group dump must be created.
* @param compress If {@code true} then compress partition files.
* @param encrypt If {@code true} then content of dump encrypted.
* @param snpSndr Factory which produces snapshot receiver instance.
* @return Snapshot operation task which should be registered on checkpoint to run.
*/
Expand All @@ -2745,6 +2761,7 @@ AbstractSnapshotFutureTask<?> registerSnapshotTask(
boolean withMetaStorage,
boolean dump,
boolean compress,
boolean encrypt,
SnapshotSender snpSndr
) {
AbstractSnapshotFutureTask<?> task = registerTask(snpName, dump
Expand All @@ -2757,7 +2774,8 @@ AbstractSnapshotFutureTask<?> registerSnapshotTask(
transferRateLimiter,
snpSndr,
parts,
compress
compress,
encrypt
)
: new SnapshotFutureTask(cctx, srcNodeId, requestId, snpName, tmpWorkDir, ioFactory, snpSndr, parts, withMetaStorage, locBuff));

Expand Down Expand Up @@ -4681,6 +4699,9 @@ private static class CreateSnapshotCallable implements IgniteCallable<Void> {
/** If {@code true} then compress partition files. */
private final boolean comprParts;

/** If {@code true} then content of dump encrypted. */
private final boolean encrypt;

/** Auto-injected grid instance. */
@IgniteInstanceResource
private transient IgniteEx ignite;
Expand All @@ -4692,21 +4713,24 @@ private static class CreateSnapshotCallable implements IgniteCallable<Void> {
* @param onlyPrimary If {@code true} then only copy of primary partitions will be created.
* @param dump If {@code true} then cache dump must be created.
* @param comprParts If {@code true} then compress partition files.
* @param encrypt If {@code true} then content of dump encrypted.
*/
public CreateSnapshotCallable(
String snpName,
@Nullable Collection<String> cacheGroupNames,
boolean incremental,
boolean onlyPrimary,
boolean dump,
boolean comprParts
boolean comprParts,
boolean encrypt
) {
this.snpName = snpName;
this.cacheGroupNames = cacheGroupNames;
this.incremental = incremental;
this.onlyPrimary = onlyPrimary;
this.dump = dump;
this.comprParts = comprParts;
this.encrypt = encrypt;
}

/** {@inheritDoc} */
Expand All @@ -4721,7 +4745,8 @@ public CreateSnapshotCallable(
false,
onlyPrimary,
dump,
comprParts
comprParts,
encrypt
).get();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ public class SnapshotMetadata implements Serializable {
/** If {@code true} cache group dump stored. */
private boolean dump;

/** Encryption key. */
private @Nullable byte[] encKey;

/**
* @param rqId Unique request id.
* @param snpName Snapshot name.
Expand Down Expand Up @@ -139,7 +142,8 @@ public SnapshotMetadata(
@Nullable WALPointer snpRecPtr,
@Nullable byte[] masterKeyDigest,
boolean onlyPrimary,
boolean dump
boolean dump,
byte[] encKey
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nullable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

) {
this.rqId = rqId;
this.snpName = snpName;
Expand All @@ -153,6 +157,7 @@ public SnapshotMetadata(
this.masterKeyDigest = masterKeyDigest;
this.onlyPrimary = onlyPrimary;
this.dump = dump;
this.encKey = encKey;

if (!F.isEmpty(compGrpIds)) {
hasComprGrps = true;
Expand Down Expand Up @@ -332,6 +337,11 @@ public byte[] masterKeyDigest() {
return masterKeyDigest;
}

/** @return Encryption key. */
public byte[] encryptionKey() {
return encKey;
}

/**
* @param warnings Snapshot creation warnings.
*/
Expand Down Expand Up @@ -364,6 +374,7 @@ public List<String> warnings() {
Objects.equals(grpIds, meta.grpIds) &&
Objects.equals(bltNodes, meta.bltNodes) &&
Arrays.equals(masterKeyDigest, meta.masterKeyDigest) &&
Arrays.equals(encKey, meta.encKey) &&
Objects.equals(warnings, meta.warnings) &&
Objects.equals(hasComprGrps, meta.hasComprGrps) &&
Objects.equals(comprGrpIds, meta.comprGrpIds) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ public class SnapshotOperationRequest implements Serializable {
/** If {@code true} then compress partition files. */
private final boolean compress;

/** If {@code true} then content of dump encrypted. */
private final boolean encrypt;

/**
* @param reqId Request ID.
* @param opNodeId Operational node ID.
Expand All @@ -109,6 +112,7 @@ public class SnapshotOperationRequest implements Serializable {
* @param onlyPrimary If {@code true} snapshot only primary copies of partitions.
* @param dump If {@code true} then create dump.
* @param compress If {@code true} then compress partition files.
* @param encrypt If {@code true} then content of dump encrypted.
*/
public SnapshotOperationRequest(
UUID reqId,
Expand All @@ -121,7 +125,8 @@ public SnapshotOperationRequest(
int incIdx,
boolean onlyPrimary,
boolean dump,
boolean compress
boolean compress,
boolean encrypt
) {
this.reqId = reqId;
this.opNodeId = opNodeId;
Expand All @@ -134,6 +139,7 @@ public SnapshotOperationRequest(
this.onlyPrimary = onlyPrimary;
this.dump = dump;
this.compress = compress;
this.encrypt = encrypt;
startTime = U.currentTimeMillis();
}

Expand Down Expand Up @@ -218,6 +224,11 @@ public boolean compress() {
return compress;
}

/** @return If {@code true} then content of dump encrypted. */
public boolean encrypt() {
return encrypt;
}

/** @return Start time. */
public long startTime() {
return startTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.spi.encryption.EncryptionSpi;
import org.jetbrains.annotations.Nullable;

import static org.apache.ignite.internal.pagemem.PageIdAllocator.FLAG_DATA;
Expand Down Expand Up @@ -364,7 +365,9 @@ private Map<PartitionKeyV2, PartitionHashRecordV2> checkDumpFiles(
try {
String consistentId = cctx.kernalContext().pdsFolderResolver().resolveFolders().consistentId().toString();

try (Dump dump = new Dump(opCtx.snapshotDirectory(), consistentId, true, true, log)) {
EncryptionSpi encSpi = opCtx.metadata().encryptionKey() != null ? cctx.gridConfig().getEncryptionSpi() : null;

try (Dump dump = new Dump(opCtx.snapshotDirectory(), consistentId, true, true, encSpi, log)) {
Collection<PartitionHashRecordV2> partitionHashRecordV2s = U.doInParallel(
cctx.snapshotMgr().snapshotExecutorService(),
partFiles,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ public IgniteFutureImpl<Void> start(
incIdx,
onlyPrimary,
false,
false,
false
);

Expand Down
Loading