Cognito Identity PoolsのUnauthenticated Identity(認証されていないID)を使ってS3へアップロードする

実現するのは以下のイメージです。
f:id:kenjifunasaki:20181004165338p:plain

JavaScriptを使って、Cognito Identity Poolから必要なトークンを取得、トークンに含まれる一時的な認証情報を使って、S3へファイルをアップロードします。

前提条件

Cognito ID Poolを作成する

f:id:kenjifunasaki:20181004185340p:plain
IDプール名を入れて、認証されていないIDに対してアクセスを有効にします。

作成するプールのIDに割り当てるIAMロールを作成

f:id:kenjifunasaki:20181004185730p:plain

JavaScript用のコードの確認

f:id:kenjifunasaki:20181004190020p:plain
こちらにあるIdentityPoolIdは後程使います。

作成したIAMロールにS3の権限を与える

UnAuthRoleとAuthRoleが作成されているのが分かります。
f:id:kenjifunasaki:20181004190511p:plain

今回はUnAuthRoleを使うので、こちらにAmazonS3FullAccess権限を追加します。今回はテスト用にFullAccess権限を追加していますが、最小権限の権限を追加するようにしてください。
f:id:kenjifunasaki:20181004191445p:plain

JavaScriptファイルを作成する

s3upload-unauth.htmlを作成します。

<html>
<head>
<script type="text/javascript" src="https://sdk.amazonaws.com/js/aws-sdk-2.6.9.min.js"></script>
</head>
<body>
<input type='file' name='upload' id='upload-file'>
<button id='upload-button'>upload</button>
<div id="results"></div>

<script type="text/javascript">
var upload = document.getElementById('upload-button');
var results = document.getElementById('results');

upload.addEventListener('click', function() {
    var uploadFile = document.getElementById('upload-file');
    var file = uploadFile.files[0];
    if(file) {
        var params = {
            IdentityPoolId: "ap-northeast-1:xxxxxxxx-xxxxx-xxxxxx-xxxx-xxxxxxxxxx"
        };
        AWS.config.region = 'ap-northeast-1';
        AWS.config.credentials = new AWS.CognitoIdentityCredentials(params);
        AWS.config.credentials.get(function(err) {
            if (!err) {
                console.log(AWS.config.credentials.identityId);
                var bucket = new AWS.S3({params: {Bucket: 'mybucketname'}});
                var params1 = {Key: file.name, ContentType: file.type, Body: file};
                bucket.putObject(params1, function (err, data) {
                    results.innerHTML = err ? 'ERROR!' : 'UPLOADED.';
                });
            }
        });
    } else {
        results.innterHTML = 'Noting to upload.';
    }
}, false);
</script>
</body>
</html>

IdentityPoolIdの部分に作成したCognito IDプールのIDを入れます。さらに、mybucketnameの部分に自身のバケット名を入れます。

Apache Httpd Serverをインストールして、作成したJavaScriptを配置する

sudo yum install httpd -y
sudo service httpd start

/var/www/html配下に作成したs3upload-unauth.htmlを配置する。

S3へのアップロード

http:///s3upload-unauth.html へアクセスすると、以下のような画面が表示される。
f:id:kenjifunasaki:20181004193646p:plain

ファイルを選択してアップロードします。

f:id:kenjifunasaki:20181004194241p:plain

成功すると、以下のようにUPLOADと表示されます。上手くいかない場合はChromeであれば、ChromeのDeveloper Toolのコンソールを見るなどしてエラー内容を確認します。

S3の指定したバケットにで正しくアップロードされていることを確認できました!

このように、Cognito Identityを使って、一時的な認証情報を取得し、S3へアップロードすることができました。

AWS Systems Managerでパッチコンプライアンスのステータスを確認する

AWS Systems ManagerのエージェントをWindows EC2インスタンスにインストール済みで、マネージドインスタンスとして確認がとれているインスタンスのパッチコンプライアンスのステータスを確認してみたいと思います。

以下のi-0fc8232827e0748d1のマネージドインスタンスをベースにして見てみます。
f:id:kenjifunasaki:20180502184058p:plain

