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

Add support for AWS session tokens #30414

Merged
merged 32 commits into from
Jul 3, 2018

Conversation

DaveCTurner
Copy link
Contributor

@DaveCTurner DaveCTurner commented May 6, 2018

AWS supports the creation and use of credentials that are only valid for a
fixed period of time. These credentials comprise three parts: the usual access
key and secret key, together with a session token. This commit adds support for
these three-part credentials to the EC2 discovery plugin and the S3 repository
plugin.

Note that session tokens are only valid for a limited period of time and yet
there is no mechanism for refreshing or rotating them when they expire without
restarting Elasticsearch. Nonetheless, this feature is already useful for
nodes that need only run for a few days, such as for training, testing or
evaluation. #29135 tracks the work towards allowing these credentials to be
refreshed at runtime.

Resolves #16428

AWS supports the creation and use of credentials that are only valid for a
fixed period of time. These credentials comprise three parts: the usual access
key and secret key, together with a session token. This commit adds support for
these three-part credentials to the EC2 discovery plugin and the S3 repository
plugin.

Note that session tokens are only valid for a limited period of time and yet
there is no mechanism for refreshing or rotating them when they expire without
restarting Elasticsearch.  Nonetheless, this feature is already useful for
nodes that need only run for a few days, such as for training, testing or
evaluation. elastic#29135 tracks the work towards allowing these credentials to be
refreshed at runtime.

Resolves elastic#16428
@DaveCTurner DaveCTurner added >enhancement :Distributed/Snapshot/Restore Anything directly related to the `_snapshot/*` APIs :Distributed/Discovery-Plugins Anything related to our integration plugins with EC2, GCP and Azure v7.0.0 :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) v6.4.0 labels May 6, 2018
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-distributed

@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-security

@tlrx tlrx self-requested a review May 7, 2018 09:02
Copy link
Member

@tlrx tlrx left a comment

Choose a reason for hiding this comment

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

Thanks @DaveCTurner, this looks great. I'm curious to see how it will play with reloadable secured settings (#29135.

Anyway, do you think that we can have an integration test in :qa:amazon-s3 for this? That might be tricky to rotate tokens on infra, but I think it worth the trouble.

assertThat(defaultSettings.proxyPassword, isEmptyString());
assertThat(defaultSettings.readTimeoutMillis, is(ClientConfiguration.DEFAULT_SOCKET_TIMEOUT));
assertThat(defaultSettings.maxRetries, is(ClientConfiguration.DEFAULT_RETRY_POLICY.getMaxErrorRetry()));
assertThat(defaultSettings.throttleRetries, is(ClientConfiguration.DEFAULT_THROTTLE_RETRIES));
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for adding these

() -> {
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString("s3.client.default.access_key", "aws_key");
S3ClientSettings.load(Settings.builder().setSecureSettings(secureSettings).build());
Copy link
Member

Choose a reason for hiding this comment

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

Nit: you can build the settings outside the expectThrows block, I find it easier to "spot" where the exception is expected to be thrown

Copy link
Contributor Author

Choose a reason for hiding this comment

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

++ I pushed ee41de6

@@ -46,6 +46,11 @@ Those that must be stored in the keystore are marked as `Secure`.

An s3 secret key. The `access_key` setting must also be specified. (Secure)

`session_token`::

An s3 session token. The `access_key` and `secret_key` settings must also
Copy link
Member

Choose a reason for hiding this comment

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

Nit: An -> A

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is tricky but I think "an" is preferred here: S3 is pronounced "ess three" which begins with a vowel. However, on reflection these docs should refer to EC2 and not S3, so I pushed c93e568.

Copy link
Member

Choose a reason for hiding this comment

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

Did I just correct an English about his English grammar? Yes I did. Was I right? Absolutly not.

Thanks :)

@@ -73,6 +73,11 @@ are marked as `Secure`.

An s3 secret key. The `access_key` setting must also be specified. (Secure)

`session_token`::

An s3 session token. The `access_key` and `secret_key` settings must also
Copy link
Member

Choose a reason for hiding this comment

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

Nit: An -> A

@DaveCTurner
Copy link
Contributor Author

@tlrx I duplicated the QA tests as we discussed, and tightened up the auth checks in AmazonS3TestServer a bit in order to check that the right bucket is being accessed. This is ready for another look.

Copy link
Member

@tlrx tlrx left a comment

Choose a reason for hiding this comment

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

It looks great, I left more comment, mostly around the naming of the env vars (I'd like to keep the old names) and also allow the tests to be executed separatly.

}

