GCS Repository: Add secure storage of credentials (#24697)
This commit adds gcs credential settings to the elasticsearch keystore. The setting name follows the same pattern as the s3 client settings, beginning with `gcs.client.`, followed by the client name, and then the setting name, in this case, `credentials_file`. Using the legacy service file setting is also deprecated.
This commit is contained in:
parent
f80799acc2
commit
d74760c306
|
@ -41,34 +41,19 @@ The bucket should now be created.
|
|||
|
||||
The plugin supports two authentication modes:
|
||||
|
||||
* the built-in <<repository-gcs-using-compute-engine, Compute Engine authentication>>. This mode is
|
||||
* The built-in <<repository-gcs-using-compute-engine, Compute Engine authentication>>. This mode is
|
||||
recommended if your elasticsearch node is running on a Compute Engine virtual machine.
|
||||
|
||||
* the <<repository-gcs-using-service-account, Service Account>> authentication mode.
|
||||
* Specifying <<repository-gcs-using-service-account, Service Account>> credentials.
|
||||
|
||||
[[repository-gcs-using-compute-engine]]
|
||||
===== Using Compute Engine
|
||||
When running on Compute Engine, the plugin use the Google's built-in authentication mechanism to
|
||||
When running on Compute Engine, the plugin use Google's built-in authentication mechanism to
|
||||
authenticate on the Storage service. Compute Engine virtual machines are usually associated to a
|
||||
default service account. This service account can be found in the VM instance details in the
|
||||
https://console.cloud.google.com/compute/[Compute Engine console].
|
||||
|
||||
To indicate that a repository should use the built-in authentication,
|
||||
the repository `service_account` setting must be set to `_default_`:
|
||||
|
||||
[source,js]
|
||||
----
|
||||
PUT _snapshot/my_gcs_repository_on_compute_engine
|
||||
{
|
||||
"type": "gcs",
|
||||
"settings": {
|
||||
"bucket": "my_bucket",
|
||||
"service_account": "_default_"
|
||||
}
|
||||
}
|
||||
----
|
||||
// CONSOLE
|
||||
// TEST[skip:we don't have gcs setup while testing this]
|
||||
This is the default authentication mode and requires no configuration.
|
||||
|
||||
NOTE: The Compute Engine VM must be allowed to use the Storage service. This can be done only at VM
|
||||
creation time, when "Storage" access can be configured to "Read/Write" permission. Check your
|
||||
|
@ -76,7 +61,7 @@ instance details at the section "Cloud API access scopes".
|
|||
|
||||
[[repository-gcs-using-service-account]]
|
||||
===== Using a Service Account
|
||||
If your elasticsearch node is not running on Compute Engine, or if you don't want to use Google
|
||||
If your elasticsearch node is not running on Compute Engine, or if you don't want to use Google's
|
||||
built-in authentication mechanism, you can authenticate on the Storage service using a
|
||||
https://cloud.google.com/iam/docs/overview#service_account[Service Account] file.
|
||||
|
||||
|
@ -107,10 +92,14 @@ A service account file looks like this:
|
|||
----
|
||||
// NOTCONSOLE
|
||||
|
||||
This file must be copied in the `config` directory of the elasticsearch installation and on
|
||||
every node of the cluster.
|
||||
This file must be stored in the <<secure-settings, elasticsearch keystore>>, under a setting name
|
||||
of the form `gcs.client.NAME.credentials_file`, where `NAME` is the name of the client congiguration.
|
||||
The default client name is `default`, but a different client name can be specified in repository
|
||||
settings using `client`.
|
||||
|
||||
To indicate that a repository should use a service account file:
|
||||
For example, if specifying the credentials file in the keystore under
|
||||
`gcs.client.my_alternate_client.credentials_file`, you can configure a repository to use these
|
||||
credentials like this:
|
||||
|
||||
[source,js]
|
||||
----
|
||||
|
@ -119,7 +108,7 @@ PUT _snapshot/my_gcs_repository
|
|||
"type": "gcs",
|
||||
"settings": {
|
||||
"bucket": "my_bucket",
|
||||
"service_account": "service_account.json"
|
||||
"client": "my_alternate_client"
|
||||
}
|
||||
}
|
||||
----
|
||||
|
@ -150,8 +139,7 @@ PUT _snapshot/my_gcs_repository
|
|||
{
|
||||
"type": "gcs",
|
||||
"settings": {
|
||||
"bucket": "my_bucket",
|
||||
"service_account": "service_account.json"
|
||||
"bucket": "my_bucket"
|
||||
}
|
||||
}
|
||||
----
|
||||
|
@ -164,10 +152,10 @@ The following settings are supported:
|
|||
|
||||
The name of the bucket to be used for snapshots. (Mandatory)
|
||||
|
||||
`service_account`::
|
||||
`client`::
|
||||
|
||||
The service account to use. It can be a relative path to a service account JSON file
|
||||
or the value `_default_` that indicate to use built-in Compute Engine service account.
|
||||
The client congfiguration to use. This controls which credentials are used to connect
|
||||
to Compute Engine.
|
||||
|
||||
`base_path`::
|
||||
|
||||
|
|
|
@ -22,10 +22,12 @@ package org.elasticsearch.repositories.gcs;
|
|||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.api.client.auth.oauth2.TokenRequest;
|
||||
import com.google.api.client.auth.oauth2.TokenResponse;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
||||
import com.google.api.client.googleapis.json.GoogleJsonError;
|
||||
import com.google.api.client.http.GenericUrl;
|
||||
import com.google.api.client.http.HttpHeaders;
|
||||
|
@ -39,6 +41,8 @@ import com.google.api.services.storage.model.Bucket;
|
|||
import com.google.api.services.storage.model.Objects;
|
||||
import com.google.api.services.storage.model.StorageObject;
|
||||
import org.elasticsearch.SpecialPermission;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
|
@ -108,9 +112,15 @@ public class GoogleCloudStoragePlugin extends Plugin implements RepositoryPlugin
|
|||
});
|
||||
}
|
||||
|
||||
private final Map<String, GoogleCredential> credentials;
|
||||
|
||||
public GoogleCloudStoragePlugin(Settings settings) {
|
||||
credentials = GoogleCloudStorageService.loadClientCredentials(settings);
|
||||
}
|
||||
|
||||
// overridable for tests
|
||||
protected GoogleCloudStorageService createStorageService(Environment environment) {
|
||||
return new GoogleCloudStorageService.InternalGoogleCloudStorageService(environment);
|
||||
return new GoogleCloudStorageService.InternalGoogleCloudStorageService(environment, credentials);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,4 +128,9 @@ public class GoogleCloudStoragePlugin extends Plugin implements RepositoryPlugin
|
|||
return Collections.singletonMap(GoogleCloudStorageRepository.TYPE,
|
||||
(metadata) -> new GoogleCloudStorageRepository(metadata, env, namedXContentRegistry, createStorageService(env)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Setting<?>> getSettings() {
|
||||
return Collections.singletonList(GoogleCloudStorageService.CREDENTIALS_FILE_SETTING);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,25 +48,26 @@ class GoogleCloudStorageRepository extends BlobStoreRepository {
|
|||
static final ByteSizeValue MIN_CHUNK_SIZE = new ByteSizeValue(1, ByteSizeUnit.BYTES);
|
||||
static final ByteSizeValue MAX_CHUNK_SIZE = new ByteSizeValue(100, ByteSizeUnit.MB);
|
||||
|
||||
public static final String TYPE = "gcs";
|
||||
static final String TYPE = "gcs";
|
||||
|
||||
public static final TimeValue NO_TIMEOUT = timeValueMillis(-1);
|
||||
static final TimeValue NO_TIMEOUT = timeValueMillis(-1);
|
||||
|
||||
public static final Setting<String> BUCKET =
|
||||
static final Setting<String> BUCKET =
|
||||
simpleString("bucket", Property.NodeScope, Property.Dynamic);
|
||||
public static final Setting<String> BASE_PATH =
|
||||
static final Setting<String> BASE_PATH =
|
||||
simpleString("base_path", Property.NodeScope, Property.Dynamic);
|
||||
public static final Setting<Boolean> COMPRESS =
|
||||
static final Setting<Boolean> COMPRESS =
|
||||
boolSetting("compress", false, Property.NodeScope, Property.Dynamic);
|
||||
public static final Setting<ByteSizeValue> CHUNK_SIZE =
|
||||
static final Setting<ByteSizeValue> CHUNK_SIZE =
|
||||
byteSizeSetting("chunk_size", MAX_CHUNK_SIZE, MIN_CHUNK_SIZE, MAX_CHUNK_SIZE, Property.NodeScope, Property.Dynamic);
|
||||
public static final Setting<String> APPLICATION_NAME =
|
||||
static final Setting<String> APPLICATION_NAME =
|
||||
new Setting<>("application_name", GoogleCloudStoragePlugin.NAME, Function.identity(), Property.NodeScope, Property.Dynamic);
|
||||
public static final Setting<String> SERVICE_ACCOUNT =
|
||||
simpleString("service_account", Property.NodeScope, Property.Dynamic);
|
||||
public static final Setting<TimeValue> HTTP_READ_TIMEOUT =
|
||||
static final Setting<String> SERVICE_ACCOUNT =
|
||||
new Setting<>("service_account", "_default_", Function.identity(), Property.NodeScope, Property.Dynamic, Property.Deprecated);
|
||||
static final Setting<String> CLIENT_NAME = new Setting<>("client", "default", Function.identity());
|
||||
static final Setting<TimeValue> HTTP_READ_TIMEOUT =
|
||||
timeSetting("http.read_timeout", NO_TIMEOUT, Property.NodeScope, Property.Dynamic);
|
||||
public static final Setting<TimeValue> HTTP_CONNECT_TIMEOUT =
|
||||
static final Setting<TimeValue> HTTP_CONNECT_TIMEOUT =
|
||||
timeSetting("http.connect_timeout", NO_TIMEOUT, Property.NodeScope, Property.Dynamic);
|
||||
|
||||
private final ByteSizeValue chunkSize;
|
||||
|
@ -81,7 +82,8 @@ class GoogleCloudStorageRepository extends BlobStoreRepository {
|
|||
|
||||
String bucket = getSetting(BUCKET, metadata);
|
||||
String application = getSetting(APPLICATION_NAME, metadata);
|
||||
String serviceAccount = getSetting(SERVICE_ACCOUNT, metadata);
|
||||
String serviceAccount = SERVICE_ACCOUNT.get(metadata.settings());
|
||||
String clientName = CLIENT_NAME.get(metadata.settings());
|
||||
|
||||
String basePath = BASE_PATH.get(metadata.settings());
|
||||
if (Strings.hasLength(basePath)) {
|
||||
|
@ -113,7 +115,7 @@ class GoogleCloudStorageRepository extends BlobStoreRepository {
|
|||
logger.debug("using bucket [{}], base_path [{}], chunk_size [{}], compress [{}], application [{}]",
|
||||
bucket, basePath, chunkSize, compress, application);
|
||||
|
||||
Storage client = storageService.createClient(serviceAccount, application, connectTimeout, readTimeout);
|
||||
Storage client = storageService.createClient(serviceAccount, clientName, application, connectTimeout, readTimeout);
|
||||
this.blobStore = new GoogleCloudStorageBlobStore(settings, bucket, client);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,28 +35,43 @@ import com.google.api.services.storage.StorageScopes;
|
|||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.SecureSetting;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
interface GoogleCloudStorageService {
|
||||
|
||||
String SETTINGS_PREFIX = "gcs.client.";
|
||||
|
||||
/** A json credentials file loaded from secure settings. */
|
||||
Setting.AffixSetting<InputStream> CREDENTIALS_FILE_SETTING = Setting.affixKeySetting(SETTINGS_PREFIX, "credentials_file",
|
||||
key -> SecureSetting.secureFile(key, null));
|
||||
|
||||
/**
|
||||
* Creates a client that can be used to manage Google Cloud Storage objects.
|
||||
*
|
||||
* @param serviceAccount path to service account file
|
||||
* @param clientName name of client settings to use from secure settings
|
||||
* @param application name of the application
|
||||
* @param connectTimeout connection timeout for HTTP requests
|
||||
* @param readTimeout read timeout for HTTP requests
|
||||
* @return a Client instance that can be used to manage objects
|
||||
*/
|
||||
Storage createClient(String serviceAccount, String application, TimeValue connectTimeout, TimeValue readTimeout) throws Exception;
|
||||
Storage createClient(String serviceAccount, String clientName, String application,
|
||||
TimeValue connectTimeout, TimeValue readTimeout) throws Exception;
|
||||
|
||||
/**
|
||||
* Default implementation
|
||||
|
@ -67,58 +82,60 @@ interface GoogleCloudStorageService {
|
|||
|
||||
private final Environment environment;
|
||||
|
||||
InternalGoogleCloudStorageService(Environment environment) {
|
||||
/** Credentials identified by client name. */
|
||||
private final Map<String, GoogleCredential> credentials;
|
||||
|
||||
InternalGoogleCloudStorageService(Environment environment, Map<String, GoogleCredential> credentials) {
|
||||
super(environment.settings());
|
||||
this.environment = environment;
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Storage createClient(String serviceAccount, String application, TimeValue connectTimeout, TimeValue readTimeout)
|
||||
throws Exception {
|
||||
public Storage createClient(String serviceAccountFile, String clientName, String application,
|
||||
TimeValue connectTimeout, TimeValue readTimeout) throws Exception {
|
||||
try {
|
||||
GoogleCredential credentials = (DEFAULT.equalsIgnoreCase(serviceAccount)) ? loadDefault() : loadCredentials(serviceAccount);
|
||||
GoogleCredential credential = getCredential(serviceAccountFile, clientName);
|
||||
NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
|
||||
|
||||
Storage.Builder storage = new Storage.Builder(httpTransport, JacksonFactory.getDefaultInstance(),
|
||||
new DefaultHttpRequestInitializer(credentials, connectTimeout, readTimeout));
|
||||
new DefaultHttpRequestInitializer(credential, connectTimeout, readTimeout));
|
||||
storage.setApplicationName(application);
|
||||
|
||||
logger.debug("initializing client with service account [{}/{}]",
|
||||
credentials.getServiceAccountId(), credentials.getServiceAccountUser());
|
||||
credential.getServiceAccountId(), credential.getServiceAccountUser());
|
||||
return storage.build();
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchException("Error when loading Google Cloud Storage credentials file", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request initializer that loads credentials from the service account file
|
||||
* and manages authentication for HTTP requests
|
||||
*/
|
||||
private GoogleCredential loadCredentials(String serviceAccount) throws IOException {
|
||||
if (serviceAccount == null) {
|
||||
throw new ElasticsearchException("Cannot load Google Cloud Storage service account file from a null path");
|
||||
}
|
||||
|
||||
Path account = environment.configFile().resolve(serviceAccount);
|
||||
if (Files.exists(account) == false) {
|
||||
throw new ElasticsearchException("Unable to find service account file [" + serviceAccount
|
||||
// pkg private for tests
|
||||
GoogleCredential getCredential(String serviceAccountFile, String clientName) throws IOException {
|
||||
if (DEFAULT.equalsIgnoreCase(serviceAccountFile) == false) {
|
||||
deprecationLogger.deprecated("Using GCS service account file from disk is deprecated. " +
|
||||
"Move the file into the elasticsearch keystore.");
|
||||
Path account = environment.configFile().resolve(serviceAccountFile);
|
||||
if (Files.exists(account) == false) {
|
||||
throw new IllegalArgumentException("Unable to find service account file [" + serviceAccountFile
|
||||
+ "] defined for repository");
|
||||
}
|
||||
|
||||
try (InputStream is = Files.newInputStream(account)) {
|
||||
GoogleCredential credential = GoogleCredential.fromStream(is);
|
||||
if (credential.createScopedRequired()) {
|
||||
credential = credential.createScoped(Collections.singleton(StorageScopes.DEVSTORAGE_FULL_CONTROL));
|
||||
}
|
||||
return credential;
|
||||
|
||||
try (InputStream is = Files.newInputStream(account)) {
|
||||
GoogleCredential credential = GoogleCredential.fromStream(is);
|
||||
if (credential.createScopedRequired()) {
|
||||
credential = credential.createScoped(Collections.singleton(StorageScopes.DEVSTORAGE_FULL_CONTROL));
|
||||
}
|
||||
return credential;
|
||||
}
|
||||
} else if (credentials.containsKey(clientName)) {
|
||||
return credentials.get(clientName);
|
||||
}
|
||||
return getDefaultCredential();
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request initializer that loads default credentials when running on Compute Engine
|
||||
*/
|
||||
private GoogleCredential loadDefault() throws IOException {
|
||||
// pkg private for tests
|
||||
GoogleCredential getDefaultCredential() throws IOException {
|
||||
return GoogleCredential.getApplicationDefault();
|
||||
}
|
||||
|
||||
|
@ -172,4 +189,23 @@ interface GoogleCloudStorageService {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Load all secure credentials from the settings. */
|
||||
static Map<String, GoogleCredential> loadClientCredentials(Settings settings) {
|
||||
Set<String> clientNames = settings.getGroups(SETTINGS_PREFIX).keySet();
|
||||
Map<String, GoogleCredential> credentials = new HashMap<>();
|
||||
for (String clientName : clientNames) {
|
||||
Setting<InputStream> concreteSetting = CREDENTIALS_FILE_SETTING.getConcreteSettingForNamespace(clientName);
|
||||
try (InputStream credStream = concreteSetting.get(settings)) {
|
||||
GoogleCredential credential = GoogleCredential.fromStream(credStream);
|
||||
if (credential.createScopedRequired()) {
|
||||
credential = credential.createScoped(Collections.singleton(StorageScopes.DEVSTORAGE_FULL_CONTROL));
|
||||
}
|
||||
credentials.put(clientName, credential);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
return credentials;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,9 @@ public class GoogleCloudStorageBlobStoreRepositoryTests extends ESBlobStoreRepos
|
|||
}
|
||||
|
||||
public static class MockGoogleCloudStoragePlugin extends GoogleCloudStoragePlugin {
|
||||
public MockGoogleCloudStoragePlugin() {
|
||||
super(Settings.EMPTY);
|
||||
}
|
||||
@Override
|
||||
protected GoogleCloudStorageService createStorageService(Environment environment) {
|
||||
return new MockGoogleCloudStorageService();
|
||||
|
@ -75,7 +78,8 @@ public class GoogleCloudStorageBlobStoreRepositoryTests extends ESBlobStoreRepos
|
|||
|
||||
public static class MockGoogleCloudStorageService implements GoogleCloudStorageService {
|
||||
@Override
|
||||
public Storage createClient(String serviceAccount, String application, TimeValue connectTimeout, TimeValue readTimeout) throws
|
||||
public Storage createClient(String serviceAccount, String accountName, String application,
|
||||
TimeValue connectTimeout, TimeValue readTimeout) throws
|
||||
Exception {
|
||||
return storage.get();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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 java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.repositories.gcs.GoogleCloudStorageService.InternalGoogleCloudStorageService;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
public class GoogleCloudStorageServiceTests extends ESTestCase {
|
||||
|
||||
private InputStream getDummyCredentialStream() throws IOException {
|
||||
return GoogleCloudStorageServiceTests.class.getResourceAsStream("/dummy-account.json");
|
||||
}
|
||||
|
||||
public void testDefaultCredential() throws Exception {
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
GoogleCredential cred = GoogleCredential.fromStream(getDummyCredentialStream());
|
||||
InternalGoogleCloudStorageService service = new InternalGoogleCloudStorageService(env, Collections.emptyMap()) {
|
||||
@Override
|
||||
GoogleCredential getDefaultCredential() throws IOException {
|
||||
return cred;
|
||||
}
|
||||
};
|
||||
assertSame(cred, service.getCredential("_default_", "default"));
|
||||
}
|
||||
|
||||
public void testFileCredentialBackcompat() throws Exception {
|
||||
Path home = createTempDir();
|
||||
Path config = home.resolve("config");
|
||||
Files.createDirectories(config);
|
||||
Settings settings = Settings.builder()
|
||||
.put("path.home", home).build();
|
||||
Environment env = new Environment(settings);
|
||||
Files.copy(getDummyCredentialStream(), config.resolve("test-cred.json"));
|
||||
InternalGoogleCloudStorageService service = new InternalGoogleCloudStorageService(env, Collections.emptyMap());
|
||||
GoogleCredential cred = service.getCredential("test-cred.json", "default");
|
||||
assertEquals("some-project-name@appspot.gserviceaccount.com", cred.getServiceAccountId());
|
||||
assertWarnings("Using GCS service account file from disk is deprecated. Move the file into the elasticsearch keystore.");
|
||||
}
|
||||
|
||||
public void testFileCredentialMissing() throws Exception {
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
InternalGoogleCloudStorageService service = new InternalGoogleCloudStorageService(env, Collections.emptyMap());
|
||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
|
||||
service.getCredential("test-cred.json", "default"));
|
||||
assertThat(e.getMessage(), containsString("Unable to find service account file"));
|
||||
assertWarnings("Using GCS service account file from disk is deprecated. Move the file into the elasticsearch keystore.");
|
||||
}
|
||||
|
||||
public void testClientCredential() throws Exception {
|
||||
GoogleCredential cred = GoogleCredential.fromStream(getDummyCredentialStream());
|
||||
Map<String, GoogleCredential> credentials = Collections.singletonMap("clientname", cred);
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
InternalGoogleCloudStorageService service = new InternalGoogleCloudStorageService(env, credentials);
|
||||
assertSame(cred, service.getCredential("_default_", "clientname"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"type": "service_account",
|
||||
"project_id": "some-project-name",
|
||||
"private_key_id": "c7cefcb7c72a2880ecce49cb9d1095de5a61aff0",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDa+7r0RE1YykXC\n+d+DXlN3Dg3aL1YOfYuhy5PF/Vi0FFQHyXuPtAvkVHZD2NxMDZq2DxTu3AVLh1UE\nt2hMrWjDQDuArPl8FezpyYQwde04Qlx1YpQ1xUjTaFWd0hrOZEfsxY00h3ilxR3G\nJsofR3PZBKYI11VGruNemCgjiJg5hcoJDxLXUgcfpKJaiPeHutczCeZ1RANQwQF1\n/dPXhqbtWiaS/iu5so64P54TsrVX5DcXmbGr6hQAReIcI6cjA8QhSu6QBtdvEPhv\n27uTuSu4XRtTh3djVGFzFV9pamGZeGELkTiHVSDI8IkQ32s8yuP5Zys/4bFJk7nn\niqJpe0/DAgMBAAECggEAEexQnPWKLx4/H3o8JRBvXGs2DwmYzY7RAukaqzXVMMgJ\nKKoBBv4Biyquk1cIkOD8LLKHUBWKCWiGOOCaFMyMqo5zUFDYCqPwxCHOQ/ki9VvZ\nHXJ4Fv6Su1rqxwQPVZ03ldWFfSspYMgFa9Z47J54iOasgES/og1mZrOldWMUsoBu\nCKf0fH+vIsxWPwmRtyxKCMwqenqdc22nGGLhmpm8tuw1eQp6XtTXagqkPtAVMMga\nmgC0EGqhZA/IklGW1JuGWELjXVMgS/tLIPq+hYsmY14y6Ie032YoSMWkz6Z5p7i0\n/JwCzVZNO1mD0MwVj7nDmokXOpoyM7Qcbx8r1E4Q4QKBgQDxqAZ6D+A671mCNU0J\n6Qzc3cOZq7MBj4y7M/2qPXHC7i/DdbmnM7PPPriaBBch2nX7jZRlRmVDBsmrC4OG\n3m5+HAx7YPVbefwe6h5ki5O9wg1pLcgYY9uvgLSlD85lVZKAzO7QK2W5zfM19kPD\nSckIa+U7DKFbwKhtCsxcP6ARJwKBgQDn+zAPHepGP2Zf78pOLlVXcQqVA1uOu+bW\nrG4G+lPrytB0C4QdwWdBV3Lcqmnw/ae5PkQBs0dCbtWG8+MT8gA6k5kleflaZrAY\ngdUJIUP6J7ocWYxVTfqGFyFF1n5VT8/jbVucaT7izBZfZvlGyf7Vz7ewQzgWQWlK\nCQ0qstV2BQKBgQCajAQAYlDcQCC1dlMbqHDye91RVQ65S84MF1b+Xid4LA5d6dde\nyGERhKJY1Y7ZtrZHt6cVEe1G7XtiKY3nXi+59URCT6L66svEFaR0VxOYgxdCkeXr\nO0nPNvfQrIgqJIz6VJXSij6XktAdTa7OoUyxVxeWKSC05kSQ4BwMTyCWdwKBgQCW\noqlmZ4qE6w5TJaY8diG8kg7JDFEbsjAHHhikN1DfP+d0MzYrDDc8WsifOZlpf4y1\n4RTP9dZD8Sx+YUgG35H+d3FuwHGGnj+i6kunjg5SFhHn7s4NZoFTKRnV+541T4oy\nqARg4IaRRu0QLhGYQfpUZHlm339AFGGGTbJbE51A8QKBgQDTEN5O+3bRG3Fa1J6z\nU9PMrjjs6l8xhXFso10YEYG5KRnfhzCFujyWNiLE6WrlUL8invVBaCxsZr51GDgA\nhyEEdm4kXCRrv4JyhOvIuGxNcAIiQK/e91UQEM6u1t6hUI1rE7ZOyJQzBxj9hFlV\n7OvhBlHXQUtAOdq0XLHr9GzdSA==\n-----END PRIVATE KEY-----\n",
|
||||
"client_email": "some-project-name@appspot.gserviceaccount.com",
|
||||
"client_id": "123456789101112130594",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://accounts.google.com/o/oauth2/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/some-project-name%40appspot.gserviceaccount.com"
|
||||
}
|
Loading…
Reference in New Issue