AWS Systems Manager Session Manager導入メモ

新規アカウント作成からの手順メモです。

# Session Managerってなに
![sessionManager-head.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618258/a8f7fcb1-623a-5157-79dc-5ee5c31e486c.png)

* https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager.html
* あらかじめエージェントをインストールしたマシンにAWS経由でアクセスできるサービス
* EC2にAWSコンソール（ブラウザ）を使ってアクセスしたりできる
  * 秘密鍵などの扱いが不要なのが強い（認証はAWSで行う）
  * IAM Policyで条件を絞った権限を与えることで細かなアクセス許可が実現可能
      * 「特定のユーザーが、特定のIPアドレスから、特定のマシンへ、特定の時間帯にだけログインできる」という状態が作り出せる
  * ログはすべてS3/CloudWatch Logsに残せる

# AWSアカウント新規作成
* MFA有効化
* 「AWS のコストと使用状況レポート」の有効化
* 適切なIAMユーザー作成
* 等々

# EC2インスタンス作成
* Amazon Linux 2 で新規インスタンスを作成
  * エージェントのインストールが不要なので楽だから
* パブリックIPアドレスは**必須**
  * Security Groupは不要（どこからもアクセスを受け付ける必要はない）
  * パブリックIPアドレスを付け忘れると「インスタンスにアタッチされている IAM インスタンスプロファイルに必要な許可が含まれていることを確認してください」というエラーが発生する
  * あたかもIAM Roleが正しく割り当てられていないかのようなエラーメッセージなので困惑する
* この時点ではIAM Roleはアタッチしなくて良い
* ASCII文字だけを値に持つタグを付けておく（例: `Hostname` タグなど）
  * 後でプロンプトに出す値に使う
  * `Name` タグでも構わないが日本語等が混じる可能性があるなら避けた方が良い

# ログ用S3バケット作成
* Session Managerのログを保存するバケットを作成
* **バージョニングを有効にしておく**
* とりあえずデフォルト暗号化としてサーバサイド暗号化（KMSを使わない方）で暗号化をかけておく

# Systems Managerセットアップ
このセクションは初回だけで良い。

## Systems Manager 高速セットアップ実行
* Permissions
  * Instance profile role としては Use the default role を選択
      * `AmazonSSMRoleForInstancesQuickSetup` ロールが作成される
  * Assume role for Systems Manager としてもやはり Use the default role を選択
      * `AmazonSSMRoleForAutomationAssumeQuickSetup` ロールが作成される
* Quick Setup options はとりあえずデフォルトのまま
* Targets として Choose instances manually を選択し、さっき作ったEC2インスタンスを選択
  * このEC2インスタンスに `AmazonSSMRoleForInstancesQuickSetup` ロールが自動的に割り当てられる

## IAM Role修正
* 上の作業で作成された `AmazonSSMRoleForInstancesQuickSetup` ロールに次のインラインポリシーを追加する
  * 前半は自分自身のインスタンス情報を取得してプロンプトに表示するため
  * 後半はログを保存するため（ログ保存はこのロールで行われる）

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstances",
                "ec2:DescribeTags"
            ],
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetEncryptionConfiguration"
            ],
            "Resource": [
                "arn:aws:s3:::YOUR-BUCKET-NAME",
                "arn:aws:s3:::YOUR-BUCKET-NAME/*"
            ]
        }
    ]
}
```

## Session Manager設定変更
* 「Amazon S3 バケットにセッション出力を書き込む」
  * 「S3バケット」にチェック
  * 「ログデータを暗号化する」にチェック
      * 上のS3バケットの設定と合わせる必要がある。暗号化しないバケットならこのチェックは外す
  * 「S3バケット名」で作成済みのバケット名を選択

# セッション開始
* ここまでの下準備でセッション開始ができるようになっているはず

![sessionManager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618258/6783c963-9649-a814-8da8-0cab9fc05143.png)

## .bashrc追記
* これだけでは心許ないにも程があるのでなんとかしたい
  * インスタンスIDだけは画面に出ているがそれ以外の情報が何もない
* 参考: https://dev.classmethod.jp/articles/mitigation-idea-for-session-manager/
* 4行目で指定している `Hostname` はEC2インスタンスに割り当てたタグの名前

```
instance_id=$(curl -s 169.254.169.254/latest/meta-data/instance-id)
az=$(curl -s 169.254.169.254/latest/meta-data/placement/availability-zone)
region=${az%?}
tagged_name=$(aws ec2 describe-instances --region $region --instance-ids $instance_id --query 'Reservations[].Instances[].[Tags[?Key==`Hostname`].Value]' --output text)

export PS1="[\u@$tagged_name \W]\$ "
```

* これでプロンプトがだいぶ安心できる感じになる

```
sh-4.2$ sudo -iu `whoami`
[ssm-user@MyEC2Instance ~]$
```

* 相変わらず `.bashrc` は自動的に実行されないので、セッション開始時には

```
sudo -iu `whoami`
```

を手動で実行するようにする必要がある

# IAM Policy
## コンソールからSession Managerまで辿り着くのに必要な権限
* 最低限次のポリシーをアタッチしておけばSession Managerを開くところまでは行く
 
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ssm:DescribeSessions",
                "ssm:DescribeInstanceProperties",
                "ec2:describeInstances",
                "ssm:GetConnectionStatus"
            ],
            "Resource": "*"
        }
    ]
}
```

## セッションを開始するのに必要な権限
* 実際にセッションを開始するには `ssm:StartSession`, `ssm:TerminateSession` が必要
* サンプルとして日時とEC2インスタンスのARNも追加してある
  * 「指定した時間帯のみ」「指定したEC2インスタンスに対してのみ」セッションを開始することができるという意味

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "ssm:StartSession",
            "Resource": [
                "arn:aws:ec2:ap-northeast-1:999999999999:instance/i-01234567890abcdef"
            ],
            "Condition": {
                "DateGreaterThan": {
                    "aws:CurrentTime": "2020-04-15T00:00:00+00:00"
                },
                "DateLessThan": {
                    "aws:CurrentTime": "2020-04-15T04:00:00+00:00"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssm:TerminateSession"
            ],
            "Resource": [
                "arn:aws:ssm:*:*:session/${aws:username}-*"
            ]
        }
    ]
}
```

# 補足
## S3のバージョニングについて
* S3にログを転送するため、EC2にアタッチするIAM Roleに `s3:PutObject` を持たせないといけない
* つまりEC2から `aws s3 cp empty.txt s3://YOUR-BUCKET/xxxx.log` でS3上のログを別のファイルで上書きできてしまう
* これを防ぐためにはバージョニングが必要
  * 悪意を想定しないならここまでしなくてもいい
  * 作業ログを監査等に利用する場合は必須だと思われる
  * CloudWatchにログを転送する手もあるが（これなら上書きはできない）、料金が高額になる、扱いが面倒になるという問題がある

## パブリックIPアドレスについて
* パブリックIPアドレスがないEC2インスタンスはターゲットインスタンス一覧に出てこない
* EIPを付けたり外したりしているとSystems ManagerがEC2インスタンスを見失うことがある
* しばらくリロードを繰り返しても一覧に出てこないときはEC2を再起動する