Блог Amazon Web Services

Настраиваем доступ к бакету Amazon S3 только для указанной роли

Зарегистрируйтесь, чтобы получать приглашения на мероприятия AWS на русском языке.

Оригинал статьи: ссылка (Chris Craig, Senior Security Engineer)

Клиенты часто спрашивают, каким образом можно настроить доступ к бакету Amazon S3 так, чтобы ограничить его только одной указанной ролью AWS Identity and Access Management (IAM). Как правило, они делают это аналогично настройке для пользователей IAM: например, создают политику бакета, в которой явным образом запрещают (поле Effect = Deny) доступ для всех пользователей и ролей (поле Principal), у которых не должно быть прав на бакет. Минус такого подхода в том, что политику бакета необходимо постоянно обновлять, потому что если в аккаунте создаётся новый пользователь или роль с разрешёнными действиями s3:*, то они автоматически получают доступ и к указанному бакету. Вместо этого вы можете использовать обратную логику и использовать поле NotPrincipal в инструкции Deny политики бакета. Таким образом вы можете явным образом запретить доступ для всех пользователей, не указанных в значении этого поля.

Однако использование такой логики для ролей IAM может быть несколько затруднительно, потому что в качестве значения Principal роль использует два идентификатора Amazon Resource Name (ARN): ARN самой роли и ARN принятой роли (assumed-role), который используется для идентификации определённой сессии в логах. При использовании NotPrincipal вам необходимо включать в его значение оба ARN, чтобы подход сработал, но при этом второй ARN содержит название сессии, которое может меняться. В обычной ситуации вы бы просто использовали символ подстановки *, но он запрещён в полях Principal и NotPrincipal. В этой статье мы покажем, как вы можете предоставить доступ к бакету S3 только указанной роли IAM с использованием условий (поле Condition) вместо использования поля NotPrincipal. Таким образом, даже если у другого пользователя в том же аккаунте есть права доступа администратора или ему назначена политика s3:*, он не сможет получить доступ без явного указания в политике бакета. Например, вы можете использовать такую конфигурацию для настройки доступа к бакету только для инстансов из указанной группы автоматического масштабирования (Auto Scaling Group). Также её можно использовать для ограничения прав на бакет с высокими требованиями к безопасности.

Обзор решения

Решение, приведённое в этой статье, использует политику бакета для ограничения доступа даже при наличии полных прав на S3 API. Диаграмма ниже показывает, как это работает, если бакет и роль находятся в одном аккаунте.

Диаграмма: доступ к бакету S3 роли IAM в том же аккаунте

  1. Политика доступа для пользователей и роли IAM предоставляет полный доступ s3:*.
  2. Политика бакета S3 ограничивает доступ только одной ролью
  3. И пользователи, и роль имеют доступ к бакетам в аккаунте AWS. При этом роль может работать с двумя бакетами, а пользователи получают доступ только к бакету без назначенной политики. Таким образом, несмотря на то, что и у пользователей, и у роли выданы права доступа s3:*, политика бакета запрещает доступ всем, кто не принял указанную роль.

Основное отличие в случае с несколькими аккаунтами заключается в том, что на первый бакет тоже необходимо назначить политику доступа. Диаграмма ниже показывает, как работает такой сценарий.

Диаграмма: доступ к бакету S3 роли IAM в другом аккаунте

  1. Политика доступа для пользователей и роли IAM предоставляет полный доступ к s3:*.
  2. Политика бакета запрещает доступ всем, чей userId не соответствует идентификатору роли, а также определяет, какие действия с бакетом разрешены этой роли.
  3. Политика бакета разрешает доступ для роли из другого аккаунта.
  4. И пользователь, и роль могут получить доступ к бакету, у которого нет Deny в его политике. Роль также может получить доступ ко второму бакету, так как Deny относится только к сущностям, у которых userId не соответствует идентификатору роли.

Что такое поле NotPrincipal и как его использовать

Вы можете использовать поле NotPrincipal, чтобы заблокировать доступ для всех пользователей, которые не указаны в массиве его значений, даже если их политики IAM такой доступ разрешают. Например, если вам необходимо предоставить пользователю права доступа ко всем бакетам кроме одного, вы можете настроить такое ограничение в самом бакете без изменения IAM-политик пользователя.

