Ansible 提供了便捷的模組,能有效簡化 AWS VPC 的組態和管理。透過 ec2_vpc 模組,可以輕鬆建立 VPC 和子網,並設定路由表和網際網路閘道器。同時,利用 ec2 模組佈署 NAT 例項,確保私有子網中的例項可以連外,並使用 ec2_eip 模組關聯彈性 IP,提供穩定的對外連線。此外,文章也說明瞭如何建立跳板機,以便從外部管理 VPC 內的資源,並透過 OpenVPN 建立安全連線。最後,示範了自定義 Ansible 模組 vpc_lookup 的方法,可以根據標籤查詢 VPC 和子網 ID,進一步提升自動化管理的效率。
使用Ansible進行VPC組態與NAT例項佈署
前言
在雲端運算中,虛擬私有雲(VPC)提供了隔離的網路環境,讓使用者能夠在雲端佈署自己的網路架構。Amazon Web Services(AWS)提供了VPC服務,允許使用者建立自己的虛擬網路,並控制網路的組態和安全。本篇文章將介紹如何使用Ansible自動化工具來組態VPC並佈署NAT例項,以實作私有子網中的例項能夠存取網際網路。
VPC與子網的建立
首先,我們需要建立一個VPC並在其下建立子網。Ansible提供了ec2_vpc模組來建立和管理VPC及其相關資源。
---
- hosts: localhost
connection: local
gather_facts: no
vars:
region: ap-southeast-2
prefix: staging
az0: ap-southeast-2a
az1: ap-southeast-2b
tasks:
- name: create vpc with multi-az subnets
ec2_vpc:
region: "{{ region }}"
cidr_block: 10.0.0.0/16
resource_tags: '{"Name":"{{ prefix }}_vpc"}'
subnets:
- cidr: 10.0.0.0/24
az: "{{ az0 }}"
resource_tags: '{"Name":"{{ prefix }}_subnet_public_0"}'
- cidr: 10.0.1.0/24
az: "{{ az0 }}"
resource_tags: '{"Name":"{{ prefix }}_subnet_private_0"}'
- cidr: 10.0.2.0/24
az: "{{ az1 }}"
resource_tags: '{"Name":"{{ prefix }}_subnet_public_1"}'
- cidr: 10.0.3.0/24
az: "{{ az1 }}"
resource_tags: '{"Name":"{{ prefix }}_subnet_private_1"}'
internet_gateway: yes
route_tables:
- subnets:
- 10.0.0.0/24
- 10.0.2.0/24
routes:
- dest: 0.0.0.0/0
gw: igw
register: vpc
內容解密
ec2_vpc模組:用於建立和管理VPC。region:指定AWS區域。cidr_block:定義VPC的CIDR區塊。subnets:定義子網及其相關屬性,如CIDR區塊和可用區域(AZ)。internet_gateway:啟用網際網路閘道。route_tables:組態路由表,將公有子網與網際網路閘道關聯。
NAT例項的佈署
為了使私有子網中的例項能夠存取網際網路,我們需要佈署一個NAT例項。
---
- hosts: localhost
connection: local
gather_facts: no
vars_files:
- staging_vpc_info
vars:
region: ap-southeast-2
key: yan-key-pair-apsydney
instance_type: t1.micro
image: ami-3bae3201
prefix: staging
tasks:
- name: NAT instance provisioning
ec2:
region: "{{ region }}"
key_name: "{{ key }}"
instance_type: "{{ instance_type }}"
image: "{{ image }}"
wait: yes
group: "{{ prefix }}_sg_nat"
instance_tags:
Name: "{{ prefix }}_nat"
class: nat
environment: staging
id: nat_launch_01
vpc_subnet_id: "{{ staging_subnet_public }}"
source_dest_check: no
wait: yes
register: ec2
- name: associate new EIP for the instance
ec2_eip:
region: "{{ region }}"
instance_id: "{{ item.id }}"
with_items: ec2.instances
when: item.id is defined
內容解密:
ec2模組:用於啟動EC2例項。key_name:指定用於連線例項的金鑰對。instance_type和image:定義例項型別和AMI映像。vpc_subnet_id:指定例項啟動的子網。source_dest_check: no:停用源/目標檢查,允許NAT例項轉發流量。ec2_eip模組:為NAT例項關聯彈性IP(EIP)。
路由表的更新
最後,我們需要更新路由表,以使私有子網中的流量能夠透過NAT例項存取網際網路。
- 在AWS VPC控制檯中,選擇路由表。
- 編輯主路由表,新增一條路由,將目標設為NAT例項。
在 VPC 中使用 Ansible 進行組態管理
在前面的章節中,我們已經使用 Ansible 成功建立了一個 VPC 以及相關的子網和安全組。本章節將探討如何在 VPC 環境中使用 Ansible 進行例項的管理和組態。
VPC 中的例項管理挑戰
由於 VPC 中的私有子網無法直接接收來自網際網路的流量,因此無法直接使用 Ansible 從網際網路上管理私有子網中的伺服器組態。為瞭解決這個問題,我們有兩種可行的方案:
在公有子網中安裝 Ansible:在公有子網中啟動一個例項並安裝 Ansible,然後允許該 Ansible 機器透過 SSH 連線到私有子網中的主機進行管理。這台 Ansible 機器也可以作為跳板機,允許從網際網路透過 SSH 連線到私有子網中的主機(先 SSH 到 Ansible 機器,然後再從 Ansible 機器 SSH 到私有子網中的主機)。
建立 VPN 連線:在公有子網中啟動一個 OpenVPN 伺服器例項(可從 AWS Marketplace 獲得),然後在 Ansible 機器上使用 OpenVPN 使用者端連線到 VPN,從而透過 SSH 連線到私有子網中的主機。
建立跳板機例項
為了示範第一種方法,我們將在公有子網中建立一個跳板機例項並在其上安裝 Ansible。首先,需要為這個例項建立一個新的安全組。
建立跳板機安全組
以下是建立跳板機安全組的 playbook(sg_jumpbox.yml):
---
- hosts: localhost
connection: local
gather_facts: no
vars_files:
- staging_vpc_info
vars:
region: ap-southeast-2
allowed_ip: 123.xxx.xxx.xxx/32
prefix: staging
vpc_id: "{{ staging_vpc }}"
tasks:
- name: create security group for jump box instance
ec2_group:
region: "{{ region }}"
vpc_id: "{{ vpc_id }}"
name: "{{ prefix }}_sg_jumpbox"
description: security group for jump box
rules:
- proto: tcp
from_port: 22
to_port: 22
cidr_ip: "{{ allowed_ip }}"
rules_egress:
- proto: all
cidr_ip: 0.0.0.0/0
執行以下命令來建立安全組:
$ ansible-playbook -i hosts sg_jumpbox.yml
建立跳板機例項
接下來,使用以下 playbook(ec2_vpc_jumpbox.yml)在公有子網 A 中啟動跳板機例項:
---
- hosts: localhost
connection: local
gather_facts: no
vars_files:
- staging_vpc_info
vars:
region: ap-southeast-2
key: yan-key-pair-apsydney
instance_type: t2.micro
image: ami-d9fe9be3
prefix: staging
vpc_subnet_id: "{{ staging_subnet_public_0 }}"
tasks:
- name: jump box instance provisioning
ec2:
region: "{{ region }}"
key_name: "{{ key }}"
instance_type: "{{ instance_type }}"
image: "{{ image }}"
wait: yes
group: "{{ prefix }}_sg_jumpbox"
instance_tags:
Name: "{{ prefix }}_jumpbox"
class: jumpbox
environment: "{{ prefix }}"
id: jumpbox_launch_01
vpc_subnet_id: "{{ vpc_subnet_id }}"
register: ec2
- name: associate new EIP for the instance
ec2_eip:
region: "{{ region }}"
instance_id: "{{ item.id }}"
with_items: ec2.instances
執行以下命令來啟動跳板機例項:
$ ansible-playbook -i ec2.py ec2_vpc_jumpbox.yml
在跳板機上安裝 Ansible
為了在跳板機上安裝 Ansible,首先需要建立一個角色(role)來執行安裝任務。
建立 Ansible 安裝角色
建立 roles/ansible/tasks/main.yml 檔案,內容如下:
---
- name: upgrade all packages
yum: name=* state=latest
- name: install the 'Development tools' package group
yum: name="@Development tools" state=present
- name: install required packages
yum: name={{ item }} state=present
with_items:
- epel-release.noarch
- python-pip
- python-devel
- name: install setuptools
pip: name=setuptools extra_args='--upgrade'
- name: install ansible
pip: name=ansible
然後,建立一個 playbook(install_ansible.yml)來應用這個角色:
---
- hosts: tag_class_jumpbox
become: yes
roles:
- ansible
執行以下命令來安裝 Ansible:
$ ansible-playbook -i ec2.py install_ansible.yml
組態安全組規則以允許 SSH 存取
為了允許從跳板機到其他例項的 SSH 連線,需要修改相關的安全組規則。例如,如果要在私有子網中安裝 MySQL 資料函式庫伺服器並使用 Ansible 管理其組態,可以修改 sg_modify.yml 中的規則:
- name: modify sg_database rules
ec2_group:
region: "{{ region }}"
vpc_id: "{{ vpc_id }}"
name: "{{ prefix }}_sg_database"
description: security group for databases
rules:
# allow ssh from the jump box
- proto: tcp
from_port: 22
to_port: 22
group_name: "{{ prefix }}_sg_jumpbox"
# allow mysql access from web servers
- proto: tcp
from_port: 3306
to_port: 3306
group_name: "{{ prefix }}_sg_web"
rules_egress:
- proto: tcp
from_port: 80
to_port: 80
cidr_ip: 0.0.0.0/0
- proto: tcp
from_port: 443
to_port: 443
cidr_ip: 0.0.0.0/0
執行以下命令來修改安全組規則:
$ ansible-playbook -i hosts sg_modify.yml
在Ansible中組態VPC:OpenVPN伺服器佈署
OpenVPN伺服器簡介
OpenVPN Access Server是一種功能全面的SSL VPN軟體解決方案,它整合了OpenVPN伺服器功能、企業管理功能、簡化的OpenVPN Connect UI,以及支援Windows、MAC和Linux作業系統環境的OpenVPN客戶端軟體套件。
啟動OpenVPN例項
首先,我們需要知道OpenVPN Access Server在我們所選區域的AMI ID。
取得AMI ID步驟:
- 前往EC2儀錶板,選擇您的區域,然後點選「啟動例項」按鈕。
- 在左側導航欄中,選擇「社群AMI」。
- 當AMI選擇對話框出現時,在搜尋框中輸入「OpenVPN」。
- 找到由openvpn.net提供的最新版本的OpenVPN Access Server AMI,並記錄其AMI ID。
- 選擇「取消並離開」。
建立OpenVPN伺服器的安全組
$ vi sg_openvpn.yml
---
- hosts: localhost
connection: local
gather_facts: no
vars_files:
- staging_vpc_info
vars:
region: ap-southeast-2
allowed_ip: 123.xxx.xxx.xxx/32
prefix: staging
vpc_id: "{{ staging_vpc }}"
tasks:
- name: create security group for openvpn instance
ec2_group:
region: "{{ region }}"
vpc_id: "{{ vpc_id }}"
name: "{{ prefix }}_sg_openvpn"
description: security group for openvpn
rules:
- proto: tcp
from_port: 22
to_port: 22
cidr_ip: "{{ allowed_ip }}"
- proto: tcp
from_port: 443
to_port: 443
cidr_ip: 0.0.0.0/0
- proto: tcp
from_port: 943
to_port: 943
cidr_ip: 0.0.0.0/0
- proto: udp
from_port: 1194
to_port: 1194
cidr_ip: 0.0.0.0/0
rules_egress:
- proto: all
cidr_ip: 0.0.0.0/0
程式碼解密:
此YAML檔案定義了一個Ansible playbook,用於建立OpenVPN例項的安全組。主要步驟包括:
- 指定目標主機為localhost,並設定連線方式為local。
- 載入變數檔案
staging_vpc_info,並定義了一些變數,如區域、允許的IP位址、字首和VPC ID。 - 使用
ec2_group模組建立安全組,名稱和描述根據變數動態生成。 - 設定安全組的入站規則,允許特定的TCP和UDP流量。
- 設定安全組的出站規則,允許所有流量。
執行playbook:
$ ansible-playbook -i hosts sg_openvpn.yml
啟動OpenVPN伺服器例項
$ vi ec2_vpc_openvpn.yml
---
- hosts: localhost
connection: local
gather_facts: no
vars_files:
- staging_vpc_info
vars:
region: ap-southeast-2
key: yan-key-pair-apsydney
instance_type: t2.micro
image: ami-a17f199b
prefix: staging
vpc_subnet_id: "{{ staging_subnet_public_0 }}"
tasks:
- name: openvpn server instance provisioning
ec2:
region: "{{ region }}"
key_name: "{{ key }}"
instance_type: "{{ instance_type }}"
image: "{{ image }}"
source_dest_check: no
wait: yes
group: "{{ prefix }}_sg_openvpn"
instance_tags:
Name: "{{ prefix }}_openvpn"
class: openvpn
environment: "{{ prefix }}"
id: openvpn_launch_01
vpc_subnet_id: "{{ vpc_subnet_id }}"
register: ec2
- name: associate new EIP for the instance
ec2_eip:
region: "{{ region }}"
instance_id: "{{ item.id }}"
with_items: ec2.instances
程式碼解密:
此YAML檔案定義了另一個Ansible playbook,用於啟動OpenVPN伺服器例項。主要步驟包括:
- 指定目標主機為localhost,並設定連線方式為local。
- 載入變數檔案
staging_vpc_info,並定義了一些變數,如區域、金鑰名稱、例項型別、映像ID、字首和VPC子網ID。 - 使用
ec2模組啟動一個EC2例項,根據變數設定例項的屬性,如區域、金鑰名稱、例項型別、映像ID、安全組和標籤等。 - 使用
ec2_eip模組為新啟動的例項分配一個新的彈性IP位址。
組態OpenVPN伺服器
SSH到OpenVPN Access Server,使用openvpnas使用者:
# ssh -i ~/.ssh/yan-key-pair-apsydney.pem openvpnas@openvpn-ipaddress
按照提示完成OpenVPN Access Server設定精靈。
連線客戶端
使用者可以透過存取https://openvpn-ipaddress來使用Connect Client。使用者可以選擇直接連線到VPN或登入到Connect Client以下載使用者組態檔案(client.ovpn)並使用其他OpenVPN客戶端連線到VPN。
使用Ansible進行VPC資源管理
自定義Ansible模組取得VPC與子網ID
在自動化AWS資源管理過程中,經常需要根據特定的標籤(tags)來取得VPC或子網的ID。雖然Ansible提供了豐富的AWS相關模組,但某些特定功能仍需要自定義模組來實作。本章節將介紹如何建立一個自定義的Ansible模組vpc_lookup,用於根據資源標籤取得VPC和子網ID。
建立vpc_lookup模組
首先,在您的playbook目錄下建立一個名為library的子目錄,並在其中建立vpc_lookup檔案:
$ cd /home/yan/ansible4aws
$ mkdir library
$ vi library/vpc_lookup
將以下Python指令碼內容複製到vpc_lookup檔案中:
#!/usr/bin/python
# author: John Jarvis
import sys
AWS_REGIONS = ['ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2', 'eu-west-1', 'sa-east-1', 'us-east-1', 'us-west-1', 'us-west-2']
try:
from boto.vpc import VPCConnection
from boto.vpc import connect_to_region
except ImportError:
print("failed=True msg='boto required for this module'")
sys.exit(1)
def main():
module = AnsibleModule(
argument_spec=dict(
region=dict(choices=AWS_REGIONS),
aws_secret_key=dict(aliases=['ec2_secret_key', 'secret_key'], no_log=True),
aws_access_key=dict(aliases=['ec2_access_key', 'access_key']),
tags=dict(default=None, type='dict'),
)
)
tags = module.params.get('tags')
aws_secret_key = module.params.get('aws_secret_key')
aws_access_key = module.params.get('aws_access_key')
region = module.params.get('region')
if region:
try:
vpc = connect_to_region(region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key)
except boto.exception.NoAuthHandlerFound as e:
module.fail_json(msg=str(e))
else:
module.fail_json(msg="region must be specified")
subnet_ids = []
for tag, value in tags.items():
for subnet in vpc.get_all_subnets(filters={"tag:" + tag: value}):
subnet_ids.append(subnet.id)
vpc_ids = []
for tag, value in tags.items():
for vpc_item in vpc.get_all_vpcs(filters={"tag:" + tag: value}):
vpc_ids.append(vpc_item.id)
module.exit_json(changed=False, vpc_ids=vpc_ids, subnet_ids=subnet_ids)
# this is magic, see lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main()
儲存並關閉檔案後,賦予該檔案執行許可權:
# chmod 755 library/vpc_lookup
vpc_lookup模組解密
此Python指令碼定義了一個名為vpc_lookup的Ansible模組,主要功能是根據提供的標籤(tags)查詢對應的VPC和子網ID,並以JSON格式傳回結果。
- 匯入必要的模組:指令碼首先匯入了必要的Python模組,包括
sys和boto.vpc相關模組。boto是一個Python介面,用於存取AWS服務。 - 定義支援的AWS區域:變數
AWS_REGIONS列出了該模組支援的AWS區域。 AnsibleModule定義:透過AnsibleModule類別定義了模組的介面,包括接受的引數如region、aws_secret_key、aws_access_key和tags。- 連線至指定AWS區域:根據提供的
region、aws_access_key和aws_secret_key,指令碼嘗試連線到指定的AWS區域。 - 查詢VPC和子網ID:遍歷提供的
tags,使用boto.vpc連線查詢符合標籤過濾條件的VPC和子網,並收集其ID。 - 傳回結果:最終,指令碼以JSON格式傳回查詢結果,包括
vpc_ids和subnet_ids列表。
使用vpc_lookup模組
建立一個playbook檔案,例如vpc_delete.yml,來演示如何使用剛才建立的vpc_lookup模組:
---
- hosts: localhost
connection: local
gather_facts: no
vars:
region: ap-southeast-2
tasks:
- name: 取得VPC ID
vpc_lookup:
region: "{{ region }}"
tags:
Name: test-vpc
register: vpc
- name: 刪除VPC
ec2_vpc:
region: "{{ region }}"
state: absent
vpc_id: "{{ item }}"
wait: yes
with_items: "{{ vpc.vpc_ids }}"
Playbook解密
此playbook執行兩個主要任務:
- 使用
vpc_lookup模組根據標籤"Name": "test-vpc"查詢VPC ID,並將結果註冊到變數vpc中。 - 利用查詢到的VPC ID,透過
ec2_vpc模組刪除對應的VPC資源。