goodbyegangsterのブログ

備忘録的な

AWS IoT Greengrass環境の設定

UbuntuAWS IoT Greengrass Coreソフトウェアをインストールして、Greengrass利用環境を作成する手順を確認します。

環境

  • Ubuntu 20.04
  • AWS IoT Greengrass Core 1.10.1

事前準備

Greengrassモジュールとなる AWS IoT Greengrass Core をインストールするにあたり、前提条件を確認します。下記を参考にしつつ作業を実施しています。

Amazon EC2 インスタンスのセットアップ

OSユーザー・グループの作成

作成します。

$ sudo adduser --system ggc_user
$ sudo groupadd --system ggc_group

このOSユーザーは、Greengrass上でLambdaを実行する際に利用されるユーザーとのことです。

ハードウェア/ソフトウェア・シンボリックリンクの保護設定

fs.protected_hardlinksfs.protected_symlinks の設定値が1となっている事を確認します。

$ sudo sysctl -a | grep fs.protected
fs.protected_fifos = 1
fs.protected_hardlinks = 1
fs.protected_regular = 2
fs.protected_symlinks = 1

シンボリックリンクの保護についてよく分からず検索。RedHatのマニュアルでしたが詳細を記載してくれていました。

To prevent malicious users from exploiting potential vulnerabilities caused by unprotected hard and symbolic links, Red Hat Enterprise Linux 7 includes a feature that only allows links to be created or followed provided certain conditions are met.

In case of hard links, one of the following needs to be true:

・The user owns the file to which they link.

・The user already has read and write access to the file to which they link.

In case of symbolic links, processes are only permitted to follow links when outside of world-writeable directories with sticky bits, or one of the following needs to be true:

・The process following the symbolic link is the owner of the symbolic link.

・The owner of the directory is the same as the owner of the symbolic link.

4.2.6. Protecting Hard and Symbolic Links

Symlink race というシンボリックリンクを利用した脆弱性があるんですね。

Symlink race

cgroupのマウント

cgroup用ファイルシステムをマウントします。AWS側で用意してくれているシェルスクリプトをダウンロードして実行します。Ubuntuであれば、デフォルトにて既にマウントされている筈なので、特に何か設定される事はないです。

$ curl https://raw.githubusercontent.com/tianon/cgroupfs-mount/951c38ee8d802330454bdede20d85ec1c0f8d312/cgroupfs-mount > cgroupfs-mount.sh
$ chmod +x cgroupfs-mount.sh
$ sudo bash ./cgroupfs-mount.sh

Greengrass上でLambdaを実行させる場合、LambdaはGreengrassにて用意されたコンテナ環境上で実行されることになり、そのためにcgroupfsが必要となっています。Greengrass上Lambdaの動作に関しては以下を参照。

Lambda 関数のコンテナ化を選択する場合の考慮事項

Java Runtimeのインストール

バージョン8をインストールします。

$ sudo apt install openjdk-8-jdk
$ java -version
openjdk version "1.8.0_252"
OpenJDK Runtime Environment (build 1.8.0_252-8u252-b09-1ubuntu1-b09)
OpenJDK 64-Bit Server VM (build 25.252-b09, mixed mode)

Python3.7のインストール

Greengrass上でLambdaを動かす場合、当然そのためのRuntimeが必要になります。今後Python3.7のプログラムを動かす予定あるため、Python3.7をインストールしておきます。Ubuntu20のプリインストールされたPythonバージョンは3.8でした。

Python3.7をインストールできるPPA(Personal Package Archive)を探してきてリポジトリを追加、インストールします。

$ sudo add-apt-repository ppa:deadsnakes/ppa
$ sudo apt-get update
$ sudo apt-get install python3.7

依存関係の確認

依存関係を満たしているか、確認用シェルスクリプトを実行します。これもAWS側で用意してくれているので、ダウンロードして実行します。

$ wget https://github.com/aws-samples/aws-greengrass-samples/raw/master/greengrass-dependency-checker-GGCv1.10.x.zip
$ unzip greengrass-dependency-checker-GGCv1.10.x.zip
$ cd greengrass-dependency-checker-GGCv1.10.x
$ sudo ./check_ggc_dependencies | more

僕の環境では、Javaが見つからないと言われました。以下参考。

----------------------------Commands and software packages--------------------------
Python 2.7: Not found
Python 3.7 version: 3.7.7
NodeJS 12.x: Not found
Java 8: Not found

シェルスクリプトの中身を見てみると java8 というコマンドにて探しているみたいで、以下のようなシンボリックリンクを作成した後に、再度チェックスクリプトを実行すると Not found ではなくなりました。

