Greengrass Lambdaから使える環境変数について調べてみた

はじめに

サーバーレス開発部@大阪の岩田です。 AWS Lambdaの実行環境で利用できる環境変数については公式ドキュメントに記載がありますが、GreengrassのCoreデバイス上で動作するGreengrass Lambdaについては環境変数に関する情報が特に見つかりませんでした。

自分用のメモとしてGreengrass Lambdaから利用できる環境変数について調べてみたので、内容をご紹介します。

環境変数をログに出力して確認してみる

環境変数を出力するだけの簡単なLambdaを作成し、Greengrassグループにデプロイ&実行してみます。Python2.7で実装しています。

import os

def lambda_handler(event, context):

    print(os.environ)

Greengrassグループにデプロイ&実行すると/greengrass/ggc/var/log/user/<リージョン>/<AWSアカウントID>/<Lambda関数名>にログが出力されます。ログに出力された環境変数をJSONに整形すると以下のようになりました。

{
  "AWS_CONTAINER_AUTHORIZATION_TOKEN": "Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "AWS_CONTAINER_CREDENTIALS_FULL_URI": "http://localhost:8000/2016-11-01/credentialprovider/",
  "AWS_DEFAULT_REGION": "ap-northeast-1",
  "AWS_GG_FIPS_MODE": "false",
  "AWS_GG_HTTP_ENDPOINT": "greengrass-ats.iot.ap-northeast-1.amazonaws.com:8443",
  "AWS_GG_MQTT_ENDPOINT": "greengrass-ats.iot.ap-northeast-1.amazonaws.com:8883",
  "AWS_IOT_HTTP_ENDPOINT": "xxxxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com:8443",
  "AWS_IOT_MQTT_ENDPOINT": "xxxxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com:8883",
  "AWS_IOT_THING_NAME": "CM-Iwata-GGGroup_Core",
  "AWS_REGION": "ap-northeast-1",
  "ENCODING_TYPE": "json",
  "GGC_MAX_INTERFACE_VERSION": "1.2",
  "GG_MQTT_CONNECT_MAX_RETRY_INTERVAL": "60",
  "GG_MQTT_CONNECT_TIMEOUT": "30",
  "GG_MQTT_KEEP_ALIVE": "60",
  "HOME": "/lambda",
  "IPC_SOCK_FILE": "/greengrass_ipc.sock",
  "LOG_LEVEL": "INFO",
  "MY_FUNCTION_ARN": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:CM-IwataPrintEnvVar:1",
  "PATH": "/usr/bin:/usr/local/bin",
  "PYTHONPATH": "/lambda",
  "ROUTER_FUNCTION_ARN": "arn:aws:lambda:::function:GGRouter",
  "SECRETS_MANAGER_FUNCTION_ARN": "arn:aws:lambda:::function:GGSecretManager:1",
  "SHADOW_FUNCTION_ARN": "arn:aws:lambda:::function:GGShadowService",
  "_GG_LOG_FD_DEBUG": "3",
  "_GG_LOG_FD_ERROR": "2",
  "_GG_LOG_FD_FATAL": "5",
  "_GG_LOG_FD_INFO": "1",
  "_GG_LOG_FD_WARN": "4"
}

名前から察するにAWS_IOT_THING_NAMEにはCoreデバイスのモノの名前が入っていそうです。 またGG_MQTT_CONNECT_MAX_RETRY_INTERVALGG_MQTT_KEEP_ALIVEはGreengrassの設定ファイルconfig.jsonで設定した値がセットされていそうです。 他の環境変数に関しても、なんとなく名前から設定値の意味が読み取れます。

こうしてみると同じLambdaとはいえ通常のAWS LambdaとGreengrass Lambdaでは環境変数の中身が結構違いますね。

Greengrass Lambdaの裏側を少しのぞいて見る

せっかくなのでGreengrass Lambdaの環境変数から取得した情報で少し遊んでみます。 環境変数AWS_CONTAINER_CREDENTIALS_FULL_URI に入っているURLに対しておもむろにリクエストを投げてみます。

$ curl http://localhost:8000/2016-11-01/credentialprovider/
Request is missing auth token

どうも認証が必要なようです。AWS_CONTAINER_AUTHORIZATION_TOKENという環境変数にいかにもな文字列が入っているので、今度はAuthorizationヘッダに環境変数AWS_CONTAINER_AUTHORIZATION_TOKENの値を入れてリクエストしてみます。

$ curl http://localhost:8000/2016-11-01/credentialprovider/ -H "Authorization: Basic xxxxxxxxxx"
{\n  \"Message\" : \"You need to attach an IAM role to this deployment group.\"\n}

エラーメッセージが変わりました。今度はちゃんと認証できているようですが、IAMロールをアタッチしろ!と怒られています。そういえばLambdaをデプロイしたGreengrassグループにIAMロールをアタッチしていませんでした。IAMロールをアタッチしてから再度試してみます。

$ curl http://localhost:8000/2016-11-01/credentialprovider/ -H "Authorization: Basic xxxxxxxxxx"
{"AccessKeyId":"xxxxxxxxxx","SecretAccessKey":"xxxxxxxxxx","Token":"xxxxxxxxxx","Expiration":"2019-03-22T03:26:06Z"}

何やらAWSのアクセスキーが払い出されました。このアクセスキーを使ってAWS CLIを叩いてみましょう。

$ export AWS_ACCESS_KEY_ID=xxxxxxxxxx
$ export AWS_SECRET_ACCESS_KEY=xxxxxxxxxx
$ export AWS_SESSION_TOKEN=xxxxxxxxxx
$ aws sts get-caller-identity
{
    "Account": "<AWSアカウントID>",
    "UserId": "xxxxxxxxx:GreenGrassSession",
    "Arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/<Greengrassグループにアタッチしたロール名>/GreenGrassSession"
}

こんな結果が返ってきました。 ここまでの動きを見る限り、環境変数AWS_CONTAINER_CREDENTIALS_FULL_URIで定義されたエンドポイントに対して認証情報付きのリクエストを発行することで、GreengrassグループにアタッチしたロールにAssume Roleするためのクレデンシャルを取得できるようです。 Greengrass LambdaがAWSのサービスにアクセスする際の裏側の動作が少し垣間見えました。

まとめ

Greengrass Lambdaから利用できる環境変数について公式ドキュメントが見当たらなかったので、備忘も兼ねてブログにまとめてみました。 元々はGreengrass LambdaからCoreデバイスのモノの名前を取得するにはどうしたら良いんだっけ?というところから調べ始めたのですが、とりあえず目的は達成できたので良かったです。 誰かの参考になれば幸いです。