Python On LambdaでIAM管理Tips - User List取得

AWSのマネジメントコンソールでIAMユーザ管理する場合、一覧してみることができますが、
ユーザ名以外でソートができないようです。
そうすると、払い出して一度も使っていないユーザや、最近ログインしていないユーザを把握するのが面倒くさくなります。
そこでIAMユーザリストを取得するREST APIを作って、別のツールと組み合わせて管理できるようにと考えてみました。
##OverView
![overview.png](https://qiita-image-store.s3.amazonaws.com/0/191079/c4be23ab-413b-67c7-c4fa-9f4334bf2679.png)
こんな感じなことを実現したい

##Lambda
Lambdaの管理画面でCreate Fuction
![lambda1.png](https://qiita-image-store.s3.amazonaws.com/0/191079/9fae3f3a-e37a-7074-09f8-05ae61ba3f9a.png)
今回はpython3.6を使いたいので、テンプレートを一番シンプルなhello-world-python3とします。

![lambda2.png](https://qiita-image-store.s3.amazonaws.com/0/191079/0179f6fb-ba10-464d-477f-c91cfaacabd8.png)
トリガーにAPI Gatewayを選択
API Nameは任意で、Deployment stageもデフォルト値のprodで問題ありません。
Securityだけ必要に応じて、

- AWS IAM
- Open
- Open with access key
 
から選ぶ必要があります。
外から読み取りたいのと、IAM情報なので、最低限の認証を行いたいため、
Open with access keyを選びました。
「Next」でLambda作成画面に遷移、Name、Description等は任意で、
重要なのはRoleの設定
![lambda3.png](https://qiita-image-store.s3.amazonaws.com/0/191079/18a4f7f6-7312-0bdc-7776-689a4482e8e1.png)
IAMの情報取得したいので、AWSLambdaFullAccessポリシーを付与したRoleでは、IAMへのアクセス権はないです。
![lambda4.png](https://qiita-image-store.s3.amazonaws.com/0/191079/f94a076e-71ca-335b-9cdc-e227cad4dd9b.png)
RoleにIAMのList*をすべて許可するポリシーを追加
最後に、「Next」で設定した情報を確認して完了とします。

##Python
ここから肝心なPythonを書いてIAM情報を取得し、jsonで返したいです。

``` py
# -*- coding: utf-8 -*-

import json
import boto3

client = boto3.client('iam')

# def function_handler
def lambda_handler(event, context):
  response = client.list_users()
  jsonObj = [""] * len(response["Users"])
  i = 0
  for user in response["Users"]:
    jsonObj[i] = {}
    jsonObj[i]["UserName"] = getValueFromUser(user, "UserName")
    jsonObj[i]["UserId"] = getValueFromUser(user, "UserId")
    jsonObj[i]["Arn"] = getValueFromUser(user, "Arn")
    jsonObj[i]["CreateDate"] = getValueFromUser(user, "CreateDate")
    jsonObj[i]["PasswordLastUsed"] = getValueFromUser(user, "PasswordLastUsed")
    i = i + 1  
  
  return {'statusCode': 200,
          'body': json.dumps(jsonObj),
          'headers': {'Content-Type': 'application/json'}}
  
# def function get value from user object
def getValueFromUser(user, key):
  try:
      return str(user[key])
  except (KeyError):
      return "None"
```
Python自体初心者なので、きれいなコードが書けないです。
はまったポイントだけメモっておきますと、
getValueFromUserをもともと作る想定はなく、

``` py
jsonObj[i]["PasswordLastUsed"] = user["PasswordLastUsed"]
```
のような感じで記述していました。
実行すると、KeyErrorが発生する場合があります。
試行錯誤した結果、IAMユーザ払い出して、一度もログインしたことがない人がいるため、
その人のuser["PasswordLastUsed"]が取れないようです。

``` json
{
  "errorMessage": "'PasswordLastUsed'",
  "errorType": "KeyError",
  "stackTrace": [
    [
      "/var/task/lambda_function.py",
      21,
      "lambda_handler",
      "jsonObj[i][\"PasswordLastUsed\"] = user[\"PasswordLastUsed\"]"
    ]
  ]
}
```
KeyErrorじゃなくて、Noneで返してくれればいいのに。。。
仕方なく、例外処理をとりあえずやってうまく実行ができました。
Python力が上がればもっといい方法はきっとあるはず
成功すると結果が帰ってきます。Detailsを開けばjsonの中身やlogも表示されます。
![lambda5.png](https://qiita-image-store.s3.amazonaws.com/0/191079/958ee100-2c12-be3c-9e35-8c1ec56af0a1.png)


##API Gateway Deploy
次はAPI Gatewayの設定
![aipgateway1.png](https://qiita-image-store.s3.amazonaws.com/0/191079/dccfb0ed-fdb4-2b76-eb18-7c0a561276a8.png)
Triggerで作成されたAPIを開きますと、Resourceとして、下記のようなフローがすでに作成されています。
![apigateway2.png](https://qiita-image-store.s3.amazonaws.com/0/191079/a194a483-c616-fce8-2e1a-55d400df916d.png)
TESTアイコンをクリックして、Methodを選択しAPIテストをコンソール上で実行可能
![apigateway3.png](https://qiita-image-store.s3.amazonaws.com/0/191079/77ee44e8-1298-be1e-27d3-016b7a00cbf6.png)

ただし、これだけでは外部から呼べないです。
APIを作ったら、Stageにデプロイして初めてEndPointと紐付けて、外部からアクセスできるようになります。
Actoinsボタンをクリックして、メニューを展開、Deploy API を選択すると、
Deploy APIポップアップが表示されます。
![apigateway4.png](https://qiita-image-store.s3.amazonaws.com/0/191079/dd389318-c178-9ce2-3227-29dcba8147c1.png)
Deployment stageを選択し、Deployボタンクリック
※このDeployment stageはLambda関数作成するとに設定はものです。

メニューからStagesを選択し、prod配下に作られたAPIがデプロイされる状態になります。
![apigateway５.png](https://qiita-image-store.s3.amazonaws.com/0/191079/e5891c68-2fbc-8b73-0101-df233e700124.png)
ここでGETメソッドを選択すると、右にInvoke URL が表示されます。
クリックすると、jsonデータが表示されます。

ただし、認証をOpen with access keyとしたため、このままではアクセスできません。
ブラウザに下記が表示されます。

``` json
{"message":"Forbidden"}
```

## API Keys & Usage Plans
Access Keyを紐づけさせるには、まずAPI Keys画面に遷移し、ActionsボタンでCreate API Key
![apikey1.png](https://qiita-image-store.s3.amazonaws.com/0/191079/52d449d4-e3b6-09ec-b4b1-a13f9774746b.png)
作っただけでは意味がなく、APIと紐づける必要があります。
そのためにUsage Planを作成
![usageplan1.png](https://qiita-image-store.s3.amazonaws.com/0/191079/a709f240-e08c-2ad3-727a-74cc625b4615.png)

APIをUsage Planに追加し、
![apitousage.png](https://qiita-image-store.s3.amazonaws.com/0/191079/492f6227-26d6-3e3f-991f-76af96eb2d86.png)
次に、API KeyをUsage Planに追加します。
![apikeytousage1.png](https://qiita-image-store.s3.amazonaws.com/0/191079/b3580b09-865d-1382-8bfb-a2884ccadc71.png)
![apikeytousage2.png](https://qiita-image-store.s3.amazonaws.com/0/191079/5ebcfe7f-d2c4-eb8f-e3d4-4faff9a09c7e.png)

## QlikSenseから取得
はやりのBIツールからREST API呼び出して表示してみましょう。
今回はQlikSense Desktopを使ってみます。
起動して、Hubから新規アプリを作成
![qliksense1.png](https://qiita-image-store.s3.amazonaws.com/0/191079/1ae66d15-0a8b-ac7e-89ce-e0c5020bca05.png)
データを追加をクリックし、データソースの選択にRESTをクリック
![qliksense2.png](https://qiita-image-store.s3.amazonaws.com/0/191079/8a8dfc69-b6b9-0a36-78d4-2bc88a650140.png)
URLにInvoke URLを入れます。
![qliksense3.png](https://qiita-image-store.s3.amazonaws.com/0/191079/333665f8-5e44-834c-3275-84551bc5684a.png)
Query headerに**x-api-key**をキーに、API Keyを値として入れます。
![qliksense4.png](https://qiita-image-store.s3.amazonaws.com/0/191079/75eb14d0-f792-e936-f147-f5a306f4c3ef.png)
次へ進みますと、接続しました。
![qliksense5.png](https://qiita-image-store.s3.amazonaws.com/0/191079/0aed51fb-2f2c-5ca2-ee96-30b6442f73f8.png)
その後データをロード出来たら、チャート等自由に作成ができます。