final RequestHandler handler = handlers.retrieve(method + " " + path, params);
if (handler != null) {
final String bucket = params.get("bucket");
if (bucket != null && permittedBucket.equals(bucket) == false) {
// allow a null bucket to support bucket-free APIs like ListBuckets?
Copy link
Member

Choose a reason for hiding this comment

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

allow a null bucket to support bucket-free APIs like ListBuckets?

I don't think it's needed, returning an error seems the right thing to do

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is needed, but it's not ListBuckets so I pushed 63caae2. It's the multi-object delete API, which puts the bucket name in the Host header rather than in a URL parameter, which I do not think is worth adding the extra plumbing for.

s3Bucket = 'bucket_test'
s3BasePath = 'integration_test'
// We test against two repositories, one which uses the usual two-part "permanent" credentials and
// the other which uses three-part "temporary" or "session" credentials.
Copy link
Member

Choose a reason for hiding this comment

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

Hopefully we'll split this into two QA projects in a follow up PR, so for now I'd prefer to not rename the existing env vars.

I understand the permanent/temporary renaming for repositories or buckets but I still think that the env vars names should reflect the feature implemented, ie keeping amazon_s3_access_key for the default use case, and maybe amazon_s3_access_key_for_session_tokens.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have reverted the changes to the names of the existing environment variables.

// If all these variables are missing then we are testing against the internal fixture instead, which has the following
// credentials hard-coded in.

if (!s3PermanentAccessKey && !s3PermanentSecretKey && !s3PermanentBucket && !s3PermanentBasePath
Copy link
Member

Choose a reason for hiding this comment

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

Can we set the defaults in separate condition blocks? So that if a set [amazon_s3_access_key/amazon_s3_secret_key/amazon_s3_base_path/amazon_s3_bucket] is set it runs against the real service whatever is set for amazon_s3_access_key_for_session_tokens

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As it currently stands, I think it makes more sense to either test entirely against the fake fixture or entirely against the real service (and therefore not run the fake fixture). If there is a followup that allows these two cases to run separately then hopefully it's not too hard to disentangle this then.

@@ -57,26 +78,34 @@ task s3Fixture(type: AntFixture) {
dependsOn compileTestJava
env 'CLASSPATH', "${ -> project.sourceSets.test.runtimeClasspath.asPath }"
executable = new File(project.runtimeJavaHome, 'bin/java')
args 'org.elasticsearch.repositories.s3.AmazonS3Fixture', baseDir, s3Bucket
args 'org.elasticsearch.repositories.s3.AmazonS3Fixture', baseDir
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer if we continue to pass the bucket names to the fixture so that we can reuse it in different projects more easily.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I've reverted that. There is, however, already some other coupling (duplication of string values) between the build.gradle file and the fake S3 fixture that would need attention to use this fixture elsewhere.

@@ -53,8 +53,8 @@
public class AmazonS3Fixture {

public static void main(String[] args) throws Exception {
if (args == null || args.length != 2) {
throw new IllegalArgumentException("AmazonS3Fixture <working directory> <bucket>");
if (args == null || args.length != 1) {
Copy link
Member

Choose a reason for hiding this comment

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

Can we revert this please?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We now pass the bucket names in on the command line again.

@@ -72,7 +72,8 @@ public static void main(String[] args) throws Exception {
// Emulates S3
final String storageUrl = "http://" + addressAndPort;
final AmazonS3TestServer storageTestServer = new AmazonS3TestServer(storageUrl);
storageTestServer.createBucket(args[1]);
storageTestServer.createBucket("permanent_bucket_test");
storageTestServer.createBucket("temporary_bucket_test");
Copy link
Member

Choose a reason for hiding this comment

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

Can we revert this please, and pass the bucket names as program args?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We now pass the bucket names in on the command line again.

@DaveCTurner
Copy link
Contributor Author

DaveCTurner commented Jun 25, 2018

@tlrx I have merged master, which was nontrivial thanks to #31383, and addressed some of your comments. I can't see how these two cases (permanent vs temporary credentials) are eventually going to work as two separate Gradle tasks, so I've held off on any changes that depends on that. I would prefer to merge this and proceed from there, but if you think anything here will prove obstructive then it'd be better not to.

Copy link
Member

@tlrx tlrx left a comment

Choose a reason for hiding this comment

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

Sorry for the time it took me to review this.

This PR should be merged before #31688, in which the QA project is dropped.

As a follow ups:

  • we need to add a test for session tokens with discovery-ec2
  • this PR will prevent the current third party tests to run on CI until session tokens are injected to the Jenkins job (that's why I suggested to decorrelate env vars)
  • I think we can clean up test and have something similar to Fixture for Minio testing #31688, ie executing the same tests but with a different repository set up. We talked about this already and decided to do this as a follow up as this PR was already large enough. I can take care of this and mark you as a reviewer because there are other things I want to clean up.

@DaveCTurner DaveCTurner merged commit 4108722 into elastic:master Jul 3, 2018
@DaveCTurner DaveCTurner deleted the 2018-05-06-aws-session-token branch July 3, 2018 13:12
DaveCTurner added a commit that referenced this pull request Jul 3, 2018
AWS supports the creation and use of credentials that are only valid for a
fixed period of time. These credentials comprise three parts: the usual access
key and secret key, together with a session token. This commit adds support for
these three-part credentials to the EC2 discovery plugin and the S3 repository
plugin.

Note that session tokens are only valid for a limited period of time and yet
there is no mechanism for refreshing or rotating them when they expire without
restarting Elasticsearch.  Nonetheless, this feature is already useful for
nodes that need only run for a few days, such as for training, testing or
evaluation. #29135 tracks the work towards allowing these credentials to be
refreshed at runtime.

Resolves #16428
dnhatn added a commit that referenced this pull request Jul 4, 2018
* 6.x:
  Fix not waiting for Netty ThreadDeathWatcher in IT (#31758) (#31789)
  [Docs] Correct default window_size (#31582)
  S3 fixture should report 404 on unknown bucket (#31782)
  [ML] Limit ML filter items to 10K (#31731)
  Fixture for Minio testing (#31688)
  [ML] Return statistics about forecasts as part of the jobsstats and usage API (#31647)
  [DOCS] Add missing get mappings docs to HLRC (#31765)
  [DOCS] Starting Elasticsearch (#31701)
  Fix coerce validation_method in GeoBoundingBoxQueryBuilder (#31747)
  Painless: Complete Removal of Painless Type (#31699)
  Consolidate watcher setting update registration (#31762)
  [DOCS] Adds empty 6.3.1 release notes page
  ingest: Introduction of a bytes processor (#31733)
  [test] don't run bats tests for suse boxes (#31749)
  Add analyze API to high-level rest client (#31577)
  Implemented XContent serialisation for GetIndexResponse (#31675)
  [DOCS] Typos
  DOC: Add examples to the SQL docs (#31633)
  Add support for AWS session tokens (#30414)
  Watcher: Reenable start/stop yaml tests (#31754)
  JDBC: Fix stackoverflow on getObject and timestamp conversion (#31735)
  Support multiple system store types (#31650)
  Add write*Blob option to replace existing blob (#31729)
  Split CircuitBreaker-related tests (#31659)
  Painless: Add Context Docs (#31190)
  Docs: Remove missing reference
  Migrate scripted metric aggregation scripts to ScriptContext design (#30111)
  Watcher: Fix chain input toXcontent serialization (#31721)
  Remove _all example (#31711)
  rest-high-level: added get cluster settings (#31706)
  Docs: Match the examples in the description (#31710)
  [Docs] Correct typos (#31720)
  Extend allowed characters for grok field names (#21745) (#31653) (#31722)
  [DOCS] Check for Windows and *nix file paths (#31648)
  [ML] Validate ML filter_id (#31535)
  Fix gradle4.8 deprecation warnings (#31654)
  Update numbers to reflect 4-byte UTF-8-encoded characters (#27083)
dnhatn added a commit that referenced this pull request Jul 4, 2018
* master:
  [ML] Rate limit established model memory updates (#31768)
  [Docs] Correct default window_size (#31582)
  S3 fixture should report 404 on unknown bucket (#31782)
  Detach Transport from TransportService (#31727)
  [ML] Limit ML filter items to 10K (#31731)
  [ML] Return statistics about forecasts as part of the jobsstats and usage API (#31647)
  Fixture for Minio testing (#31688)
  [DOCS] Add missing get mappings docs to HLRC (#31765)
  [DOCS] Starting Elasticsearch (#31701)
  Painless: Complete Removal of Painless Type (#31699)
  Fix not waiting for Netty ThreadDeathWatcher in IT (#31758)
  Consolidate watcher setting update registration (#31762)
  Build: re-enabled bwc (#31769)
  ingest: Introduction of a bytes processor (#31733)
  Fix coerce validation_method in GeoBoundingBoxQueryBuilder (#31747)
  Add analyze API to high-level rest client (#31577)
  [DOCS] Typos
  DOC: Add examples to the SQL docs (#31633)
  Add support for AWS session tokens (#30414)
  Watcher: Reenable start/stop yaml tests (#31754)
  Implemented XContent serialisation for GetIndexResponse (#31675)
  JDBC: Fix stackoverflow on getObject and timestamp conversion (#31735)
  resolveHasher defaults to NOOP (#31723)
  Account for XContent overhead in in-flight breaker
  Split CircuitBreaker-related tests (#31659)
  Add write*Blob option to replace existing blob (#31729)
  Painless: Add Context Docs (#31190)
  Watcher: Fix chain input toXcontent serialization (#31721)
  Docs: Match the examples in the description (#31710)
  rest-high-level: added get cluster settings (#31706)
  [Docs] Correct typos (#31720)
  Clean up double semicolon code typos (#31687)
  [DOCS] Check for Windows and *nix file paths (#31648)
  [ML] Validate ML filter_id (#31535)
  Revert long lines
  Fix TransportChangePasswordActionTests
@jpountz jpountz removed :Distributed/Discovery-Plugins Anything related to our integration plugins with EC2, GCP and Azure :Distributed/Snapshot/Restore Anything directly related to the `_snapshot/*` APIs labels Jan 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>enhancement :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) v6.4.0 v7.0.0-beta1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for AWS STS credentials for snapshots
5 participants