/// <summary> /// Fetches the api token to use with metadata requests. /// </summary> /// <param name="tries">The number of tries to fetch the api token before giving up and throwing the web exception</param> /// <returns>The API token or null if an API token couldn't be obtained and doesn't need to be used</returns> private static string FetchApiToken(int tries) { for (int retry = 1; retry <= tries; retry++) { if (!IsIMDSEnabled || useNullToken) { return(null); } try { var uriForToken = new Uri(EC2_APITOKEN_URL); var headers = new Dictionary <string, string>(); headers.Add(HeaderKeys.XAwsEc2MetadataTokenTtlSeconds, DEFAULT_APITOKEN_TTL.ToString(CultureInfo.InvariantCulture)); var content = AWSSDKUtils.ExecuteHttpRequest(uriForToken, "PUT", null, TimeSpan.FromSeconds(5), Proxy, headers); return(content.Trim()); } catch (Exception e) { HttpStatusCode?httpStatusCode = ExceptionUtils.DetermineHttpStatusCode(e); if (httpStatusCode == HttpStatusCode.NotFound || httpStatusCode == HttpStatusCode.MethodNotAllowed || httpStatusCode == HttpStatusCode.Forbidden) { useNullToken = true; return(null); } if (retry >= tries) { if (httpStatusCode == HttpStatusCode.BadRequest) { Logger.GetLogger(typeof(EC2InstanceMetadata)).Error(e, "Unable to contact EC2 Metadata service to obtain a metadata token."); throw; } Logger.GetLogger(typeof(EC2InstanceMetadata)).Error(e, "Unable to contact EC2 Metadata service to obtain a metadata token. Attempting to access IMDS without a token."); //If there isn't a status code, it was a failure to contact the server which would be //a request failure, a network issue, or a timeout. Cache this response and fallback //to IMDS flow without a token. If the non token IMDS flow returns unauthorized, the //useNullToken flag will be cleared and the IMDS flow will attempt to obtain another //token. if (httpStatusCode == null) { useNullToken = true; } //Return null to fallback to the IMDS flow without using a token. return(null); } PauseExponentially(retry - 1); } } return(null); }
protected override CredentialsRefreshState GenerateNewCredentials() { CredentialsRefreshState newState = null; var token = EC2InstanceMetadata.FetchApiToken(); try { // Attempt to get early credentials. OK to fail at this point. newState = GetRefreshState(token); } catch (Exception e) { HttpStatusCode?httpStatusCode = ExceptionUtils.DetermineHttpStatusCode(e); if (httpStatusCode == HttpStatusCode.Unauthorized) { EC2InstanceMetadata.ClearTokenFlag(); Logger.GetLogger(typeof(EC2InstanceMetadata)).Error(e, "EC2 Metadata service returned unauthorized for token based secure data flow."); throw; } var logger = Logger.GetLogger(typeof(InstanceProfileAWSCredentials)); logger.InfoFormat("Error getting credentials from Instance Profile service: {0}", e); } // If successful, save new credentials if (newState != null) { _currentRefreshState = newState; } // If still not successful (no credentials available at start), attempt once more to // get credentials, but now without swallowing exception if (_currentRefreshState == null) { try { _currentRefreshState = GetRefreshState(token); } catch (Exception e) { HttpStatusCode?httpStatusCode = ExceptionUtils.DetermineHttpStatusCode(e); if (httpStatusCode == HttpStatusCode.Unauthorized) { EC2InstanceMetadata.ClearTokenFlag(); Logger.GetLogger(typeof(EC2InstanceMetadata)).Error(e, "EC2 Metadata service returned unauthorized for token based secure data flow."); } throw; } } // Return credentials that will expire in at most one hour CredentialsRefreshState state = GetEarlyRefreshState(_currentRefreshState); return(state); }
/// <summary> /// Retrieves a list of all roles available through current InstanceProfile service /// </summary> /// <returns></returns> public static IEnumerable <string> GetAvailableRoles(IWebProxy proxy) { var token = EC2InstanceMetadata.FetchApiToken(); var allAliases = string.Empty; try { allAliases = GetContents(RolesUri, proxy, CreateMetadataTokenHeaders(token)); } catch (Exception e) { HttpStatusCode?httpStatusCode = ExceptionUtils.DetermineHttpStatusCode(e); if (httpStatusCode == HttpStatusCode.Unauthorized) { EC2InstanceMetadata.ClearTokenFlag(); Logger.GetLogger(typeof(EC2InstanceMetadata)).Error(e, "EC2 Metadata service returned unauthorized for token based secure data flow."); } throw; } if (string.IsNullOrEmpty(allAliases)) { yield break; } string[] parts = allAliases.Split(AliasSeparators, StringSplitOptions.RemoveEmptyEntries); foreach (var part in parts) { var trim = part.Trim(); if (!string.IsNullOrEmpty(trim)) { yield return(trim); } } }
private static List <string> GetItems(string relativeOrAbsolutePath, int tries, bool slurp, string token) { var items = new List <string>(); //For all meta-data queries we need to fetch an api token to use. In the event a //token cannot be obtained we will fallback to not using a token. Dictionary <string, string> headers = null; if (token == null) { token = FetchApiToken(DEFAULT_RETRIES); } if (!string.IsNullOrEmpty(token)) { headers = new Dictionary <string, string>(); headers.Add(HeaderKeys.XAwsEc2MetadataToken, token); } try { if (!IsIMDSEnabled) { throw new IMDSDisabledException(); } // if we are given a relative path, we assume the data we need exists under the // main metadata root var uri = relativeOrAbsolutePath.StartsWith(EC2_METADATA_SVC, StringComparison.Ordinal) ? new Uri(relativeOrAbsolutePath) : new Uri(EC2_METADATA_ROOT + relativeOrAbsolutePath); var content = AWSSDKUtils.ExecuteHttpRequest(uri, "GET", null, TimeSpan.FromSeconds(5), Proxy, headers); using (var stream = new StringReader(content)) { if (slurp) { items.Add(stream.ReadToEnd()); } else { string line; do { line = stream.ReadLine(); if (line != null) { items.Add(line.Trim()); } }while (line != null); } } } catch (IMDSDisabledException) { // Keep this behavior identical to when HttpStatusCode.NotFound is returned. return(null); } catch (Exception e) { HttpStatusCode?httpStatusCode = ExceptionUtils.DetermineHttpStatusCode(e); if (httpStatusCode == HttpStatusCode.NotFound) { return(null); } else if (httpStatusCode == HttpStatusCode.Unauthorized) { ClearTokenFlag(); Logger.GetLogger(typeof(EC2InstanceMetadata)).Error(e, "EC2 Metadata service returned unauthorized for token based secure data flow."); throw; } if (tries <= 1) { Logger.GetLogger(typeof(EC2InstanceMetadata)).Error(e, "Unable to contact EC2 Metadata service."); return(null); } PauseExponentially(DEFAULT_RETRIES - tries); return(GetItems(relativeOrAbsolutePath, tries - 1, slurp, token)); } return(items); }
protected override CredentialsRefreshState GenerateNewCredentials() { CredentialsRefreshState newState = null; var token = EC2InstanceMetadata.FetchApiToken(); try { // Attempt to get early credentials. OK to fail at this point. newState = GetRefreshState(token); } catch (Exception e) { HttpStatusCode?httpStatusCode = ExceptionUtils.DetermineHttpStatusCode(e); if (httpStatusCode == HttpStatusCode.Unauthorized) { EC2InstanceMetadata.ClearTokenFlag(); Logger.GetLogger(typeof(EC2InstanceMetadata)).Error(e, "EC2 Metadata service returned unauthorized for token based secure data flow."); throw; } var logger = Logger.GetLogger(typeof(InstanceProfileAWSCredentials)); logger.InfoFormat("Error getting credentials from Instance Profile service: {0}", e); // if we already have cached credentials, we'll continue to use those credentials, // but try again to refresh them in 2 minutes. if (null != _currentRefreshState) { #pragma warning disable CS0612 // Type or member is obsolete var newExpiryTime = AWSSDKUtils.CorrectedUtcNow.ToLocalTime() + TimeSpan.FromMinutes(2); #pragma warning restore CS0612 // Type or member is obsolete _currentRefreshState = new CredentialsRefreshState(_currentRefreshState.Credentials.Copy(), newExpiryTime); return(_currentRefreshState); } } if (newState?.IsExpiredWithin(TimeSpan.Zero) == true) { // special case - credentials returned are expired _logger.InfoFormat(_receivedExpiredCredentialsFromIMDS); // use a custom refresh time #pragma warning disable CS0612 // Type or member is obsolete var newExpiryTime = AWSSDKUtils.CorrectedUtcNow.ToLocalTime() + TimeSpan.FromMinutes(new Random().Next(5, 16)); #pragma warning restore CS0612 // Type or member is obsolete _currentRefreshState = new CredentialsRefreshState(newState.Credentials.Copy(), newExpiryTime); return(_currentRefreshState); } // If successful, save new credentials if (newState != null) { _currentRefreshState = newState; } // If still not successful (no credentials available at start), attempt once more to // get credentials, but now without swallowing exception if (_currentRefreshState == null) { try { _currentRefreshState = GetRefreshState(token); } catch (Exception e) { HttpStatusCode?httpStatusCode = ExceptionUtils.DetermineHttpStatusCode(e); if (httpStatusCode == HttpStatusCode.Unauthorized) { EC2InstanceMetadata.ClearTokenFlag(); Logger.GetLogger(typeof(EC2InstanceMetadata)).Error(e, "EC2 Metadata service returned unauthorized for token based secure data flow."); } throw; } } // Return credentials that will expire in at most one hour CredentialsRefreshState state = GetEarlyRefreshState(_currentRefreshState); return(state); }