AWS Systems Managerにてコンプライアンスのステータスを確認するには、Systems Manager(SSM)のマネージメントコンソールにて、Complianceを選択します。
f:id:kenjifunasaki:20180502184335p:plain

こちらを見ると、私の環境で以前確認したインスタンスコンプライアンスステータスが見れますが、今回見ようとしているi-0fc8232827e0748d1はまだ何も表示されていません。

こちらの状態でAWS-RunPatchBaselineのコマンドで、引数をScanで指定して実行してみます。同じ画面の下部でScanを指定して、コマンドを実行します。
f:id:kenjifunasaki:20180502184707p:plain

AWS-RunPatchBaselineのコマンドでScanを実行した結果、成功と表示されました。
f:id:kenjifunasaki:20180502185149p:plain

実行した結果、以下のメッセージが出力されました。

Patch Summary for i-0fc8232827e0748d1

PatchGroup : 

BaselineId : pb-04ba050f612fba3a6

SnapshotId : e2a05e73-f205-4959-88c9-c763bb3c63b2

OwnerInformation : 

OperationType : Scan

OperationStartTime : 2018-05-02T09:47:31.5522091Z

OperationEndTime : 2018-05-02T09:47:47.0833793Z

InstalledCount : 1

InstalledOtherCount : 11

FailedCount : 0

MissingCount : 1

NotApplicableCount : 2403

EC2AMAZ-99HABA7 - PatchBaselineOperations Assessment Results - 2018-05-02T09:47:49.520

Scan found the following updates missing:

KB4093120

PatchBaselineOperaseion Assessment結果としては、一部Updateが不足しているようです。この状態でAWS Systems Managerのコンプライアンスの画面を見てみます。

f:id:kenjifunasaki:20180502185604p:plain

先ほどのコンプライアンススクリーンショットと比較してみてください。先ほどは表示されていなかったi-0fc8232827e0748d1のコンプライアンスステータスが表示されるようになり、かつPatchBaselineOperationに非準拠であるため、グラフで赤く表示されているのが分かります。

このように、AWS-RunPatchBaselineのScanを実行するだけで、自動でコンプライアンスのステータスを確認できるようになるようです。

以上で、パッチコンプライアンスのステータスを確認することができました。PatchBaselineのインストールの手順は前回の記事で紹介しているので、今回は割愛します。

AWS Systems ManagerでAWS-RunPatchBaselineをRun Commandで実行して、Windowsインスタンスにパッチを適用する

以前の記事にあるように、EC2 WindowsインスタンスAWS Systems Manager(SSM)のマネージドインスタンスとして登録してあるのを前提とします。

本記事では、このWindowsのマネージドインスタンスにSSMのRun CommandでAWS-RunPatchBaselineを実行してみます。

AWS-RunPatchBaselineでは引数として、ScanまたはInstallを選べます。
SSM ドキュメント AWS-RunPatchBaseline について - AWS Systems Manager

ですので、最初にScanを実行して、適用すべきパッチを確認した後で、Installを実行してみます。

AWS-RunPatchBaselineのScanの実行

SSMの画面で、Run Commandの画面を開いて、コマンドの実行を選択します。

f:id:kenjifunasaki:20180502114709p:plain

続いて、検索条件に「ドキュメントのプレフィックス名」で「等しい」でAWS-RunPatchBaselineを入力して、ドキュメントをフィルターします。表示されたAWS-RunPatchBaselineを選択します。
f:id:kenjifunasaki:20180502114722p:plain

同じ画面で、続いてターゲットインスタンスを指定します。
f:id:kenjifunasaki:20180502115726p:plain

さらに同じ画面で、コマンドのパラメータでScanを選択して、
f:id:kenjifunasaki:20180502115113p:plain

実行を選択します。

その後、進行中のステータスが表示されます。
f:id:kenjifunasaki:20180502120115p:plain

その後、実行が成功し、実行ターゲットであったマネージドインスタンスのリンクを開いてみると以下のように今回のAWS-RunPatchBaselineのコマンドの実行結果が表示されます。
f:id:kenjifunasaki:20180502120446p:plain

こちらのスクリーンショットの画面上部にあるプラグイン名 PatchLinuxのコマンドはステータスが成功にはなっていますが、出力を見ると、

Step execution skipped due to incompatible platform. Step name: PatchLinux

と表示され、Linuxのpatch適用はskipされたことがわかります。今回のターゲットはWindowsインスタンスのためです。

出力2を確認してみます。
f:id:kenjifunasaki:20180502120740p:plain

Scan found the following updates missing:

KB4093120

KB4093120のアップデートが不足しているようです。

記事執筆時点では、2018年5月2日ですが、2018年4月18日時点で出ている以下の修正が必要なようです。

https://support.microsoft.com/ja-jp/help/4093120/windows-10-update-kb4093120

AWS-RunPatchBaselineでInstallを実行してみる。

上記アップデートを実行してみます。

Scan時同様に、AWS Systems ManagerのRun Command画面でコマンドの実行を選択し、AWS-RunPatchBaselineのドキュメントを選択し、ターゲットのインスタンスも同様に選択します。そのうえでコマンドのパラメータはInstallを選択します。

f:id:kenjifunasaki:20180502121448p:plain

Installの実行開始後、しばらくアップデートに時間がかかり、その間はステータスが進行中になっています。実行が完了して、成功すると、以下のように表示されます。

f:id:kenjifunasaki:20180502180357p:plain

同じ画面でターゲットのインスタンスのリンクをクリックして
f:id:kenjifunasaki:20180502180544p:plain

実際のInstallの実行結果を確認します。
f:id:kenjifunasaki:20180502180624p:plain

KB4093120 Yes Success

インストールが問題なく実行完了できたことがわかりました。

Windows Server 2016 AMIを起動して、AWS Systems Managerでマネージドインスタンスとして管理する

AWSから提供されているWindows Server 2016のAMIには、デフォルトでAWS Systems Managet(SSM)のエージェントがインストールされています。SSMエージェントのパスは以下です。

C:\Program Files\Amazon\SSM\amazon-ssm-agent.exe

SSMエージェント用のIAMロールをこちらのEC2 Windowsインスタンスに割り当てておかないと、上記amazon-ssm-agent.exeを実行しても、マネージドインスタンスとしてSystems Managerのマネージメントコンソールからは見えてきません。

以下ページにある手順でIAMロールを作成して、インスタンスに割り当てて、amazon-ssm-agent.exeを実行したら、マネージドインスタンスとして表示されました。

Systems Manager のアクセス設定 - AWS Systems Manager

Windows EC2インスタンスを起動する際に、最初からこちらのIAMロールを割り当てて起動すると、自動でSSMエージェントが実行されて、マネージドインスタンスとして表示されるようです。
f:id:kenjifunasaki:20180502105453p:plain

注意事項
起動したインスタンスは、アウトバウンドでSystems Managerのエンドポイントと通信できる必要があります。Systems Manager用のVPCエンドポイントを設定するか、インターネットにアウトバウンド通信できるように、起動したインスタンスのサブネットのルートテーブルを設定する必要があります。

AWS Systems Managerでインベントリを実行して、/home/ec2-user以下にある*.txtファイルを確認、さらにカスタムインベントリで独自メタデータも登録・確認してみる。

事前にEC2インスタンスにSSM(Systems Manager)エージェントをインストール済みとします。

まずはAWS Systems Managerのマネージメントコンソールにて、Inventoryを選択して、セットアップインベントリを選択します。
f:id:kenjifunasaki:20180427192524p:plain

インスタンスの手動選択」にて、該当するインスタンスを選択します。スケジュールはCronスケジュールビルダーを選んで、今回は30分ごとの実行とします。
f:id:kenjifunasaki:20180427192914p:plain

同じ画面のパラメータにて、デフォルト設定のままで、ファイルの部分のパスに/home/ec2-userを、パターンに*.txtを、再帰的にチェックを入れて「セットアップインベントリ」を選択します。
f:id:kenjifunasaki:20180427194151p:plain

Managed Instancesを選択して、先ほど指定したインスタンスを選択します。
f:id:kenjifunasaki:20180427194001p:plain

インベントリタブを選択して、インベントリタイプにてAWS:Fileを選択します。
f:id:kenjifunasaki:20180427194357p:plain

