やりたいこと
・AWS CloudformationをS3にアップロードすると、CI/CDパイプラインを通じてデプロイを行う。
・CI/CDパイプラインは、AWSCodePipelineとAWSLambdaで構築する。
・LambdaでEBボリュームが暗号化されているのかのチェックと
リリースする前に、人間系の承認工程(Human Approval)を設けてDevSecOpsの環境を整備する。
※AWS Adding Security into DevOpsワークショップを参考
構成

流れ
1.Cloudformationの開発環境としてCloud9を用意する。
2.CodePiplineを構築する。パイプライン上にセキュリティチェックと人間系の承認工程を挟む。
3.Cloud9で編集したCloudformationのテンプレートをS3バケットに投入し、パイプライン上に流す。
前提
・AWS Account, Admin IAM Userが利用できること
・us-west-2 (Oregon) リージョンで実施
Cloud9の用意
us-west-2 (Oregon) リージョンでCloud9を作成。
特に設定は変更せず、デフォルトのまま作成。



起動を確認する。

ワークショップで提供されているgitをcloneする。
git clone https://github.com/aws-samples/secure-pipelines-in-aws-workshop.git

cloneできたことを確認する。

S3バケットの用意
US-West-2オレゴンリージョンにs3バケットを作成する。

git cloneでDLした2つのファイルをアップロードする。
・codepipe-AWS-devsecops.zip
・SecGuardRails.zip

CodePipline構築
git cloneでDLした「Pipeline.yml」を用いてCFNからCodePiplineを構築する。
任意の名前をつけて、S3bucketに用意したバッケット名「devsecops-20211002」を入れる。
オプションは設定せずそのまま作成。
作成後、CFNの画面からパイプラインが作成されたことを確認する。
CodePiplineを確認するとパイプラインが失敗している。S3バケットからの取得に失敗している様子。
CFNで作成されたS3バケットに「codepipe-AWS-devsecops.zip」が無いことが原因。
ファイルをアップロードして、CodePiplineを確認する。成功しているのでOK。
ところが、StaticCodeAnalysisが成功しているのでおかしい。パイプラインに流したEBSボリュームは暗号化されていないので、StaticCodeAnalysisのチェックに引っかかり失敗になるはず。

StaticCodeAnalysisで利用するLamdaのプログラムを見ると'ruledata'の項目が機能していない様子。
client.put_item(
TableName=logTable,
Item={
'rule' : {'S': "VolumesNotEncrypted"},
'category' : {'S': "Volume"},
'ruletype' : {'S': "regex"},
'ruledata' : {'S': "^.*Encrypted.?\s*:\s*u?.?false"},
'riskvalue' : {'N': "90"},
'active' : {'S': "Y"}
}
)
client.put_item(
TableName=logTable,
Item={
'rule' : {'S': "VolumesNotEncrypted"},
'category' : {'S': "Volume"},
'ruletype' : {'S': "regex"},
'ruledata' : {'S': "Encrypted":"false"},
'riskvalue' : {'N': "90"},
'active' : {'S': "Y"}
}
)
Lamdaの画面で「Deploy」しないと反映されないので注意。
再度実行すると、「StaticCodeAnalysis」で失敗となり想定通り。
エラー内容(Function exception: Failed filters['VolumesNotEncrypted'])も良さそう。
codepipe-AWS-devsecopsにあるresources.jsonを修正する。"Encrypted"をfalseからtrueに変更。
"EC2Volume" : {
"Type" : "AWS::EC2::Volume",
"Properties" : {
"Size" : "8",
"Encrypted" : "false",
"AvailabilityZone" : {
"Fn::Select" : [ "0", { "Fn::GetAZs" : "" } ]
},
"Tags" : [
{"Key": "Name", "Value": "AWS"},
{"Key": "LOB", "Value": "SecurityJam"}
]
}
},
"EC2Volume" : {
"Type" : "AWS::EC2::Volume",
"Properties" : {
"Size" : "8",
"Encrypted" : "true",
"AvailabilityZone" : {
"Fn::Select" : [ "0", { "Fn::GetAZs" : "" } ]
},
"Tags" : [
{"Key": "Name", "Value": "AWS"},
{"Key": "LOB", "Value": "SecurityJam"}
]
}
},
変更後、odepipe-AWS-devsecopsフォルダをzip化してS3バケットに再度アップロードする。
CodePiplineを見ると、TestDeploymentでエラーが発生して止まっている。

CFNのスタック(AWS-devsecops-TestStack)がロールバックしている様子。ただ、理由が不明。
CFNを見ると、ステータスが"UPDATE_ROLLBAK_COMPLETE"になっている。
ログで詳細を見ると
Volume properties other than AutoEnableIO, type, size, and IOPS cannot be updated. Change the properties back to previous values and update the stack again.
とあり、すでに作成されたボリュームについて変更できない箇所がある旨エラーがでていた。
なので、ロールバックしているスタック(AWS-devsecops-TestStack)を削除。
CodePiplineに戻りパイプラインを再実行すると、承認工程(ApprovalTestStack)までパイプラインが流れており良さそう。
承認してパイプラインを流すと今度はProductionDeploymentでエラー発生。
以前、作成した同名のスタック(AWS-devsecops-ProdStack)が残っていたので削除。
CodePiplineに戻りパイプラインを再実行すると、今度は全てのパイプラインが流れて無事成功(^ω^;)
まとめ
AWSCodePipelineとAWSLambdaを用いたパイプライン内にセキュリティ観点のチェック工程を入れることでDecSecOpsのパイプラインを構築できた。エラー対応が多かった・・・(汗
参考