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

AmazonSQSClient not refreshing AWSCredentials when Credentials File is updated

当我的 AWS 凭证文件 (see docs) 被外部进程更新时,AmazonSQSClient 没有重新读取它,SendMessageAsync 失败并出现 security/token 错误。

我们使用自定义 powershell 脚本定期刷新本地 AWS cred 的文件。该脚本工作正常,文件在 AWS 上的凭证到期之前刷新。但是,如果我的应用程序是 运行,当文件被刷新时,新的凭据不会从文件中重新读取,"client" 将显示以前的凭据仍在使用中。

AWS docs 列出了几个 AWSCredential 提供商,但其中 none 似乎是正确的选择...我认为..

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

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

我认为 运行ning 应用程序无法获取在凭据文件中刷新的默认凭据。 Node.js loading credentials from a JSON file 有一个解决方案。您可以在 C# 中创建类似的解决方案。您还可以 运行 本地数据库来存储凭据,因此每当更新凭据文件时,数据库 table 或 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);
}

下面的工作 "ok" 但我只用一个配置文件测试过它,文件观察器没有你想要的那么及时,所以我建议你将你的使用包装在重试机制中。

// 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;
        }
    }
}