Однако для роли IAM всё немного сложнее, так как она стоит из двух идентификаторов: ARN самой роли и ARN принятой роли. ARN роли (arn:aws:iam::ACCOUNTNUMBER:role/ROLE-NAME) является статическим и не зависит от того, кто инициировал сессию, использующую роль (не забудьте заменить шаблоны, которые в этой статье указаны красным цветом, на необходимые значения из своего аккаунта AWS). ARN принятой роли (arn:aws:sts::ACCOUNTNUMBER:assumed-role/ROLE-NAME/ROLE-SESSION-NAME) может изменяться в зависимости от названия сессии. Вы можете заметить это, посмотрев на показанный ниже JSON-документ, соответствующий значению поля Identity из события AWS CloudTrail, которое было создано при API-вызове от пользователя, принявшего на себя роль.

{
  "type": "AssumedRole",
  "principalId": "AROAJI4AVVEXAMPLE:ROLE-SESSION-NAME",
  "arn": "arn:aws:sts::ACCOUNTNUMBER:assumed-role/ROLE-NAME/ROLE-SESSION-NAME",
  "accountId": "ACCOUNTNUMBER",
  "accessKeyId": "ASIAEXAMPLEKEY",
  "sessionContext": {
    "attributes": {
      "mfaAuthenticated": "false",
      "creationDate": "XXXX-XX-XXTXX:XX:XXZ"
    },
    "sessionIssuer": {
      "type": "Role",
      "principalId": "AROAJI4AVV3EXAMPLEID",
      "arn": "arn:aws:iam::ACCOUNTNUMBER:role/ROLE-NAME",
      "accountId": "ACCOUNTNUBMER",
      "userName": "ROLE-SESSION-NAME"
    }
  }
}

В этом документе вы можете увидеть как ARN самой роли, так и ARN принятой роли. Значение ROLE-SESSION-NAME может меняться в зависимости от того, кто принял роль. Значение principalId также включает указанную информацию, но при этом мы можем его использовать вне поля Principal в политике бакета, чем мы и воспользуемся.

Предоставление доступа к бакету для роли в том же аккаунте

При доступе к бакету из того же аккаунта в большинстве случаев нет необходимости создавать политику бакета, потому что она задаёт тот же доступ, что уже назначен пользователю его IAM-политикой. Как правило, политики бакетов S3 используются для доступа из другого аккаунта, но их также можно использовать для явного запрета, который будет применяться ко всем сущностям, как в том же, так и в других аккаунтах.

Сущность IAM (пользователь или роль) указывается в переменной aws:userid. Вам необходимо будет использовать её, чтобы указать пользователя или роль в качестве исключения в условии применения политики.

Значение aws:userId для принятой роли указывается как UNIQUE-ROLE-ID:ROLE-SESSION-NAME (например, AROAEXAMPLEID:userdefinedsessionname).

Чтобы получить AROAEXAMPLEID для роли IAM, выполните следующие действия:

  1. Убедитесь, что у вас установлен AWS CLI, и откройте командную строку или shell.
  2. Запустите следующую команду: aws iam get-role --role-name ROLE-NAME.
  3. В выводе команды найдите значение RoleId, которое начинается со строки AROA. Вы будете использовать его в политике бакета.

В приведённом выше примере события CloudTrail этот идентификатор соответствует первой части значения поля principalId. Это важно, так как в условиях политик IAM переменные можно проверять на соответствие определённой строке: то есть, вместо того чтобы указывать все значения ARN роли и принятой роли в поле NotPrincipal, вы можете использовать поле aws:userId и условие StringNotLike, а также символ шаблона. Кроме того, мы рекомендуем указать в политике root-пользователя аккаунта, чтобы не потерять доступ к бакету, если указанная роль будет удалена. Для root-пользователя значение userId соответствует идентификатору самого аккаунта.

После того как вы получили идентификатор роли, для которой должен быть разрешён доступ, вам необходимо заблокировать доступ к бакету для всех других пользователей (кроме root) из того же аккаунта. Пример такой политики приведён ниже:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::MyExampleBucket",
        "arn:aws:s3:::MyExampleBucket/*"
      ],
      "Condition": {
        "StringNotLike": {
          "aws:userId": [
            "AROAEXAMPLEID:*",
            "111111111111"
          ]
        }
      }
    }
  ]
}

Вы можете использовать эту же политику и для пользователей IAM: в их случае уникальный идентификатор начинается с AIDA. Чтобы получить его значение, выполните следующие действия:

  1. Убедитесь, что у вас установлен AWS CLI, и откройте командную строку или shell.
  1. Запустите следующую команду: aws iam get-user --user-name USER-NAME.
  2. В выводе команды найдите значение UserId, которое начинается со строки AIDA.

