CDKでIAMポリシーやSGのルールを直接書くのは出来るだけ避けよう
かわごえです
稀にCDKのコードを見ていると、せっかくCDKを使っているのにIAMのポリシーやSGのルールを書いているコードを見かけます。
また、IConnectableやIGrantableについての日本語記事もなかなか見かけないのでポエムを書いてみようと思った次第です。
IGrantableとは
IGrantableとは、権限を付与することできるプリンシパルが関連づけられたオブジェクトです。
利用する際には、以下のようにgrantメソッドと共に利用します。
// IGrantable
const s3 = new Bucket(stack, 'Bucket')
const role = new Role(stack, 'Role')
s3.grantPut(role) // Role=>S3にPutが可能な権限が付与される
このように、リソースのクラスに実装されているgrantメソッドを利用することで、権限の付与を簡単に実現することが可能です。S3バケットの場合はgrantPutやgrantReadなど、S3の操作のユースケースに合わせてメソッドが定義されています。grantを利用することで、それぞれのリソースごとにユースケースに合わせた最小権限を簡単に実装することが可能です。
この際、権限を付与するプリンシパルとして利用できるのがIGrantableをしたクラスです。みんな大好きNodejsFunctionやRole、Instanceなど数多くのL2コンストラクトに実装がされています。
IConnectableとは
IConnectableとは、IGrantableと同様、通信の許可を付与することができるコンポーネントが関連づけられたオブジェクトのことです。
Connectionsと共に利用し、通信を許可するコンポーネントを指定することで、SGの通信をこちらも最小権限に近い形で実装することができます。
const instance = new Instance(this, "Instance", {...});
const db = new DatabaseCluster(this, "Database", {...});
instance.connections.allowTo(db, Port.tcp(5432)); // DBのセキュリティグループにinstanceからのTCP 5432の通信が許可される
こちらもVPCが必要なリソースの大半のL2に実装がされています。
そもそもなぜIAMポリシー/SGのルールが必要なのか
当初やりたかったことは、IAMポリシーの場合「AがBに対してリソースの操作することを許可する」ことであったはずです。しかしCloudFormationやCLI、マネジメントコンソールでAWSリソースを作成し、IAMやSGを作成する・書くことに慣れてしまったためCDKを利用しているのにも関わらず今までやっていたのと同じ書き方で書いていたりしないでしょうか???
直接IAMポリシーやSGのルールの中身をCDKで書けばその分コード量も増えますし、リソースがどういう権限を持っているか・どういう通信が可能になっているかを確認したい場合にIAMポリシーやSGのルールを読み解くという作業が発生します。grantやConnectionのメソッドで利用されているようなものは直感的にもわかりやすいだけでなく、実装やメンテナンスに割く時間を大幅に短縮できると考えてます。
このような理由から、CDKのコードレビューをする際にも 「CDKでIAMポリシーやSGのルールを直接書くのは出来るだけ避けてください」 と口酸っぱく言うようにしてます。
いままでこういうやり方をしてたから、ではなく、本来やりたいことは何なのかをきちんと考えましょうね。という話でした。
このIGrantable/IConnectableのおかげで、CDKにおいてはIAM権限の付与や通信の許可をかなり簡潔に定義できるようになっています。ありがたい機能ですし全てにL2が実装された際にはIAMポリシーやSGを書かなくてもいい世界が訪れることでしょう。(そうなってくれ)
おまけ
どのようにaws-cdk-libで実装されているかを確認したい方は、IFunctionの実装やBaseFunctionの実装を見ていただくと理解しやすいかなと思います。
Discussion