Skip to content

Instantly share code, notes, and snippets.

@emeraldsanto
Last active June 26, 2024 16:09
Show Gist options
  • Save emeraldsanto/76c371e2a10d663baf92f82f9590bb1e to your computer and use it in GitHub Desktop.
Save emeraldsanto/76c371e2a10d663baf92f82f9590bb1e to your computer and use it in GitHub Desktop.
Presign an AWS STS GetCallerIdentity request for later use, adapted to JavaScript from https://donchev.is/post/aws-lambda-invoker-identification
import { defaultProvider } from "@aws-sdk/credential-provider-node";
import { HttpRequest } from "@aws-sdk/protocol-http";
import { Sha256 } from '@aws-crypto/sha256-js';
import { SignatureV4 } from "@aws-sdk/signature-v4";
import { stringify } from "qs";
async function main(): Promise<string> {
const signer = new SignatureV4({
credentials: defaultProvider(),
region: process.env.AWS_REGION,
service: "sts",
sha256: Sha256,
});
const host = `sts.${process.env.AWS_REGION}.amazonaws.com`;
const req = new HttpRequest({
headers: {
'Content-Type': 'application/json',
host
},
hostname: host,
method: "GET",
path: '/',
query: {
Action: 'GetCallerIdentity',
Version: '2011-06-15',
},
});
const signed = await signer.presign(req, { expiresIn: 60 * 10 });
return `https://${signed.hostname}${signed.path}?${stringify(signed.query)}`;
}
main()
.then((output) => console.log(output))
.catch((e) => console.log(e));
@adamjarret
Copy link

Thanks for this, it saved me some time! I made a few tweaks for my use case:

  • use fromNodeProviderChain for credentials to support all the same mechanisms as the AWS CLI
  • switched to non-deprecated @smithy/... packages
  • switched to the native querystring library built into node

presign-sts-get-caller-identity.mjs

import { Sha256 } from '@aws-crypto/sha256-js';
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
import { HttpRequest } from '@smithy/protocol-http';
import { SignatureV4 } from '@smithy/signature-v4';
import { stringify } from 'querystring';

/**
 * Return a presigned URL that can be used to invoke STS GetCallerIdentity
 * with the credentials that were used to sign the URL.
 *
 * @param {string} region - AWS region (default: us-east-1)
 * @returns {Promise<string>}
 */
async function presignGetCallerIdentity(region = 'us-east-1') {
  const signer = new SignatureV4({
    credentials: fromNodeProviderChain(),
    region,
    service: 'sts',
    sha256: Sha256,
  });

  const host = `sts.${region}.amazonaws.com`;

  const req = new HttpRequest({
    headers: {
      'Content-Type': 'application/json',
      host,
    },
    hostname: host,
    method: 'GET',
    path: '/',
    query: {
      Action: 'GetCallerIdentity',
      Version: '2011-06-15',
    },
  });

  const { hostname, path, query } = await signer.presign(req, { expiresIn: 60 * 10 });

  return `https://${hostname}${path}?${stringify(query)}`;
}

console.log(await presignGetCallerIdentity(process.env.AWS_REGION));

Usage example with curl:

curl -H 'Content-Type: application/json' -H 'host: sts.us-east-1.amazonaws.com' $(node presign-sts-get-caller-identity.mjs)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment