[アップデート] Amazon Route 53 が DNS リソースレコードセットレベルでのアクセス許可をサポートしました

Route 53のレコードに対して詳細なアクセス制限ができるようになりました
2022.09.22

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

この人はこのレコードに対して更新しかできないようにしたい

こんにちは、のんピ(@non____97)です。

皆さんはAmazon Route 53を使っていて「この人はこのレコードに対して更新しかできないようにしたい」と思ったことはありますか? 私はあります。

レコードに対する処理はChangeResourceRecordSets APIで行います。

従来、IAMポリシーでRoute 53のレコードの操作を制限するのはホストゾーン単位でした。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "route53:ChangeResourceRecordSets",
      "Resource": "arn:aws:route53:::hostedzone/<ホストゾーンID>"
    }
  ]
}

そのため、「このレコードのみ変更加えても良い」といった制限をかけることはできませんでした。

また、処理の種類はCREATE/DELETE/UPSERTの3種類ありますが、「CREATEしか行わせないようにする」といった制限もできませんでした。

今回、Amazon Route 53 が DNS リソースレコードセットレベルでのアクセス許可をサポートしました。

これにより、ホストゾーン単位ではなく、レコード単位でアクセス制限をすることができます。

具体的にはIAMのResourceではなくConditionで制限をします。

早速試してみたので、紹介します。

いきなりまとめ

  • 追加されたConditionの条件キーは以下の3つ
    1. route53:ChangeResourceRecordSetsNormalizedRecordNames
    2. route53:ChangeResourceRecordSetsRecordTypes
    3. route53:ChangeResourceRecordSetsActions
  • いずれも複数の値を指定することができる

追加されたConditionの条件キーを確認

それでは今回のアップデートで追加されたConditionの条件キーを確認します。

追加されたConditionの条件キーは以下の3つです。

  1. route53:ChangeResourceRecordSetsNormalizedRecordNames
  2. route53:ChangeResourceRecordSetsRecordTypes
  3. route53:ChangeResourceRecordSetsActions

名前から大体どんな制限ができそうか想像できますね。

一つ一つ確認していきます。

route53:ChangeResourceRecordSetsNormalizedRecordNames

まず、route53:ChangeResourceRecordSetsNormalizedRecordNamesです。

こちらはレコードの名前に対して制限をかける条件キーです。

複数のレコード名を値として指定できます。値は以下の条件を満たす必要があります。

  • 使用できる文字は
    • a-z
    • 0-9
    • -(ハイフン)
    • _(アンダースコア)
    • .(ドット)
  • それ以外の文字はエスケープコード/を付与した3桁の8進数にエンコードする必要がある
    • かな文字などASCII文字以外は8進数にエンコードすると3桁に収まらないので、全ての文字がエンコードすれば設定できるという訳ではない
  • すべての文字は小文字でなければならない
  • 末尾にドットを付けてはならない

実際に試してみましょう。

rrset-test.non-97.netというPublic Hosted Zoneを作成しました。

Public Hosted Zoneの確認

また、以下のようなIAMポリシーを用意しました。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "route53:ChangeResourceRecordSets",
      "Resource": "arn:aws:route53:::hostedzone/Z10299392E0FL5KN3PZOY",
      "Condition": {
        "StringLike": {
          "route53:ChangeResourceRecordSetsNormalizedRecordNames": [
            "rrset-test.non-97.net",
            "\\050wassyoi\\040\\041\\051.rrset-test.non-97.net",
            "*.sub.rrset-test.non-97.net"
          ]
        }
      }
    }
  ]
}

こちらのIAMポリシーを使って、test.rrset-test.non-97.netというAレコードを作成しようとしてみます。

$ hosted_zone_id=Z10299392E0FL5KN3PZOY
$ change_resource_record_sets_input=$(cat <<EOM
{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "test.rrset-test.non-97.net",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "10.0.0.1"
          }
        ]
      }
    }
  ]
}
EOM
)

$ aws route53 change-resource-record-sets \
    --hosted-zone-id "$hosted_zone_id" \
    --change-batch "$change_resource_record_sets_input"

An error occurred (AccessDenied) when calling the ChangeResourceRecordSets operation: User: arn:aws:sts::<AWSアカウントID>:assumed-role/route-53-test/<IAMユーザー名> is not authorized to perform: route53:ChangeResourceRecordSets on resource: arn:aws:route53:::hostedzone/Z10299392E0FL5KN3PZOY because no identity-based policy allows the route53:ChangeResourceRecordSets action

Conditionのroute53:ChangeResourceRecordSetsNormalizedRecordNamesに指定されていない値なので権限不足で弾かれましたね。

次に、Zone Apexであるrrset-test.non-97.netのAレコードを作成しようとしています。

$ change_resource_record_sets_input=$(cat <<EOM
{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "rrset-test.non-97.net",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "10.0.0.1"
          }
        ]
      }
    }
  ]
}
EOM
)

$ aws route53 change-resource-record-sets \
    --hosted-zone-id "$hosted_zone_id" \
    --change-batch "$change_resource_record_sets_input"
{
    "ChangeInfo": {
        "Id": "/change/C02410842653BYPKVC5A8",
        "Status": "PENDING",
        "SubmittedAt": "2022-09-22T00:28:25.262000+00:00"
    }
}

こちらはConditionのroute53:ChangeResourceRecordSetsNormalizedRecordNamesに指定されている値なので作成できたようですね。

次に、(wassyoi !).rrset-test.non-97.netというレコードを作成しようとしてみます。

$ change_resource_record_sets_input=$(cat <<"EOM"
{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "\\050wassyoi\\040\\041\\051.rrset-test.non-97.net",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "10.0.0.1"
          }
        ]
      }
    }
  ]
}
EOM
)

$ aws route53 change-resource-record-sets \
    --hosted-zone-id "$hosted_zone_id" \
    --change-batch "$change_resource_record_sets_input"
{
    "ChangeInfo": {
        "Id": "/change/C0975728197YW8XZCU9I1",
        "Status": "PENDING",
        "SubmittedAt": "2022-09-22T00:47:59.049000+00:00"
    }
}

Conditionの\\050wassyoi\\040\\041\\051.rrset-test.non-97.net()!、スペースを3桁の8進数にエンコードしているので許可されました。

次に、test.sub.rrset-test.non-97.netというレコードを作成しようとしてみます。

$ change_resource_record_sets_input=$(cat <<EOM
{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "test.sub.rrset-test.non-97.net",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "10.0.0.1"
          }
        ]
      }
    }
  ]
}
EOM
)

$ aws route53 change-resource-record-sets \
    --hosted-zone-id "$hosted_zone_id" \
    --change-batch "$change_resource_record_sets_input"
{
    "ChangeInfo": {
        "Id": "/change/C09867703SFPH0YQ6T8D4",
        "Status": "PENDING",
        "SubmittedAt": "2022-09-22T00:59:54.207000+00:00"
    }
}

Conditionの*.sub.rrset-test.non-97.netで許可されているので通りました。

なお、当然ですがsub.rrset-test.non-97.netはConditionで指定されていないので、拒否されます。

$ change_resource_record_sets_input=$(cat <<EOM
{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "sub.rrset-test.non-97.net",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "10.0.0.1"
          }
        ]
      }
    }
  ]
}
EOM
)

$ aws route53 change-resource-record-sets \
    --hosted-zone-id "$hosted_zone_id" \
    --change-batch "$change_resource_record_sets_input"

An error occurred (AccessDenied) when calling the ChangeResourceRecordSets operation: User: arn:aws:sts::<AWSアカウントID>:assumed-role/route-53-test/<IAMユーザー名> is not authorized to perform: route53:ChangeResourceRecordSets on resource: arn:aws:route53:::hostedzone/Z10299392E0FL5KN3PZOY because no identity-based policy allows the route53:ChangeResourceRecordSets action

route53:ChangeResourceRecordSetsRecordTypes

次に、route53:ChangeResourceRecordSetsRecordTypesの確認をします。

