更新凭证文件时,AmazonSQSClient不刷新AWSCredentials

时间:2019-01-21 18:39:50

标签: c# amazon-web-services amazon-sqs credentials

当我的AWS凭证文件(see docs)由外部流程更新时,AmazonSQSClient不重新读取它,SendMessageAsync失败,并显示安全/令牌错误。

我们使用定制的powershell脚本定期刷新本地AWS cred的文件。脚本运行良好,在凭证在AWS上到期之前刷新了文件。但是,如果刷新文件后我的应用程序正在运行,则不会从文件中重新读取新的凭据,“客户端”将显示以前的凭据仍在使用中。

AWS docs列出了几个AWSCredential提供程序,但似乎都不是正确的选择... 我认为..

重新启动该应用程序即可正常工作,可以正确读取新凭据并发送消息,直到下次更新cred的文件为止。

using (var client = new AmazonSQSClient(Amazon.RegionEndpoint.EUWest1))
{
    return client.SendMessageAsync(request);
}

2 个答案:

答案 0 :(得分:0)

我不认为正在运行的应用程序有办法获取凭证文件中刷新的默认凭证。有一个针对Node.js loading credentials from a JSON file的解决方案。您可以在C#中创建类似的解决方案。您还可以运行本地数据库来存储凭据,以便每当凭据文件更新时,数据库表或JSON文件也会更新。您将需要在SQS客户端构造函数中使用access keysecret key,而不是使用默认凭据。

// Load these from JSON file or DB.
var accessKey = "";
var secretKey = "";

using (var client = new AmazonSQSClient(accessKey, secretKey, Amazon.RegionEndpoint.EUWest1))
{
    return client.SendMessageAsync(request);
}

答案 1 :(得分:0)

以下方法可以“正常”运行,但我仅使用一个配置文件对其进行了测试,并且文件监视程序的运行时间不如您所愿,因此建议您将使用情况包装在重试机制中。

// Usage..
var credentials = new AwsCredentialsFile();
using (var client = new AmazonSQSClient(credentials, Amazon.RegionEndpoint.EUWest1))
{
    return client.SendMessageAsync(request);
}

public class AwsCredentialsFile : AWSCredentials
{
    // https://docs.aws.amazon.com/sdk-for-net/v2/developer-guide/net-dg-config-creds.html#creds-file

    private const string DefaultProfileName = "default";

    private static ConcurrentDictionary<string, ImmutableCredentials> _credentials = new ConcurrentDictionary<string, ImmutableCredentials>(StringComparer.OrdinalIgnoreCase);

    private static FileSystemWatcher _watcher = BuildFileSystemWatcher();

    private readonly System.Text.Encoding _encoding;

    private readonly string _profileName;

    public AwsCredentialsFile()
        : this(AwsCredentialsFile.DefaultProfileName, System.Text.Encoding.UTF8)
    {
    }

    public AwsCredentialsFile(string profileName)
        : this(profileName, System.Text.Encoding.UTF8)
    {
    }

    public AwsCredentialsFile(string profileName, System.Text.Encoding encoding)
    {
        _profileName = profileName;
        _encoding = encoding;
    }

    private static FileSystemWatcher BuildFileSystemWatcher()
    {
        var watcher = new FileSystemWatcher
        {
            Path = Path.GetDirectoryName(GetDefaultCredentialsFilePath()),
            NotifyFilter = NotifyFilters.LastWrite,
            Filter = "credentials"
        };
        watcher.Changed += (object source, FileSystemEventArgs e) => { _credentials?.Clear(); };
        watcher.EnableRaisingEvents = true;
        return watcher;
    }

    public static string GetDefaultCredentialsFilePath()
    {
        return System.Environment.ExpandEnvironmentVariables(@"C:\Users\%USERNAME%\.aws\credentials");
    }

    public static (string AccessKey, string SecretAccessKey, string Token) ReadCredentialsFromFile(string profileName, System.Text.Encoding encoding)
    {
        var profile = $"[{profileName}]";
        string awsAccessKeyId = null;
        string awsSecretAccessKey = null;
        string token = null;

        var lines = File.ReadAllLines(GetDefaultCredentialsFilePath(), encoding);

        for (int i = 0; i < lines.Length; i++)
        {
            var text = lines[i];
            if (text.Equals(profile, StringComparison.OrdinalIgnoreCase))
            {
                awsAccessKeyId = lines[i + 1].Replace("aws_access_key_id = ", string.Empty);
                awsSecretAccessKey = lines[i + 2].Replace("aws_secret_access_key = ", string.Empty);

                if (lines.Length >= i + 3)
                {
                    token = lines[i + 3].Replace("aws_session_token = ", string.Empty);
                }

                break;
            }
        }

        var result = (AccessKey: awsAccessKeyId, SecretAccessKey: awsSecretAccessKey, Token: token);
        return result;
    }

    public override ImmutableCredentials GetCredentials()
    {
        if (_credentials.TryGetValue(_profileName, out ImmutableCredentials value))
        {
            return value;
        }
        else
        {
            var (AccessKey, SecretAccessKey, Token) = ReadCredentialsFromFile(_profileName, _encoding);
            var credentials = new ImmutableCredentials(AccessKey, SecretAccessKey, Token);
            _credentials.TryAdd(_profileName, credentials);
            return credentials;
        }
    }
}