VMware Content Library (コンテンツライブラリ) 作成を Amazon S3 + AWS Lambda で自動化してみた

# 1. はじめに

VMware 仮想環境を作ったり消したりしていると、仮想マシンのイメージファイル(ISOやOVFとか)を毎回 vCenter にアップロードするのが面倒だったりしませんか？ 
本番環境と PoC 環境間で OVF ファイルを毎回手動でやりとりするのは大変ではないでしょうか。

[Amazon S3](https://aws.amazon.com/jp/s3/) を [VMware Content Lirabry (コンテンツライラブリ)](https://docs.vmware.com/jp/VMware-vSphere/8.0/vsphere-vm-administration/GUID-254B2CE8-20A8-43F0-90E8-3F6776C2C896.html) として活用することで、安価に仮想マシンのイメージファイルの保管することができます。

本来 Amazon S3 を VMware Content Library として利用するにはひと手間(ファイルのインデックス化)が必要なのですが、今回はその処理も [AWS Lambda](https://aws.amazon.com/jp/lambda/) で自動化させます。

## 構成イメージ

事前にセットアップした Amazon S3 バケットに対して仮想マシンイメージ (OVF) ファイルをアップロードすることで、オンプレミスあるいはクラウド上の VMware 仮想環境 (vCenter) から VMware Content Library としてイメージファイルを利用できるようにします。

今回は VMware 仮想環境として [VMware Cloud on AWS](https://aws.amazon.com/jp/vmware/) を利用していますが、
対象の VMware vCenter が Amazon S3 に対してアクセスさえ可能であればオンプレミス VMware 仮想環境からでも利用可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/4005678f-e6f0-86b3-7711-d8d2f0c292d8.png)

登録されている仮想マシンイメージはそのまま仮想マシンとして VMware 仮想環境にデプロイ可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/245a760b-5d20-11f0-dd4f-cd94e54b4bb2.png)


手順は基本的に次の AWS re:Post 投稿をそのままなぞっていきます。

https://repost.aws/articles/ARKmqoc3ZTTiWOCui9ZT1e7A/automated-s3-content-library-indexing-with-aws-lambda

:::note
執筆時点で、Amazon S3 (標準) の東京リージョンにおけるストレージ料金は、
 1 ヶ月あたり 0.025USD/GB です。
例えば 200GB のイメージファイルを 1 ヶ月保管してもたったの 5 ドル、
低頻度アクセスの S3 ストレージクラスにすると容量単価はさらに安価です。
:::

https://aws.amazon.com/jp/s3/pricing/


# 2. セットアップしてみる

前提条件として、AWS リソース作成および設定が可能な AWS アクセス権限があること、また動作確認用に VMware 仮想マシンの OVF ファイルを持っていることが必要です。

## Amazon S3 の Bucket (バケット) 作成

任意のリージョンにで作成します。
以下、各リソースに対する命名はすべて任意です。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/d03f7ecd-9aaa-3df5-ccce-55e26964cc30.png)

今回は vCenter の Public IP 経由でのアクセスを想定しているので、パブリックアクセスのブロックは無効にしておきます。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/c0bc2be0-5bde-de88-7e61-7a7d948dc0e7.png)

その他の設定はデフォルトのままとしています。
バケットが作成されたら、「`lib1`」という名前のフォルダを作成しておきます。
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/ed65fcad-a86d-e463-6054-647e7f8d4390.png)

### S3 Bucket Policy の設定

特定の Public IP 経由でのアクセス許可をするため、次のように S3 Bucket Policy を設定します。
S3 Bucket の ARN は作成したものに置き換えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/54fdb3c0-fdc3-bf3f-0ba3-ec1129937fdc.png)

```ruby:S3 Bucket Policy (sample)
{
    "Version": "2012-10-17",
    "Id": "S3BucketPolicyForVMCContentsLibrary",
    "Statement": [
        {
            "Sid": "AccessLimitationByIPADDR",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::[作成した S3 Bucket の ARN]/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "x.x.x.x/32",
                        "y.y.y.y/32"
                    ]
                }
            }
        }
    ]
}
```

## AWS IAM 設定

AWS Lambda に S3 に対する操作権限を付与するための AWS IAM Policy / Role を作成していきます。

### IAM Policy 作成

次のように IAM Policy を作成します。
![i1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/54ad3a5a-09cd-9f9c-bc00-2ef8d9f3641a.png)


```ruby:IAM Policy for Lambda (sample)
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "34s3vmware",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:GetObjectAttributes",
                "s3:ListBucket",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::[作成した S3 Bucket の ARN]",
                "arn:aws:s3:::[作成した S3 Bucket の ARN]/*"
            ]
        }
    ]
}
```

IAM Policy が作成されたことを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/32c88141-1b92-9ca9-5046-f04d037b38e0.png)

### IAM Role 作成

先ほど作成したカスタム IAM Policy に加えて、次の 2 つの既存 IAM Policy を含む IAM Role を作成します。

・ `AWSLambdaBasicExecutionRole`
・ `AmazonS3ObjectLambdaExecutionRolePolicy`

![i4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/951cc02f-3b93-e7d4-a26e-f83c905bd9cb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/14b32148-bcf6-027e-bc02-455d80e2a253.png)

IAM Role が作成されたことを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/cc71b0a7-5f76-423b-95b6-d25df3e96656.png)

## AWS Lambda Function の作成

次のように Lambda Function を作成していきます。
Runtime には `Python` を選択し、先ほど作成したカスタム IAM Role をアタッチします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/37c8ef8b-0d66-552f-a209-49136436412c.png)

### Code Source の作成
次のように Code を編集していきます。

#### lambda.function.py の編集

次の GitHub 上のコードをコピー&ペーストし、デフォルトのサンプルコードを上書きして再利用します。
ファイル名は変更可能です。

https://github.com/lamw/vmware-scripts/blob/master/python/sample_lambda_function_for_make_vcsp_2018.py

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/7d2d5506-597e-b283-8898-a3931a68da9b.png)

また 32 行目は作成した S3 Bucket の情報に書き換えておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/b2dd61ad-3c42-e121-16f8-b907d8b41195.png)

```ruby: 変更前
make_vcsp_2018.make_vcsp_s3('REPLACE-ME','REPLACE-ME',False,'REPLACE-ME')
```
```ruby: 変更後 (sample)
make_vcsp_2018.make_vcsp_s3('[作成した S3 Bucket の ARN]','[作成した S3 Bucket の ARN]/lib1',False,'[作成した S3 Bucket の Region]')
```

編集後は保存 (Save) を忘れないようにします。

#### make_vcsp_2018.py の新規作成

次の GitHub 上のコードをコピー&ペーストし、`make_vcsp_2018.py`というファイル名で新規作成して保存します。

https://github.com/lamw/vmware-scripts/blob/master/python/make_vcsp_2018.py

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/be3c9b0f-17ee-58af-da0d-8f681087c13a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/46f84dd1-ddaf-2f91-399f-817bfa645045.png)

### Lambda Function の 詳細設定

#### リソース設定

必要に応じてリソース設定を編集します。
今回はデフォルトのままとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/3821755e-d663-3fa1-dd9c-47e43d810f6b.png)

#### トリガー設定

トリガーを設定していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/ce6b775c-e0f5-e113-b7ba-34fff9627dca.png)

作成した S3 Bucket に対する `create` `delete` イベントに対して、それぞれトリガーを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/8926715a-3d27-1d02-6bce-708e5754edfe.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/830e1589-f26c-e143-2698-518106cef09d.png)

#### Lambda Function の deploy

最後に作成した Lambda Function がデプロイできることを確認しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/d0e24981-b763-b637-cca2-fb388f14a66d.png)

## VMware Content Library の動作テスト

### Amazon S3 への OVF ファイルアップロードおよびインデックス化

対象 S3 Bucket の `lib1` フォルダ配下に、任意の VMware 仮想マシンの OVF ファイルをフォルダごとアップロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/38f75024-7481-5aa7-f291-f05508f0593f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/3b93b92b-657a-24ce-def9-268ed2aeb3e8.png)

アップロードが完了すると自動的に Lambda によって、Amazon S3 を VMware Content Library として利用可能にするために必要なファイルのインデックス化が実行されているのが確認できます。(`items.json` `libs.json`ファイルの作成によって確認できます。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/e29ea385-4f03-589f-e9de-bfd55f2d1a39.png)

### オブジェクトファイルの URL 取得
作成した S3 Bucket の `lib1` フォルダ配下の `lib.json` のファイルの オブジェクト URL をコピーしておきます。
次のステップで利用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/1155d19c-2d8a-4b9c-7684-a364ca10e8a3.png)

### AWS Lambda の実行確認

Lambda Function を確認すると、わずかな時間ですがトリガーを検知して Lambda が動作していたことも確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/a265415e-cd82-2299-95dd-0f895b0b21a8.png)

## Content Library の利用

VMware Cloud on AWS 環境の vCenter から Amazon S3 で作成した Content Library を利用します。

### Amazon S3 との接続設定
今回は S3 Endpoint を利用せず、vCenter の Public IP から直接 Amazon S3 にアクセスさせます。

#### S3 Endpoint 経由でのアクセス無効化
VMware Cloud コンソールから、次のように S3 Gateway Endpoint 経由でのアクセス無効にしておきます。(デフォルトでは有効)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/41fb2831-75ed-2fa7-6e5d-12fedbe28df9.png)

### VMware Content Library の作成
次に vCenter のメニューから「コンテンツライブラリ」に遷移し、作成を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/a76297fa-a0b8-f032-46c0-ea374e6ae92e.png)

次のようにコンテンツライラブリの作成を進めていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/29fd54e8-99e3-8c70-20dc-64dde32c7633.png)

`サブスクライブ済みコンテンツライブラリ`を選択し、先ほどコピーしておいた `lib.json` のファイルの オブジェクト URL を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/c2812dd6-f60f-03e9-a0c6-f75be7217116.png)

証明書、セキュリティポリシーの適用についてはデフォルトのまま次に進みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/5a2dce97-dca8-a3be-84ab-2a81c051ccfa.png)

利用するストレージ領域を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/b7597abf-e4a7-c009-214e-8d4a32c5d2df.png)

設定を確認し、コンテンツライブラリの作成を完了します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/a3050e1b-6cbb-76cd-79ca-44fc195fcbe4.png)

同期が完了すると、次のように確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/3f6e0c9f-55e4-c2f5-1c1b-6dc37a980682.png)

Amazon S3 にアップロードした仮想マシンイメージの OVF ファイルは OVF テンプレートとして登録されているため、そのまま仮想マシンとしてデプロイすることができます。

こちらでセットアップ手順は完了です。

## (補足) Amazon S3 のアクセス制限

今回は Amazon S3 へのアクセスを IP アドレスだけに絞っています。
別のポリシーでアクセス制限をしたい場合は、AWS Policy Generator が便利なのでぜひご活用ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/fbb0d892-c85e-159b-45a4-00708488c5fe.png)

https://awspolicygen.s3.amazonaws.com/policygen.html

また VMware Cloud on AWS 環境においては Amazon S3 に S3 エンドポイント経由でアクセスする場合、Connected VPC 側での設定も必要になります。詳細は次の VMware Docs および AWS 公式ガイドもご参考ください。

[VMware Cloud on AWS 運用ガイド | S3 エンドポイントを使用した S3 バケットへのアクセス](https://docs.vmware.com/jp/VMware-Cloud-on-AWS/services/com.vmware.vmc-aws-operations/GUID-B501FA3C-EAF9-4005-AC72-155C3F592281.html)

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/example-bucket-policies-vpc-endpoint.html

# 3. おわりに

余談ですが、Amazon S3 の VMware Content Library 利用に過去聞き覚えがある方は VMware 界隈で非常に著名な William Lam のブログを以前にご覧になったのかもしれません。

すでに 2018 年頃からブログの中で紹介されていました。

https://williamlam.com/2018/07/creating-a-vsphere-content-library-directly-on-amazon-s3.html

# 4. 参考情報

https://qiita.com/sanjushi003/items/2870c8feced5fd367604

https://qiita.com/sanjushi003/items/d702c39cd4d5fdc469db

https://repost.aws/articles/ARKmqoc3ZTTiWOCui9ZT1e7A/automated-s3-content-library-indexing-with-aws-lambda

https://dev.classmethod.jp/articles/vmware-cloud-on-aws-with-s3-via-vpce/

[(VMware Docs )VMware Content Library について](https://docs.vmware.com/jp/VMware-vSphere/8.0/vsphere-vm-administration/GUID-254B2CE8-20A8-43F0-90E8-3F6776C2C896.html)

[VMware Cloud on AWS 運用ガイド | S3 エンドポイントを使用した S3 バケットへのアクセス](https://docs.vmware.com/jp/VMware-Cloud-on-AWS/services/com.vmware.vmc-aws-operations/GUID-B501FA3C-EAF9-4005-AC72-155C3F592281.html)