$ sudo ln -s /usr/bin/java /usr/local/bin/java8
$ java8 -version
openjdk version "1.8.0_252"
OpenJDK Runtime Environment (build 1.8.0_252-8u252-b09-1ubuntu1-b09)
OpenJDK 64-Bit Server VM (build 25.252-b09, mixed mode)

該当シェルスクリプトのReadmeはこちら。

Greengrass core v1.10.x dependencies checker

AWS IoT側の準備

Greengrassと通信することになるAWS IoT側の設定を実施します。参考マニュアルはこちら。

AWS IoT の AWS IoT Greengrass の設定

AWS IoTのAWSコンソールに行き、Greengrassの Get started ページを開きます。

create a Group をクリックします。

f:id:goodbyegangster:20200617193609p:plain

Greengrassが他のAWSサービスをアクセスするため、必要なIAMポリシーをもったService-Linked IAM Roleを作成し、Greengrassにアタッチします。 Grant permission をクリックします。

f:id:goodbyegangster:20200617193627p:plain

作成し付与されたService-Linked Roleは、以下コマンドにて確認できます。

$ aws greengrass get-service-role-for-account --region ap-northeast-1
{
    "AssociatedAt": "2020-06-09T14:28:34Z",
    "RoleArn": "arn:aws:iam::12345678901:role/service-role/Greengrass_ServiceRole"
}

IAM Roleのより詳細を確認すると、 AWSGreengrassResourceAccessRolePolicy というIAMポリシーが付与されており、AWS IoTやLambda、S3等に対するアクセス権限を与えられています。

Greengrass サービスロールを取得する (CLI)

続いて、具体的なGreengrass向け設定を行います。 Use Default creation をクリックします。

f:id:goodbyegangster:20200617193650p:plain

作成するGreengrass Group名を入力します。

f:id:goodbyegangster:20200617193703p:plain

Greengrassグループが良く分からず、マニュアルを確認したのですが、それでもあまり理解できず。

Greengrass グループは、Greengrass コア、デバイスサブスクリプションなどのコンポーネントと設定のコレクションです。グループは、操作の範囲を定義するために使用されます。たとえば、グループは建物の 1 つの階、1 台のトラック、または採掘現場全体を表します。

AWS IoT Greengrass グループ

結局、Greengrassグループ単位でLambdaがデプロイされることになるので、それを踏まえてグループ単位を考えてあげればいいのでは、と考えています。

続いて、Greengrass Core名を入力します。

f:id:goodbyegangster:20200617193716p:plain

これもイマイチ分からなかったのですが、連携されるIoT機器がここで設定した名前にて、AWS IoTのThingsとして管理されることになります、ということは理解しました。

AWS IoT Greengrass コア は、エッジ環境でハブまたはゲートウェイとして機能する AWS IoT のモノ (デバイス) です。他の AWS IoT デバイスと同様に、コアはレジストリ内にあり、デバイスシャドウを保持し、AWS IoT を認証するデバイス証明書を使用します。コアデバイスAWS IoT Greengrass Core ソフトウェアを実行します。これによって、通信、車道同期やトークン交換などの Greengrass グループのローカルプロセスを管理することができます。

AWS IoT Greengrass Core の設定

実行される内容を確認して、 Create Group and Core をクリックします。

f:id:goodbyegangster:20200617193726p:plain

デフォルトを利用して作成される設定を確認しています。

Create a new Greengrass Group in the cloud

その名の通り、Greengrassグループを作成してくれています。

Provision a new Core in the IoT Registry and add to the Group

Greengrass CoreをThingsとして登録してくれています。

Generate public and private key set for your Core

IoT機器側にインストールされるGreengrass CoreソフトウェアとAWS IoTとは、デバイス証明書と呼ばれるX.509証明書(公開鍵証明書)により通信することになります。そのため、X.509証明書作成用の秘密鍵と公開鍵を作成しています。作成された鍵ファイルは、次のステップでダウンロードすることになります。

Generate a new security certificate for the Core using the keys

上述の公開鍵と秘密鍵によりX.509証明書を作成しています。この証明書も、次のステップでダウンロードすることになります。

Attach a default security policy to the certificate

