"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.fromInstanceMetadata = void 0; const node_config_provider_1 = require("@smithy/node-config-provider"); const property_provider_1 = require("@smithy/property-provider"); const InstanceMetadataV1FallbackError_1 = require("./error/InstanceMetadataV1FallbackError"); const httpRequest_1 = require("./remoteProvider/httpRequest"); const ImdsCredentials_1 = require("./remoteProvider/ImdsCredentials"); const RemoteProviderInit_1 = require("./remoteProvider/RemoteProviderInit"); const retry_1 = require("./remoteProvider/retry"); const getInstanceMetadataEndpoint_1 = require("./utils/getInstanceMetadataEndpoint"); const staticStabilityProvider_1 = require("./utils/staticStabilityProvider"); const IMDS_PATH = "/latest/meta-data/iam/security-credentials/"; const IMDS_TOKEN_PATH = "/latest/api/token"; const AWS_EC2_METADATA_V1_DISABLED = "AWS_EC2_METADATA_V1_DISABLED"; const PROFILE_AWS_EC2_METADATA_V1_DISABLED = "ec2_metadata_v1_disabled"; const X_AWS_EC2_METADATA_TOKEN = "x-aws-ec2-metadata-token"; const fromInstanceMetadata = (init = {}) => (0, staticStabilityProvider_1.staticStabilityProvider)(getInstanceImdsProvider(init), { logger: init.logger }); exports.fromInstanceMetadata = fromInstanceMetadata; const getInstanceImdsProvider = (init) => { let disableFetchToken = false; const { logger, profile } = init; const { timeout, maxRetries } = (0, RemoteProviderInit_1.providerConfigFromInit)(init); const getCredentials = async (maxRetries, options) => { var _a; const isImdsV1Fallback = disableFetchToken || ((_a = options.headers) === null || _a === void 0 ? void 0 : _a[X_AWS_EC2_METADATA_TOKEN]) == null; if (isImdsV1Fallback) { let fallbackBlockedFromProfile = false; let fallbackBlockedFromProcessEnv = false; const configValue = await (0, node_config_provider_1.loadConfig)({ environmentVariableSelector: (env) => { const envValue = env[AWS_EC2_METADATA_V1_DISABLED]; fallbackBlockedFromProcessEnv = !!envValue && envValue !== "false"; if (envValue === undefined) { throw new property_provider_1.CredentialsProviderError(`${AWS_EC2_METADATA_V1_DISABLED} not set in env, checking config file next.`); } return fallbackBlockedFromProcessEnv; }, configFileSelector: (profile) => { const profileValue = profile[PROFILE_AWS_EC2_METADATA_V1_DISABLED]; fallbackBlockedFromProfile = !!profileValue && profileValue !== "false"; return fallbackBlockedFromProfile; }, default: false, }, { profile, })(); if (init.ec2MetadataV1Disabled || configValue) { const causes = []; if (init.ec2MetadataV1Disabled) causes.push("credential provider initialization (runtime option ec2MetadataV1Disabled)"); if (fallbackBlockedFromProfile) causes.push(`config file profile (${PROFILE_AWS_EC2_METADATA_V1_DISABLED})`); if (fallbackBlockedFromProcessEnv) causes.push(`process environment variable (${AWS_EC2_METADATA_V1_DISABLED})`); throw new InstanceMetadataV1FallbackError_1.InstanceMetadataV1FallbackError(`AWS EC2 Metadata v1 fallback has been blocked by AWS SDK configuration in the following: [${causes.join(", ")}].`); } } const imdsProfile = (await (0, retry_1.retry)(async () => { let profile; try { profile = await getProfile(options); } catch (err) { if (err.statusCode === 401) { disableFetchToken = false; } throw err; } return profile; }, maxRetries)).trim(); return (0, retry_1.retry)(async () => { let creds; try { creds = await getCredentialsFromProfile(imdsProfile, options); } catch (err) { if (err.statusCode === 401) { disableFetchToken = false; } throw err; } return creds; }, maxRetries); }; return async () => { const endpoint = await (0, getInstanceMetadataEndpoint_1.getInstanceMetadataEndpoint)(); if (disableFetchToken) { logger === null || logger === void 0 ? void 0 : logger.debug("AWS SDK Instance Metadata", "using v1 fallback (no token fetch)"); return getCredentials(maxRetries, { ...endpoint, timeout }); } else { let token; try { token = (await getMetadataToken({ ...endpoint, timeout })).toString(); } catch (error) { if ((error === null || error === void 0 ? void 0 : error.statusCode) === 400) { throw Object.assign(error, { message: "EC2 Metadata token request returned error", }); } else if (error.message === "TimeoutError" || [403, 404, 405].includes(error.statusCode)) { disableFetchToken = true; } logger === null || logger === void 0 ? void 0 : logger.debug("AWS SDK Instance Metadata", "using v1 fallback (initial)"); return getCredentials(maxRetries, { ...endpoint, timeout }); } return getCredentials(maxRetries, { ...endpoint, headers: { [X_AWS_EC2_METADATA_TOKEN]: token, }, timeout, }); } }; }; const getMetadataToken = async (options) => (0, httpRequest_1.httpRequest)({ ...options, path: IMDS_TOKEN_PATH, method: "PUT", headers: { "x-aws-ec2-metadata-token-ttl-seconds": "21600", }, }); const getProfile = async (options) => (await (0, httpRequest_1.httpRequest)({ ...options, path: IMDS_PATH })).toString(); const getCredentialsFromProfile = async (profile, options) => { const credsResponse = JSON.parse((await (0, httpRequest_1.httpRequest)({ ...options, path: IMDS_PATH + profile, })).toString()); if (!(0, ImdsCredentials_1.isImdsCredentials)(credsResponse)) { throw new property_provider_1.CredentialsProviderError("Invalid response received from instance metadata service."); } return (0, ImdsCredentials_1.fromImdsCredentials)(credsResponse); };