CI/CDによるIaC運用
Shigeyukiです。
今回は、CD/CIを利用したIaCの運用方法について、紹介したいと思います。
IaCの運用状況
アプリのリリース頻度が高くなるため、どうしてもアプリのためのCI/CDが最優先となってしまい、IaC自体はCI/CDの対象外となり、手動運用されている方はまだ多いのではないかと思います。
CI/CDによるIaC運用に関する情報はネットには少なく、これからIaCを本番運用される人向けに、分かりやすく汎用性が高いCI/CDを解説したいと思います。
IaCの運用に対する課題
IaCを手動運用するとした場合、初回リリースはできても、再リリースする場合はどうでしょうか。
CIとCDでの実施内容に対して人手を介すほど、ミスの発生リスクが高まったり、IaCに対するセキュリティ統制も図れなかったりすると思います。
デプロイするインフラコードに関して、一貫したセキュリティチェックやコード内容の妥当性確認や既存リソースへの影響確認が必要となります。
そこで、CloudFormationを題材にして、IaCのCI/CDで運用する方法を解説したいと思います。
IaCをCI/CDで運用する目的
IaCもプログラムである以上、アプリのプログラムと同様にCI/CDで運用することで、インフラ整備の作業効率と安定した運用が可能となります。
そのためには、インフラコード(テンプレートファイル)はGit上で管理する必要があり、インフラコードに対する検証とデリバリーを導入することで、質の高いDevOpsが実現されることで上記の課題は解消されると考えております。
IaCをGitなどで管理してCI/CDすることで、インフラ整備の作業効率と安定した運用
アプリのデプロイに比べて、インフラ整備のデプロイ頻度は少なく、IaCが
IaCもDevOps的に運用して作業効率を図りたい。
アプリのデプロイに比べて、インフラ整備のデプロイ頻度は少なく、IaCがDevOpsされていないことが多いのではないかと思います。
IaCをGitなどで管理してCI/CDすることで、インフラ整備の作業効率と安定した運用が可能となります。
Point
インフラコードをGit管理しDevOpsで運用することにより、セキュリティ統制を図りながら品質の高いインフラの迅速な提供をします。
手操作によるミスを徹底排除します。
全体構成:CodePipeline + CloudFormation
IaCをCI/CDするために、CodePipeline上でCloudFormationを利用した基本構成は以下のイメージとなります。
CI構成(CodeCommit + CodeBuild)
ここでは、全体構成のうちCI構成にフォーカスして解説します。
管理者にてコンプライアンスチェック用のテンプレートを事前に配置します。
開発者は作成したテンプレートをCodeCommitの対象ブランチにPushuします。
これにより、開発者がPushしたテンプレートは自動的に静的解析(文法チェック、コンプライアンスチェック)され、簡易的なセキュリティ統制を図ります。
テンプレートチェックの処理構成(参考)
- テンプレートの文法チェック(cfn-lint)
- コンプラインスチェック(cfn-guard)
構成イメージは以下となります。
事前に管理者はソースアーティファクトに、コンプライアンスチェックとなるテンプレートをS3へアップロードしておきます。
その上で開発者はインフラコードとなるテンプレートをCodeCommitへPushします。
CI/CD作成テンプレートの内、CIとなる部分のイメージは以下となります。
AWSTemplateFormatVersion: "2010-09-09"
Description: CodeBuild Stack
# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
# アーティファクトS3
# ------------------------------------------------------------#
CodeArtifactS3:
Type: AWS::S3::Bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
BucketName: !Sub ${AWS::StackName}-${AWS::AccountId}-artifact
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerEnforced
PublicAccessBlockConfiguration:
BlockPublicAcls: True
BlockPublicPolicy: True
IgnorePublicAcls: True
RestrictPublicBuckets: True
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-${AWS::AccountId}-artifact
# ------------------------------------------------------------#
# CodeCommit
# ------------------------------------------------------------#
CodeCommit:
Type: AWS::CodeCommit::Repository
Properties:
RepositoryDescription: !Ref RepositoryDescription
RepositoryName: !Ref RepositoryName
# ------------------------------------------------------------#
# CodeBuild
# ------------------------------------------------------------#
CodeBuild:
Type: AWS::CodeBuild::Project
DependsOn:
- CodeBuildIAMRole
Properties:
Artifacts:
Type: CODEPIPELINE
Description: !Ref CodeBuildDescription
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
Type: LINUX_CONTAINER
Name: !Ref CodeBuildName
ServiceRole: !GetAtt CodeBuildIAMRole.Arn
Source:
BuildSpec: buildspec.yml
Type: CODEPIPELINE
Tags:
- Key: Name
Value: test-build
# ------------------------------------------------------------#
# EventBridge
# ------------------------------------------------------------#
EventBridgeIAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
<省略>
EventBridgeIAMRole:
Type: AWS::IAM::Role
Properties:
<省略>
EventBridge:
Type: AWS::Events::Rule
Properties:
Description: for codepipeline
EventPattern:
source:
- aws.codecommit
detail-type:
- 'CodeCommit Repository State Change'
resources:
- !GetAtt CodeCommit.Arn
detail:
event:
- referenceCreated
- referenceUpdated
referenceType:
- branch
referenceName:
- main
Name: eventbridge-codepipeline
State: ENABLED
Targets:
- Arn: !Join
- ''
- - 'arn:aws:codepipeline:ap-northeast-1:'
- !Sub '${AWS::AccountId}:'
- !Ref CodePipeline
Id: CodePipeline
RoleArn: !GetAtt EventBridgeIAMRole.Arn
CIのメイン処理となるビルドスペックファイルは以下となります。
version: 0.2
phases:
install:
runtime-versions:
python: 3.9
commands:
- pip install --upgrade pip
- pip install cfn-lint --user
- cfn-lint -v
- curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/aws-cloudformation/cloudformation-guard/main/install-guard.sh | sh
build:
commands:
- cfn-lint --template deploy/*.yml
- cfn-guard rulegen --template <S3パス>/check.yml --output check/check.guard
- cfn-guard validate --data deploy/*.yml -- rulescheck/check.guard --output-format yaml --show-summary all
artifacts:
files:
- "template/*"
ポイントは、ビルド時にコンプライアンスチェック用テンプレート(check.yml)からセキュリティチェックルールを生成して、自動チェックするところとなります。
Point
サーバ側でセキュリティ統制を図るために、一元的にテンプレートに関するチェックを実施します。
CD構成(CodePipeline統合CloudFormation + 変更セット + 手動承認)
ここでは、全体構成のうちCD構成にフォーカスして解説します。
CD構成では、CI構成でテンプレートチェックされたテンプレートを使用して、CloudFormationの変更セットを生成し、変更セットに関してレビューアが問題ないか確認します。
問題がなければ、パイプラインの後続処理によりデプロイされ、問題があればパイプラインを中止し、開発者へ修正依頼メールを送信します。
継続デリバリの構成
- 変更セットの作成
- 手動承認(IaCのレビュー作業)
- 変更セットの実施(レビューがOKの場合のみ)
IaCで既存インフラを更新する場合は、既存インフラに対して無停止・再起動・再作成のいずれかが発生するため、変更セットによる事前確認が必須となります。
レビュー時にはコード内容の妥当性を確認するだけでなく、既存インフラへの影響を確認します。
レビュー時確認ポイント
・変更セットから想定外のリソース削除が発生しないか確認(重要)
・変更セットから想定外のリソース再起動が発生しないか確認(重要)
・コード内容が妥当であるか確認
# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
# ArtifactStoreBucket
# ------------------------------------------------------------#
ArtifactStoreBucket:
Type: AWS::S3::Bucket
Properties:
VersioningConfiguration:
Status: Enabled
# ------------------------------------------------------------#
# CodePipelineSNSTopic
# ------------------------------------------------------------#
CodePipelineSNSTopic:
Type: AWS::SNS::Topic
Properties:
Subscription:
- Endpoint: !Ref Email
Protocol: email
# ------------------------------------------------------------#
# Pipeline
# ------------------------------------------------------------#
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStore:
Location: !Ref 'ArtifactStoreBucket'
Type: S3
DisableInboundStageTransitions: []
Name: !Ref 'PipelineName'
RoleArn: !GetAtt [PipelineRole, Arn]
Stages:
- Name: S3Source
Actions:
- Name: TemplateSource
ActionTypeId:
Category: Source
Owner: AWS
Provider: S3
Version: '1'
Configuration:
S3Bucket: !Ref 'S3Bucket'
S3ObjectKey: !Ref 'SourceS3Key'
OutputArtifacts:
- Name: TemplateSource
RunOrder: '1'
- Name: ProdStage
Actions:
- Name: CreateChangeSet
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: '1'
InputArtifacts:
- Name: TemplateSource
Configuration:
ActionMode: CHANGE_SET_REPLACE
RoleArn: !GetAtt [CFNRole, Arn]
StackName: !Ref DeployStackName
ChangeSetName: !Ref ChangeSetName
TemplatePath: "BuildArtifact::template/cfn-template.yml"
RunOrder: '1'
- Name: ApproveChangeSet
ActionTypeId:
Category: Approval
Owner: AWS
Provider: Manual
Version: '1'
Configuration:
NotificationArn: !Ref CodePipelineSNSTopic
CustomData: !Sub 'A new change set was created for the ${DeployStackName} stack. Do you want to implement the changes?'
RunOrder: '2'
- Name: ExecuteChangeSet
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: '1'
Configuration:
ActionMode: CHANGE_SET_EXECUTE
ChangeSetName: !Ref ChangeSetName
RoleArn: !GetAtt [CFNRole, Arn]
StackName: !Ref DeployStackName
RunOrder: '3'
# ------------------------------------------------------------#
# EventBridge
# ------------------------------------------------------------#
EventBridgeForManualAppoveReject:
Type: AWS::Events::Rule
Properties:
Description: 'for codepipeline'
EventPattern:
source:
- 'aws.codepipeline'
detail-type:
- 'CodePipeline Action Execution State Change'
resources:
- 'arn:aws:codepipeline:\:\:'
detail:
stage:
- 'Approve'
action:
- 'Approve'
state:
- 'FAILED'
Name: eventbridge-manualapprove-reject
State: ENABLED
Targets:
- Arn: !Join
- ''
- - 'arn:aws:codepipeline:ap-northeast-1:'
- !Sub '${AWS::AccountId}:'
- !Ref CodePipeline
Id: CodePipeline
RoleArn: !GetAtt EventBridgeIAMRole.Arn
画面イメージ
発展
IaCをCI/CD構成に取り込むことで、IaCのDevOpsベースラインとなり、IaCによる運用が効率的に実施できるようになります。また、IaC毎にCI/CDを作成したり、要件に応じてCIとCDの内容を拡張しやすいと考えております。
次回移行のブログで解説してみます。
まとめ
IaCをDevOps化させることで、インフラ整備を安定して効率的に実施できます。
本トピックは基本的な構成となるため、機能拡張のさせ方で応用が利かせやすいと考えております。
またIaCの種類に応じてCIやCDに対して機能拡張して、実務に合うようにカスタマイズできます。