AWS スイッチ先(他アカウント)のサービスを制御

#目的
 * ソースにアクセスキーを書かない
 * ローカルにセキュリティキーをそのまま置かない　<- 開発環境
 * スイッチ先のRDSに接続したい、S3のデータを取りたい ...


#プロフィール準備
ローカルまたは運用サーバにAWS1のUSERのプロフィールを作成
（ECSのようなサーバレスは環境変数にSSMを利用）

STS(Security Token Service)を使用してスイッチ先のクレデンシャル取得

### クレデンシャル取得フロー
AWS1(IAM USER) -> スイッチ先：AWS{2-N}(IAM ROLE)

# IAM
## AWS1 IAM USER
arn:aws:iam::012345678:user/aspnet
ポリシー

```bash
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRole"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```

## スイッチ先 IAM Role
arn:aws:iam::123456789:role/aspnet
信頼関係

```bash
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::012345678:user/aspnet",
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

# 例）.NET Application

## プロファイル追加

```PowerShell
Set-AWSCredentials -AccessKey XXXXX -SecretKey XXXXX -StoreAs aspnet -ProfileLocation C:\workspace\ps1\credentials
```

## app.config

```xml
<appSettings>
  <add key="AwsRoleArnBaseProfile" value="aspnet"/> ← IAM USER
  <add key="AwsRoleArnAws1" value="arn:aws:iam::123456789:role/aspnet"/> ← スイッチ先Role
  <add key="AwsRoleArnAws2" value="arn:aws:iam::234567891:role/aspnet"/>
  ...
  <!-- サーバ側はユーザプロファイルではないフォルダを指定 -->
  <add key="AWSProfilesLocation" value="C:\workspace\ps1\credentials" />
  ...

</appSettings>
```

## AmazonConfig.cs

```C#
using Amazon;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;
using Amazon.Runtime;
using Amazon.Runtime.CredentialManagement;

//スイッチ先
public enum AccountNo
{
    AWS1 = 1,
    AWS2 = 2,
    ...
}

function ... (AccountNo accountNo){
    var roleArn = $"AwsRoleArnAws{(byte)accountNo}";    //accountNo: 1~N
    var chain = new CredentialProfileStoreChain();
    AWSCredentials awsCredentials;
    var profile =  System.Configuration.ConfigurationManager.AppSettings["AwsRoleArnBaseProfile"];
    if (chain.TryGetAWSCredentials(profile, out awsCredentials))    
    {
        var sts = new  AmazonSecurityTokenServiceClient(awsCredentials);
        var arn =  System.Configuration.ConfigurationManager.AppSettings[roleArn];
        var stsreq = new AssumeRoleRequest
        {
            RoleArn = arn,
            RoleSessionName =  $"{(byte)accountNo}_{region.SystemName}_{DateTime.Now.ToString("yyyyMMddHHmmsssss")}",
            DurationSeconds = 900
        };
        var stsres = sts.AssumeRole(stsreq);
        StsCredentials = stsres.Credentials;    
    }
}
```

## Ec2Service.cs

```C#
using Amazon;
using Amazon.EC2;
using Amazon.EC2.Model;

...
aconf = new AmazonConfig(accountNo);
IAmazonEC2 client = new AmazonEC2Client(aconf.StsCredentials,  RegionEndpoint.APNortheast1);
...

```


# 参考
 * https://docs.aws.amazon.com/ja_jp/sdk-for-net/v3/developer-guide/net-dg-config-creds.html
 * https://dev.classmethod.jp/articles/sts-temporality-credential/

 * 名前付きプロファイル
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-profiles.html
https://docs.aws.amazon.com/ja_jp/powershell/latest/userguide/specifying-your-aws-credentials.html
(Windowsはオプションでセキュリティキーが暗号化され保存される <-開発環境)

 * AWS SDK for .NET can't access credentials with IIS
https://stackoverflow.com/questions/25560545/aws-sdk-for-net-cant-access-credentials-with-iis

# バグ対応
リリースすると本番環境のみ、下記のエラーが、

```C#
アセンブリ 'AWSSDK.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604' から型 'Amazon.Runtime.SharedInterfaces.ICoreAmazonSTS_WebIdentity' を読み込めませんでした。
説明: 現在の Web 要求を実行中に、ハンドルされていない例外が発生しました。エラーに関する詳細および例外の発生場所については、スタック トレースを参照してください。

例外の詳細: System.TypeLoadException: アセンブリ 'AWSSDK.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604' から型 'Amazon.Runtime.SharedInterfaces.ICoreAmazonSTS_WebIdentity' を読み込めませんでした。
```
STSを実装したアセンブリを参照するプロジェクトに古いAWSSDK.SecurityTokenが残っていた。削除で解決。半日飛んだー
https://hydracards.hydratecinc.com/cards/card-839