最初は何もFile情報が表示されませんが、少し時間がたってから確認すると、以下のようにファイルがあることが確認できます。
f:id:kenjifunasaki:20180427200023p:plain

カスタムインベントリを実行してみる

続いて、こちら にあるCustom Inventoryの方法を用いて、独自のメタデータインスタンスに割り当ててみます。

独自のメタデータインスタンスに割り当てる方法として、AWS CLIを使う方法が紹介されていたので、こちらでやってみます。

AWS CLIでコマンドを実行するのに必要な権限を割り当てた上で以下コマンドを実行します。

https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-inventory-walk-custom.html

State Managerを選択して、関連づけ(AWS-GatherSoftwareInventory)を選択して「関連付けの編集」を選択します。

aws ssm put-inventory --instance-id "xxxx" --items '[{"CaptureTime": "2018-04-30T10:01:01Z", "TypeName": "Custom:RackInfo", "Content":[{"RackLocation": "Bay B/Row C/Rack D/Shelf E"}], "SchemaVersion": "1.0"}]'

実行後に、そのメタデータが取得できるようになっているかを以下コマンドで確認します。

aws ssm list-inventory-entries --instance-id xxx --type-name "Custom:RackInfo"

結果は以下のように出力され、正しくメタデータが登録されていることがわかりました。

{
    "InstanceId": "i-005991248a5f30bc2",
    "TypeName": "Custom:RackInfo",
    "Entries": [
        {
            "RackLocation": "Bay B/Row C/Rack D/Shelf E"
        }
    ],
    "SchemaVersion": "1.0",[f:id:kenjifunasaki:20180430210852p:plain]
    "CaptureTime": "2018-04-30T10:01:01Z"
}

Management Console上でも以下のようにカスタムインベントリ情報を選択ができ、
f:id:kenjifunasaki:20180430210819p:plain

登録したメタデータも確認ができました。
f:id:kenjifunasaki:20180430210852p:plain

これで、デフォルトのインベントリ以外でも任意のメタデータをマネージドインスタンスごとに登録・取得できますね。

注意事項

一つのマネージドインスタンスに複数のインベントリを関連づけることはできません。すでに別のインベントリが関連付けされていると、別のインベントリの実行が失敗しますので、ご注意ください。

AWS Systems ManagerでサンプルのAutomation Documentを作成・実行してみる(3)~承認のステップを追加~

前回のメモでは、AWS Systems ManagerのAutomation Documentにて複数ステップを実行しました。今回はそのDocumentをベースに、承認のステップを追加します。分かりやすさのため、前回のAutomation Documentでの「ファイル削除」のステップは割愛します。

今回使用するサンプルのAutomation Documentは以下です。

{
  "description": "Automation Document Example JSON Template",
  "schemaVersion": "0.3",
  "assumeRole": "{{ AutomationAssumeRole }}",
  "parameters": {
    "AutomationAssumeRole": {
      "type": "String",
      "description": "(Optional) The ARN of the role that allows Automation to perform the actions on your behalf.",
      "default": ""
    }
  },
  "mainSteps": [
    {
    "name":"createText1",
      "action":"aws:runCommand",
      "maxAttempts":3,
      "timeoutSeconds":1200,
      "onFailure":"Abort",
      "inputs":{
        "DocumentName":"AWS-RunShellScript",
        "InstanceIds":[
          "i-04e0ac63bc6e4105f"
        ],
        "Parameters":{
          "workingDirectory":"/home/ec2-user",
          "commands":[
            "echo hello1 > testfile1"
          ]
        }
      }
    },
    {
         "name":"approve",
         "action":"aws:approve",
         "timeoutSeconds":1000,
         "onFailure":"Abort",
         "inputs":{
            "NotificationArn":"arn:aws:sns:ap-northeast-1:123456789012:test",
            "Message":"Please approve this automation.",
            "MinRequiredApprovals":1,
            "Approvers":[
               "arn:aws:iam::123456789012:user/user1"
            ]
         }
    },
    {
    "name":"ls",
      "action":"aws:runCommand",
      "maxAttempts":3,
      "timeoutSeconds":1200,
      "onFailure":"Abort",
      "inputs":{
        "DocumentName":"AWS-RunShellScript",
        "InstanceIds":[
          "i-04e0ac63bc6e4105f"
        ],
        "Parameters":{
          "workingDirectory":"/home/ec2-user",
          "commands":[
            "ls"
          ]
        }
      }
    }
  ]
}

