-
Notifications
You must be signed in to change notification settings - Fork 24.9k
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
Encrypted blob store repository #50846
Changes from 155 commits
92a3b34
d07c05f
de603a7
7cc62e0
cbd3c50
9eb9bcf
5919a11
47f6aea
8263062
cf97ba2
3c82ba9
76d8271
6b30902
4e9778e
24d6d27
3cd79bd
c610fe8
e4f8564
c816c45
29c484b
db5f58e
d6dc875
7cb48f6
83e028b
26a624f
aeb6698
2939289
76678a6
f44b97c
016164a
5b26ff6
bae9a8d
80a079b
0a4cc77
a0751c6
92e177f
5d9321a
c231486
bda96b6
cb6006d
fad9eb4
65f0adb
b40d999
cb7bc1c
7acaf54
dfeea83
da29e2f
8c465be
bed1e51
5e7269b
14ee4aa
7ee63c0
74f38b2
fee2d79
eda1fe0
e85aefe
8a0773a
07d7ac8
fd10914
2e41d4f
97f5917
4fd6dcc
3d1daf4
4fcd49d
9ef136e
cb966b2
0f9f77c
5924356
3cf85b4
151b248
7d1b3cc
31a2b30
591e48c
1ee490a
5a1eee5
e51a304
1087294
b788e98
4e204a3
3248163
f1406ff
78c1984
2565d6e
2c40aad
db374fb
f73b54c
36062db
677bbb7
d2133e0
6353f7a
a26b2b9
948b3c6
83c0e44
da10d0a
0a14765
6d562fc
bceda55
eeac0b5
29fa2aa
bb33045
0308140
d7e400c
8751c7d
90bcaab
57ab5ad
5d9d4c1
03a58ed
3ee957d
82e8a89
b994d28
2e14453
19fe147
4aaf895
8a9fe5d
80e536c
60c4ad9
7953174
9f7f4b4
19a7828
63c6855
b593d66
30d4f58
1745345
68b9235
74c3d58
1889aba
3d82aa4
b085c12
901b04a
0ba402a
0d7077d
1b0d732
6cf5812
9e8001b
7ffaefb
950686f
710ef33
b88ec6d
426bd05
6936339
10e84d3
94b3847
6708354
12a074b
a8c931c
ffe0b63
28dd9e1
b9ba309
ef4c860
40fa0eb
b7e140c
fe505e5
8e036f0
262b3e9
a7e2dac
62c1566
83031ae
d81d20a
856cfe3
bcc42df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* | ||
* Licensed to Elasticsearch under one or more contributor | ||
* license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright | ||
* ownership. Elasticsearch licenses this file to you under | ||
* the Apache License, Version 2.0 (the "License"); you may | ||
* not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
package org.elasticsearch.repositories.azure; | ||
|
||
import org.elasticsearch.common.blobstore.BlobMetaData; | ||
import org.elasticsearch.common.settings.MockSecureSettings; | ||
import org.elasticsearch.common.settings.Settings; | ||
import org.elasticsearch.common.unit.ByteSizeUnit; | ||
import org.elasticsearch.common.unit.ByteSizeValue; | ||
import org.elasticsearch.license.License; | ||
import org.elasticsearch.license.LicenseService; | ||
import org.elasticsearch.plugins.Plugin; | ||
import org.elasticsearch.repositories.blobstore.BlobStoreRepository; | ||
import org.elasticsearch.repositories.encrypted.DecryptionPacketsInputStream; | ||
import org.elasticsearch.repositories.encrypted.EncryptedRepository; | ||
import org.elasticsearch.repositories.encrypted.EncryptedRepositoryPlugin; | ||
import org.elasticsearch.repositories.encrypted.LocalStateEncryptedRepositoryPlugin; | ||
import org.elasticsearch.test.ESTestCase; | ||
import org.junit.BeforeClass; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
public class EncryptedAzureBlobStoreRepositoryIntegTests extends AzureBlobStoreRepositoryTests { | ||
|
||
private static List<String> repositoryNames; | ||
|
||
@BeforeClass | ||
private static void preGenerateRepositoryNames() { | ||
List<String> names = new ArrayList<>(); | ||
for (int i = 0; i < 32; i++) { | ||
names.add("test-repo-" + i); | ||
} | ||
repositoryNames = Collections.synchronizedList(names); | ||
} | ||
|
||
@Override | ||
protected Settings nodeSettings(int nodeOrdinal) { | ||
return Settings.builder() | ||
.put(super.nodeSettings(nodeOrdinal)) | ||
.put(LicenseService.SELF_GENERATED_LICENSE_TYPE.getKey(), License.LicenseType.TRIAL.getTypeName()) | ||
.build(); | ||
} | ||
|
||
@Override | ||
protected MockSecureSettings nodeSecureSettings(int nodeOrdinal) { | ||
MockSecureSettings secureSettings = super.nodeSecureSettings(nodeOrdinal); | ||
for (String repositoryName : repositoryNames) { | ||
secureSettings.setString(EncryptedRepositoryPlugin.ENCRYPTION_PASSWORD_SETTING. | ||
getConcreteSettingForNamespace(repositoryName).getKey(), "password" + repositoryName); | ||
} | ||
return secureSettings; | ||
} | ||
|
||
@Override | ||
protected String randomRepositoryName() { | ||
return repositoryNames.remove(randomIntBetween(0, repositoryNames.size() - 1)); | ||
} | ||
|
||
protected long blobLengthFromDiskLength(BlobMetaData blobMetaData) { | ||
if (BlobStoreRepository.INDEX_LATEST_BLOB.equals(blobMetaData.name())) { | ||
// index.latest is not encrypted, hence the size on disk is equal to the content | ||
return blobMetaData.length(); | ||
} else { | ||
return DecryptionPacketsInputStream.getDecryptionLength(blobMetaData.length() - | ||
EncryptedRepository.MetadataIdentifier.byteLength(), EncryptedRepository.PACKET_LENGTH_IN_BYTES); | ||
} | ||
} | ||
|
||
@Override | ||
protected Collection<Class<? extends Plugin>> nodePlugins() { | ||
return Arrays.asList(LocalStateEncryptedRepositoryPlugin.class, TestAzureRepositoryPlugin.class); | ||
} | ||
|
||
@Override | ||
protected String repositoryType() { | ||
return EncryptedRepositoryPlugin.REPOSITORY_TYPE_NAME; | ||
} | ||
|
||
@Override | ||
protected Settings repositorySettings() { | ||
final Settings.Builder settings = Settings.builder(); | ||
settings.put(super.repositorySettings()); | ||
settings.put(EncryptedRepositoryPlugin.DELEGATE_TYPE.getKey(), AzureRepository.TYPE); | ||
if (ESTestCase.randomBoolean()) { | ||
long size = 1 << ESTestCase.randomInt(10); | ||
settings.put("chunk_size", new ByteSizeValue(size, ByteSizeUnit.KB)); | ||
} | ||
return settings.build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,8 @@ dependencies { | |
compile 'com.google.apis:google-api-services-storage:v1-rev20190426-1.28.0' | ||
|
||
testCompile project(':test:fixtures:gcs-fixture') | ||
// required by the test for the encrypted GCS repository | ||
testCompile project(path: ':x-pack:plugin:repository-encrypted', configuration: 'testArtifacts') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not the right person to judge this but this pattern in the build seems troubling to me. We are using non-Apache licensed code in the tests of Apache licensed code now. Is that ok? Maybe it's better to run these tests in a separate module downstream? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we discussed this synchronously, and also the tests requiring this might not be relevant anymore, but I'm presenting my counter for posterity I see your point, and I didn't look at it like this. I had minor qualms about having tests for non-Apache licensed code as Apache licensed. The fact that we pull non-Apache test artifacts is a slightly different point. When I went on this path, I worried that the reverse alternative (having the encrypted repo depend in tests on the cloud repository) would entail more project setup boilerplate code. I'm not so sure about it right now, and I think it is beneficial if we keep these tests inside the encrypted-repo module, for subjective reasons of code organization. |
||
} | ||
|
||
dependencyLicenses { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
/* | ||
* Licensed to Elasticsearch under one or more contributor | ||
* license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright | ||
* ownership. Elasticsearch licenses this file to you under | ||
* the Apache License, Version 2.0 (the "License"); you may | ||
* not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
package org.elasticsearch.repositories.gcs; | ||
|
||
import org.elasticsearch.action.admin.cluster.repositories.cleanup.CleanupRepositoryResponse; | ||
import org.elasticsearch.action.support.master.AcknowledgedResponse; | ||
import org.elasticsearch.common.blobstore.BlobMetaData; | ||
import org.elasticsearch.common.blobstore.BlobPath; | ||
import org.elasticsearch.common.settings.MockSecureSettings; | ||
import org.elasticsearch.common.settings.SecureSettings; | ||
import org.elasticsearch.common.settings.Settings; | ||
import org.elasticsearch.plugins.Plugin; | ||
import org.elasticsearch.repositories.encrypted.EncryptedRepository; | ||
import org.elasticsearch.repositories.encrypted.EncryptedRepositoryPlugin; | ||
import org.elasticsearch.xpack.core.XPackPlugin; | ||
|
||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import static org.hamcrest.Matchers.equalTo; | ||
|
||
public class EncryptedGoogleCloudStorageThirdPartyTests extends GoogleCloudStorageThirdPartyTests { | ||
|
||
@Override | ||
protected Collection<Class<? extends Plugin>> getPlugins() { | ||
return pluginList(XPackPlugin.class, EncryptedRepositoryPlugin.class, GoogleCloudStoragePlugin.class); | ||
} | ||
|
||
@Override | ||
protected Settings nodeSettings() { | ||
return Settings.builder() | ||
.put(super.nodeSettings()) | ||
.put("xpack.license.self_generated.type", "trial") | ||
.build(); | ||
} | ||
|
||
@Override | ||
protected SecureSettings credentials() { | ||
MockSecureSettings secureSettings = (MockSecureSettings) super.credentials(); | ||
secureSettings.setString(EncryptedRepositoryPlugin.ENCRYPTION_PASSWORD_SETTING. | ||
getConcreteSettingForNamespace("test-encrypted-repo").getKey(), "password-test-repo"); | ||
return secureSettings; | ||
} | ||
|
||
@Override | ||
protected void createRepository(final String repoName) { | ||
AcknowledgedResponse putRepositoryResponse = client().admin().cluster() | ||
.preparePutRepository("test-encrypted-repo") | ||
.setType("encrypted") | ||
.setSettings(Settings.builder() | ||
.put("delegate_type", "gcs") | ||
.put("bucket", System.getProperty("test.google.bucket")) | ||
.put("base_path", System.getProperty("test.google.base", "") | ||
+ "/" + EncryptedGoogleCloudStorageThirdPartyTests.class.getName() ) | ||
).get(); | ||
assertThat(putRepositoryResponse.isAcknowledged(), equalTo(true)); | ||
} | ||
|
||
@Override | ||
protected void assertCleanupResponse(CleanupRepositoryResponse response, long bytes, long blobs) { | ||
// TODO cleanup of root blobs does not count the encryption metadata blobs, but the cleanup of blob containers ("indices" folder) | ||
// does count them; ideally there should be consistency, one way or the other | ||
assertThat(response.result().blobs(), equalTo(1L + 2L + 1L /* one metadata blob */)); | ||
// the cleanup stats of the encrypted repository currently includes only some of the metadata blobs (as per above), which are | ||
// themselves cumbersome to size; but the bytes count is stable | ||
assertThat(response.result().bytes(), equalTo(244L)); | ||
} | ||
|
||
@Override | ||
protected void assertBlobsByPrefix(BlobPath path, String prefix, Map<String, BlobMetaData> blobs) throws Exception { | ||
// blobs are larger after encryption | ||
Map<String, BlobMetaData> blobsWithSizeAfterEncryption = new HashMap<>(); | ||
blobs.forEach((name, meta) -> { | ||
blobsWithSizeAfterEncryption.put(name, new BlobMetaData() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: Probably shorter to just do:
here :) |
||
@Override | ||
public String name() { | ||
return meta.name(); | ||
} | ||
|
||
@Override | ||
public long length() { | ||
return EncryptedRepository.getEncryptedBlobByteLength(meta.length()); | ||
} | ||
}); | ||
}); | ||
super.assertBlobsByPrefix(path, prefix, blobsWithSizeAfterEncryption); | ||
} | ||
|
||
@Override | ||
protected String getTestRepoName() { | ||
return "test-encrypted-repo"; | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doe this list have to be
synchronized
? No right?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does, because the test methods in the class can run in parallel and there should not be two tests that use the same repository.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nah I don't think we can have two test methods from the same class run concurrently in the same JVM. How would that work with the single static reference to the internal node/cluster and its cleanup after every test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, I don't know what made me believe otherwise.