この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
やりたいこと
EC2インスタンスへのセキュリティグループ関連付けを制限したいです。 具体的には特定セキュリティグループのみ付与が可能、 ほかセキュリティグループはインスタンスへ関連付けできないようにします。
これを行うモチベーションは「インスタンスの通信制限の徹底」です。 セキュリティグループは 許可リスト方式 を取ります。 そのため、セキュリティグループの付与により インバウンド/アウトバウンドの許可範囲が増えます。 AWS利用者の意図しないセキュリティグループの付与により 「SSH/RDP フルオープンになっている」といった事態になってしまう...そういった懸念がある場合の解決案の1つです。
どうやって実現するか
セキュリティグループへタグ付けを行い、「特定セキュリティグループ」と 「それ以外」を分類します。
このタグをベースに、許可/拒否を決定する IAMポリシーを作成します。
本ブログでは「 AdminManaged = yes タグ
を付与した セキュリティグループ」と
「それ以外のセキュリティグループ」の前提で実装を進めます。
IAMポリシー(メイン)
まずは「タグが AdminManaged = yes
以外 のセキュリティグループ」の
関連付けアクションを禁止する IAMポリシーです。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyNotAllowedSGAttach",
"Effect": "Deny",
"Action": "ec2:ModifyNetworkInterfaceAttribute",
"Resource": "arn:aws:ec2:*:*:security-group/*",
],
"Condition": {
"StringNotEqualsIfExists": {
"aws:ResourceTag/AdminManaged": "yes"
}
}
}
]
}
▼ 以下 ステートメント解説
EC2インスタンスのセキュリティグループ関連付け設定の変更は ec2:ModifyNetworkInterfaceAttribute で行います。
全てのセキュリティグループのリソースARNは
arn:aws:ec2:*:*:security-group/*
で表せます。
(参考: Amazon EC2 で定義されるリソースタイプ)
Condition を使って
セキュリティグループの AdminManagedタグが "yes" かどうか 判断しています。
条件キーの aws:ResourceTag/AdminManaged
が
リソースに付与されている AdminManaged
タグ値を表します。
ケース(SGのタグ情報) | 条件の真偽 | 【結果】 |
---|---|---|
AdminManaged = yes | StringNotEquals により false | Denyされない |
AdminManaged ≠ yes | StringNotEquals により true | Denyされる |
AdminManaged タグ無し | IfExists により true | Denyされる |
(参考) 活用している条件演算子( StringNotEquals
や IfExists
) の詳細は
以下参照ください。
IAMポリシー(タグ編集のガードレール)
前述のIAMポリシーだけでは不十分です。
なぜなら、AWS利用者自身で AdminManaged
タグを追加/更新/削除できるためです。
「特定セキュリティグループ」の枠組みを破壊されないようにするための
ガードレールが必要です。
今回は以下内容の制限を設けて実現しました。
AdminManaged
タグを持つ SG … 任意タグの追加/更新/削除を禁止するAdminManaged
タグを持たない SG …AdminManaged
タグの追加を禁止する
この 2つの制限を IAMポリシーに書くと以下のようになります。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyTagOperationsForManagedSG",
"Effect": "Deny",
"Action": [
"ec2:CreateTags",
"ec2:DeleteTags"
],
"Resource": "arn:aws:ec2:*:*:security-group/*",
"Condition": {
"Null": {
"aws:ResourceTag/AdminManaged": false
}
}
},
{
"Sid": "DenyTagCreationForNonManagedSG",
"Effect": "Deny",
"Action": "ec2:CreateTags",
"Resource": "arn:aws:ec2:*:*:security-group/*",
"Condition": {
"Null": {
"aws:ResourceTag/AdminManaged": true,
"aws:RequestTag/AdminManaged": false
}
}
}
]
}
1つ目のステートメント解説
セキュリティグループに対して、タグの操作 ec2:CreateTags, ec2:DeleteTags
を Condition 次第で禁止します。
Condition では Null を活用しています。条件キーが存在するかどうか、判断します。
ケース(SGのタグ情報) | 条件の真偽 | 【結果】 |
---|---|---|
AdminManaged タグ 有り | true | Denyされる |
AdminManaged タグ 無し | false | Denyされない |
結果として 「AdminManaged タグが付与されているセキュリティグループ」には タグ操作ができなくなります。
2つ目のステートメント解説
セキュリティグループに対して、タグの追加/更新 ec2:CreateTags
を Condition 次第で禁止します。
Condition では 同じく Null を活用しています。条件キーが存在するかどうか、判断します。
ケース#1(リソースタグ) | 条件#1 | ケース#2(リクエストタグ) | 条件#2 | 条件の真偽 | 【結果】 |
---|---|---|---|---|---|
AdminManaged 有り | false | AdminManaged 有り | true | false | Deny されない |
AdminManaged 有り | false | AdminManaged 無し | false | false | Deny されない |
AdminManaged 無し | true | AdminManaged 有り | true | true | Deny される |
AdminManaged 無し | true | AdminManaged 無し | false | false | Deny されない |
上の表の 条件#1は "aws:ResourceTag/AdminManaged": true
部分
条件#2 は "aws:RequestTag/AdminManaged": false
部分を表しています。
最終的に各条件の AND
が計算されます。
結果として「AdminManaged タグが付与されていないセキュリティグループ」に対して 「AdminManaged タグ を追加」できなくなります。
(参考) 本IAMポリシーで説明した Null や Conditionの評価ロジックについては以下参考になります。
- 【小ネタ】 AWS IAMポリシーの Conditionで使える条件演算子 “Null” の使いみちを考える | DevelopersIO
- 複数のキーまたは値による条件の作成 - AWS Identity and Access Management
試してみる
以下 権限を付与した IAMロールを使って検証しました。
- PowerUserAccess
- 前述の「IAMポリシー(メイン)」
- 前述の「IAMポリシー(タグ編集のガードレール)」
セキュリティグループとして以下 4つを使ってテストします。
aws ec2 describe-security-groups --filters Name=group-name,Values="*ManagedSG*" --output table \
--query "SecurityGroups[].[GroupName, GroupId, Tags[?Key=='AdminManaged']|[0].Value]"
# -----------------------------------------------------
# | DescribeSecurityGroups |
# +------------------+------------------------+-------+
# | NonManagedSG2 | sg-031xxxxxxxxxxxxxx | None | → AdminManagedタグ無しのSG
# | NonManagedSG1 | sg-058xxxxxxxxxxxxxx | no | → AdminManaged=no のSG
# | AdminManagedSG2 | sg-089xxxxxxxxxxxxxx | yes | → AdminManaged=yes のSG
# | AdminManagedSG1 | sg-08cxxxxxxxxxxxxxx | yes | → AdminManaged=yes のSG
# +------------------+------------------------+-------+
EC2インスタンスには予め AdminManagedSG1 をアタッチしています。
aws ec2 describe-instances --filters Name=instance-id,Values=$INSTANCE --output table \
--query "Reservations[].Instances[].SecurityGroups"
# ---------------------------------------------
# | DescribeInstances |
# +-----------------------+-------------------+
# | GroupId | GroupName |
# +-----------------------+-------------------+
# | sg-08cxxxxxxxxxxxxxx | AdminManagedSG1 |
# +-----------------------+-------------------+
EC2インスタンスのSG関連付け設定の変更
以下のように AdminManaged=yes の SGは自由に付け外しできます。
# AdminManagedSG2 を付ける
aws ec2 modify-network-interface-attribute --network-interface-id $ENI \
--groups $AdminManagedSG1 $AdminManagedSG2
### Check
aws ec2 describe-instances --filters Name=instance-id,Values=$INSTANCE --output table \
--query "Reservations[].Instances[].[SecurityGroups]"
# ---------------------------------------------
# | DescribeInstances |
# +-----------------------+-------------------+
# | GroupId | GroupName |
# +-----------------------+-------------------+
# | sg-08cxxxxxxxxxxxxxx | AdminManagedSG1 |
# | sg-089xxxxxxxxxxxxxx | AdminManagedSG2 |
# +-----------------------+-------------------+
# AdminManagedSG2 を外す
aws ec2 modify-network-interface-attribute --network-interface-id $ENI \
--groups $AdminManagedSG1
### Check
aws ec2 describe-instances --filters Name=instance-id,Values=$INSTANCE --output table \
--query "Reservations[].Instances[].[SecurityGroups]"
# ---------------------------------------------
# | DescribeInstances |
# +-----------------------+-------------------+
# | GroupId | GroupName |
# +-----------------------+-------------------+
# | sg-08cxxxxxxxxxxxxxx | AdminManagedSG1 |
# +-----------------------+-------------------+
それ以外の SGはそもそも付けることができません。
aws ec2 modify-network-interface-attribute --network-interface-id $ENI \
--groups $AdminManagedSG1 $NonManagedSG1
# An error occurred (UnauthorizedOperation) when calling the ModifyNetworkInterfaceAttribute operation: You are not authorized to perform this operation. ...
aws ec2 modify-network-interface-attribute --network-interface-id $ENI \
--groups $AdminManagedSG1 $NonManagedSG2
# An error occurred (UnauthorizedOperation) when calling the ModifyNetworkInterfaceAttribute operation: You are not authorized to perform this operation. ...
SGのタグ付け
AdminManaged=yes の SGに対して、タグの追加、更新、削除はできません。
### 追加
aws ec2 create-tags --resources $AdminManagedSG1 --tags Key=Hoge,Value=Fuga
# An error occurred (UnauthorizedOperation) when calling the CreateTags operation: You are not authorized to perform this operation. ...
### 更新
aws ec2 create-tags --resources $AdminManagedSG1 --tags Key=AdminManaged,Value=no
# An error occurred (UnauthorizedOperation) when calling the CreateTags operation: You are not authorized to perform this operation. ...
### 削除
aws --profile kensho-r ec2 delete-tags --resources $AdminManagedSG1 --tags Key=AdminManaged
# An error occurred (UnauthorizedOperation) when calling the DeleteTags operation: You are not authorized to perform this operation. ...
ほかSGは AdminManagedタグは追加できません 。 それ以外のタグは追加できます。
### AdminManaged タグの追加 --> ダメ
aws ec2 create-tags --resources $NonManagedSG2 --tags Key=AdminManaged,Value=yes
# An error occurred (UnauthorizedOperation) when calling the CreateTags operation: You are not authorized to perform this operation. ...
### AdminManaged 以外タグの追加 --> OK
aws ec2 create-tags --resources $NonManagedSG2 --tags Key=Name,Value=NonManagedSG2
aws ec2 describe-security-groups --filters Name=group-id,Values=$NonManagedSG2 --query "SecurityGroups[].Tags" --output table
# ---------------------------
# | DescribeSecurityGroups |
# +-------+-----------------+
# | Key | Value |
# +-------+-----------------+
# | Name | NonManagedSG2 |
# +-------+-----------------+
おわりに
EC2インスタンスへの セキュリティグループアタッチ/デタッチ制御例を紹介しました。
「どのようにポリシー設計するか」だけでなく 「このポリシーをどのように使って、運用していくか」も実際に使う際には 重要になってきます。しっかりと規則化、ドキュメント化する必要があるでしょう。
参考になれば幸いです。
参考
- AWS Documents
- DevelopersIO