CloudFormation 範本是 AWS 基礎設施即程式碼的核心,其正確性直接影響佈署結果。除了 AWS 提供的範本驗證功能外,使用靜態檢查工具能更有效地找出潛在問題,例如資源屬性缺失、語法錯誤或不符合最佳實務的設定。cfn-lint 提供了豐富的內建規則,並支援自定義規則和區域特定檢查,可更精準地控制檢查範圍。cloudformation-guard 則以根據策略的方式簡化規則的撰寫和維護,提升檢查效率。兩種工具各有優勢,開發者可根據專案需求選擇合適的工具,或結合使用以達到最佳效果。在 CI/CD 流程中整合靜態檢查,更能確保範本的品質,減少佈署錯誤並提升自動化程度。
驗證、靜態檢查與佈署堆積疊
範本驗證的重要性
雖然範本驗證是堆積疊佈署前的必要步驟,但許多問題仍可能導致佈署失敗,即使驗證成功也不例外。常見問題包括:
- 缺少必要的資源屬性
- 資源屬性名稱的語法錯誤或拼寫錯誤
- 資源屬性值不存在
執行範本驗證的指令非常簡單:
$ aws cloudformation validate-template --template-body file://path_to_your_template
例如,若要驗證核心範本,我們需要執行以下指令:
$ aws cloudformation validate-template --template-body file://core.yaml
如果範本中有錯誤,我們將看到類別似以下的輸出(在此範例中,我將PublicSubnet1
資源型別改為完全不存在的型別——即AWS::EC2::DoesNotExist
):
An error occurred (ValidationError) when calling the ValidateTemplate operation: Template format error: Unrecognized resource types: [AWS::EC2::DoesNotExist]
若我們在內建函式中模擬拼寫錯誤,將會得到另一個錯誤(在此範例中,我將Fn::Select
內建函式改為不存在的Fn::NoSelect
內建函式):
An error occurred (ValidationError) when calling the ValidateTemplate operation: Template format error: YAML not well-formed. (line 31, column 18)
然而,如果範本有效,我們將看到範本的引數、描述以及IAM許可權及其原因,這表明需要這些許可權的資源:
{
"Parameters": [
{
"ParameterKey": "VpcCidr",
"NoEcho": false
},
{
"ParameterKey": "Environment",
"NoEcho": false
}
],
"Description": "Core template. Contains network and IAM roles",
"Capabilities": [
"CAPABILITY_IAM"
],
"CapabilitiesReason": "The following resource(s) require capabilities: [AWS::IAM::Role]"
}
驗證器總是在堆積疊佈署前執行,但為了節省時間並盡早捕捉所有錯誤,您應該總是考慮在佈署堆積疊前執行驗證,並將其作為CI/CD流程中的一個步驟(我們將在下一章節中介紹)。
使用靜態檢查工具最佳化範本
靜態檢查工具(linter)是一種用於靜態原始碼分析的工具,用於標記明顯的程式錯誤和臭蟲,以及風格和非慣用問題。靜態檢查工具通常根據一組預定義的規則和風格進行操作。CloudFormation有兩款可用的靜態檢查工具:cfn-lint
,一款由Python編寫的前一代靜態檢查工具,仍在維護中;以及cloudformation-guard
,一款由Rust編寫的根據策略的靜態檢查工具。在本章節中,我們將探討這兩款工具,並找出哪一款最適合我們的應用場景。
使用cfn-lint評估範本
cfn-lint
是一款命令列工具,能夠檢查您的範本,並將宣告的資源與大量編寫的規則進行對比。
與範本驗證器不同,cfn-lint
能夠檢測出更複雜的問題,例如缺少資源屬性或內建函式中的引數。
CloudFormation的靜態檢查工具是一款外部工具,可以使用pip安裝:
$ pip install cfn-lint
它將自動出現在$PATH中,因此我們可以立即執行:
$ cfn-lint core.yaml
如果範本符合所有規則要求,我們將看不到任何輸出(並且命令的傳回碼將為0)。然而,如果存在錯誤,靜態檢查工具將立即通知我們。
例子:使用cfn-lint檢查範本錯誤
在此範例中,我註解掉了VpcId
屬性,並刪除了Fn::Cidr
函式中的遮罩位元。PublicSubnet2
資源如下所示:
PublicSubnet2:
Type: "AWS::EC2::Subnet"
Properties:
# 缺少遮罩位元引數!!!
# 正確格式應為:
# !Select [1, !Cidr [!Ref VpcCidr, 12, 8]]
CidrBlock: !Select [1, !Cidr [!Ref VpcCidr, 12]]
# VpcId: !Ref Vpc # 缺少屬性!
MapPublicIpOnLaunch: True
AvailabilityZone: !Select
- 1
- Fn::GetAZs: !Ref "AWS::Region"
Tags:
- Key: "Name"
Value: !Sub "${Environment}-public-subnet02"
- Key: "Env"
Value: !Ref "Environment"
執行靜態檢查工具後的輸出如下:
$ cfn-lint core_broken.yaml
E0002 Unknown exception while processing rule E1024: list index out of range
core.yaml:1:1
E3003 Property VpcId missing at Resources/PublicSubnet2/Properties
core.yaml:45:5
傳回碼將為1或2(這些是Linux系統中常見的錯誤傳回碼)。
重要注意事項
- 您可能已經注意到,
cfn-lint
也會顯示它發現錯誤的行號。然而,當您修改內建函式的引數時,您將看到錯誤出現在第一行,這並不是實際的錯誤位置。 - 錯誤並不是靜態檢查工具直接指出的實際錯誤,而是一個Python例外。
自訂靜態檢查規則
cfn-lint
不僅能夠根據內建規則檢查範本,還支援自訂和調整。
針對特定區域進行靜態檢查
當您執行cfn-lint
時,它將根據預設區域(即us-east-1
)檢查您的範本。若要檢查其他區域,您可以手動指定:
$ cfn-lint core.yaml --regions 'eu-west-1'
# 或...
$ cfn-lint core.yaml --regions 'eu-west-1','us-east-1'
# 或甚至...
$ cfn-lint core.yaml --regions 'ALL_REGIONS'
在前面的範例中,您將獲得更為有趣的結果:
E3001 Invalid or unsupported Type AWS::SSM::Parameter for resource MiddlewareAsgMaxSizeParameter in us-gov-west-1
core.yaml:393:5
E3001 Invalid or unsupported Type AWS::SSM::Parameter for resource MiddlewareAsgMaxSizeParameter in us-gov-east-1
core.yaml:393:5
E3001 Invalid or unsupported Type AWS::SSM::Parameter for resource MiddlewareAsgMaxSizeParameter in eu-north-1
core.yaml:393:5
E3001 Invalid or unsupported Type AWS::SSM::Parameter for resource MiddlewareAsgMaxSizeParameter in ap-east-1
core.yaml:393:5
出現此錯誤是因為所提到的區域不支援此資源型別。如果您計劃將範本佈署到多個區域,建議包含所有或部分割槽域進行檢查,以確保您想要提供的服務和資源在CloudFormation中得到支援。
在範本中新增區域檢查
另一種方式是在範本的後設資料中新增區域檢查:
// core.yaml
Metadata:
cfn-lint:
regions:
- us-east-1
- eu-west-1
- eu-central-1
然後,cfn-lint
將在您執行檢查時自動選取這些區域。
重要注意事項
請注意,範本後設資料中的值總是會被命令列引數覆寫。
圖表翻譯:靜態檢查流程圖
graph LR A[開始靜態檢查] --> B{檢查範本語法} B -->|正確| C[檢查資源屬性] B -->|錯誤| D[傳回錯誤資訊] C -->|正確| E[檢查區域支援] C -->|錯誤| F[傳回錯誤資訊] E -->|正確| G[完成檢查] E -->|錯誤| H[傳回錯誤資訊]
圖表翻譯:
此圖示展示了靜態檢查的主要流程,包括語法檢查、資源屬性檢查和區域支援檢查。每一步驟都可能傳回錯誤資訊或完成檢查。
使用 Linter 提升 CloudFormation 範本最佳實踐
在開發和佈署 CloudFormation 範本時,保持範本的正確性和最佳實踐至關重要。本章節將探討如何使用 cfn-lint
進行範本檢查,以及如何自定義規則來滿足特定需求。同時,我們還會介紹 cloudformation-guard
,一個根據策略的 Linter 工具。
瞭解 cfn-lint 與其重要性
cfn-lint
是一個用於檢查 CloudFormation 範本語法正確性和最佳實踐的工具。它能夠幫助開發者識別範本中的錯誤和潛在問題,從而確保範本的品質和可靠性。
為什麼使用 cfn-lint?
- 範本驗證:
cfn-lint
能夠驗證範本的語法是否正確,確保範本可以成功佈署。 - 最佳實踐檢查:除了語法檢查,
cfn-lint
還能檢查範本是否遵循 AWS 推薦的最佳實踐。 - 自定義規則:開發者可以根據組織需求自定義檢查規則,進一步提升範本品質。
忽略特定規則
在某些情況下,開發者可能需要忽略某些 cfn-lint
規則。例如,當使用某些無法被 Linter 解析的宏(Macros)時,就需要忽略相關的檢查警告。
如何忽略特定規則?
- 使用
--ignore-checks
引數:執行cfn-lint
時,可以透過--ignore-checks
引數指定要忽略的規則。cfn-lint core.yaml --ignore-checks 'W2001'
- 在範本後設資料中指定:也可以在範本的後設資料(Metadata)中指定要忽略的規則。
Metadata: cfn-lint: regions: - us-east-1 - eu-west-1 - eu-central-1 ignore-checks: - W2001
建立自定義規則
除了內建規則,cfn-lint
還支援開發者建立自定義規則,以滿足特定的需求。
開發自定義規則步驟
- 確定規則需求:首先,明確自定義規則的目的和檢查內容。例如,檢查 RDS 資源是否具有正確的
DeletionPolicy
。 - 建立 Python 類別:自定義規則需要寫成 Python 類別,並且繼承自
CloudFormationLintRule
。 - 實作
match
方法:在match
方法中實作具體的檢查邏輯。
示例:檢查 RDS 資源的 DeletionPolicy
# rdsdeletionpolicy.py
from cfnlint import CloudFormationLintRule, RuleMatch
class RdsDeletionPolicy(CloudFormationLintRule):
id = 'W9001'
shortdesc = '檢查 RDS Deletion Policy'
description = '檢查 RDS 資源的 DeletionPolicy 是否為 Snapshot 或 Retain'
RDS_RESOURCES = [
'AWS::RDS::DBInstance',
'AWS::RDS::DBCluster'
]
def match(self, cfn):
matches = []
resources = cfn.get_resources(self.RDS_RESOURCES)
for resource_name, resource in resources.items():
deletion_policy = resource.get('DeletionPolicy')
path = ['Resources', resource_name]
if deletion_policy is None:
message = f'資源 {resource_name} 沒有 Deletion Policy!'
matches.append(RuleMatch(path, message))
elif deletion_policy not in ('Snapshot', 'Retain'):
message = f'資源 {resource_name} 的 Deletion Policy 不是 Snapshot 或 Retain!'
matches.append(RuleMatch(path, message))
return matches
執行自定義規則檢查
cfn-lint database_failing.yaml -a custom_rules
使用根據策略的 Linter:cloudformation-guard
cloudformation-guard
是另一個 Linter 工具,它根據策略(Policy-based)進行範本檢查。這使得規則的編寫和維護更加簡單。
為什麼選擇 cloudformation-guard?
- 簡潔的規則:
cloudformation-guard
的規則通常比cfn-lint
的自定義規則更簡潔。 - 易於維護:根據策略的方法使得規則的維護更加容易。
重要注意事項
自定義規則的命名:確保自定義規則的類別名與檔名一致,這是
cfn-lint
正確處理自定義規則的前提。規則的測試:在實際使用自定義規則之前,進行充分的測試以確保規則的正確性和有效性。
整合更多工具:探索將
cfn-lint
和cloudformation-guard
與其他 DevOps 工具整合的可能性,進一步提升範本開發和佈署的自動化水平。規則分享:鼓勵在團隊或社群中分享自定義規則,促進最佳實踐的傳播和採用。
參考資源
進一步閱讀
- AWS 檔案:使用 CloudFormation Linter
- AWS 檔案:使用 cloudformation-guard