REST API で vCenter Server のマシンSSL証明書を置き換える

Share on:

Table of contents

2021/09/16 追記: PowerCLI 12.4 で証明書管理が追加

2021/09/16 にリリースされた PowerCLI 12.4 で vSphere Automation API のモジュールが追加されました。このモジュールには vCenter Server の証明書管理のコマンドレットが含まれています。

PowerCLI 12.4 - What’s New - VMware PowerCLI Blog

The new vSphere Management Module A new module is introduced for vSphere Management. It is a PowerShell-based module backed by the newly introduced vSphere Automation API SDK modules. … Currently, the module contains 6 cmdlets to complement certificate management. Explore the cmdlet documentation to know more.

  • Add-VITrustedCertificate
  • Get-VIMachineCertificate
  • Get-VITrustedCertificate
  • New-VIMachineCertificateSigningRequest
  • Remove-VITrustedCertificate
  • Set-VIMachineCertificate

本記事では PowerShell から Invoke-WebRequest で直接 vCenter Server の REST API (vSphere Automation API) を叩いて証明書の置き換えを行っていましたが、VMware 公式から PowerCLI のコマンドレットが用意されましたので、わざわざ PowerShell から REST API を直接操作する必要性はなくなりました。

今後、PowerShell から vCenter Server のマシン SSL 証明書を管理したい場合は素直に公式の PowerCLI コマンドレットを使用するのが良いと思います。

概要

前回の記事では vSphere Client から vCenter Server のマシン SSL 証明書の CSR を発行して置き換えました。今回の記事では vCenter Server の REST API (vSphere Automation API) を使用して同様の作業を行ってみたいと思います。

vSphere Automation API

vSphere Automation API は vSphere 6.5 から追加された vCenter Server の API です。SOAP ベースだった従来の vSphere Web Services API (VMOMI) とは異なり、REST ベースの API となっています。

VMOMI の機能を完全に網羅して実装しているわけではなさそうですが、基本的な vCenter Server のインベントリ操作の他にも vCenter Server Appliance の構成や管理、証明書の構成なども vSphere Automation API から実行することが可能になっています。

また、vSphere Client の [ホーム] > [デベロッパー センター] にある API Explorer を使用することで、vSphere Automation API に含まれる個々の API の URL や必要なパラメータ、実際の実行結果の確認などを行うことが出来ます。

API Explorer を使用した API の取得

個別のプログラミング言語用の SDK としては現在は Java 向けと Python 向けの2つが最新の vCenter Server 7.0 Update 2 まで対応しています。

その他の言語向けの SDK の状況としては、Perl 向けと .NET 向けは廃止、Ruby 向けは直近のコミットが 2020/06 (開発停滞中?)、Golang 向けは現時点では Beta 版で vCenter Server は未サポート(VMC on AWS と NSX-T の機能のみ)のようです。

今回の記事では動作の理解も含めて SDK は使わず、Windows に付属している PowerShell v5.1 から直接 REST API を叩いて証明書の置き換えを実施していきます。

vSphere Automation API Reference

また、本記事では vCenter Server 6.7 Update 2 ~ 7.0 Update 1 を対象とした REST API を使用しています。vCenter Server 7.0 Update 2 では API がアップデートされており、古い API は引き続き使用できるものの非推奨/廃止となっていますのでご注意ください。

認証および API セッションの作成

vSphere Automation API ではまずはじめにユーザーの認証を行って API 用のセッションを作成する必要があります。POST /rest/com/vmware/cis/session を実行することで可能です。

