-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Use IMDSv2 for S3 instance credentials #7709
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
Conversation
|
Thanks for opening a pull request and helping make RubyGems and Bundler better! Someone from the RubyGems team will take a look at your pull request shortly and leave any feedback. Please make sure that your pull request has tests for any changes or added functionality. We use GitHub Actions to test and make sure your change works functionally and uses acceptable conventions, you can review the current progress of GitHub Actions in the PR status window below. If you have any questions or concerns that you wish to ask, feel free to leave a comment in this PR or join our #rubygems or #bundler channel on Slack. For more information about contributing to the RubyGems project feel free to review our CONTRIBUTING guide |
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 may be good to add some tests, but looking at git history, s3 fetcher is mainly maintained by Stripe people, and we don't really get many issues with it. So I'm happy to just merge this if you don't have time for tests.
|
@geanboegman since you originally requested this, does this look good to you? Would you like to try it? |
|
Looking at the code this is looks good yes, what I considered:
I did not test the change, feedback only based on code review. Thanks for this! |
|
@deivid-rodriguez I haven't been able to run the tests in my environment so would rather not have to spend the time setting all of that up. Any thoughts on how to handle |
Could you share the problems you run into? Even if you don't end up contributing tests this time, I'd like to make this easier for other future contributions.
Is it possible to increase it when getting a timeout, and then try with v2 again? |
Hi @deivid-rodriguez , that makes a lot of sense and it's great that you maintain a high bar. Unfortunately I did not run into this issues myself as we do not use Ruby Gems but I did notice that there code was still using V1 while doing a code audit as part of an environment assessment, so decided to log a ticket as it is little effort and would benefit the the open community overall.
and
My take here is that even when setting the hop limit to two, you will still benefit from an improved posture when using V2 and disabling V1, so when in doubt set the hop-limit to 2. Since these settings are instance level it would not be 1) trivial to change the hop limit dynamically as it would require permissions and AWS service calls (SDK or CLI), and 2) you should not try to change the hop limit from the Ruby code, it's a instances or account setting, it need to be managed at the account ownership level, so you are are the mercy of the instance configuration in this case (this is the reason some SDKs implement fallback logic when there is a timeout on the PUT token request - the response when running on a container and the hop limit is set to 1 - i.e. the router drops the token request after one hop). I think you have two options, either document that users need to up the hop-limit, or implement fallback logic to use V1 - but be sure to log some message to inform the user that they are using V1 not V2. |
Oh, no worries, your feedback is great! I actually meant this for @folbricht-stripe since he said "I haven't been able to run tests on my environment".
Yeah, makes sense to not mess with trying to change this dynamically. I think ideally we implement a fallback with a warning for backwards compatibility. |
|
Code looks OK. IMDSv1 seems soft-deprecated for years already. Any idea what IMDSv2 endpoint returns when not enabled? Would it be possible to just provide some friendly error explaining RubyGems requires IMDSv2 enabled? Btw. @folbricht-stripe any plans to share your experience on using RubyGems with S3 in Stripe? Blog post would be amazing. |
|
I'm not really involved in how RubyGems is used here. I just looked at it because it was the last thing using IMDSv1 on a few hosts, requiring me to enable v1 again. I'm also not normally working with Ruby, which probably explains why I fail to run any tests. I get errors even just trying to install the dependencies with Probably some issues with the version I have here. According to https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-options.html it doesn't seem possible to disable v2 only. IMDS is either off for all versions, or v2 is turned on. There's no way to turn off v2 while leaving v1 active. But given that it's possible v2 fails due to a misconfigured hop-limit, perhaps adding a fallback to v1 would be best. Though I'm not really a fan of automated fallback to less secure implementations. Do you want me to add v1 fallback? The changes should be quite straightforward, but testing is not (last time I had to hand-patch a deployed version). |
I have to agree, although in some cases having a fallback as an interim measure can avoid impacting customers unintentionally (when they forget to up the hop in containers). If you decide to add a fallback, I would recommend that: 1) you clearly log when this happens, and 2) you allow customers to disable the fallback. The latter is needed as it can be really hard to bottom out on where calls are coming from, and it gives the customer control over his posture. |
Indeed. You're using Ruby older than Ruby 3.0 but RubyGems requires at least 3.0. The error you got is super unhelpful thought, I'm introducing a better error at #7942. @simi Thoughts on adding a fallback + clear warning? I think that's probably the safest approach? |
|
#7942 closed this accidentally, reopening. |
|
Howdy folks, I'm picking up this work (coordinating with @folbricht-stripe). Going to push my changes to this branch to keep the conversation. |
920bdd4 to
1c4090b
Compare
|
Sorry for dumping so many changes at once. I had to do some surgery
|
|
Thank you! Regarding bullet point number 4, I think |
|
Ok! I have tested everything locally on our infra and it successfully pulls gems from S3 using imdsv2 🎉 I believe this PR is in a state for review if folks could take a look 🙏 |
|
Thanks for your work, I'll try find time to review it. Can you address CI issues in the mean time? |
|
Done! |
|
Howdy folks, following up. Is there anything I can do to help review here? |
|
|
||
| case uri.to_s | ||
| when "http://169.254.169.254/latest/api/token" | ||
| if $imdsv2_token_failure |
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.
What about to set at least class shared variable instead of global one to control this? FakeS3URISigner.return_token = "mysecrettoken" => returns token, FakeS3URISigner.return_token = false returns 401 instead. And reset before each test + set whenever failure is needed in with_imds_v2_failure method?
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.
Works for me! I was largely following the convention in this file which was using global variables.
Will make the change! (Sorry for the slow response, was on holiday)
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.
Done! Removed all global variables ❤️
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.
OK, updated, had to do some more test surgery where places were assuming a V1 output erroneously. I hand inspected the tests and things look right now.
|
Hi friends, sorry for the thrash. I believe this is ready for review again :) |
|
Howdy, @simi @deivid-rodriguez, any chance this could get a look over? |
|
I'm falling a bit behind on reviewing PRs, sorry. Not sure if @simi is planning to follow up soon, otherwise I'll get to it as soon as I can. Do we have a way/guide to setup s3 sources so I can try this in real life? I've never used this feature, and being able to try it would help me when I review it. |
I do. |
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.
Looks good!
|
This PR needs a rebase now to fix conflicts. I'd also squash the dummy "fix linter" commits into the more meaningful ones while at it. |
|
Phew, sorry for the radio silence there, had a bunch of other things that took all my time. Just rebased, fixed conflicts, colocated commits, and I believe all tests / lints are passing. Do you think you could take another look? Thanks! |
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.
Thank you! I'll merge in a couple of days (just in case @simi wants to double check the latest changes).
Use IMDSv2 for S3 instance credentials (cherry picked from commit 76abc01)
Use IMDSv2 for S3 instance credentials (cherry picked from commit 76abc01)
What was the end-user or developer problem that led to this PR?
The use of IMDSv1 is discouraged and AWS recommends using IMDSv2 to obtain instance credentials as outlined here and here. On instances without IMDSv1 support,
rubygemscan not be used to install gems from S3 using the instance profile.Implements #5763
What is your fix for the problem, implemented in this PR?
Swiches the S3 URI signer to using IMDSv2.
Make sure the following tasks are checked