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

Provide utilities for accessing EC2 Instance Metadata Service #4004

Closed
1 of 2 tasks
nwalters512 opened this issue Sep 29, 2022 · 28 comments
Closed
1 of 2 tasks

Provide utilities for accessing EC2 Instance Metadata Service #4004

nwalters512 opened this issue Sep 29, 2022 · 28 comments
Assignees
Labels
closed-for-staleness feature-request New feature or enhancement. May require GitHub community feedback. p2 This is a standard priority issue response-requested Waiting on additional info and feedback. Will move to \"closing-soon\" in 7 days.

Comments

@nwalters512
Copy link
Contributor

Describe the feature

I'd like an easy way to access information from the EC2 Instance Metadata Service, similar to the MetadataService that's available in the v2 SDK: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/MetadataService.html.

Use Case

I'd rather not re-implement the logic for picking the appropriate endpoint, refreshing the token, refetching the token, etc.

Proposed Solution

No response

Other Information

It looks like credential-provider-imds has already implemented a lot of the token fetching, error handling, etc. Maybe that can be refactored into a shared place?

SDKs for other languages already implement this feature, including Go (https://docs.aws.amazon.com/sdk-for-go/api/aws/ec2metadata/).

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

SDK version used

3.178.0

Environment details (OS name and version, etc.)

macOS 12.5.1

@nwalters512 nwalters512 added feature-request New feature or enhancement. May require GitHub community feedback. needs-triage This issue or PR still needs to be triaged. labels Sep 29, 2022
@ajredniwja
Copy link
Contributor

@nwalters512 thanks for opening this issue, I see it is implemented in go-v2 https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws/ec2metadata as well, I'll discuss the feature with the team and update you soon.

@ajredniwja ajredniwja removed the needs-triage This issue or PR still needs to be triaged. label Oct 3, 2022
@albertodiazdorado
Copy link

+1

I have aborted the migration to v3 because of this -- it does not make sense to migrate all my clients but still keep aws-sdk v2 around solely for MetaDataService :(

@RanVaknin RanVaknin added p2 This is a standard priority issue needs-review This issue/pr needs review from an internal developer. labels Jan 19, 2023
@jpike88
Copy link

jpike88 commented Feb 20, 2023

Similar, I have also aborted upgrade to v3, this is an extremely critical piece of our infrastructure as we use it to determine which of our instances in the elastic beanstalk environment is the 'first' one as it does the cron jobs.

Please, @RanVaknin escalate this as a priority for the team as there is already signs this part of your SDK has been neglected. See aws/aws-sdk-js#3584

@nwalters512
Copy link
Contributor Author

@ajredniwja It's been almost 5 months, can you share an update from your team? I'd be happy to work on PR for this if it's something that y'all would accept.

@jpike88
Copy link

jpike88 commented Feb 21, 2023

@kuhe pulling in another amazon employee here. Considering that these irritating 4-line warnings are now spamming my dev team's console on every run, yet we are literally unable to migrate due to an incomplete v3 offering, this kind of unresponsiveness is very concerning and now reaching levels of being unacceptable.

@RanVaknin RanVaknin self-assigned this Feb 21, 2023
@RanVaknin
Copy link
Contributor

Hi all,

I apologize for the long wait. I'll try to get someone to take a look, but since we have some higher priority issues they will probably take precedence.

I'll do my best.
Ran~

@RanVaknin
Copy link
Contributor

RanVaknin commented Feb 22, 2023

Hi @nwalters512 ,

I've discussed it with the team. Each SDK has implemented this in a different fashion. This likely will not be transformed into its own IMDS Client like in the Golang SDK. If there are customizations needed for the provider can you please elaborate the use cases?

Additionally, if you'd like to take a stab at cutting a PR, I'll have someone review it.

Thanks!
Ran~

@RanVaknin RanVaknin added response-requested Waiting on additional info and feedback. Will move to \"closing-soon\" in 7 days. and removed needs-review This issue/pr needs review from an internal developer. labels Feb 22, 2023
@nwalters512
Copy link
Contributor Author

@RanVaknin I'm not looking to customize @aws-sdk/credential-provider-imds per se - I just want some abstraction for "make an arbitrary request to the IMDS" just like what was available in the v2 SDK. As I mentioned in the original issue, I don't want to have to duplicate code for handling token fetching, expiration, refreshing, and so on. Most of that logic is already implemented in @aws-sdk/credential-provider-imds, just not in a way that I can reuse it for generalized IMDS requests.

If you want a specific use case: I want to be able to discover the instance ID of the host on which my code is running. But in general, I want to be able to fetch any of the categories of information listed here: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html.

If you're not willing to implement this as a separate client package (e.g. @aws-sdk/client-ec2-metadata), I'm not sure where I'd start with a PR. Are you thinking this would be a function exposed from @aws-sdk/client-ec2? IIRC most of the clients are code-genned, so I'd appreciate some guidance on how to work with that.

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to \"closing-soon\" in 7 days. label Feb 24, 2023
@jpike88
Copy link

jpike88 commented Feb 24, 2023

As I'm becoming unsure of whether this will be providing similar functionality to v2, below is my use case in TypeScript:

The code is basically saying, 'is this current instance the first instance in the array of instances in my elastic beanstalk environment? if so, I consider this to be the 'master' instance, and I want this to be my Cron job runner.'. It is incomplete in the first 10 lines as I just cut and paste some bits together to tell the story.

Notice the casting of MetadataService to the any type in order to be able to access the fetchMetadataToken property. It was reported here (aws/aws-sdk-js#3584), and was never resolved, just auto-closed. It would be nice for this typing issue to be fixed as part of this issue as well.

import AWS from 'aws-sdk';

const ElasticBeanstalk = new AWS.ElasticBeanstalk(opts);
const EC2 = new AWS.EC2(opts);
const MetadataService = new AWS.MetadataService(opts);

const elasticbeanstalk = ElasticBeanstalk;
const ec2 = EC2;
const metadata = MetadataService;
let masterInstanceInitialized = false;

async function cronChecker() {
	const token: string = await promisify(
		(metadata as any).fetchMetadataToken.bind(metadata)
	)();

	const currentInstanceId = await promisify(metadata.request.bind(metadata))(
		'/latest/meta-data/instance-id',
		{
			headers: { 'x-aws-ec2-metadata-token': token },
		}
	);
	console.info('InstanceId', currentInstanceId);
	const params = {
		Filters: [
			{
				Name: 'resource-id',
				Values: [currentInstanceId],
			},
		],
	};
	const data = await promisify(ec2.describeTags.bind(ec2))(params);
	const envIdTag = data.Tags.find(
		(t) => t.Key === 'elasticbeanstalk:environment-id'
	);
	if (envIdTag === null) {
		throw new Error(
			'Failed to find the value of "elasticbeanstalk:environment-id" tag.'
		);
	}
	const ebData = await elasticbeanstalk
		.describeEnvironmentResources({ EnvironmentId: envIdTag.Value })
		.promise();
	const isMaster = !(
		currentInstanceId !== ebData.EnvironmentResources.Instances[0].Id
	);
	const health = await elasticbeanstalk
		.describeEnvironmentHealth({
			AttributeNames: ['HealthStatus'],
			EnvironmentId: envIdTag.Value,
		})
		.promise();
	console.warn('Environment health is ' + health.HealthStatus + '.');
	if (isMaster) {
		initCronJobs();
	} else {
		killJobs();
	}
}

@nwalters512
Copy link
Contributor Author

I'm now receiving warnings about the impending deprecation of the v2 SDK (aws/aws-sdk-js#4354):

(node:50693) NOTE: We are formalizing our plans to enter AWS SDK for JavaScript (v2) into maintenance mode in 2023.

Please migrate your code to use AWS SDK for JavaScript (v3).
For more information, check the migration guide at https://a.co/7PzMCcy

AWS.MetadataService isn't mentioned anywhere on https://github.com/aws/aws-sdk-js-v3/blob/main/UPGRADING.md, nor is it handled by https://github.com/awslabs/aws-sdk-js-codemod. It feels very irresponsible to be so insistently pushing for a migration to a new package if that package is lacking necessary features.

@psk200
Copy link

psk200 commented Mar 5, 2023

I'm using the below js v3 sdk version

"@aws-sdk/client-secrets-manager": "^3.14.0", "@aws-sdk/client-sts": "^3.282.0", "@aws-sdk/credential-provider-imds": "^3.272.0",

Environment : EKS Pod

EC2 - worker

aws ec2 modify-instance-metadata-options --instance-id <instance_id> --http-tokens required --http-endpoint enabled --http-put-response-hop-limit 1

Pod is getting the role
from service account
the complete process of assuming role to service account is followed from below link
https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html

This part of the code is assuming the pod role

        const command = new GetCallerIdentityCommand({});
        const data = await client1.send(command);
        console.log(":get_caller_identity:", data)

Response

:get_caller_identity: {
  '$metadata': {
    httpStatusCode: 200,
    requestId: 'requestId',
    extendedRequestId: undefined,
    cfId: undefined,
    attempts: 1,
    totalRetryDelay: 0
  },
  UserId: 'EXAMPLEID:aws-sdk-js-session-EXAMPLE_SESSION',
  Account: 'ACCOUNT_ID',
  Arn: 'arn:aws:sts::<ACCOUNT_ID>:assumed-role/<role_name_from_service_account>/aws-sdk-js-session-EXAMPLE_SESSION'
}
const client = new SecretsManagerClient({
          region: process.env.REGION,
        });
        response = await client.send(
          new GetSecretValueCommand({
            SecretId: process.env.APP_SECRET_NAME,
            VersionStage: "AWSCURRENT",
          })
        );

This above code returns the following response

 [ProviderError: Error response received from instance metadata service] {
  tryNextLink: true,
  statusCode: 401
}

Complete code snippet

const {
    SecretsManagerClient,
    GetSecretValueCommand,
  } = require("@aws-sdk/client-secrets-manager");
  
  const { STSClient, GetCallerIdentityCommand } = require("@aws-sdk/client-sts");
  
  
  const getSecret = async () => {
    return new Promise(async (resolve, reject) => {
  
      try {
        const client1 = new STSClient({ region: process.env.REGION});
        const command = new GetCallerIdentityCommand({});
        const data = await client1.send(command);
        console.log(":get_caller_identity:", data)
      } catch (error) {
        console.log("getting sts failed ")
        return reject(error);
      }
  
      let response;
  
      try {
        const client = new SecretsManagerClient({
          region: process.env.REGION,
        });
        response = await client.send(
          new GetSecretValueCommand({
            SecretId: process.env.APP_SECRET_NAME,
            VersionStage: "AWSCURRENT",
          })
        );
      } catch (error) {
        console.log("Secret fetching failed ", error)
        return reject(error);
      }
  
      const secret_string = response.SecretString;
  
      const secrets = JSON.parse(secret_string);
  
      
      resolve(secrets);
    })
  }
  
  module.exports = { getSecret };

@nwalters512
Copy link
Contributor Author

@psk200 that looks unrelated to this issue, which is specifically about making requests directly to the metadata service. As far as I can tell, your comment is just about obtaining credentials from the metadata service, which indeed works correctly. If you're experiencing any problems with that, please open a separate issue.

@jpike88
Copy link

jpike88 commented May 12, 2023

It's now over 2 months since the last comment. Is there an ETA on this?

What are the minimal changes I am supposed to make to the existing code above (#4004 (comment))?

@e920528
Copy link

e920528 commented May 18, 2023

+1

I have aborted the migration to v3 because of this -- it does not make sense to migrate all my clients but still keep aws-sdk v2 around solely for MetaDataService :(

Same here

@siddsriv siddsriv self-assigned this Jun 12, 2023
@nwalters512
Copy link
Contributor Author

I ultimately built and published a small package to make talking to IMDS easier: @prairielearn/aws-imds. Source and minimal documentation are available here: https://github.com/PrairieLearn/PrairieLearn/tree/master/packages/aws-imds

@sameer-hashflow
Copy link

Hi this is also blocking our migration to v3.

@jpike88
Copy link

jpike88 commented Aug 7, 2023

@RanVaknin I elaborated on the use case as requested back in February, and it's now almost 6 months later, in Q2 of 2023, when v2 is supposed to be dropped in favor of v3. Zero follow up, zero alternative method or code examples provided, just putting things off over and over. This is placing my team in an increasingly risky scenario as year end approaches, and I think that's it's fair that some sort of conclusion is brought to this issue.

If not, please tell me the appropriate person to escalate this issue to.

@siddsriv
Copy link
Contributor

Hi @nwalters512, could I ask you to clarify what exactly the "easy way to access information from the EC2 Instance Metadata Service" might look like for you? Are you specifically requesting a client that can access things like, say instanceID?
Would using a (possibly external) HTTP client in conjunction with the instancedata URL (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html) be satisfactory?

You mention credential-provider-imds has a lot of functionality that you might require, do you just want a straightforward exposure to a functionality specifically like fetching (like in the package you published) or is the requirement "make an arbitrary request to the IMDS" mean the request() method from v2 be ported to v3 as is?

@nwalters512
Copy link
Contributor Author

I don't want to prescribe any particular solution here. At a high level, I just don't want to have to worry about IMDS tokens: fetching, refreshing, TTLs, error handling, retries, etc. If that manifests as an almost-direct port of v2's request(), hopefully with Promise support, great! If you want to copy what Golang did and provide specific functions with well-defined return types like EC2Metadata.GetInstanceIdentityDocument, even better (though the JS SDK's stubborn insistence on typing everything as potentially undefined would make this less-useful than in Golang).

@andreaswittig
Copy link

Gone are the days when AWS focused on reducing undifferentiated heavy lifting. Today, AWS creates problems for us developers that we didn't have in the past.

hayemaxi added a commit to hayemaxi/aws-toolkit-vscode that referenced this issue Feb 1, 2024
Problem: We did not attach the token to IMDS calls, resulting in IMDSv1 being used. The SDK does support using tokens but only
for calls to the endpoint `/latest/meta-data/iam/security-credentials/`.
https://github.com/aws/aws-sdk-js/blob/3333f8b49283f5bbff823ab8a8469acedb7fe3d5/lib/metadata_service.js#L123-L235

Solution: Call the "private" sdk method to get the token so code isn't duplicated, and attach that in the header of our calls
just like the sdk does for the above endpoint.

AWS SDK v3 does not support token handling aws/aws-sdk-js-v3#4004
hayemaxi added a commit to hayemaxi/aws-toolkit-vscode that referenced this issue Feb 1, 2024
Problem: We did not attach the token to IMDS calls, resulting in IMDSv1 being used. The SDK does support using tokens but only
for calls to the endpoint `/latest/meta-data/iam/security-credentials/`.
https://github.com/aws/aws-sdk-js/blob/3333f8b49283f5bbff823ab8a8469acedb7fe3d5/lib/metadata_service.js#L123-L235

Solution: Call the "private" sdk method to get the token so code isn't duplicated, and attach that in the header of our calls
just like the sdk does for the above endpoint.

AWS SDK v3 does not support token handling aws/aws-sdk-js-v3#4004
hayemaxi added a commit to aws/aws-toolkit-vscode that referenced this issue Feb 2, 2024
* fix: use IMDSv2 for all metadata service calls.

Problem: We did not attach the token to IMDS calls, resulting in IMDSv1 being used. The SDK does support using tokens but only
for calls to the endpoint `/latest/meta-data/iam/security-credentials/`.
https://github.com/aws/aws-sdk-js/blob/3333f8b49283f5bbff823ab8a8469acedb7fe3d5/lib/metadata_service.js#L123-L235

Solution: Call the "private" sdk method to get the token so code isn't duplicated, and attach that in the header of our calls
just like the sdk does for the above endpoint.

AWS SDK v3 does not support token handling aws/aws-sdk-js-v3#4004

* add imdsv1 fallback and changelog
@RanVaknin RanVaknin added the queued This issues is on the AWS team's backlog label Feb 14, 2024
@kuhe kuhe added pending-release This issue will be fixed by an approved PR that hasn't been released yet. and removed queued This issues is on the AWS team's backlog labels Mar 20, 2024
@kuhe
Copy link
Contributor

kuhe commented Mar 20, 2024

@siddsriv has created https://www.npmjs.com/package/@aws-sdk/ec2-metadata-service.

import { MetadataService } from "@aws-sdk/ec2-metadata-service";

const metadataService = new MetadataService({
  ec2MetadataV1Disabled: true,
});
const token = await metadataService.fetchMetadataToken();
const metadata = await metadataService.request("/latest/meta-data/", {});

console.log({
  metadata,
});

@aBurmeseDev aBurmeseDev self-assigned this Mar 20, 2024
@aBurmeseDev
Copy link
Member

Hi @nwalters512 and everyone else on the thread!

Please check out the last comment where we created the package that provides utils to access EC2 Instance Metadata Service (IMDS).

Let us know if you have any questions!

@aBurmeseDev aBurmeseDev added response-requested Waiting on additional info and feedback. Will move to \"closing-soon\" in 7 days. and removed pending-release This issue will be fixed by an approved PR that hasn't been released yet. labels Mar 20, 2024
@nwalters512
Copy link
Contributor Author

@aBurmeseDev @kuhe this is great, thanks for getting this done! Unfortunately the package isn't being built/published correctly; the file dist-types/MetadataService.d.ts tries to read from dist-types/MetadataServiceOptions, which does not exist. This causes a build error for tsc in projects with "skipLibCheck": false in their tsconfig.json:

../../node_modules/@aws-sdk/ec2-metadata-service/dist-types/MetadataService.d.ts:1:40 - error TS2307: Cannot find module './MetadataServiceOptions' or its corresponding type declarations.

1 import { MetadataServiceOptions } from "./MetadataServiceOptions";
                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~


Found 1 error in ../../node_modules/@aws-sdk/ec2-metadata-service/dist-types/MetadataService.d.ts:1

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to \"closing-soon\" in 7 days. label Mar 21, 2024
@siddsriv
Copy link
Contributor

siddsriv commented Mar 21, 2024

thank you for reporting this, we just put a fix out that will be released later today. let us know if you encounter any other issues or have questions.

@aBurmeseDev aBurmeseDev added the response-requested Waiting on additional info and feedback. Will move to \"closing-soon\" in 7 days. label Mar 22, 2024
@sdenardi
Copy link

@aBurmeseDev @siddsriv Thank you for pushing this out!

Can you point me to the SDK docs for the package? All good if they're not out yet, didn't know if I wasn't looking in the right place.

@kuhe
Copy link
Contributor

kuhe commented Mar 22, 2024

https://www.npmjs.com/package/@aws-sdk/ec2-metadata-service has basic instructions on how to make a request, which is most of what the package does.

You can then use the general documentation for IMDS https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html and take the URLs in those and input them to the JavaScript package for the same effect.

@siddsriv siddsriv added the closing-soon This issue will automatically close in 4 days unless further comments are made. label Mar 22, 2024
@github-actions github-actions bot added closed-for-staleness and removed closing-soon This issue will automatically close in 4 days unless further comments are made. labels Mar 27, 2024
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
closed-for-staleness feature-request New feature or enhancement. May require GitHub community feedback. p2 This is a standard priority issue response-requested Waiting on additional info and feedback. Will move to \"closing-soon\" in 7 days.
Projects
None yet
Development

No branches or pull requests