こちらはレコードタイプに制限をかける条件キーです。

複数のレコードタイプを値として指定できます。値は大文字でRoute 53がサポートしているレコードタイプである必要があります。

  • A
  • AAAA
  • CAA
  • CNAME
  • DS
  • MX
  • NAPTR
  • NS
  • PTR
  • SOA
  • SPF
  • SRV
  • TXT

実際に試してみます。

CNAMETXTレコードのみが作成できるIAMポリシーを用意しました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "route53:ChangeResourceRecordSets",
            "Resource": "arn:aws:route53:::hostedzone/Z10299392E0FL5KN3PZOY",
            "Condition": {
                "StringLike": {
                    "route53:ChangeResourceRecordSetsNormalizedRecordNames": [
                        "rrset-test.non-97.net",
                        "\\050wassyoi\\040\\041\\051.rrset-test.non-97.net",
                        "*.sub.rrset-test.non-97.net"
                    ]
                },
                "StringEquals": {
                    "route53:ChangeResourceRecordSetsRecordTypes": ["CNAME","TXT"]
                }
            }
        }
    ]
}

試しにyeah.sub.rrset-test.non-97.netでAレコードを作成しようとしてみます。

$ change_resource_record_sets_input=$(cat <<EOM
{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "yeah.sub.rrset-test.non-97.net",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "10.0.0.1"
          }
        ]
      }
    }
  ]
}
EOM
)

$ aws route53 change-resource-record-sets \
    --hosted-zone-id "$hosted_zone_id" \
    --change-batch "$change_resource_record_sets_input"

An error occurred (AccessDenied) when calling the ChangeResourceRecordSets operation: User: arn:aws:sts::<AWSアカウントID>:assumed-role/route-53-test/<IAMユーザー名> is not authorized to perform: route53:ChangeResourceRecordSets on resource: arn:aws:route53:::hostedzone/Z10299392E0FL5KN3PZOY because no identity-based policy allows the route53:ChangeResourceRecordSets action

許可されていないので弾かれました。

続いてyeah.sub.rrset-test.non-97.netのCNAMEレコードを作成しようとみます。

$ change_resource_record_sets_input=$(cat <<EOM
{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "yeah.sub.rrset-test.non-97.net",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "test.sub.rrset-test.non-97.net"
          }
        ]
      }
    }
  ]
}
EOM
)

$ aws route53 change-resource-record-sets \
    --hosted-zone-id "$hosted_zone_id" \
    --change-batch "$change_resource_record_sets_input"
{
    "ChangeInfo": {
        "Id": "/change/C014001034MVS6DL0GB1Y",
        "Status": "PENDING",
        "SubmittedAt": "2022-09-22T01:25:09.185000+00:00"
    }
}

こちらは通りましたね。

ちなみに、Conditonの条件キーが複数ある場合は、ANDで評価されます。

そのため、route53:ChangeResourceRecordSetsNormalizedRecordNamesで指定していない名前のレコードを作成することはできません。

sub.rrset-test.non-97.netのCNAMEレコードを作成しようとすると、以下のように怒られます。

$ change_resource_record_sets_input=$(cat <<EOM
{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "sub.rrset-test.non-97.net",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "test.sub.rrset-test.non-97.net"
          }
        ]
      }
    }
  ]
}
EOM
)

$ aws route53 change-resource-record-sets \
    --hosted-zone-id "$hosted_zone_id" \
    --change-batch "$change_resource_record_sets_input"

An error occurred (AccessDenied) when calling the ChangeResourceRecordSets operation: User: arn:aws:sts::<AWSアカウントID>:assumed-role/route-53-test/<IAMユーザー名> is not authorized to perform: route53:ChangeResourceRecordSets on resource: arn:aws:route53:::hostedzone/Z10299392E0FL5KN3PZOY because no identity-based policy allows the route53:ChangeResourceRecordSets action

route53:ChangeResourceRecordSetsActions

最後にroute53:ChangeResourceRecordSetsActionsについて確認します。