Amazon SNS (Simple Notification Service)のトピックはすでに作成済みで、そのトピックに対して、今回は自分のメールアドレスでsubscribeしています。

上記Automation Documentを実行した直後の結果は以下。

f:id:kenjifunasaki:20180413190010p:plain

approveのステップで待機中となっているのが分かります。この状態で、自分のメールボックスを確認すると、以下のような内容のメールが届いていました。

Please approve this automation.

-- Approval Details --

Approval Step Name: approve
Region: ap-northeast-1
Automation Execution Id: 59cf7cbe-3f00-11e8-8d8a-6d3cffee791e
Approval Expires At: 2018-04-13 10:09 AM UTC

-- Approve or reject through AWS CLI --

Approve:   aws ssm send-automation-signal --automation-execution-id 59cf7cbe-3f00-11e8-8d8a-6d3cffee791e --signal-type Approve --payload Comment=Replace_This_With_Approve_Comment 

Reject:   aws ssm send-automation-signal --automation-execution-id 59cf7cbe-3f00-11e8-8d8a-6d3cffee791e --signal-type Reject --payload Comment=Replace_This_With_Reject_Comment

Approval Expiresには、今回タイムアウト時間を1000秒に指定しているため、その時間経過との時刻が指定されているようです。この時刻になる前に、指定された以下コマンドを、先ほどのドキュメントで指定したIAMユーザで実行してみます。

aws ssm send-automation-signal --automation-execution-id 59cf7cbe-3f00-11e8-8d8a-6d3cffee791e --signal-type Approve --payload Comment=I_approved_this_automation

実行後、Automationの実行結果を確認すると
f:id:kenjifunasaki:20180413190440p:plain

無事approveのステップが成功になり、その後のステップも成功していることが確認できました。

AWS Systems ManagerでサンプルのAutomation Documentを作成・実行してみる(2)~複数ステップ実行 & ステップ実行エラー時の動作確認~

前回のメモでは、AWS Systems ManagerでAutomation Documentのサンプルを作成しましたが、実行ステップ数が1個のみだったので、今回は複数ステップで実行してみます。

新規Automation Documentを作成します。名前はMySampleAutomationDocument2、ドキュメントタイプはオートメーションドキュメントにします。

f:id:kenjifunasaki:20180413144636p:plain

コンテンツは今回は2ステップで実行したいので、以下を入れてみます。

{
  "description": "Automation Document Example JSON Template",
  "schemaVersion": "0.3",
  "assumeRole": "{{ AutomationAssumeRole }}",
  "parameters": {
    "AutomationAssumeRole": {
      "type": "String",
      "description": "(Optional) The ARN of the role that allows Automation to perform the actions on your behalf.",
      "default": ""
    }
  },
  "mainSteps": [
    {
    "name":"createText1",
      "action":"aws:runCommand",
      "maxAttempts":3,
      "timeoutSeconds":1200,
      "onFailure":"Abort",
      "inputs":{
        "DocumentName":"AWS-RunShellScript",
        "InstanceIds":[
          "i-04e0ac63bc6e4105f"
        ],
        "Parameters":{
          "workingDirectory":"/home/ec2-user",
          "commands":[
            "echo hello1 > testfile1"
          ]
        }
      }
    },
    {
    "name":"ls",
      "action":"aws:runCommand",
      "maxAttempts":3,
      "timeoutSeconds":1200,
      "onFailure":"Abort",
      "inputs":{
        "DocumentName":"AWS-RunShellScript",
        "InstanceIds":[
          "i-04e0ac63bc6e4105f"
        ],
        "Parameters":{
          "workingDirectory":"/home/ec2-user",
          "commands":[
            "ls"
          ]
        }
      }
    }
  ]
}

/home/ec2-userディレクトリ内にtestfile1を作成して、こちらのディレクトリ内でlsコマンドを実行します。