После того как вы нашли идентификатор UserId, вы можете добавить его в массив значений условия aws:userId, как показано в следующем примере:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::MyExampleBucket",
        "arn:aws:s3:::MyExampleBucket/*"
      ],
      "Condition": {
        "StringNotLike": {
          "aws:userId": [
            "AROAEXAMPLEID:*",
            "AIDAEXAMPLEID",
            "111111111111"
          ]
        }
      }
    }
  ]
}

Предоставление доступа к бакету для роли из другого аккаунта

В предыдущем разделе мы показали, как настроить доступ к бакету S3 только для определённых ролей и пользователей IAM, созданных в том же аккаунте. Теперь покажем, как настроить такой доступ для роли из другого аккаунта. Для этого вам необходимо указать, какие действия она сможет выполнять. В другой статье в блоге AWS показаны необходимые привилегии для доступа к бакету через CLI / API и через консоль. Используя эту информацию, политика для доступа через CLI / API будет выглядеть следующим образом:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111111111111:role/ROLENAME"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::MyExampleBucket"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111111111111:role/ROLENAME"
            },
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::MyExampleBucket/*"
        },
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::MyExampleBucket",
                "arn:aws:s3:::MyExampleBucket/*"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:userId": [
                        "AROAEXAMPLEID:*",
                        "111111111111"
                    ]
                }
            }
        }
    ]
}

Привилегии, которые необходимы для доступа через консоль, например при использовании функциональности Switch Roles, показаны в следующей политике:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111111111111:role/ROLENAME"
            },
            "Action": [
                "s3:ListAllMyBuckets",
                "s3:GetBucketLocation"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111111111111:role/ROLENAME"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::MyExampleBucket"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111111111111:role/ROLENAME"
            },
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::MyExampleBucket/*"
        },
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::MyExampleBucket",
                "arn:aws:s3:::MyExampleBucket/*"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:userId": [
                        "AROAEXAMPLEID:*",
                        "111111111111"
                    ]
                }
            }
        }
    ]
}

Чтобы предоставить доступ к API / CLI пользователю IAM из другого аккаунта, вам необходимо добавить AIDAEXAMPLEID этого пользователя в значение условия aws:userId, как мы делали в предыдущем разделе. Кроме того, вам необходимо указать полный ARN пользователя в значении поля Principal для разрешающих политик. Имейте в виду, что вы не можете предоставить пользователям из других аккаунтов доступ через консоль, так как им в любом случае потребуется принять роль в текущем аккаунте, но вы можете предоставить доступ через API / CLI следующим образом:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": [
                {
                    "AWS": [
                        "arn:aws:iam::222222222222:role/ROLENAME",
                        "arn:aws:iam::222222222222:user/USERNAME"
                    ]
                }
            ],
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::MyExampleBucket"
        },
        {
            "Effect": "Allow",
            "Principal": [
                {
                    "AWS": [
                        "arn:aws:iam::222222222222:role/ROLENAME",
                        "arn:aws:iam::222222222222:user/USERNAME"
                    ]
                }
            ],
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::MyExampleBucket/*"
        },
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::MyExampleBucket",
                "arn:aws:s3:::MyExampleBucket/*"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:userId": [
                        "AROAEXAMPLEID:*",
                        "AIDAEXAMPLEID",
                        "111111111111"
                    ]
                }
            }
        }
    ]
}

Кроме включения роли в политику бакета, вам также нужно добавить необходимые привилегии в политику самой роли или пользователя IAM. Для этого вы можете создать customer managed policy со следующим содержанием и назначить её на необходимую роль или пользователя через консоль IAM:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListAllMyBuckets",
        "s3:GetBucketLocation"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::MyExampleBucket"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::MyExampleBucket/*"
    }
  ]
}

Используя инструкции из этой статьи, вы можете ограничить доступ к бакету S3, предоставив его только для определённой роли или пользователя IAM, которые созданы в том же или в другом аккаунте AWS. Это ограничение будет работать даже если другие пользователи и роли имеют уровень доступа администратора или политику s3:*. Вы можете использовать такой подход для различных сценариев, например, для предоставления доступа к бакету только инстансам из определённой группы автоматического масштабирования. Также вы можете использовать его для ограничения доступа к бакетам с высокими требованиями к безопасности, например, содержащими данные о сотрудниках или бухгалтерской информации. Мы рекомендуем назначать пользователям и ролям минимально возможные привилегии, необходимые для выполнения их задач.