(本文同步發表於 Medium、Laravel 道場)
為 Ansible 取得必要的權限
不管是使用哪一種 Infrastructure as Code 或 Configuration Management 工具,如要透過工具直接管理或操作雲端服務,首先都要為工具取得必要的授權及權限。而目前在 Azure 和 Ansible 的官網上,皆已經有文件在教學如何透過 Ansible 來管理 Azure,但在查閱了數篇之後發現,Azure 能夠提供授權給 Ansible 使用的方式主要有兩種:- Active Directory Username/Password
- Service Principal Credentials
如果你打算按著文件,逐一步驟建立「Service Principal Credentials」,我可以預告你很有可能會遇見一個坑,那就是明明是按著文件圖文一步步地操作,但最終就是無法輕易找到下面這四個所需參數。
subscription_id=xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
client_id=xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
secret=xxxxxxxxxxxxxxxxx
tenant=xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
在嘗試幾種操作之後,個人發現目前最簡單的做法應該是這份文件提到的指令。
只要按著文件中說明的 Azure CLI 指令
az ad sp create-for-rbac
,即可順利透過它取得上述四個參數中的後三項。而最簡單執行 Azure CLI 的方式,則是透過 Azure portal 的 Cloud Shell。只要登入 Azure portal,在點擊上方工具列 Cloud Shell 的 Icon 即可操作它。

如下圖,可以直接在瀏覽器操作 Cloud Shell,而其中已經內建安裝好各種 Commands。(貼心小提醒,Cloud Shell 一段時間沒操作就會自己斷線,因此要做任何操作時最好是一氣呵成為佳。)

因此我們就直接在 Cloud Shell 中執行指令來建立 Service principal。
az ad sp create-for-rbac --name YourServicePrincipalName --password YourPassword
(Service principal 除了用密碼驗證之外,還可以用 Key 驗證,這部分就請自行查看文件。)
沒意外應該就會出現類似下圖的結果,順利取得所需參數。

你也可以在 Azure Active Directory 的 App registrations 中,查看剛才建立的 Service principal。

取得所需的參數之後,我們準備回到 Ansible 這邊。
首先,請先確保你欲執行
ansible
的 Client 有安裝所需的 Ansible Azure 相關 Modules,按 Ansible 官方文件說明,可以透過 pip
指令安裝。pip install 'ansible[azure]'
接著利用前面取得的重要參數,建立
credentials
。因為 Ansible 的 Azure Module 預設會直接查看
~/.azure/
之下有沒有 credentials
的相關檔案。這裡我們就直接建立 ~/.azure/credentials
,然後將上述四個參數存放在內。#建立資料夾與檔案
mkdir ~/.azure/
vim ~/.azure/credentials
#檔案內容如下
[default]
subscription_id=這個可以在 Azure portal 的 Subscriptions 找到。
client_id=就是前面透過 az 得到的 appId
secret=就是前面透過 az 得到的 password
tenant=就是前面透過 az 得到的 tenant
測試執行
既然 Ansible 已經擁有了權限,接著就來測試看看,首先有一個非常適合用來測試的 task,即是 Create resource group,如下所示。# CreateResourceGroup.yml
- hosts: localhost
connection: local
tasks:
- name: Create resource group
azure_rm_resourcegroup:
name: YourResourceGroupName
location: japanwest
Azure 提供了 Rresource group 的概念,你可以將單一專案所需的資源全都放在同一個 Resource group 內方便管理,因此要正式開始創建 Azure 的服務前,第一步就是要建立一個 Resource group。
(小提醒,如果想知道
location
有哪些選擇,可以在 Cloud Shell 輸入指令 az account list-locations
查詢。位於台灣,可以考慮選 japanwest
。)將上述的 task 建立成 Ansible Playbook 之後,就執行
ansible-playbook
試試看吧!ansible-playbook CreateResourceGroup.yml
如順利執行,應該在 Azure portal 的 Resource groups,即可看見剛才透過 Ansible 建立的 Resource group。

