現代資料中心管理仰賴虛擬機器自動化,而將既有 VMware 虛擬機器整合至 Terraform 時,逆向工程扮演關鍵角色。本文示範如何以 Python 透過 vSphere 的 Managed Object Browser(MOB)逆向分析虛擬機器,擷取必要組態資訊。首先需安裝 pyVim 和 pyVmomi 函式庫,以便與 MOB 互動。範例程式碼示範如何透過 vCenter API 取得虛擬機器資訊,包含名稱、作業系統等。程式碼中設定 vCenter 連線資訊、目標虛擬機器名稱,並使用相關函式庫連線至 vCenter,透過 MOB 瀏覽並取得虛擬機器物件,最終印出所需資訊。此外,文章也說明瞭 Terraform 的架構,包含提供者、核心、外掛等元件,以及它們如何協同運作以管理基礎設施,並說明如何運用這些資訊來建構反向工程解決方案,以自動化匯入流程並提升管理效率。
使用 Python 透過 vSphere 的 Managed Object Browser(MOB)逆向工程 VMware 虛擬機器
在現代資料中心中,VMware 虛擬機器的管理和自動化是一項關鍵任務。然而,當我們需要將現有的 VMware 虛擬機器匯入到 Terraform 中時,逆向工程成為一個重要的步驟。這篇文章將探討如何使用 Python 透過 vSphere 的 Managed Object Browser(MOB)來逆向工程 VMware 虛擬機器,並提取所需的組態資訊。
前置準備
在開始之前,我們需要確保安裝了以下 Python 函式庫:pyVim 和 pyVmomi。這些函式庫允許我們與 vSphere 的 Managed Object Browser(MOB)進行互動。如果這些函式庫尚未安裝,可以使用以下命令進行安裝:
sudo pip install pyvim
sudo pip install pyvmomi
構建 Python 程式碼
接下來,我們將展示如何使用 Python 程式碼來提取 VMware 虛擬機器的詳細資訊。以下是完整的程式碼範例,這段程式碼可以從 GitHub 倉函式庫中取得(https://github.com/sumitbhatia1986/Terraform-VMware-ReverseEngineering/blob/main/MOB_walkthrough.py):
# -*- coding: utf-8 -*-
"""
Created on Sat Feb 18 13:11:43 2023
@author: SBhatia3
"""
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from pyVim import connect
import ssl
from pyVmomi import vim
app_settings = {
'api_pass': "xxxx",
'api_user': "user@vsphere.local",
'api_url': "https://<vCenterFQDN/rest/",
'vcenter_ip': "vCenter IP",
'VM_name': "UbantuTest" ### Desired VM for which we need to find details
}
def auth_vcenter(username, password):
resp = requests.post(
'{}/com/vmware/cis/session'.format(app_settings['api_url']),
auth=(app_settings['api_user'], app_settings['api_pass']),
verify=False
)
if resp.status_code != 200:
print('Error! API responded with: {}'.format(resp.status_code))
return
return resp.json()['value']
def get_api_data(req_url):
sid = auth_vcenter(app_settings['api_user'], app_settings['api_pass'])
resp = requests.get(req_url, verify=False, headers={'vmware-api-session-id': sid})
if resp.status_code != 200:
print('Error! API responded with: {}'.format(resp.status_code))
return
return resp
def get_vm(vm_name):
resp = get_api_data('{}/vcenter/vm?filter.names={}'.format(app_settings['api_url'], vm_name))
j = resp.json()
return j
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
vmdetails = get_vm(app_settings['VM_name'])
vmid = vmdetails['value'][0]['vm']
s = ssl._create_unverified_context()
service_instance = connect.SmartConnect(
host=app_settings['vcenter_ip'],
user=app_settings['api_user'],
pwd=app_settings['api_pass'],
sslContext=s
)
content = service_instance.RetrieveContent()
container = content.rootFolder # starting point to look into
viewType = [vim.VirtualMachine] # object types to look for
recursive = True # whether we should look into it recursively
containerView = content.viewManager.CreateContainerView(container, viewType, recursive) # create container view
children = containerView.view
for child in children: # for each statement to iterate all names of VMs in the environment
if str(vmid) in str(child):
vm_summary = child.summary #Summary of the desired VM to import
vm_config = child.config #Complete config data hierarchy and child item values loaded in the variable
vm_resourcepool = child.resourcePool #Resource pool details
vm_network = child.network #Network details of the VM
vm_datastore = child.datastore
vm_parent = child.parent
vm_name = child.name
print("VM name: ", vm_name)
print ("VM guestFullName: ", vm_config.guestFullName)
print("VM guestID: ", vm_config.guestId)
內容解密:
- app_settings:這個字典包含了與 vCenter API 和虛擬機器相關的設定引數,包括 API 命令、使用者名稱、密碼、URL 以及目標虛擬機器的名稱。
- auth_vcenter(username, password):這個函式用來進行 vCenter 的驗證,傳回會話 ID(sid)。
- get_api_data(req_url):這個函式使用會話 ID(sid)來取得 API 資料。
- get_vm(vm_name):這個函式根據虛擬機器名稱來取得虛擬機器的詳細資訊。
- ssl._create_unverified_context():這行程式碼用來建立一個不驗證 SSL 憑證的上下文,這在某些情況下可能會有安全風險。
- connect.SmartConnect():這行程式碼用來連線到 vCenter Server。
- content.RetrieveContent():這行程式碼用來取得 vCenter 中的內容。
- content.viewManager.CreateContainerView():這行程式碼用來建立一個容器檢視,用於遍歷所有虛擬機器。
- children:這個變數包含了所有虛擬機器的物件。
- vm_summary, vm_config, vm_resourcepool, vm_network, vm_datastore, vm_parent, vm_name:這些變數分別儲存了虛擬機器的摘要、組態、資源池、網路、儲存區、父物件以及名稱。
執行結果
執行上述程式碼後,我們可以得到以下輸出:
VM name: UbantuTest
VM guestFullName: Ubuntu Linux (64-bit)
VM guestID: ubuntu64Guest
應用與改進
透過上述程式碼,我們成功地提取了虛擬機器的名稱、guestFullName 和 guestID。類別似地,我們也可以提取其他必要或選擇性的物件資訊,以生成 Terraform 組態檔案所需的資料。這樣的方法不僅能夠幫助我們自動化 Terraform 的匯入流程,還能夠提供更多靈活性和可控性。
隨著技術的不斷進步,未來可能會有更多工具和方法來簡化逆向工程流程。然而,理解其背後的原理和邏輯將永遠是成功應用技術的關鍵。玄貓建議持續關注相關技術發展,並不斷學習和實踐,以應對不斷變化的技術挑戰。
Terraform 搭建及其反向工程應用
情報提取與反向工程
在第三章中,我們探討了反向工程的三個基本步驟。第一步是情報提取,我們需要收集有關產品設計和運作的資訊。這一節,我們將探討 Terraform 架構,並解釋這種架構如何幫助我們模型化所需的資訊,以進一步構建反向工程解決方案。以下將介紹的架構是通用的,它解釋了 Terraform 的核心功能以及如何與不同的基礎設施平台互動。本文的目的是讓讀者瞭解 Terraform 如何與前面章節中所討論的「真實來源」一起運作。
此圖示展示了 Terraform 的架構:
graph TD;
A[Providers] --> B[Terraform Core];
C[Provisioners] --> B;
D[Plugins] --> B;
E[Golang] --> B;
F[Client Library] --> B;
G[HTTP(S)] --> B;
H[RPC] --> B;
此圖示展示了 Terraform 的核心元件及其與各種外掛、函式庫和通訊協定的互動方式。
提供者(Providers)
Terraform 目前支援多個提供者和超過 800 個提供者二進位制檔案。為了管理這些多樣化的提供者二進位制檔案,HashiCorp 並不直接管理每一個。相反,HashiCorp 設計了一個可擴充套件的架構。這意味著各個平台需要提供支援並維護自己的提供者外掛及其生命週期。Terraform 提供了「提供者 SDK」,這是一個軟體開發套件,定義了 Terraform 核心如何與特定平台所撰寫的外掛互動。此外,為了支援提供者的撰寫(每個平台都有其特定的提供者),Terraform 提供了「Terraform-provider-scaffolding」,這是一個包含範本的程式碼倉函式庫,定義瞭如何撰寫提供者。該範本包括以下內容:
- 資源和資料來源(internal/provider/)
- 範例(examples/)和生成檔案(docs/)
- 其他元檔案
HashiCorp 提供的這個範本包含了一些需要編輯以建立自定義 Terraform 提供者的範例程式碼。一旦撰寫完畢,平台供應商需要將其發布在由 HashiCorp 維護的 Terraform 登入檔中,以便該提供者可以被廣泛使用。
由於 Terraform 是根據外掛的架構,這些 Terraform 外掛使所有開發人員都能透過撰寫新外掛或編譯現有外掛來擴充套件 Terraform 的使用。如上圖所示,Terraform 的兩個主要元件是 Terraform 核心和 Terraform 外掛。Terraform 核心透過遠端程式呼叫(RPCs)與外掛互動,並提供多種方法來發現和載入外掛以進一步與目標平台互動。正是這些 Terraform 外掛使 Terraform 能夠針對特定服務(如 Azure、VMware、GCP 等)暴露實作。
Terraform 核心
Terraform 核心是開原始碼,並託管在 GitHub 上(https://github.com/hashicorp/Terraform)。它是由 Go 語言編寫的一組經常編譯的二進位制檔案列表。這些編譯後的二進位制檔案稱為 Terraform CLI。CLI 使用 RPCs 與 Terraform 外掛進行通訊,並提供多種方法來發現和載入外掛以進行使用。Terraform 核心的關鍵功能包括:
- 模擬基礎設施即程式碼(IaC):讀取和內插組態檔案和 Terraform 模組。
- 管理由 Terraform 控制的資源狀態。
- 從 Terraform 組態中構建依賴圖表,並遍歷該圖表以生成 Terraform 暨計劃、更新狀態等。
- 執行 Terraform 暨計劃。
- 與外掛透過 RPCs 進行通訊。
此圖示展示了 Terraform 核心與外掛之間的互動方式:
graph TD;
A[Providers] --> B[Terafom Core];
C[Core] --> D[Plugins];
E[Upstream APIs] --> D;
此圖示展示了 Terraform 核心如何透過 RPCs 與提供者進行互動。
外掛功能
Terraform 外掛包含兩個關鍵元件:提供者和佈署器。提供者是由開發人員使用 Go 語言編寫的程式碼,這些程式碼是可執行的二進位制檔案,透過 RPCs 被 Terraform 核心呼叫。在第二章中我們討論過 Terraform 的佈署器;它允許在受支援平台上直接執行自定義程式碼。每個外掛都暴露了一個特定服務(如 Azure、GCP、VMware 等)的實作。
終端使用者在其組態檔案中定義相應的提供者和佈署器,這進一步允許透過 RPCs 與目標平台進行互動。Terraform 有許多內建佈署器,而提供者則根據相應平台開發人員新增支援時動態新增。這就是 Terraform 核心 SDK 的魅力;它提供了一個高層框架,抽象化了外掛發現和 RPC 呼叫通訊的細節。
以下是提供者外掛的一些關鍵職責:
- 初始化任何包含在客戶端特定函式庫中的 API 呼叫到上游 API 平台
- 與支援基礎設施平台進行驗證
- 定義受控資源對映到特定服務
如上圖所示,一些使提供者與上游 API 進行互動的一些重要功能包括 create()、Read()、Delete() 和 Update()。
以下是佈署器在外掛中的關鍵職責:在指定資源建立或銷毀後執行命令或指令碼。
最重要的是:
每次提到程式碼後面都會有詳細解說
func createResource(resourceName string, resourceData map[string]interface{}) error {
// 初始化 API 呼叫所需的客戶端特定函式庫
client := initializeClient()
// 執行建立資源操作
err := client.Create(resourceName, resourceData)
if err != nil {
return fmt.Errorf("failed to create resource: %v", err)
}
return nil
}
內容解密:
- 初始化客戶端特定函式庫:首先我們需要初始化一個客戶端來進行 API 呼叫。
- 執行建立資源操作:接著我們呼叫
client.Create方法來建立指定名稱和資料組態之資源。 - 錯誤處理:如果操作失敗我們會傳回一條錯誤訊息。
未來趨勢及應用評估
隨著雲端基礎設施日益複雜,Terraform 的可擴充套件性和靈活性使其成為管理多雲環境中的不可或缺工具。未來,我們可以預見更多自動化工具將整合到 Terraform 中,進一步簡化佈署流程並提升效率。此外,隨著安全性需求不斷增加,Terraform 在安全性方面也將有更多改進。
對於企業來說,理解並掌握反向工程技術將有助於更好地維護現有系統並提升系統安全性。透過對基礎設施即程式碼(IaC)工具如 Terraform 的深入研究,企業可以更靈活地管理其基礎設施組態並減少人為錯誤。
總結來說,TerraForm 是一款非常強大且靈活的工具,而玄貓相信你也能學習到很多有用得東西