ホーム > 未分類 > 設定ファイル、環境変数、AWSSecretsManagerに定義された設定値を透過的に扱う

設定ファイル、環境変数、AWSSecretsManagerに定義された設定値を透過的に扱う


ASP.NET Coreでは 環境変数と設定ファイルの値を両方から取得し、IWebHost構築時にConfigurationに定義した優先度で設定値をマージして利用する。

Kralizerk.Extensions.Configuration.AWSSecretsManager ( https://github.com/Kralizek/AWSSecretsManagerConfigurationExtensions )を利用すると、上記に加えAWS SecretsManagerのエントリも環境変数やJSONファイルと同列に扱うことができ、設定値をセキュアに運用することができる。

方針と設定情報の構築

下記の設定では appSettings.jsonappSettings.Development.json(ASPNETCORE_ENVIRONMENTに依存)⇒環境変数 ⇒SecretsManagerの順に設定値を読み込み、後に定義された値を優先して利用する。SecretsManagerは環境変数SECRETSMANAGER_PREFIXDev/App1のように定義すると、Dev/App1/Secrets1Dev/App1/Secrets1といったキーのシークレット情報を取得できるようになる。

AWSが提供するSDKを利用する場合、ServiceCollection構築時にAddDefaultAWSOptionsを指定するとAWS:Regionの設定を考慮してRegionをライブラリに設定してくれるのだが、Kralizerk.Extensions.Configuration.AWSSecretsManagerでは読み込んでくれなかったので、環境変数AWS__Regionから明示的にRegionを取得している。
また、ローカル開発時に、無駄にSecretsManagerから値をとらないように、前述した環境変数SECRETSMANAGER_PREFIXが定義されていない場合は、SecretsManagerから値を取得しないといった小細工を入れている。

        public static IWebHost CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                    {
                        var env = hostingContext.HostingEnvironment.EnvironmentName;
                        config.SetBasePath(Directory.GetCurrentDirectory());
                        config.AddJsonFile("appSettings.json");
                        config.AddJsonFile($"appSettings.{env}.json", optional: true);

                        config.AddEnvironmentVariables();

                        var region = Environment.GetEnvironmentVariable("AWS__Region");
                        if (string.IsNullOrEmpty(region))
                        {
                            region = "ap-northeast-1";
                        }
                        var secretsManagerPrefix = Environment.GetEnvironmentVariable("SECRETSMANAGER_PREFIX");
                        if (!string.IsNullOrEmpty(secretsManagerPrefix))
                        {
                            config.AddSecretsManager(
                                region: RegionEndpoint.GetBySystemName(region),
                                configurator: cfg =>
                                {
                                    cfg.KeyGenerator = (entry, key) =>
                                    {
                                        var customKey = key.Substring(entry.Name.Length).Trim(':').Trim();
                                        return string.IsNullOrEmpty(customKey) ? key : customKey;
                                    };
                                    cfg.SecretFilter = entry => entry.Name.StartsWith(secretsManagerPrefix);
                                });
                        }
                    })
                .UseStartup()
                .Build();

値の設定例

例えば、それぞれ下記のように定義されていた場合
appSettings.json

{
  "Section1": {
    "Value1": "Value1",
    "Value2": "Value2",
    "Value3": "Value3",
    "Value4": "Value4",
    "Value5": "Value5"
  }
}

appSettings.Development.json

{
  "Section1": {
    "Value2": "from appSettings.Development.json",
  }
}

環境変数.sh

export Section1__Value3=fromEnvironment

SecretsManager Dev/App1/Secrets1

{
  "Section1": {
    "Value4": "from Dev/App1/Secrets1"
  }
}

SecretsManager Dev/App1/Secrets2

{
  "Section1": {
    "Value5": "from Dev/App1/Secrets2"
  }
}

実行結果

下記の結果で出力される値は次のようになる。

    public partial class App
    {
        public IConfiguration Configuration { get; }

        public App(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public void Run()
        {
            Console.WriteLine(Configuration.GetValue("Section1:Value1");
            Console.WriteLine(Configuration.GetValue("Section1:Value2");
            Console.WriteLine(Configuration.GetValue("Section1:Value3");
            Console.WriteLine(Configuration.GetValue("Section1:Value4");
            Console.WriteLine(Configuration.GetValue("Section1:Value5");
        }
    }

実行結果

Value1
from appSettings.Development.json
fromEnvironment
from Dev/App1/Secrets1
from Dev/App1/Secrets2

AWS で必要となるポリシー

Kralizerk.Extensions.Configuration.AWSSecretsManagerはSecretFilterで与えられたキーをSecretsManagerから検索して列挙するため、AWSのポリシーとしてsecretsmanager:ListSecretsとGetSecretValueの二つが必要になる。
これらのポリシーが無いロールで実行しようとした場合、下記のような例外メッセージが表示される。

Unhandled Exception: Amazon.SecretsManager.AmazonSecretsManagerException: User: arn:aws:sts::571419068914:assumed-role/EcsLinuxClusterInstance-Stg-EcsInstanceRole-16ODQN6YR1TPC/i-0159b6dc3deb1e536 is not authorized to perform: secretsmanager:ListSecrets —> Amazon.Runtime.Internal.HttpErrorResponseException: Exception of type ‘Amazon.Runtime.Internal.HttpErrorResponseException’ was thrown.

カテゴリー:未分類
  1. まだコメントはありません。
  1. No trackbacks yet.

コメントを残す