システム運用統制を実現する承認ワークフロー・操作ログ取得をSystemsManagerとStep Functionsで構築する

これは[ミクシィグループ Advent Calendar 2020](https://qiita.com/advent-calendar/2020/mixi)の13日目の記事です。

# はじめに
一般的にシステムの健全性を保証するためにシステム運用統制は必要と考えられています。特に[FISC](https://www.fisc.or.jp/)や[PCIDSS](https://ja.pcisecuritystandards.org/minisite/env2/)に準拠する必要がある場合は必須です。なお、ここでの統制とは承認されている作業のみを許可し、予定されていない作業を抑止したり制御することを指します。

こういったシステム運用統制を実現するために、パッケージやSaaSを導入する場合もありますが、利用料が高すぎて導入できないといったことがあると思います。そこで今回は**AWSサービスのみでシステム運用統制を実現する方法の1つ**を紹介します。

# 概要
今回は例として「**個人情報を含むDBへ接続して行う運用作業時は事前承認を必須とし、作業時の操作ログを取得すること」**と定義されるシステム運用統制をAWSサービスを利用して実現します。

# システム構成図
初めにイメージを掴んでもらうためにシステム構成図を載せておきます。
![system-architech.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/b3e92e05-8bc7-4861-0f00-f42e8fa642e0.png)


①：作業者は作業時間、作業内容をインプットとしてSSM Automationを実行します。実行後、承認者に通知されるます。
②：承認者は申請内容を確認し、問題なければ承認します。承認後、SSM AutomationはStep Functionsをキックします。
③：Step Functionsは申請時に入力した作業開始時間になったらEC2インスタンスを作成します。
④：作業者はSSM Session Manager経由でEC2にログインします。
⑤：作業者はEC2からRDSに接続し、運用作業を行います。その際の操作ログはSSM Session Managerの機能でS3にアップロードされます。
⑥：Step Functionsは申請時に入力した作業終了時間になったらEC2インスタンスを削除します。

# 今回の構成を導入することで実現できること
AWSサービスの機能だけで以下を実現することができます。

- 作業前には承認者の承認が必須となる
- 作業時間を絞ることができる
- 作業時の操作ログが取得可能

# 動作確認
上記のフローを動作確認してみます。動作確認用のAWSリソースはCloudFormationで構築しています。CloudFormationテンプレートは[こちら](https://github.com/yhamano0312/aws-approve-workflow-for-qiita-advent-mixi)にありますので、試してみたい方はどうぞ！なお、CloudFormationの実行後に以下の実施をお願いします。

- 作成後にSNSサブスクリプションの承認メールが送信されるので、メールのリンクから承認してください。
- セッションマネージャの操作ログ取得設定はCloudFormationに対応していないため、マネジメントコンソールから行ってください。AWS Systems Manager -> セッションマネージャ -> 設定 -> S3 logging
![AWS_Systems_Manager_-_Session_Manager1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/97ded18b-bea5-dca8-d8c7-70e8510cef89.png)


まず作業者用IAMユーザでログインし、Systems Manager画面からSSMAutomationを実行します。
![AWS_Systems_Manager_-_Automation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/a43930f7-cd9d-4eb7-13dc-0a6890fe1fcc.png)

![AWS_Systems_Manager_-_Automation2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/839b91da-95d0-7ad6-21ae-794d3a10abd3.png)

実行後、以下のようなメールがCloudFormation実行時のパラメータに入力した承認者メールアドレスに送信されますので、「Approve」のリンクから承認者IAMユーザでログインします。

![AWS_Notification_Message_-_g_yusuke_tkb_gmail_com_-_Gmail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/a88e1060-1871-edac-5bec-b4b14874fef0.png)

承認者は内容を確認し、問題なければ承認を行います。
![AWS_Systems_Manager_-_Automation3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/ef93ed6d-74b3-aedf-b470-087efef788cf.png)

SSMAutomation実行時のstart_timeパラメータに入力した時刻になるとEC2が起動するため、作業者IAMユーザでセッションマネージャを利用して接続します。(UserData内でSSM Agentの更新を行っているため、SSM Agentの更新を促された場合は数分時間を置いてから再度確認してください。)
![インスタンス___EC2_Management_Console1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/9ef44d60-cdae-199d-86ab-0ae77ce2680d.png)

![1インスタンスに接続___EC2_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/3bd02bc3-6174-a46c-6c89-db2100250177.png)

mysql clientを用いてRDSに接続します。接続時のユーザ名・パスワードはCloudFormationの実行時に入力したパラメータを確認してください。

```
mysql -h 【RDSエンドポイント】 -P 3306 -u admin -p
```
![1AWS_Systems_Manager_-_Session_Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/50519d8d-7068-f909-2356-366887635f97.png)

作業完了後、セッションを終了したタイミングで操作ログがS3にアップロードされ、SSMAutomation実行時のend_timeパラメータに入力した時刻になるとEC2が削除されます。

# マニフェスト解説
今回のシステム構成のメインとなるSSM DocumentとStep Functions StateMachineのマニフェスト定義を解説します。

## SSM Document

```
{
  "description": "Approve Workflow",
  "schemaVersion": "0.3",
  "parameters": {
    "Description": {
      "description": "operation description",
      "type": "String"
    },
    "EndTime": {
      "description": "(Required & format:YYYY-MM-DDThh:mm:ss+09:00) End Time",
      "type": "String",
      "allowedPattern": "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\\+09:00$"
    },
    "StartTime": {
      "description": "(Required & format:YYYY-MM-DDThh:mm:ss+09:00) Start Time",
      "type": "String",
      "allowedPattern": "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\\+09:00$"
    }
  },
  "mainSteps": [
    {
      "inputs": {
        "Message": "approve check",
        "NotificationArn": "arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:approver-topic",
        "Approvers": [
          "arn:aws:iam::xxxxxxxxxxxx:user/approver"
        ],
        "MinRequiredApprovals": 1
      },
      "name": "approve",
      "action": "aws:approve",
      "onFailure": "Abort"
    },
    {
      "inputs": {
        "UserName": "operator",
        "PolicyName": "AllowSessionManager",
        "Service": "iam",
        "PolicyDocument": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"ssm:StartSession\",\"Resource\":\"*\",\"Condition\":{\"DateGreaterThan\":{\"aws:CurrentTime\":\"{{StartTime}}\"},\"DateLessThan\":{\"aws:CurrentTime\":\"{{EndTime}}\"}}}]}",
        "Api": "PutUserPolicy"
      },
      "name": "putInlinepolicy",
      "action": "aws:executeAwsApi"
    },
    {
      "inputs": {
        "input": "{\"start_time\" : \"{{StartTime}}\", \"end_time\" : \"{{EndTime}}\"}",
        "stateMachineArn": "arn:aws:states:ap-northeast-1:xxxxxxxxxxxx:stateMachine:lambdaExec"
      },
      "name": "execStepFunction",
      "action": "aws:executeStateMachine"
    }
  ]
}
```

- parameters
    - 入力パラメータを定義しています。StartTimeとEndTimeはStepFunctions側に渡すパラメータとなります。StepFunctionsのWaitタスクに設定する時刻フォーマットがISO 8601のRFC3339に従う必要があるため、allowedPatternによるパラメータフォーマットチェックを入れています。
- mainSteps
    - aws:approveアクションが承認部分になります。承認できるIAMユーザをApproversとして指定できるのですが、**IAMユーザのARNしか指定できない**ため、複数の承認者を指定したい場合はそのユーザ数分のARNを記載する必要があります。(IAMグループやIAMロールのARNを指定できるようにしてほしい。。)
    - aws:executeAwsApiアクションで作業者IAMユーザに**セッションマネージャ接続権限を時間指定のIAMポリシーとしてアタッチ**しています。これにより特定時間帯のみ権限を付与することを実現しています。
    - aws:executeStateMachineアクションでStepFunctions StateMachineを起動しています。

## StepFunctions StateMachine

```
{
  "Comment": "lambda exec",
  "StartAt": "StartWait",
  "States": {
    "StartWait": {
      "Type": "Wait",
      "TimestampPath": "$.start_time",
      "Next": "CreateEC2"
    },
    "CreateEC2": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:start-ec2",
      "Next": "DeleteWait"
    },
    "DeleteWait": {
      "Type": "Wait",
      "TimestampPath": "$.end_time",
      "Next": "DeleteEC2"
    },
    "DeleteEC2": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:end-ec2",
      "End": true
    }
  }
}
```

![Step_Functions_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/f6426a18-f025-b13b-63ec-67137852ee93.png)

- Wait
    - SSM Automationから受け取った時刻を指定して上げることで、指定時間まで処理を待ちます。
- Task
    - ResourceにLambda FunctionsのARNを指定してあげることで、Lambda Functionsが起動されます。

# 最後に
SystemsManagerとStep Functionsを用いた作業時の承認ワークフローと操作ログ取得を紹介しました。運用統制を導入する際の参考にして頂ければ幸いです。