Create Session | CIS | vSphere CIS REST APIs

 1# ICertificatePolicy.CheckValidationResult メソッドをオーバーライドして
 2# Invoke-WebRequest による HTTPS 接続時の証明書の検証をスキップしています。
 3# 端末がマシン SSL 証明書を信頼できる場合は不要です。
 4# https://docs.microsoft.com/ja-jp/dotnet/api/system.net.icertificatepolicy.checkvalidationresult?view=netframework-4.8
 5add-type @"
 6    using System.Net;
 7    using System.Security.Cryptography.X509Certificates;
 8    public class TrustAllCertsPolicy : ICertificatePolicy {
 9        public bool CheckValidationResult(
10            ServicePoint srvPoint, X509Certificate certificate,
11            WebRequest request, int certificateProblem) {
12            return true;
13        }
14    }
15"@
16[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
17
18# vCenter SSO の認証情報
19$VC_USERNAME = "administrator@vsphere.local"
20$VC_PASSWORD = "VMware1!"
21$VC_HOSTNAME = "vcsa.api.lab"
22
23$cred = New-Object System.Management.Automation.PSCredential(
24          $VC_USERNAME,
25          (ConvertTo-SecureString $VC_PASSWORD -AsPlainText -Force)
26        )
27
28try {
29    $response = Invoke-WebRequest  -Method Post -Credential $cred `
30                    -H @{ "vmware-use-header-authn" = "string"} `
31                    -Uri "https://${VC_HOSTNAME}/rest/com/vmware/cis/session"
32} catch [System.Net.WebException] {
33    Write-Host $_.Exception
34    $_.Exception.Response
35}
36
37$session_id = (ConvertFrom-Json $response.Content).value

Invoke-WebRequest が成功するとレスポンスとしてセッション ID を含む JSON 文字列が取得できるので、ConvertFrom-Json でパースすればオブジェクトとして取り扱えます。

1PS> Write-Host $response.Content
2{"value":"bc9c22db3ada2cb3c4726effd93e042b"}
3
4PS> $session_id = (ConvertFrom-Json $response.Content).value

vCenter Server での CSR の生成

API セッションが作成できたので、続いて vCenter Server から CSR を取得してみます。取得したセッションIDを vmware-api-session-id ヘッダに指定して POST /rest/vcenter/certificate-management/vcenter/tls-csr を実行することで可能です。

Create vCenter TLS CSR | vSphere vCenter REST APIs

 1# CSR 生成のための証明書情報
 2$CSR_INFO = ConvertTo-Json @{
 3    "spec" = @{
 4        "common_name" = "vcsa.api.lab"
 5        "country" = "JP"
 6        "email_address" = "admin@api.lab"
 7        "key_size" = 2048
 8        "locality" = "Shibuya-ku"
 9        "organization" = "My Lab"
10        "organization_unit" = "API Unit"
11        "state_or_province" = "Tokyo"
12        "subject_alt_name" = @("$VC_HOSTNAME")
13    }
14}
15
16$headers = @{
17    "vmware-api-session-id" = ${session_id}
18    "Content-Type" = "application/json"
19}
20
21try {
22    $response = Invoke-WebRequest -Method Post -Headers $headers -Body $CSR_INFO `
23        -Uri "https://${VC_HOSTNAME}/rest/vcenter/certificate-management/vcenter/tls-csr"
24} catch [System.Net.WebException] {
25    Write-Host $_.Exception
26    $_.Exception.Response
27}
28
29$issue_date = Get-Date -Format "yyyyMMdd_HHmmss"
30(ConvertFrom-Json $response.Content).value.csr > "${issue_date}.csr"

Invoke-WebRequest が成功すると CSR の内容を含む JSON 文字列が取得できるので、パースしてファイルに保存しておきます。

1PS> $response.Content
2{"value":{"csr":"-----BEGIN CERTIFICATE REQUEST-----\nMIIDJTCCAg0CAQAwbTEVMBMGA1UEAwwMdmNzYS5hcGkubGFiMQswCQYDVQQGEwJK\nUDEOMAwGA1UECAwFVG9reW8xEzARBgNVBAcMClNoaWJ1eWEta3UxDzANBgNVBAoM\nBk15IExhYjERMA8GA1UECwwIQVBJIFVuaXQwggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQDIrlYJLyhmDryEDXiXFWwr4FEamarCqem9SenBILmevaQTOQE1\nIYGocqxYXPavP2Gzdo3KkU23VGt/Jgcz009eZqu96Kxw8xFxEXJDoI91aT+3d6Ip\nAaJXH6Md9h3pUT5XERtSwQcm09JVXVtRJLPMmDeVo2YUiIGyBB5FNVXz+V7Xz9Ur\nhgo+pG7o9TsKN1tp2gaJyPiO7Hm5Q6r3W22jAg1ebQLfvzpfOBw+OjblR50Zbs2R\nhsG94vydWBsl2rCGgTd+efjljqExiRZaWC9fjuGRk2cpE7F3RiFJT1umWGStzcRN\nwJkjBOQSZKOQfDdsym8cLyeCip8vcoihApatAgMBAAGgczBxBgkqhkiG9w0BCQ4x\nZDBiMAsGA1UdDwQEAwIF4DA0BgNVHREELTArgQ1hZG1pbkBhcGkubGFiggx2Y3Nh\nLmFwaS5sYWKCDHZjc2EuYXBpLmxhYjAdBgNVHQ4EFgQUmCj2XqWkB4kM2ozlnnS0\ntkabC20wDQYJKoZIhvcNAQELBQADggEBAKlu3AOD+FxmKHx5KlI9IjfBDKQLGRQj\nOHB+pjCrfmgzxElbIp6H+PolyIYHcIm+n9uc1Ymm2v4z2UHvvl2JLxoBTIYPVX+T\nouZnKsHlyMCDVwsaPbvUjn/CxQtG8q6nwXuapqtE2B01B2b5LUBEbjjkb1IDKVsz\nifNTXMYav1EkYh1kw9tDZcXXED8OJd3XIlqwMj6BLXjs1zpZYghJTuLZiARFnMNI\nYvzifN4EkOSYmAE7UBYVxjCc8vkZKlc817ELURK4S51zKkbR0gN7pofB+XR4OYa+\nt6mctK/h5TTDlS5n8dq1ei45TGrqbAqZGwaAwJJn1AKVM5R3qzpOAHM=\n-----END CERTIFICATE REQUEST-----"}}
3
4PS> $issue_date = Get-Date -Format "yyyyMMdd_HHmmss"
5PS> (ConvertFrom-Json $response.Content).value.csr > "${issue_date}.csr"

CA への証明書の署名を要求

CSR が生成できたので CA に証明書の署名を要求します。今回は certreq.exe で ADCS に証明書を要求しています。

1$CERTREQ_CONFIG = "ADCS.api.lab\api-ADCS-CA-1"
2certreq -submit -attrib CertificateTemplate:WebServer `
3    -config ${CERTREQ_CONFIG} `
4    "${issue_date}.csr" `
5    "${issue_date}.crt"

なお、証明書テンプレートにデフォルトの [Web サーバー] を使って雑に対応してしまっていますが、本来は以下の KB2112009 を参考に適切な証明書テンプレートを作っておいてください。

vSphere 6.x/7.x で SSL 証明書を作成するために Microsoft 認証局テンプレートを作成する (2112009)

vCenter Server の証明書の置き換え

署名済み証明書が取得できたので CA 証明書と合わせて vCenter Server にインポートします。PUT /rest/vcenter/certificate-management/vcenter/tls を実行することで可能です。

Set vCenter TLS | Certificate Management | vSphere vCenter REST APIs

KB80803 対策のため改行コードは LF に置き換えています。

 1$issued_cert = (Get-Content "${issue_date}.crt" -Raw)
 2$root_cert = (Get-Content "cacert.cer" -Raw)
 3$replace_spec = (ConvertTo-Json @{
 4  "spec" = @{
 5    "cert" = "$issued_cert"
 6    "root_cert" = "$root_cert"
 7  }
 8}).Replace("\r\n","\n")
 9
10try {
11    Invoke-WebRequest -Method Put -Headers $headers -Body $replace_spec `
12        -Uri https://${VC_HOSTNAME}/rest/vcenter/certificate-management/vcenter/tls
13} catch [System.Net.WebException] {
14    Write-Host $_.Exception
15    $_.Exception.Response
16}

成功すると vCenter Server のサービスが再起動します。再起動が終わったら証明書の置き換えは完了です。

おわりに

今回の記事では vSphere Automation API を使用して vCenter Server での CSR 生成やマシンSSL証明書の置き換えを行いました。CSR を vCenter Server で生成しているため発行された証明書の有効期限は2年固定になりますが、openssl などを使って自前で秘密鍵 / CSR / 証明書を作成すれば有効期限がより短い証明書をインポートすることも出来ます。

vCenter Server 外部で一から作成した証明書は秘密鍵もインポートが必要になるため、PUT /rest/vcenter/certificate-management/vcenter/tls のリクエストボディに追加する必要がありますが、実装次第では Let’s Encrypt のように証明書を90日ごとに自動更新するなども出来そうかなと思います。

なお、上述したコードをまとめたサンプルファイルを GitHub に置いています。だいぶ雑な作りですが必要に応じて参照いただけたら幸いです。

Jangari-nTK/machine-ssl-cert-replace-powershell