上述の証明書と紐づくIoTポリシーを作成しています。作成されたポリシーは下記でした。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:Publish",
        "iot:Subscribe",
        "iot:Connect",
        "iot:Receive"
      ],
      "Resource": [
        "*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:GetThingShadow",
        "iot:UpdateThingShadow",
        "iot:DeleteThingShadow"
      ],
      "Resource": [
        "*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "greengrass:*"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

Enable stream manager on the Core device

作成したGreengrassグループでのStream Manger機能を有効としています。

AWS IoT Greengrass コアでのデータストリームの管理

Download these resource as a tar.gz をクリックします。作成された各鍵ファイルと証明がダウンロードされます。

f:id:goodbyegangster:20200617193744p:plain

AWS IoT Greengrass Coreの起動設定

Ubuntu側にて、AWS IoT Greengrass Coreをインストールして起動します。参考マニュアルはこちら。

コアデバイスでの AWS IoT Greengrass の起動

鍵・証明書ファイルのアップロード

前述の処理にてダウンロードしたtarファイルを、Ubuntuにアップロードします。

AWS IoT Greengrass Coreソフトウェアのダウンロード

動作させるGreengrass Coreソフトウェアを、Ubuntuにダウンロードします。

$ wget https://d1onfpft10uf5o.cloudfront.net/greengrass-core/downloads/1.10.1/greengrass-linux-x86-64-1.10.1.tar.gz

ダウンロードURLは、以下のページより確認できます。

AWS IoT Greengrass ダウンロード

tarファイルの展開

Ubuntu上に持ってきた鍵・証明書ファイルとGreengrass Coreソフトウェアのtarファイルを展開します。展開先は / 直下としています。

$ sudo tar -xzvf greengrass-linux-x86-64-1.10.1.tar.gz -C /
$ sudo tar -xzvf xxxx-setup.tar.gz -C /greengrass

鍵・証明書ファイルのtarファイル内には、Greengrass Coreソフトウェア向けのコンフィグファイルも入っています。 /greengrass/config/config.json というファイルにて配布されているはずです。必要な設定は既に設定済となっているため編集は不要ですが、設定可能なパラーメーターは以下マニュアルにて確認できます。

AWS IoT Greengrass Core 設定ファイル

ルートCA証明書のダウンロード

AWSのルートCA証明書をダウンロードします。ダウンロード先は、先程証明書一式を展開した /greengrass/certs フォルダ内となります。

$ cd /greengrass/certs/
$ sudo wget -O root.ca.pem https://www.amazontrust.com/repository/AmazonRootCA1.pem

Greengrass Coreソフトウェア起動用のユニットファイルの作成

Greengrass Coreソフトウェアを自動起動とする、Systemdユニットファイルを作成します。今回作成したユニットファイルは下記。

/etc/systemd/system/greengrass.service

[Unit]
Description=Greengrass

[Service]
Type=simple
PIDFile=/var/run/greengrassd.pid
Restart=on-failure
ExecStart=/greengrass/ggc/core/greengrassd start
ExecReload=/greengrass/ggc/core/greengrassd restart
ExecStop=/greengrass/ggc/core/greengrassd stop

[Install]
WantedBy=multi-user.target

有効化します。

$ sudo chown root:root /etc/systemd/system/greengrass.service
$ sudo chmod 644 /etc/systemd/system/greengrass.service
$ sudo systemctl daemon-reload
$ sudo systemctl enable greengrass

Greengrass Coreソフトウェアの起動

起動します。

$ sudo systemctl start greengrass

プロセスが正しく起動されたことを確認します。

$ sudo systemctl status greengrass
● greengrass.service - Greengrass
     Loaded: loaded (/etc/systemd/system/greengrass.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2020-06-16 07:47:21 UTC; 24s ago
   Main PID: 1777 (5)
      Tasks: 88 (limit: 1113)
     Memory: 202.8M
     CGroup: /system.slice/greengrass.service
             ├─1777 /greengrass/ggc/packages/1.10.1/bin/daemon -core-dir /greengrass/ggc/packages/1.10.1 -greengrassdPid 1766
             ├─1824 /lambda/greengrassSystemComponents -runAs=connectionManager
             ├─1849 /lambda/greengrassSystemComponents -runAs=cloudSpooler
             ├─1852 /lambda/greengrassSystemComponents -runAs=shadowSync
             ├─1861 /lambda/greengrassSystemComponents -runAs=deviceCertificateManager
             ├─1866 /lambda/greengrassSystemComponents -runAs=secretManager
             ├─1873 java -cp /lambda/stream_manager/AWSGreengrassStreamManager.jar:/runtime/java8/* com.amazonaws.iot.greengrass.streammanager.StreamManagerService
             ├─1878 /lambda/greengrassSystemComponents -runAs=shadow
             ├─1884 /lambda/greengrassSystemComponents -runAs=tes
             ├─1891 /lambda/ipdetector
             └─2341 python3.7 -u /runtime/python/lambda_runtime.py --handler=lambda_function.lambda_handler

Jun 16 07:47:21 vagrant systemd[1]: Started Greengrass.
Jun 16 07:47:21 vagrant greengrassd[1766]: Setting up greengrass daemon
Jun 16 07:47:21 vagrant greengrassd[1766]: Validating hardlink/softlink protection
Jun 16 07:47:21 vagrant greengrassd[1766]: Waiting for up to 1m10s for Daemon to start
Jun 16 07:47:28 vagrant greengrassd[1766]: Greengrass successfully started with PID: 1777