目次
はじめに
What’s IAMポリシー?
IAMポリシーの作成
IAMポリシーのデザインパターン
実際の作成について
おわりに
はじめに
久しぶりの投稿になります。都内の某ITコンサルに勤める3年目のエンジニアです。
普段はアプリケーションエンジニアとして従事しているのですが、
クラウド(AWS)技術に強い興味があり、その中でも特にセキュリティ面に興味があります。
今回は、その根幹となるIAMのポリシーとそのデザインパターンについて筆を執りたいと思います。
What’s IAMポリシー?
IAMポリシーを理解するべく、まずポリシー(policy)という単語の意味を押さえます。
以下はWeblio英和辞典で検索をかけた結果です。
訳語からお分かりいただけるかと思いますが、この単語の意味は「ある目的に沿って対象の行動に影響を与えるもの」と把握できます。
ここからIAMそのものの意義を合わせると、IAMポリシーとは対象のリソースの権限を定義し、動作範囲を規定する(許可を与える)ものと理解できます。
ポリシーはそれ単体では働きません。IAMユーザーやロールといった対象にアタッチすることで、初めて意味をなします。
- IAMユーザー:アカウント内で定義される、特定の権限を持ったユーザー
- IAMロール:主にリソースに付与して使用され、特定の権限(役割)を委任するもの
policy (施策) がuser (人) やrole (役割) に影響を与えるという関係性は、単語の意味からも把握できます。
IAMポリシーの種類
IAMポリシーには大きく分けて6つの種類が存在します。詳細な説明は公式ドキュメントに譲りますが、ここでは概観をざっくり把握したいと思います。
アイデンティティベース
最も広く認知されている使用方法です。
ユーザーやロールといったアイデンティティに対し、実行できるアクションや扱えるリソース、必要な条件等をJSONドキュメント形式で定義します。
リソースベース
リソースに対してインラインポリシーを付与する使用方法です。公式では、例としてS3のバケットポリシーやIAMの信頼ポリシーが挙げられていますが、KMSのキーポリシーなんかもこれに該当します。
信頼ポリシーが分かりにくいという声を聞いたりもしますが、デフォルトのアタッチ可能範囲外に権限を付与(譲渡)したい場合、あるいは権限付与の際に特定の条件(MFAを有効化している等)を課したい場合に利用されるものだと認識しています。
より詳しくはこちらのドキュメントをご参照ください。
IAMアクセス許可の境界
IAMリソースそのもののアクセス許可を定義してしまう使用方法です。
「このポリシーで許可できるアクションはCloudWatch内のアクションに限定したい」といった際に使用できます。
そのほかのサービスのアクションも定義することはできますが、CloudWatchに関するもの以外は無効になってしまいます。
あまり考えにくいですが、アプリケーションを介してIAMポリシーの権限を変更する場合、アプリケーションの暴走を防ぐセーフティネットとしても利用することができます。
SCP(サービスコントロールポリシー)
Organizationsにおいて組織や組織単位(OU)に使用して、アクセス範囲の上限を定義します。当該組織内のメンバーはSCPで許可されていて、かつアイデンティティベースでアクセスを許可されているリソースのアクションのみ実行可能です。
ACL(アクセスコントロールリスト)
このポリシーがアタッチされたリソースへの別のアカウントからのアクセスを制限するポリシーです。代表例としてはS3のオブジェクトACL等が挙げられます。
セッションポリシー
なんですか、これ?(公式ドキュメント)
IAMポリシーの作成
具体的なIAMポリシーの定義について見ていきましょう。
ここでは主に、アイデンティティベースのポリシーについて話を進めていきます。
JSONドキュメント
IAMポリシーは以下のようなJSONドキュメントで記述されます。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "FirstStatement",
"Effect": "Allow",
"Action": [
"iam:ChangePassword"
],
"Resource": "*"
},
{
"Sid": "SecondStatement",
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*"
},
{
"Sid": "ThirdStatement",
"Effect": "Allow",
"Action": [
"s3:List*",
"s3:Get*"
],
"Resource": [
"arn:aws:s3:::confidential-data",
"arn:aws:s3:::confidential-data/*"
],
"Condition": {
"Bool": {"aws:MultiFactorAuthPresent": "true"}
}
}
]
}
以下では、各構成要素について見ていきます。
Version
"Version": "2012-10-17"
Versionには “2008-10-17” と “2012-10-17” の2つがあります。
サポートされるサービスの種類の差はあるが、記述の仕方に大きな違いはありません。
基本的には、2012を選択すると間違いないと思います。
Statement
{
"Sid": "SecondStatement",
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*"
}
どのリソースについてどのアクションをどうしたいのかを指定するオブジェクトの配列です。
例えば、上記のオブジェクトでは
「任意のリソースについてS3のバケット一覧を表示することを許可する」
と解釈ができます。
{
"Sid": "ThirdStatement",
"Effect": "Allow",
"Action": [
"s3:List*",
"s3:Get*"
],
"Resource": [
"arn:aws:s3:::confidential-data",
"arn:aws:s3:::confidential-data/*"
],
"Condition": {
"Bool": {"aws:MultiFactorAuthPresent": "true"}
}
}
こちらの例ではリソースが限定されていること加えて、この権限が有効になるための条件が定義されています。
これを踏まえると、このポリシーの内容は以下のように解釈できます。
「MFA認証済みの場合、confidential-dataバケットとその配下について、任意の対象の一覧表示および取得を許可する」
また、次のようにアクションの明示的拒否を行うこともできます。
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"192.0.2.0/24",
"203.0.113.0/24"
]
},
"Bool": {"aws:ViaAWSService": "false"}
}
}
}
こちらのポリシーの内容は、「192.0.2.0/24 または 203.0.113.0/24 からのアクセス、またはAWSサービスを介したアクセスでなければ、任意のサービスに対する任意のアクションを拒否する」 となります。
やや複雑ですが、こちらのドキュメントに記載されている MultiCondition の場合の評価ロジックに従うと解釈できます。
また、重要な点として明示的に許可されていないリソースのアクションについては暗黙的に拒否されるということが挙げられます。
加えて、各Effectの強さは明示的拒否 > 明示的許可 > 暗黙的拒否と定義されています。
IAMポリシーの設計の設計を行う場合、以上のことを踏まえておく必要があります。
IAMポリシーのデザインパターン
さて、ここからが本記事で最も触れたい内容です。
IAMポリシーの設計を行うにあたって、参考にできるデザインパターンが3つあります。
ホワイトリストパターン
{
"Effect": "Allow",
"Action": [
"s3:List*",
"s3:Get*"
],
"Resource": [
"arn:aws:s3:::confidential-data",
"arn:aws:s3:::confidential-data/*"
],
"Condition": {
"Bool": {"aws:MultiFactorAuthPresent": "true"}
}
}
最も基本的(直感的)なデザインパターンです。
ネーミングからもお分かりかと思いますが、明示的許可のみを行います。
許可を記述していないアクションについては暗黙的に拒否されるため、このポリシーの与える権限の範囲が明確なのが特徴です。
ブラックリストパターン
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"192.0.2.0/24",
"203.0.113.0/24"
]
},
"Bool": {"aws:ViaAWSService": "false"}
}
}
}
こちらも名前から明らかですが、明示的拒否のみを行うパターンです。
明示的拒否は最も強いEffectであり、一度このポリシーをアタッチしてしまうと、該当するアクションの権限は他のポリシーにより上書きすることができなくなります。
とても強い主張のため、以下のような条件を満たしていなければ権限を与えないという文脈で利用されることが多いです。
- MFA未認証
- VPCやAWSサービス外からのアクセス
- 指定の範囲外のソースIP etc.
また、注意すべき点として、このポリシーだけでは何の権限も与えないことが挙げられます。
そのため、このポリシーで権限の範囲を絞って明示的許可ポリシーでアクションを許可するという使用法になるかと思います。
ハイブリッドパターン
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:ap-northeast-1:999999999999:***",
"Condition": {
"StringNotEquals": { "aws:sourceVpc": "vpc-***" }
}
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:ap-northeast-1:999999999999:***"
}
]
}
前出の2パターンを組み合わせたデザインパターンです。
先に示したEffectの優先順位に倣い、権限を与えたくない特定の場合を明示的に拒否し、それ以外の場合を包括的に許可するという構成を取ることが可能です。
上記の例では、特定のVPC外からのAPI呼び出しは全て拒否し、それ以外、すなわちVPC内からのAPI呼び出しは全て許可しています。
他にも以下のような構成が考えられます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": { "AWS": "arn:aws:iam::999999999999:user/*" },
"Action": "iam:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::999999999999:user/*" },
"Action": "*",
"Resource": "*"
}
]
}
この例では、IAMに関する一切の権限は与えない一方でそれ以外のリソースに関する全権限を与えており、擬似Administratorのような権限を付与する内容になっていることがお分かりいただけると思います。
このように、特定のリソースまたはアクションを除いて包括的に許可したい場合に本パターンは有用であると考えられます。
実際の作成について
ハイブリッドパターンは便利な反面、他の2パターンに比べて再利用性に乏しいことが欠点として挙げられます。
管理ポリシーを作成する際は、基本的にホワイトリスト・ブラックリストで定義し、個別の事例に対応する場合のみハイブリッドを利用するのが理想的とされます。
以上を踏まえると、実際の作成(設計)手順は以下のようになります。
- 権限を与えたくないアクション(サービス)を洗い出し、ブラックリストパターンで明示的に拒否するポリシーを作成する(IAMポリシーの作成・編集などセキュリティ的にクリティカルなものをなるべく個別に)
- 権限を与えたいアクション(サービス)について、ホワイトリストパターンで(包括的に)許可していく
このような手順を取る理由としては、個別にアクションを許可することが難しいことが挙げられます。
AWSでは、あるアクション実行時に内部的に別のアクションが実行されている場合があり、表面的に必要なアクションのみを許可しただけではサービスが利用できないことが多いです。
そのため、クリティカルなものだけを明示的に拒否した上で包括的に権限を与えることで、
明示的拒否が明示的許可よりも強いという性質から、クリティカルなものを除いたアクション権限が付与されることになります。
おわりに
ここまで、IAMポリシーの定義からそのデザインパターン、実際の作成手順を見てきました。
手っ取り早く権限を付与したい場合は、ロールごとにインラインポリシーを設定してしまうのが楽だとは思います。
しかしながら、大規模プロジェクトなど、権限の一元的管理が必要で、権限定義の権限を付与する人を限定したい場合などは前節で紹介したような汎用的な(再利用性の高い)パターンで作成する必要があると考えます。
本記事が、読者の皆様のポリシー作成の参考となれば幸いです。
お読みいただきありがとうございました。