Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Use Lucene `pack` method for `half_float` and `usigned_long` when using `ApproximatePointRangeQuery`.
- Add a mapper for context aware segments grouping criteria ([#19233](https://github.com/opensearch-project/OpenSearch/pull/19233))
- Return full error for GRPC error response ([#19568](https://github.com/opensearch-project/OpenSearch/pull/19568))
- Add support for repository with Server side encryption enabled and client side encryption as well based on a flag. ([#19630)](https://github.com/opensearch-project/OpenSearch/pull/19630))
- Add pluggable gRPC interceptors with explicit ordering([#19005](https://github.com/opensearch-project/OpenSearch/pull/19005))

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ public boolean serverSideEncryptionBucketKey() {
* null as the S3 client ignores null header values
*/
public String serverSideEncryptionEncryptionContext() {
return serverSideEncryptionEncryptionContext.isEmpty()
return serverSideEncryptionEncryptionContext == null || serverSideEncryptionEncryptionContext.isEmpty()
? null
: Base64.getEncoder().encodeToString(serverSideEncryptionEncryptionContext.getBytes(StandardCharsets.UTF_8));
}
Expand All @@ -239,7 +239,7 @@ public String serverSideEncryptionEncryptionContext() {
* Returns the expected bucket owner if set, else null as the S3 client ignores null header values
*/
public String expectedBucketOwner() {
return expectedBucketOwner.isEmpty() ? null : expectedBucketOwner;
return expectedBucketOwner == null || expectedBucketOwner.isEmpty() ? null : expectedBucketOwner;
}

public long bufferSizeInBytes() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,62 @@ protected S3BlobStore createBlobStore() {
);
}

@Override
protected S3BlobStore createClientSideEncryptedBlobStore() {
serverSideEncryptionType = ServerSideEncryption.AES256.toString();
return new S3BlobStore(
service,
s3AsyncService,
multipartUploadEnabled,
bucket,
bufferSize,
cannedACL,
storageClass,
bulkDeletesSize,
metadata,
asyncUploadUtils,
urgentExecutorBuilder,
priorityExecutorBuilder,
normalExecutorBuilder,
normalPrioritySizeBasedBlockingQ,
lowPrioritySizeBasedBlockingQ,
genericStatsMetricPublisher,
serverSideEncryptionType,
null,
false,
null,
""
);
}

@Override
protected S3BlobStore createServerSideEncryptedBlobStore() {
serverSideEncryptionType = ServerSideEncryption.AWS_KMS.toString();
return new S3BlobStore(
service,
s3AsyncService,
multipartUploadEnabled,
bucket,
bufferSize,
cannedACL,
storageClass,
bulkDeletesSize,
metadata,
asyncUploadUtils,
urgentExecutorBuilder,
priorityExecutorBuilder,
normalExecutorBuilder,
normalPrioritySizeBasedBlockingQ,
lowPrioritySizeBasedBlockingQ,
genericStatsMetricPublisher,
serverSideEncryptionType,
serverSideEncryptionKmsKey,
serverSideEncryptionBucketKey,
serverSideEncryptionEncryptionContext,
expectedBucketOwner
);
}

// only use for testing (S3RepositoryTests)
@Override
protected BlobStore getBlobStore() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,9 @@ private Map<String, Map<String, Object>> getSegmentMetadata(
IndexMetadata.INDEX_REMOTE_SEGMENT_STORE_REPOSITORY_SETTING.get(indexMetadata.getSettings()),
index.getUUID(),
shardId,
indexSettings.getRemoteStorePathStrategy()
indexSettings.getRemoteStorePathStrategy(),
null,
indexSettings.isServerSideEncryptionEnabled()
);

Map<String, RemoteSegmentMetadata> segmentMetadataMapWithFilenames = remoteDirectory.readLatestNMetadataFiles(5);
Expand Down Expand Up @@ -257,7 +259,8 @@ private Map<String, Map<String, Object>> getTranslogMetadataFiles(
tracker,
indexSettings.getRemoteStorePathStrategy(),
new RemoteStoreSettings(clusterService.getSettings(), clusterService.getClusterSettings()),
RemoteStoreUtils.determineTranslogMetadataEnabled(indexMetadata)
RemoteStoreUtils.determineTranslogMetadataEnabled(indexMetadata),
indexSettings.isServerSideEncryptionEnabled()
);

Map<String, TranslogTransferMetadata> metadataMap = manager.readLatestNMetadataFiles(5);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ public Iterator<Setting<?>> settings() {
);

public static final String SETTING_REMOTE_STORE_ENABLED = "index.remote_store.enabled";
public static final String SETTING_REMOTE_STORE_SSE_ENABLED = "index.remote_store.sse.enabled";
public static final String SETTING_INDEX_APPEND_ONLY_ENABLED = "index.append_only.enabled";

public static final String SETTING_REMOTE_SEGMENT_STORE_REPOSITORY = "index.remote_store.segment.repository";
Expand Down Expand Up @@ -414,6 +415,38 @@ public Iterator<Setting<?>> settings() {
Property.Dynamic
);

/**
* Used to specify if the index data should be persisted in the remote store.
*/
public static final Setting<Boolean> INDEX_REMOTE_STORE_SSE_ENABLED_SETTING = Setting.boolSetting(
SETTING_REMOTE_STORE_SSE_ENABLED,
false,
new Setting.Validator<>() {

@Override
public void validate(final Boolean value) {}

@Override
public void validate(final Boolean value, final Map<Setting<?>, Object> settings) {
final Boolean isRemoteStoreEnabled = (Boolean) settings.get(INDEX_REMOTE_STORE_ENABLED_SETTING);
if (!isRemoteStoreEnabled && value) {
throw new IllegalArgumentException(
"Server Side Encryption can be enabled when " + INDEX_REMOTE_STORE_ENABLED_SETTING.getKey() + " is enabled. "
);
}
}

@Override
public Iterator<Setting<?>> settings() {
final List<Setting<?>> settings = List.of(INDEX_REMOTE_STORE_ENABLED_SETTING);
return settings.iterator();
}
},
Property.IndexScope,
Property.PrivateIndex,
Property.Dynamic
);

/**
* Used to specify if the index data should be persisted in the remote store.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1056,7 +1056,7 @@ static Settings aggregateIndexSettings(
indexSettingsBuilder.put(SETTING_INDEX_UUID, UUIDs.randomBase64UUID());

updateReplicationStrategy(indexSettingsBuilder, request.settings(), settings, combinedTemplateSettings, clusterSettings);
updateRemoteStoreSettings(indexSettingsBuilder, currentState, clusterSettings, settings, request.index());
updateRemoteStoreSettings(indexSettingsBuilder, currentState, clusterSettings, settings, request.index(), false);

if (sourceMetadata != null) {
assert request.resizeType() != null;
Expand Down Expand Up @@ -1162,7 +1162,8 @@ public static void updateRemoteStoreSettings(
ClusterState clusterState,
ClusterSettings clusterSettings,
Settings nodeSettings,
String indexName
String indexName,
boolean isRestoreFromSnapshot
) {
if ((isRemoteDataAttributePresent(nodeSettings)
&& clusterSettings.get(REMOTE_STORE_COMPATIBILITY_MODE_SETTING).equals(RemoteStoreNodeService.CompatibilityMode.STRICT))
Expand All @@ -1177,6 +1178,12 @@ public static void updateRemoteStoreSettings(
.findFirst();

if (remoteNode.isPresent()) {

if (!isRestoreFromSnapshot
&& RemoteStoreNodeAttribute.isRemoteStoreServerSideEncryptionEnabled(remoteNode.get().getAttributes())) {
settingsBuilder.put(IndexMetadata.SETTING_REMOTE_STORE_SSE_ENABLED, true);
}

translogRepo = RemoteStoreNodeAttribute.getTranslogRepoName(remoteNode.get().getAttributes());
segmentRepo = RemoteStoreNodeAttribute.getSegmentRepoName(remoteNode.get().getAttributes());
if (segmentRepo != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ public final class IndexScopedSettings extends AbstractScopedSettings {

// Settings for remote store enablement
IndexMetadata.INDEX_REMOTE_STORE_ENABLED_SETTING,
IndexMetadata.INDEX_REMOTE_STORE_SSE_ENABLED_SETTING,
IndexMetadata.INDEX_REMOTE_SEGMENT_STORE_REPOSITORY_SETTING,
IndexMetadata.INDEX_REMOTE_TRANSLOG_REPOSITORY_SETTING,

Expand Down
5 changes: 3 additions & 2 deletions server/src/main/java/org/opensearch/index/IndexService.java
Original file line number Diff line number Diff line change
Expand Up @@ -697,11 +697,12 @@ public synchronized IndexShard createShard(
}

remoteDirectory = ((RemoteSegmentStoreDirectoryFactory) remoteDirectoryFactory).newDirectory(
RemoteStoreNodeAttribute.getRemoteStoreSegmentRepo(this.indexSettings.getNodeSettings()),
RemoteStoreNodeAttribute.getRemoteStoreSegmentRepo(this.indexSettings.getSettings()),
this.indexSettings.getUUID(),
shardId,
this.indexSettings.getRemoteStorePathStrategy(),
this.indexSettings.getRemoteStoreSegmentPathPrefix()
this.indexSettings.getRemoteStoreSegmentPathPrefix(),
this.indexSettings.isServerSideEncryptionEnabled()
);
}
// When an instance of Store is created, a shardlock is created which is released on closing the instance of store.
Expand Down
21 changes: 20 additions & 1 deletion server/src/main/java/org/opensearch/index/IndexSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,8 @@ private void setRetentionLeaseMillis(final TimeValue retentionLease) {
*/
private final boolean isCompositeIndex;

private boolean isServerSideEncryptionEnabled;

/**
* Denotes whether search via star tree index is enabled for this index
*/
Expand Down Expand Up @@ -1035,7 +1037,7 @@ public IndexSettings(final IndexMetadata indexMetadata, final Settings nodeSetti
numberOfShards = settings.getAsInt(IndexMetadata.SETTING_NUMBER_OF_SHARDS, null);
replicationType = IndexMetadata.INDEX_REPLICATION_TYPE_SETTING.get(settings);
isRemoteStoreEnabled = settings.getAsBoolean(IndexMetadata.SETTING_REMOTE_STORE_ENABLED, false);

isServerSideEncryptionEnabled = settings.getAsBoolean(IndexMetadata.SETTING_REMOTE_STORE_SSE_ENABLED, false);
isWarmIndex = settings.getAsBoolean(IndexModule.IS_WARM_INDEX_SETTING.getKey(), false);

remoteStoreTranslogRepository = settings.get(IndexMetadata.SETTING_REMOTE_TRANSLOG_STORE_REPOSITORY);
Expand Down Expand Up @@ -1243,6 +1245,12 @@ public IndexSettings(final IndexMetadata indexMetadata, final Settings nodeSetti
);
scopedSettings.addSettingsUpdateConsumer(ALLOW_DERIVED_FIELDS, this::setAllowDerivedField);
scopedSettings.addSettingsUpdateConsumer(IndexMetadata.INDEX_REMOTE_STORE_ENABLED_SETTING, this::setRemoteStoreEnabled);

scopedSettings.addSettingsUpdateConsumer(
IndexMetadata.INDEX_REMOTE_STORE_SSE_ENABLED_SETTING,
this::setServerSideEncryptionEnabled
);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not a dynamic setting , hence we don't need it .

Looks like Index's custom metadata is the right place for it .


scopedSettings.addSettingsUpdateConsumer(
IndexMetadata.INDEX_REMOTE_SEGMENT_STORE_REPOSITORY_SETTING,
this::setRemoteStoreRepository
Expand Down Expand Up @@ -1431,6 +1439,13 @@ public boolean isRemoteStoreEnabled() {
return isRemoteStoreEnabled;
}

/**
* Returns if remote store SSE is enabled for this index.
*/
public boolean isServerSideEncryptionEnabled() {
return isServerSideEncryptionEnabled;
}

public boolean isAssignedOnRemoteNode() {
return assignedOnRemoteNode;
}
Expand Down Expand Up @@ -2141,6 +2156,10 @@ public void setRemoteStoreEnabled(boolean isRemoteStoreEnabled) {
this.isRemoteStoreEnabled = isRemoteStoreEnabled;
}

public void setServerSideEncryptionEnabled(boolean sseEnabled) {
this.isServerSideEncryptionEnabled = sseEnabled;
}

public void setRemoteStoreRepository(String remoteStoreRepository) {
this.remoteStoreRepository = remoteStoreRepository;
}
Expand Down
27 changes: 24 additions & 3 deletions server/src/main/java/org/opensearch/index/shard/IndexShard.java
Original file line number Diff line number Diff line change
Expand Up @@ -5289,7 +5289,8 @@ public void deleteTranslogFilesFromRemoteTranslog() throws IOException {
getThreadPool(),
indexSettings.getRemoteStorePathStrategy(),
remoteStoreSettings,
indexSettings().isTranslogMetadataEnabled()
indexSettings().isTranslogMetadataEnabled(),
indexSettings.isServerSideEncryptionEnabled()
);
}

Expand All @@ -5312,7 +5313,8 @@ public void syncTranslogFilesFromRemoteTranslog() throws IOException {
shardId,
indexSettings.getRemoteStorePathStrategy(),
indexSettings().isTranslogMetadataEnabled(),
0
0,
indexSettings.isServerSideEncryptionEnabled()
);
}

Expand All @@ -5322,6 +5324,24 @@ public void syncTranslogFilesFromGivenRemoteTranslog(
RemoteStorePathStrategy remoteStorePathStrategy,
boolean isTranslogMetadataEnabled,
long timestamp
) throws IOException {
this.syncTranslogFilesFromGivenRemoteTranslog(
repository,
shardId,
remoteStorePathStrategy,
isTranslogMetadataEnabled,
timestamp,
false
);
}

public void syncTranslogFilesFromGivenRemoteTranslog(
Repository repository,
ShardId shardId,
RemoteStorePathStrategy remoteStorePathStrategy,
boolean isTranslogMetadataEnabled,
long timestamp,
boolean isServerSideEncryptionEnabled
) throws IOException {
RemoteFsTranslog.download(
repository,
Expand All @@ -5333,7 +5353,8 @@ public void syncTranslogFilesFromGivenRemoteTranslog(
logger,
shouldSeedRemoteStore(),
isTranslogMetadataEnabled,
timestamp
timestamp,
isServerSideEncryptionEnabled
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import org.opensearch.core.common.unit.ByteSizeValue;
import org.opensearch.core.index.Index;
import org.opensearch.core.index.shard.ShardId;
import org.opensearch.index.IndexSettings;
import org.opensearch.index.engine.Engine;
import org.opensearch.index.engine.EngineException;
import org.opensearch.index.mapper.MapperService;
Expand Down Expand Up @@ -422,7 +423,9 @@ void recoverFromSnapshotAndRemoteStore(
remoteStoreRepository,
indexUUID,
shardId,
shallowCopyShardMetadata.getRemoteStorePathStrategy()
shallowCopyShardMetadata.getRemoteStorePathStrategy(),
null,
indexShard.indexSettings.isServerSideEncryptionEnabled()
);
RemoteSegmentMetadata remoteSegmentMetadata = sourceRemoteDirectory.initializeToSpecificCommit(
primaryTerm,
Expand Down Expand Up @@ -498,12 +501,15 @@ void recoverShallowSnapshotV2(
prevIndexMetadata.getSettings()
);
}
IndexSettings indexSettings = new IndexSettings(prevIndexMetadata, prevIndexMetadata.getSettings());
RemoteStorePathStrategy remoteStorePathStrategy = RemoteStoreUtils.determineRemoteStorePathStrategy(prevIndexMetadata);
RemoteSegmentStoreDirectory sourceRemoteDirectory = (RemoteSegmentStoreDirectory) directoryFactory.newDirectory(
remoteSegmentStoreRepository,
prevIndexMetadata.getIndexUUID(),
shardId,
remoteStorePathStrategy
remoteStorePathStrategy,
null,
indexSettings.isServerSideEncryptionEnabled()
);
RemoteSegmentMetadata remoteSegmentMetadata = sourceRemoteDirectory.initializeToSpecificTimestamp(
recoverySource.pinnedTimestamp()
Expand All @@ -523,7 +529,8 @@ void recoverShallowSnapshotV2(
new ShardId(prevIndexMetadata.getIndex(), shardId.id()),
remoteStorePathStrategy,
RemoteStoreUtils.determineTranslogMetadataEnabled(prevIndexMetadata),
recoverySource.pinnedTimestamp()
recoverySource.pinnedTimestamp(),
indexSettings.isServerSideEncryptionEnabled()
);

assert indexShard.shardRouting.primary() : "only primary shards can recover from store";
Expand Down
Loading
Loading