CDK/Pythonでオレオレガードレールを実装する
こんにちはししぃです。
わたしはCDKを使ってインフラを作るのが好きです。
インフラを作る上でオレオレルール的(もっというとコンプライアンス的なもの)なのありますよね。 例えばS3でバケット作ったら暗号化は必須にしようとか、dynamoでTable作ったときは削除policyは、、、とかとか。
でも実装時は色々考えて作ってますから、そのルールがすっかり頭から抜けて実装漏れるとか、ありますよね。
今回はそんなオレオレルール(もといガードレール)をCDKの中に組み込んで、実装漏れをふせぐ方法を書いていきます。
前知識
オレオレガードレールを作るにあたって Aspects を使います。
これはなにかというと、公式ではこんな説明されてます。
Aspects are a way to apply an operation to all constructs in a given scope. The aspect could modify the constructs, such as by adding tags, or it could verify something about the state of the constructs, such as ensuring that all buckets are encrypted. (DeepLの和訳)アスペクトは、与えられたスコープ内のすべての構成要素に操作を適用する方法です。アスペクトは、タグを追加するなどして構成要素を変更したり、すべてのバケットが暗号化されているかなど、構成要素の状態を確認したりすることができます。
https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/aspects.html
というものです。
噛み砕くとテンプレート吐き出す前に construct を検証したら、勝手に変更したりできるよ!ってことだと思います。
このへん実際に動き見たほうが早いと思いますので次行きます。
今回作ろうとしてるもの
CDK/Pythonを使って、Lambda Functionをただ1つデプロイするだけのStackを作る。
ただしオレオレルールで、アーキテクチャはARM64が必須。 かつメモリーサイズは指定してないと激おこされるようにします。
では 作っていきましょう👻
まずベースとなるFunction1つだけデプロイするStackを作ります
import aws_cdk as cdk
from aws_cdk import aws_lambda
app = cdk.App()
stack = cdk.Stack(app, "test")
lambda_ = aws_lambda.Function(
stack,
"function",
code=aws_lambda.Code.from_asset("runtime"),
runtime=aws_lambda.Runtime.PYTHON_3_9,
handler="index.handler",
)
app.synth()
ここの説明は不要だと思うので次行きます。
ここにオレオレルールを追加すると、、こんなかんじ↓
import aws_cdk as cdk
import jsii
from aws_cdk import aws_lambda
from constructs import IConstruct
# --------------------------------------
# ガードレール的なモノを定義する
@jsii.implements(cdk.IAspect)
class HogeGuardrail:
def visit(self, node: IConstruct):
if isinstance(node, aws_lambda.Function):
cfn_node: aws_lambda.CfnFunction = node.node.default_child
# アーキテクチャーの判断
if not cfn_node.architectures == ["arm64"]:
cdk.Annotations.of(node).add_error("ARM64じゃないよ!!")
# メモリーの判断
if not cfn_node.memory_size:
cdk.Annotations.of(node).add_error("メモリーサイズ設定してないよ!!デフォルトだと最小だからパフォーマンス悪いよ!!")
# --------------------------------------
# CDKでアプリを作る
app = cdk.App()
stack = cdk.Stack(app, "test")
lambda_ = aws_lambda.Function(
stack,
"function",
code=aws_lambda.Code.from_asset("runtime"),
runtime=aws_lambda.Runtime.PYTHON_3_9,
handler="index.handler",
)
cdk.Aspects.of(stack).add(HogeGuardrail())
app.synth()
じゃん。
変わったところはHogeGuardrail
のクラスが追加されたのと、下の方でそのクラスを利用するcdk.Aspects.of(stack).add(HogeGuardrail())
の行が増えたことです。
コードの説明の前に動作確認しておきます。
$ cdk -a "python3 app.py" synth
>> [Error at /test/function] ARM64じゃないよ!!
>> [Error at /test/function] メモリーサイズ設定してないよ!!デフォルトだと最小だからパフォーマンス悪いよ!!
>>
>> Found errors
>> make: *** [synth] Error 1
こんな↑感じで怒られます。
ではHogeGuardrail
クラスのコード見てきましょう
@jsii.implements(cdk.IAspect)
class HogeGuardrail:
def visit(self, node: IConstruct):
if isinstance(node, aws_lambda.Function):
cfn_node: aws_lambda.CfnFunction = node.node.default_child
# アーキテクチャーの判断
if not cfn_node.architectures == ["arm64"]:
cdk.Annotations.of(node).add_error("ARM64じゃないよ!!")
# メモリーの判断
if not cfn_node.memory_size:
cdk.Annotations.of(node).add_error("メモリーサイズ設定してないよ!!デフォルトだと最小だからパフォーマンス悪いよ!!")
真っ先にこれ↓なんぞやってとこですね
@jsii.implements(cdk.IAspect)
AWSが開発したjsii
という色々な言語でtypescriptを動かす魔法のようなパッケージがあります。jsii
経由でtypescriptを動かすためのインターフェイスを、実装するためのデコレーターが@jsii.implements(cdk.IAspect)
です。(このへん私自身もあまり詳しくないので間違ってたらツッコミいただければと、、)
そしてcdk.IAspect
の中をちらっと覗くとvisit
関数がただ一人でででーん!と存在するので、それを実装してあげます。
ちなみに、CDK/Pythonの公式ドキュメントを見ると
..略
class MyAspect(cdk.IAspect):
def visit(self, node):
..略
https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk/Aspects.html
こんな感じで実装できるぜ!!って書いてありますが、これたぶん間違いで、jsii
経由で実装しないと動かないと思います。
ここまでで、jsii
経由でvisit
関数実装すればいいんだなー、というところまでわかると、後はその中でルールを記述するだけです。
visit
は指定した construct に入ってるすべての node が来るので、まず node の型をみて Function だったらアーキテクチャとメモリーサイズを検証してます。
検証の注意点は Construct 次第では L1 Construct (CfnXXX系)にしてからでないと設定されているパラメーターを確認できないときがあるということです(今回そのパターン)
次に今回出したERRORに対応してみます。
Lambdaを作ってるところだけもってきました↓が、こんな感じ
..略
lambda_ = aws_lambda.Function(
stack,
"function",
code=aws_lambda.Code.from_asset("runtime"),
runtime=aws_lambda.Runtime.PYTHON_3_9,
handler="index.handler",
architecture=aws_lambda.Architecture.ARM_64, # 追加
memory_size=256, # 追加
)
..略
コメントがついているところを追加しただけです。
この状態で
$ cdk -a "python3 app.py" synth
すると無事ERRORが表示されなくなり、無事テンプレートが出力されます!!
めでたしめでたしですね。
ではでは今回は以上です。
最後まで読んでいただきありがとうございました!