作成したMySampleAutomationDocument2を実行してみます。
f:id:kenjifunasaki:20180413144924p:plain

結果の画面は以下です。
f:id:kenjifunasaki:20180413145038p:plain

無事2つのステップが成功しているのが分かります。あとは、lsコマンドを実行するステップの詳細を見てみます。

f:id:kenjifunasaki:20180413145206p:plain

上記画面にて、lsコマンドを/home/ec2-userディレクトリで自動実行し、作成したtextfile1ファイルがリスト表示されているのが分かります。

続いて、わざと1ステップでエラーを発生させてみます。実際には存在しないファイルの削除を行うステップを追加します。まずは、既存のMySampleAutomationDocument2で新しいバージョンを作成します。画面右上の新しいバージョンの作成を選びます。

f:id:kenjifunasaki:20180413175932p:plain

コンテンツを修正します。

f:id:kenjifunasaki:20180413180018p:plain

コンテンツの中身は以下です。ステップ2番目に存在しないファイルを削除するステップを入れてみます。

{
  "description": "Automation Document Example JSON Template",
  "schemaVersion": "0.3",
  "assumeRole": "{{ AutomationAssumeRole }}",
  "parameters": {
    "AutomationAssumeRole": {
      "type": "String",
      "description": "(Optional) The ARN of the role that allows Automation to perform the actions on your behalf.",
      "default": ""
    }
  },
  "mainSteps": [
    {
    "name":"createText1",
      "action":"aws:runCommand",
      "maxAttempts":3,
      "timeoutSeconds":1200,
      "onFailure":"Abort",
      "inputs":{
        "DocumentName":"AWS-RunShellScript",
        "InstanceIds":[
          "i-04e0ac63bc6e4105f"
        ],
        "Parameters":{
          "workingDirectory":"/home/ec2-user",
          "commands":[
            "echo hello1 > testfile1"
          ]
        }
      }
    },
    {
    "name":"rm",
      "action":"aws:runCommand",
      "maxAttempts":3,
      "timeoutSeconds":1200,
      "onFailure":"Abort",
      "inputs":{
        "DocumentName":"AWS-RunShellScript",
        "InstanceIds":[
          "i-04e0ac63bc6e4105f"
        ],
        "Parameters":{
          "workingDirectory":"/home/ec2-user",
          "commands":[
            "rm 1111.txt"
          ]
        }
      }
    },
    {
    "name":"ls",
      "action":"aws:runCommand",
      "maxAttempts":3,
      "timeoutSeconds":1200,
      "onFailure":"Abort",
      "inputs":{
        "DocumentName":"AWS-RunShellScript",
        "InstanceIds":[
          "i-04e0ac63bc6e4105f"
        ],
        "Parameters":{
          "workingDirectory":"/home/ec2-user",
          "commands":[
            "ls"
          ]
        }
      }
    }
  ]
}

新しいバージョンの作成を選んだあと、MySampleAutomationDocument2の新しいバージョンを実行します。

f:id:kenjifunasaki:20180413180230p:plain

すると当然ですが、存在しないファイルを削除しようとするステップ2が失敗します。

f:id:kenjifunasaki:20180413180507p:plain

ステップ実行の失敗時の挙動については、OnFailureで指定可能です。デフォルトではAbort (中止)の動作になりますが、Continueを指定することで、継続も可能です。
Systems Manager 自動化ドキュメントのリファレンス - AWS Systems Manager

今回は、rmのステップにて、失敗時に継続するように変更してみます。変更箇所は以下。

   {
    "name":"rm",
      "action":"aws:runCommand",
      "maxAttempts":3,
      "timeoutSeconds":1200,
      "onFailure":"Continue",
      "inputs":{
        "DocumentName":"AWS-RunShellScript",
        "InstanceIds":[
          "i-04e0ac63bc6e4105f"
        ],
        "Parameters":{
          "workingDirectory":"/home/ec2-user",
          "commands":[
            "rm 1111.txt"
          ]
        }
      }
    },

修正して再度実行した結果は以下。

f:id:kenjifunasaki:20180413182122p:plain

ステップ2が失敗しても、続けてステップ3が実行されたことが分かります。