特定セキュリティグループのみ EC2インスタンスへ関連付けできるように制限する IAMポリシー

2021.07.05

やりたいこと

img

EC2インスタンスへのセキュリティグループ関連付けを制限したいです。 具体的には特定セキュリティグループのみ付与が可能、 ほかセキュリティグループはインスタンスへ関連付けできないようにします。

これを行うモチベーションは「インスタンスの通信制限の徹底」です。 セキュリティグループは 許可リスト方式 を取ります。 そのため、セキュリティグループの付与により インバウンド/アウトバウンドの許可範囲が増えます。 AWS利用者の意図しないセキュリティグループの付与により 「SSH/RDP フルオープンになっている」といった事態になってしまう...そういった懸念がある場合の解決案の1つです。

どうやって実現するか

セキュリティグループへタグ付けを行い、「特定セキュリティグループ」と 「それ以外」を分類します。

img

このタグをベースに、許可/拒否を決定する 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される

(参考) 活用している条件演算子( StringNotEqualsIfExists ) の詳細は 以下参照ください。

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の評価ロジックについては以下参考になります。

試してみる

以下 権限を付与した 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インスタンスへの セキュリティグループアタッチ/デタッチ制御例を紹介しました。

「どのようにポリシー設計するか」だけでなく 「このポリシーをどのように使って、運用していくか」も実際に使う際には 重要になってきます。しっかりと規則化、ドキュメント化する必要があるでしょう。

参考になれば幸いです。

参考