AmazonSQSClient не обновляет AWSCredentials при обновлении файла учетных данных - PullRequest
0 голосов
/ 21 января 2019

Когда мой файл учетных данных AWS ( см. Документы ) обновляется внешним процессом, AmazonSQSClient не перечитывает его, SendMessageAsync завершается ошибкой с ошибкой безопасности / токена.

Мы используем пользовательский сценарий powershell для периодического обновления локального файла кредита AWS. Сценарий работает нормально, файл обновляется до истечения срока действия учетных данных на AWS. Однако если мое приложение работает при обновлении файла, новые учетные данные не перечитываются из файла, «клиент» покажет, что предыдущие учетные данные все еще используются.

В AWS документы перечислены несколько провайдеров AWSCredential, но ни один из них не является правильным выбором ... Я думаю ..

Перезапуск приложения работает, новые учетные данные считываются правильно, а сообщения отправляются до следующего обновления файла cred.

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

Ответы [ 2 ]

0 голосов
/ 22 января 2019

Следующее работает "хорошо", но я проверил его только с одним профилем, а средство просмотра файлов не так своевременно, как вам бы хотелось, поэтому я рекомендую вам обернуть его использование внутри механизма Retry.

// 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;
        }
    }
}
0 голосов
/ 21 января 2019

Я не думаю, что у запущенного приложения есть способ выбрать учетные данные по умолчанию, которые обновляются в файле учетных данных.Существует решение для загрузки учетных данных Node.js из файла JSON .Вы можете создать аналогичное решение в C #.Вы также можете запустить локальную БД для хранения учетных данных, чтобы при каждом обновлении файла учетных данных обновлялась таблица БД или файл JSON.Вам нужно будет использовать access key и secret key в конструкторе клиента SQS, а не использовать учетные данные по умолчанию.

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