建立 Virtual Machines
最後,終於進入了我們的主要目標「透過 Ansible 建立 Azure Virtual Machines」。不過雖然是建立 Virtual machine,但除了 VM 本身之外,還要建立其他所需的資源,包含了 Virtual Network、Subnet、Public IP、Network Security Group、Network Interface Card。
所以真正要使用的 Ansible Playbook,會如下所示,還需要加上好幾個 tasks。
- name: Create virtual network
azure_rm_virtualnetwork:
resource_group: AnsibleResourceGroup
name: AnsibleVnet
address_prefixes: "11.0.0.0/16"
- name: Add subnet
azure_rm_subnet:
resource_group: AnsibleResourceGroup
name: AnsibleSubnet
address_prefix: "11.0.1.0/24"
virtual_network: AnsibleVnet
- name: Create public IP address
azure_rm_publicipaddress:
resource_group: AnsibleResourceGroup
allocation_method: Static
name: AnsiblePublicIP
register: output_ip_address
- name: Create Network Security Group
azure_rm_securitygroup:
resource_group: AnsibleResourceGroup
name: AnsibleNetworkSecurityGroup
rules:
- name: SSH
protocol: Tcp
destination_port_range: 22
source_address_prefix: 請改成堡壘機IP
access: Allow
priority: 500
direction: Inbound
- name: MySQL
protocol: Tcp
destination_port_range: 3306
source_address_prefix: 請改成堡壘機IP
access: Allow
priority: 501
direction: Inbound
- name: HTTP
protocol: Tcp
destination_port_range: 80
access: Allow
priority: 502
direction: Inbound
- name: Create virtual network inteface card
azure_rm_networkinterface:
resource_group: AnsibleResourceGroup
name: AnsibleNIC
virtual_network: AnsibleVnet
subnet: AnsibleSubnet
public_ip_name: AnsiblePublicIP
security_group: AnsibleNetworkSecurityGroup
- name: Create VM
azure_rm_virtualmachine:
resource_group: AnsibleResourceGroup
name: AnsibleVM
vm_size: Standard_A1_v2
admin_username: 請改成你欲設置的使用者帳號
admin_password: 請改成你欲設置的密碼
network_interfaces: AnsibleNIC
image:
offer: UbuntuServer
publisher: Canonical
sku: '16.04-LTS'
version: latest
- name: Dump public IP for VM which will be created
debug:
msg: "The public IP is {{ output_ip_address.state.ip_address }}."
快速提一下幾個需要注意的要點。
首先,在透過
azure_rm_securitygroup
建立 Network Security Group 時,可以一併設置多個 rules。如上述範例,即直接設置了 port 22、3306、80 的 rules,其中 port 22 與 3306 還設置了必須透過固定 IP 的堡壘機才能連上。利用
azure_rm_virtualmachine
建立 VM 時,需要指定 admin_username
、是否使用 Key 或密碼登入、vm_size
與 image
。上面的範例是設置 SSH 以密碼登入為主,如果想要改用 Key 登入,可以參閱 Ansible Module - azure_rm_virtualmachine 文件設置。
如果要查詢你目前選擇的 Region 有哪些 VM Size 可以使用,可以透過
az
查詢。(請將 japanwest
換成你實際選擇的 region)az vm list-sizes -l japanwest
或者也可以搭配官網文件查詢,Linux VM 可查看此文件,Windows VM 則查看此文件。
而如果要查詢可以使用哪些 Image 來建立 VM,同樣可以透過
az
查詢,但 Image 很多,因此需要加上一些篩選條件,詳細的用法請自行查看 az vm image list -h
。az vm image list --location japanwest -f Ubuntu --publisher Canonical --sku 16.04
會得到類似下圖的結果。

最後執行的 Ansible Playbook
- hosts: localhost
connection: local
tasks:
- name: Create resource group
azure_rm_resourcegroup:
name: AnsibleResourceGroup
location: japanwest
- name: Create virtual network
azure_rm_virtualnetwork:
resource_group: AnsibleResourceGroup
name: AnsibleVnet
address_prefixes: "11.0.0.0/16"
- name: Add subnet
azure_rm_subnet:
resource_group: AnsibleResourceGroup
name: AnsibleSubnet
address_prefix: "11.0.1.0/24"
virtual_network: AnsibleVnet
- name: Create public IP address
azure_rm_publicipaddress:
resource_group: AnsibleResourceGroup
allocation_method: Static
name: AnsiblePublicIP
register: output_ip_address
- name: Create Network Security Group
azure_rm_securitygroup:
resource_group: AnsibleResourceGroup
name: AnsibleNetworkSecurityGroup
rules:
- name: SSH
protocol: Tcp
destination_port_range: 22
source_address_prefix: 請改成堡壘機IP
access: Allow
priority: 500
direction: Inbound
- name: MySQL
protocol: Tcp
destination_port_range: 3306
source_address_prefix: 請改成堡壘機IP
access: Allow
priority: 501
direction: Inbound
- name: HTTP
protocol: Tcp
destination_port_range: 80
access: Allow
priority: 502
direction: Inbound
- name: Create virtual network inteface card
azure_rm_networkinterface:
resource_group: AnsibleResourceGroup
name: AnsibleNIC
virtual_network: AnsibleVnet
subnet: AnsibleSubnet
public_ip_name: AnsiblePublicIP
security_group: AnsibleNetworkSecurityGroup
- name: Create VM
azure_rm_virtualmachine:
resource_group: AnsibleResourceGroup
name: AnsibleVM
vm_size: Standard_A1_v2
admin_username: 請改成你欲設置的使用者帳號
admin_password: 請改成你欲設置的密碼
network_interfaces: AnsibleNIC
image:
offer: UbuntuServer
publisher: Canonical
sku: '16.04-LTS'
version: latest
- name: Dump public IP for VM which will be created
debug:
msg: "The public IP is {{ output_ip_address.state.ip_address }}."
如果實驗完畢,想要刪除 Resource group,也同樣能透過 Playbook 達成。
- hosts: localhost
connection: local
tasks:
- name: Delete Resource Group
azure_rm_resourcegroup:
name: AnsibleResourceGroup
state: absent
force: yes
Ansible Module 官方文件
- azure_rm_resourcegroup
- azure_rm_virtualnetwork
- azure_rm_subnet
- azure_rm_publicipaddress
- azure_rm_networkinterface
參考資料
- Building Infrastructure with Microsoft Azure and Ansible
- Azure 官方文件:Ansible on Azure documentation
- Azure 官方文件:Install Ansible on Azure virtual machines
- Azure 官方文件:使用 Azure CLI 來建立 Azure 服務主體
- Azure 官方文件:How to: Use the portal to create an Azure AD application and service principal that can access resources
- Azure 官方文件:Ansible Playbooks for Azure
沒有留言:
張貼留言
不歡迎留言打廣告,所以有進行留言管理,敬請見諒。