Skip to content

Instantly share code, notes, and snippets.

@DTTerastar
Created June 15, 2020 15:07
Show Gist options
  • Save DTTerastar/f373bb6dbfc8d1437665f7b23e0a2cbb to your computer and use it in GitHub Desktop.
Save DTTerastar/f373bb6dbfc8d1437665f7b23e0a2cbb to your computer and use it in GitHub Desktop.
Fixed implementation of InstanceProfileAwsCredentials
internal class FixedInstanceProfileAwsCredentials : AWSCredentials, IDisposable
{
private static readonly Lazy<FixedInstanceProfileAwsCredentials> InstanceLazy = new Lazy<FixedInstanceProfileAwsCredentials>(() => new FixedInstanceProfileAwsCredentials());
private readonly Task _credentialsRetrieverTimer;
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
private bool _disposed;
private ImmutableCredentials _lastRetrievedCredentials;
private FixedInstanceProfileAwsCredentials()
{
_credentialsRetrieverTimer = Task.Run(async () =>
{
while (!_disposed)
try
{
_lastRetrievedCredentials = FetchCredentials();
await Task.Delay(RefreshRate);
}
catch (Exception ex)
{
Log.Error(ex, "Error in RenewCredentials");
await Task.Delay(ErrorRefreshRate);
}
});
}
private static TimeSpan ErrorRefreshRate { get; } = TimeSpan.FromSeconds(5);
private static TimeSpan RefreshRate { get; } = TimeSpan.FromMinutes(15);
public static FixedInstanceProfileAwsCredentials Instance => InstanceLazy.Value;
public void Dispose()
{
_disposed = true;
_credentialsRetrieverTimer.GetAwaiter().GetResult();
}
/// <summary>
/// Returns a copy of the most recent instance profile credentials.
/// </summary>
public override ImmutableCredentials GetCredentials()
{
return GetCredentialsAsync().GetAwaiter().GetResult();
}
/// <summary>
/// Returns a copy of the most recent instance profile credentials.
/// </summary>
public override async Task<ImmutableCredentials> GetCredentialsAsync()
{
if (!EC2InstanceMetadata.IsIMDSEnabled) throw new AmazonServiceException("Unable to retrieve credentials.");
var immutableCredentials = _lastRetrievedCredentials?.Copy();
if (immutableCredentials != null) return immutableCredentials;
await _semaphore.WaitAsync();
try
{
immutableCredentials = _lastRetrievedCredentials?.Copy();
if (immutableCredentials != null) return immutableCredentials;
return _lastRetrievedCredentials = FetchCredentials();
}
finally
{
_semaphore.Release();
}
}
private ImmutableCredentials FetchCredentials()
{
Log.Debug("Fetching Credentials");
var securityCredentials = EC2InstanceMetadata.IAMSecurityCredentials;
if (securityCredentials == null)
throw new AmazonServiceException("Unable to get IAM security credentials from EC2 Instance Metadata Service.");
var index = securityCredentials.Keys.FirstOrDefault();
if (string.IsNullOrEmpty(index))
throw new AmazonServiceException("Unable to get EC2 instance role from EC2 Instance Metadata Service.");
var credentialMetadata = securityCredentials[index];
if (credentialMetadata == null) throw new AmazonServiceException("Unable to get credentials for role \"" + index + "\" from EC2 Instance Metadata Service.");
return new ImmutableCredentials(credentialMetadata.AccessKeyId, credentialMetadata.SecretAccessKey, credentialMetadata.Token);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment