VCF Installer に Offline Depot 用の CA 証明書を API でインポートする

Overview

概要

VCF Installer での VCF9 のデプロイにあたり、オフラインデポに HTTPS での接続を試みたところ以下の KB#403203 に記載の事象に遭遇しました。

オフラインデポのサーバ証明書に署名した CA 証明書が VCF Installer 側には無いので、サーバ証明書の検証がおこなえないため失敗する状況は想定できました。しかし、VCF 9 の VCF Installer には少なくとも現時点では GUI 上からは CA 証明書をインポートする手段が無いようです。

すでに Broadcom の中の人がオフラインデポへの接続で TLS を無効する方法(裏技?)を公開していますが、せっかくなので Broadcom 公式から開発者向けドキュメントが公開されている API を使用して CA 証明書をインポートすることで解決してみました。

事前準備: オフラインデポを構成

まずはオフラインデポを構成するため、VCF Download Tool を使用して各コンポーネントのバイナリをダウンロードします(Broadcom Support Portal で生成したダウンロードトークンが必要です)。

1$ ./bin/vcf-download-tool binaries download --vcf-version 9.0.0.0 --automated-install -d /mnt/depot -t INSTALL --depot-download-token-file downloadtoken.txt

ダウンロードが完了すると、デポのディレクトリ階層は以下のようになります。

 1$ tree /mnt/depot/
 2/mnt/depot/
 3└── PROD
 4    ├── COMP
 5    │   ├── NSX_T_MANAGER
 6    │   │   └── nsx-unified-appliance-9.0.0.0.24733065.ova
 7    │   ├── SDDC_MANAGER_VCF
 8    │   │   ├── Compatibility
 9    │   │   │   └── VmwareCompatibilityData.json
10    │   │   └── VCF-SDDC-Manager-Appliance-9.0.0.0.24703748.ova
11    │   ├── VCENTER
12    │   │   └── VMware-VCSA-all-9.0.0.0.24755230.iso
13    │   ├── VCF_OPS_CLOUD_PROXY
14    │   │   └── Operations-Cloud-Proxy-9.0.0.0.24695833.ova
15    │   ├── VRA
16    │   │   └── vmsp-vcfa-combined-9.0.0.0.24701403.tar
17    │   ├── VROPS
18    │   │   └── Operations-Appliance-9.0.0.0.24695812.ova
19    │   └── VRSLCM
20    │       └── VCF-OPS-Lifecycle-Manager-Appliance-9.0.0.0.24695816.ova
21    ├── metadata
22    │   ├── manifest
23    │   │   └── v1
24    │   │       └── vcfManifest.json
25    │   └── productVersionCatalog
26    │       └── v1
27    │           ├── productVersionCatalog.json
28    │           └── productVersionCatalog.sig
29    └── vsan
30        └── hcl
31            ├── all.json
32            └── lastupdatedtime.json
33
3418 directories, 13 files

こちらのデポをルートとして HTTP(S) サーバで公開します。今回は nginx で構成しました。CA 証明書やサーバ証明書(Subject Alternative Name を含む)、秘密鍵は予め作成しておいたものを使用します。

1$ cat /etc/nginx/nginx.conf
2    ...
3        server {
4                listen          443 ssl;
5                root            /mnt/depot;
6                ssl_certificate /etc/pki/tls/certs/server.crt;
7                ssl_certificate_key /etc/pki/tls/private/server.key;
8        }
9    ...

curl でデポの URL にアクセスし、CA 証明書でサーバ証明書の検証がおこなえることを確認します(192.168.0.128 はオフラインデポの IP アドレス)。

1$ curl --cacert ca.crt https://192.168.0.128/PROD/metadata/productVersionCatalog/v1/productVersionCatalog.json
2{
3    "version": 1,
4    "sequenceNumber": 22,
5    "creationTime": "2025-05-22T23:54:05Z",
6    "publishedTime": "2025-07-10T05:08:20Z",
7    ...
8}

なお、今回は HTTP サーバ側で Basic 認証は構成しなかったため、VCF Installer からオフラインデポへの接続時のユーザー名とパスワードは任意のもの(仮で admin)としています。

CA 証明書のインポート前: 接続失敗

この時点で VCF Installer からオフラインデポに接続を試みてみます。まだ VCF Installer 側の証明書ストアに CA 証明書がインポートされていないため、オフラインデポのサーバ証明書が検証できず接続に失敗する状況となります。

VCF Installer 側に SSH 接続して /var/log/vmware/vcf/lcm/lcm-debug.log を確認すると、以下のように TLS 接続関連のエラーが確認できます。

12025-07-17T12:31:45.854+0000 INFO  [vcf_lcm,6878ed313a62e548929ed8e57fa02114,8267] [c.v.v.l.r.a.c.v.s.DepotSettingsController,http-nio-127.0.0.1-7400-exec-3] Update Depot Settings: { "offlineAccount": { "username": "admin", "password": "*****" }, "depotConfiguration": { "isOfflineDepot": true, "hostname": "192.168.0.128", "port": 443 } }
22025-07-17T12:31:45.855+0000 INFO  [vcf_lcm,6878ed313a62e548929ed8e57fa02114,8267] [c.v.e.s.l.s.i.DepotSettingsServiceImpl,http-nio-127.0.0.1-7400-exec-3] validating VCF_DEPOT account
32025-07-17T12:31:45.855+0000 DEBUG [vcf_lcm,6878ed313a62e548929ed8e57fa02114,8267] [c.v.e.s.l.b.d.depot.DepotDownloader,http-nio-127.0.0.1-7400-exec-3] Downloading sourceFilePath /metadata/productVersionCatalog/v1/productVersionCatalog.json from host 192.168.0.128 port 443 and user admin and isOfflineDepot true
42025-07-17T12:31:45.855+0000 DEBUG [vcf_lcm,6878ed313a62e548929ed8e57fa02114,8267] [c.v.e.s.l.b.d.depot.DepotDownloader,http-nio-127.0.0.1-7400-exec-3] Getting file size for [/metadata/productVersionCatalog/v1/productVersionCatalog.json] from URL[https://192.168.0.128:443/PROD/metadata/productVersionCatalog/v1/productVersionCatalog.json]
52025-07-17T12:31:45.865+0000 DEBUG [vcf_lcm,6878ed313a62e548929ed8e57fa02114,8267] [c.v.e.s.l.b.d.depot.DepotDownloader,http-nio-127.0.0.1-7400-exec-3] Executing HEAD /PROD/metadata/productVersionCatalog/v1/productVersionCatalog.json
62025-07-17T12:31:45.877+0000 INFO  [vcf_lcm,6878ed313a62e548929ed8e57fa02114,8267] [o.a.h.c.h.i.c.HttpRequestRetryExec,http-nio-127.0.0.1-7400-exec-3] Recoverable I/O exception (org.bouncycastle.tls.TlsFatalAlert) caught when processing request to {s}->https://192.168.0.128:443
72025-07-17T12:31:45.888+0000 ERROR [vcf_lcm,6878ed313a62e548929ed8e57fa02114,8267] [c.v.e.s.l.b.d.depot.DepotDownloader,http-nio-127.0.0.1-7400-exec-3] Got TlsFatalAlert connecting to 192.168.0.128:443
82025-07-17T12:31:45.889+0000 ERROR [vcf_lcm,6878ed313a62e548929ed8e57fa02114,8267] [c.v.v.l.r.a.c.v.s.DepotSettingsController,http-nio-127.0.0.1-7400-exec-3] Update Depot Settings
9com.vmware.evo.sddc.lcm.model.depot.exception.DepotConnectionFailureException: Secure protocol communication error, check logs for more details

本題: API による CA 証明書のインポート

ようやく本題の API を使用した CA 証明書のインポートです。

流れとしては、

まず以下のようにアクセストークンを取得します(192.168.0.192は VCF Installer の IP アドレス)。

1$ curl -sk -X POST -H 'Content-Type: application/json' -d '{ "username": "admin@local", "password": "VMware1!VMware1!" }' https://192.168.0.192/v1/tokens > /tmp/token.txt
2$ cat /tmp/token.txt
3{
4  "accessToken": "eyJhbGciOiJIUz......E7XZGBOkPuZ0ERQ_MrWfN5-j8",
5  "refreshToken": {
6    "id": "12c07383-8ba4-4dfc-b1c1-30734f53ac77"
7  }
8}
9$ ACCESS_TOKEN=$(jq -r .accessToken /tmp/token.txt)

取得したアクセストークンを使用して CA 証明書(ca.crt)をインポートします。

1$ curl -sk -X POST -H "Authorization: Bearer $ACCESS_TOKEN" \
2  -H "Content-Type: application/json" \
3  -d "{ \"certificate\": \"$(cat ca.crt)\", \"certificateUsageType\": \"TRUSTED_FOR_OUTBOUND\" }" \
4  https://192.168.0.192/v1/sddc-manager/trusted-certificates

成功すると以下のようにインポートされた CA 証明書が Alias と合わせて response body として返されます。

1{"elements":[{"alias":"vcf_myrootca_4d6d26caa5fca4b9a08ad3d6491ad38916c257ca5c5ca5f7bf0080ad2b8385d6","certificate":"-----BEGIN CERTIFICATE-----\nMIIDmTCCAoGgAwIB....uCPA\u003d\u003d\n-----END CERTIFICATE-----\n"}]}

これで VCF Installer への CA 証明書のインポートは完了です。

CA 証明書のインポート後: 接続成功

CA 証明書をインポートした後に改めて VCF Installer からオフラインデポに接続すると、先ほどと異なり VCF Installer 側でサーバ証明書が検証できるため接続に成功しました。

おわりに

今回は VCF Installer からオフラインデポに HTTPS 接続するために CA 証明書を VCF Installer にインポートしてみました。

オフラインデポ側で Basic 認証を使う場合には認証情報を平文でネットワーク上に流さないために TLS での暗号化は必須になります。単なるインストールバイナリの転送とはいえど、セキュリティが厳しい環境では TLS 通信の適切なハンドリングが必要な可能性もありますので、そういった場合にお役に立てば幸いです。

補足: リフレッシュトークン

Create Token API で一緒に取得した refreshToken は Refresh Access Token API でアクセストークンを更新するためのトークンです。

アクセストークンを持っているユーザーは「それが誰かにかかわらず」トークン内で指定された機能にアクセスできるため、アクセストークンは一般に有効期限が短く設定されています。このため、定期的な処理などで利用する場合にはアクセストークンの有効期限を確認しつつ、必要に応じてリフレッシュトークンで新しいアクセストークンを生成することになります。

なお、アクセストークンの形式は JSON Web Token (JWT) のため任意のツールでデコードできます。Auth0(Okta)が提供しているデコーダーを使って iat (Issued at) と exp (Expiration time) を確認すると差が 3600(秒)、つまり1時間で有効期限が切れることが分かります。

 1{
 2  "jti": "64236353-4a5c-4023-9409-066f39aecd0d",
 3  "iat": 1752756332,
 4  "sub": "admin@local",
 5  "iss": "vcf-auth",
 6  "aud": "sddc-services",
 7  "nbf": 1752756332,
 8  "exp": 1752759932,
 9  "user": "admin@local",
10  "name": "admin@local",
11  "scope": [
12    ...
13    "CERT_READ",
14    "CERT_WRITE",
15    "CA_READ",
16    "CA_WRITE",
17    ...
18  ],
19  "role": [
20    "ADMIN"
21  ],
22  "isIssuedForJwt": false
23}