こちらはレコードに対するアクションに制限をかける条件キーです。

複数のアクションを値として指定できます。値は以下のいずれかである必要があります。

  • CREATE
  • UPSERT
  • DELETE

非常に分かりやすいですね。

以下のようにCREATEUPSERTのみ許可したIAMポリシーで動作確認をしてみます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "route53:ChangeResourceRecordSets",
      "Resource": "arn:aws:route53:::hostedzone/Z10299392E0FL5KN3PZOY",
      "Condition": {
        "StringLike": {
          "route53:ChangeResourceRecordSetsNormalizedRecordNames": [
            "rrset-test.non-97.net",
            "\\050wassyoi\\040\\041\\051.rrset-test.non-97.net",
            "*.sub.rrset-test.non-97.net"
          ]
        },
        "ForAllValues:StringEquals": {
          "route53:ChangeResourceRecordSetsRecordTypes": [
            "CNAME",
            "TXT"
          ],
          "route53:ChangeResourceRecordSetsActions": [
            "CREATE",
            "UPSERT"
          ]
        }
      }
    }
  ]
}

まず、CREATEが正常に行えることを確認します。

$ change_resource_record_sets_input=$(cat <<"EOM"
{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "\\050wassyoi\\040\\041\\051.rrset-test.non-97.net",
        "Type": "TXT",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "\"wassyoi\""
          }
        ]
      }
    }
  ]
}
EOM
)

$ aws route53 change-resource-record-sets \
    --hosted-zone-id "$hosted_zone_id" \
    --change-batch "$change_resource_record_sets_input"
{
    "ChangeInfo": {
        "Id": "/change/C0195540B7SCL9BGSA5L",
        "Status": "PENDING",
        "SubmittedAt": "2022-09-22T01:39:44.887000+00:00"
    }
}

できましたね。

作成したレコードを更新(UPSERT)してみます。

$ change_resource_record_sets_input=$(cat <<"EOM"
{
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "\\050wassyoi\\040\\041\\051.rrset-test.non-97.net",
        "Type": "TXT",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "\"wassyoi_wassyoi\""
          }
        ]
      }
    }
  ]
}
EOM
)

$ aws route53 change-resource-record-sets \
    --hosted-zone-id "$hosted_zone_id" \
    --change-batch "$change_resource_record_sets_input"
{
    "ChangeInfo": {
        "Id": "/change/C0759493CM7C297GPG52",
        "Status": "PENDING",
        "SubmittedAt": "2022-09-22T01:41:25.175000+00:00"
    }
}

こちらもできました。

それでは最後にDELETEができないことを確認します。

$ change_resource_record_sets_input=$(cat <<"EOM"
{
  "Changes": [
    {
      "Action": "DELETE",
      "ResourceRecordSet": {
        "Name": "\\050wassyoi\\040\\041\\051.rrset-test.non-97.net",
        "Type": "TXT",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "\"wassyoi_wassyoi\""
          }
        ]
      }
    }
  ]
}
EOM
)

$ aws route53 change-resource-record-sets \
    --hosted-zone-id "$hosted_zone_id" \
    --change-batch "$change_resource_record_sets_input"

An error occurred (AccessDenied) when calling the ChangeResourceRecordSets operation: User: arn:aws:sts::<AWSアカウントID>:assumed-role/route-53-test/<IAMユーザー名> is not authorized to perform: route53:ChangeResourceRecordSets on resource: arn:aws:route53:::hostedzone/Z10299392E0FL5KN3PZOY because no identity-based policy allows the route53:ChangeResourceRecordSets action

意図した通り、DELETEのみ拒否されました。

Route 53のレコードに対して詳細なアクセス制限ができるようになりました

Amazon Route 53 が DNS リソースレコードセットレベルでのアクセス許可をサポートしたアップデートを紹介しました。

今回のアップデートにより、Route 53のレコードに対して詳細なアクセス制限ができるようになりました。

「ゾーンを分けるほどでもないけど、このレコードは触ってほしくない」みたいな場合に役立ちそうです。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!