혼동된 대리자 문제는 작업을 수행할 권한이 없는 엔터티가 권한이 더 많은 엔터티에게 작업을 수행하도록 강요할 수 있는 보안 문제입니다. 이를 방지하기 위해 AWS은(는) 계정의 리소스에 타사(크로스 계정) 또는 기타 AWS 서비스(교차 서비스) 액세스를 제공할 경우 계정을 보호하는 데 도움이 되는 도구를 제공합니다.
이따금 AWS 리소스에 대한 액세스를 타사에 부여해야 할 때가 있습니다(액세스 위임). 예를 들어 Example Corp이라는 서드파티를 고용해 AWS 계정을 모니터링하고 비용을 최적화하려고 합니다. 일일 경비를 추적하기 위해 Example Corp은 AWS 리소스에 접근해야 합니다. Example Corp 역시 다른 고객을 위해 다른 많은 AWS 계정을 모니터링합니다. IAM 역할을 사용하여 AWS 계정과 Example Corp 계정 사이에 신뢰 관계를 설정할 수 있습니다. 이 시나리오에서 한 가지 중요한 부분은 외부 ID입니다. 이 ID는 IAM 역할 신뢰 정책에서 역할을 수임할 수 있는 사람을 지정하는 데 사용할 수 있는 선택적 식별자입니다. 외부 ID의 주된 기능은 혼동된 대리자 문제를 해결하고 방지하는 것입니다.
일부 AWS 서비스(직접 호출하는 서비스)는 AWS 서비스 위탁자를 사용하여 다른 AWS 서비스(직접 호출되는 서비스)의 AWS 리소스에 액세스합니다. 이러한 서비스 상호 작용 중 일부에서 다른 AWS 계정에 있는 직접 호출되는 서비스의 리소스와 통신하도록 직접 호출하는 서비스를 구성할 수 있습니다. 이에 대한 예제로, 다른 AWS 계정에 있는 중앙 Amazon S3 버킷에 쓰도록 AWS CloudTrail을 구성하는 작업이 있습니다. 직접 호출하는 서비스인 CloudTrail에는 cloudtrail.amazonaws.com에 대한 allow 문을 추가하여 s3 버킷의 정책을 사용해 s3 버킷에 대한 액세스 권한이 부여됩니다.
직접 호출하는 서비스의 AWS 서비스 위탁자가 직접 호출되는 서비스의 리소스에 액세스하는 경우 직접 호출되는 서비스의 리소스 정책은 직접 호출하는 서비스를 구성한 액터가 아닌 AWS 서비스 위탁자에게만 권한을 부여합니다. 예를 들어 조건 없이 CloudTrail 서비스 위탁자를 신뢰하는 Amazon S3 버킷은 신뢰할 수 있는 관리자가 구성하는 AWS 계정에서 CloudTrail 로그를 수신할 수 있지만, 권한이 없는 액터가 Amazon S3 버킷의 이름을 알고 있다면 AWS 계정의 해당 액터로부터 CloudTrail 로그도 수신할 수 있습니다.
혼동된 대리자 문제는 액터가 AWS 서비스의 서비스 위탁자 신뢰를 이용해 원래 액세스를 허용하지 않으려던 리소스에 액세스할 때 발생합니다.
크로스 계정 혼동된 대리자 예방
다음 다이어그램은 크로스 계정 혼동된 대리자 문제를 보여줍니다.

이 시나리오에서는 다음과 같이 가정합니다.
-
AWS1은 사용자의 AWS 계정입니다.
-
AWS1:ExampleRole은 계정의 역할입니다. 이 역할의 신뢰 정책은 Example Corp의 AWS 계정의 역할을 위임할 수 있는 것으로 지정함으로써 Example Corp을 신뢰합니다.
다음은 무슨 일이 일어나는지에 대한 것입니다.
-
Example Corp 서비스 사용을 시작할 때 Example Corp에 AWS1:ExampleRole의 ARN을 제공합니다.
-
Example Corp은 그 ARN을 사용해 임시 보안 인증을 얻어 AWS 계정의 리소스에 액세스합니다. 이러한 방식으로 Example Corp을 대신 행위할 수 있는 "대리자"로 신뢰합니다.
-
또 다른 AWS 고객도 Example Corp의 서비스를 사용하기 시작하고, 이 고객 역시 Example Corp가 사용할 AWS1:ExampleRole의 ARN을 제공합니다. 아마도 그 다른 고객은 비밀이 아닌 AWS1:ExampleRole을 알거나 짐작했을 것입니다.
-
다른 고객이 Example Corp에게(자신의 것이라고 주장하는) 계정의 AWS 리소스에 액세스할 수 있는 권한을 요청하면, Example Corp는 AWS1:ExampleRole을 사용해 계정의 리소스에 액세스합니다.
이것이 바로 다른 고객이 리소스에 무단으로 액세스하는 과정입니다. 이 고객은 Example Corp이 자신도 모르게 리소스에 대한 작업을 하도록 속일 수 있었기 때문에 Example Corp은 이제 "혼동된 대리자"가 되었습니다.
Example Corp는 사용자가 역할의 신뢰 정책에 ExternalId
조건 확인을 포함하도록 요구하여 혼동된 대리자 문제를 해결합니다. Example Corp는 각 고객에 대해 고유 ExternalId
값을 생성하며 요청에 해당 값을 사용하여 역할을 수임합니다. ExternalId
값은 Example Corp의 고객 사이에서 고유해야 하며 고객이 아닌 Example Corp에 의해 제어되어야 합니다. 이것이 바로 Example Corp에서 외부 ID를 얻고 그것을 스스로 찾아내지 않는 이유입니다. 이로 인해 Example Corp이 혼동된 대리자가 되는 것을 예방하고 다른 계정의 AWS 리소스에 대한 액세스 권한을 부여하는 것을 방지합니다.
이 시나리오에서 Example Corp의 고유 식별자가 12345이고, 다른 고객에 대해서는 그 식별자가 67890이라고 가정합시다. 이러한 식별자는 이 시나리오를 위해 단순화된 것입니다. 일반적으로 이러한 식별자는 GUID입니다. 이 식별자가 Example Corp의 고객 사이에서 고유한 것이라고 가정할 때, 외부 ID를 위해 사용하기에 합리적인 값들입니다.
Example Corp은 12345라는 외부 ID 값을 부여합니다. 그런 다음 Condition
값이 12345가 되어야 한다고 요구하는 역할의 신뢰 정책에 sts:ExternalId
요소를 다음과 같이 추가해야 합니다.
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Principal": {
"AWS": "Example Corp's AWS Account ID
"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "12345"
}
}
}
}
이 정책의 조건 요소는 AssumeRole API 호출에 12345라는 외부 ID 값이 포함될 때만 Example Corp이 역할을 수임하도록 허용합니다. Example Corp은 고객을 대신해 역할을 위임할 때마다 항상 AssumeRole 호출에 해당 고객의 외부 ID 값을 포함하도록 보장합니다. 다른 고객이 Example Corp에게 ARN을 공급한다 하더라도 Example Corp이 AWS에 대한 요청 시 포함하는 외부 ID를 제어할 수 없습니다. 이는 권한을 부여받지 않은 고객이 리소스에 액세스하지 못하도록 방지하는 데 도움이 됩니다.
다음 다이어그램에서 이 방법을 보여줍니다.

-
전과 같이 Example Corp 서비스 사용을 시작할 때 Example Corp에 AWS1:ExampleRole의 ARN을 제공합니다.
-
Example Corp가 그 ARN을 사용해 AWS1:ExampleRole 역할을 위임하는 경우 Example Corp는 AssumeRole API 호출에 외부 ID(12345)를 포함시킵니다. 외부 ID는 역할의 신뢰 정책과 일치하므로 AssumeRole API 호출은 성공하고 Example Corp는 임시 보안 인증을 획득해 AWS 계정의 리소스에 액세스합니다.
-
또 다른 AWS 고객도 Example Corp의 서비스를 사용하기 시작하고, 전과 같이 이 고객 역시 Example Corp가 사용할 AWS1:ExampleRole의 ARN을 제공합니다.
-
그러나 이번에는 Example Corp가 AWS1:ExampleRole이라는 역할을 위임하려 할 때 다른 고객과 연결된 외부 ID(67890)를 제공하므로 해당 고객은 이를 바꿀 방법이 없습니다. Example Corp이 이렇게 하는 이유는 역할을 사용하겠다는 요청이 다른 고객에게서 왔으므로, 67890은 Example Corp이 작용하고 있는 상황을 나타내기 때문입니다. AWS1:ExampleRole의 신뢰 정책에 자신의 외부 ID(12345)가 있는 조건을 추가했기 때문에 AssumeRole API 호출은 실패하고 다른 고객이 계정 리소스에 무단으로 액세스하는 것을 막을 수 있습니다(다이어그램의 빨간색 "X" 참조).
외부 ID는 다른 고객이 Example Corp을 속여 자신도 모르게 리소스에 액세스하지 못하도록 방지합니다.
교차 서비스 혼동된 대리자 방지
다음 다이어그램은 CloudTrail 및 Amazon S3 상호 작용 예제를 사용하여 교차 서비스 혼동된 대리자 문제를 보여줍니다. 여기에서는 권한이 없는 액터가 액세스 권한이 없는 Amazon S3 버킷에 CloudTrail 로그를 씁니다.

권한이 없는 액터가 AWS 위탁자의 신뢰를 이용해 리소스에 액세스하지 못하도록 하기 위해 AWS 서비스 위탁자는 자신이 대리하는 AWS 리소스, AWS 계정 및 AWS 조직에 대한 정보를 포함합니다.
이 정보는 리소스 정책 또는 AWS 서비스 위탁자가 수행한 요청에 대한 리소스 제어 정책에서 사용할 수 있는 전역 조건 키 값으로 사용 가능합니다. AWS 서비스 위탁자에게 리소스 중 하나에 액세스할 권한이 부여되는 경우 항상 리소스 정책에 aws:SourceArn, aws:SourceAccount, aws:SourceAccount 또는 aws:SourceOrgPaths를 사용하는 것이 좋습니다. 이러한 조건 키를 사용하면 리소스 정책 또는 예상되는 AWS 리소스, AWS 계정 또는 AWS Organizations를 대신하여 리소스에 액세스하는 AWS 서비스 위탁자가 사용하는 리소스 제어 정책을 테스트할 수 있습니다.
-
aws:SourceArn
을 사용하여 AWS 서비스 위탁자가 특정 AWS CloudTrail 추적 또는 AppStream 플릿과 같은 특정 리소스를 대신하여 리소스에 액세스할 수 있도록 허용합니다. -
aws:SourceAccount
를 사용하여 AWS 서비스 위탁자가 특정 AWS 계정를 대신하여 리소스에 액세스할 수 있도록 허용합니다. -
aws:SourceOrgID
를 사용하여 AWS 서비스 위탁자가 특정 AWS Organizations를 대신하여 리소스에 액세스할 수 있도록 허용합니다. -
aws:SourceOrgPaths
를 사용하여 AWS 서비스 위탁자가 특정 AWS Organizations 경로를 대신하여 리소스에 액세스할 수 있도록 허용합니다.
다음 다이어그램에서는 리소스가 aws:SourceAccount
전역 조건 컨텍스트 키로 구성되고 다른 계정의 권한이 없는 액터가 원래 액세스를 허용하지 않으려던 AWS 리소스에 액세스하려고 하는 교차 서비스 혼동된 대리자 시나리오를 보여줍니다.

정책에서 aws:SourceArn
, aws:SourceAccount
, aws:SourceOrgID
및 aws:SourceOrgPaths
전역 조건 키를 사용하면 서비스 위탁자가 사용자를 대신하여 리소스에 액세스할 수 있습니다. 리소스 중 하나에 대한 액세스 권한이 AWS 서비스 위탁자에게 부여될 때마다 이러한 조건 키를 사용하는 것이 좋습니다.
참고
일부 AWS 서비스 상호 작용에는 리소스에 대한 사용자 액세스를 테스트하는 교차 서비스 혼동된 대리자 문제를 방지하는 데 도움이 되는 추가 제어 기능이 있습니다. 예를 들어 KMS 키 부여가 AWS 서비스에 대해 실행되면 AWS KMS에서는 리소스와 연결된 암호화 컨텍스트 및 키 권한 부여를 통해 교차 서비스 혼동된 대리자 문제를 방지할 수 있습니다.
교차 서비스 혼동된 대리자 위험을 방지하는 데 도움이 될 수 있는 서비스별 메커니즘과 aws:SourceArn
, aws:SourceAccount
, aws:SourceOrgID
, aws:SourceOrgPaths
지원 여부에 대한 자세한 내용은 사용하는 서비스의 설명서를 참조하세요.
리소스 기반 정책을 사용하여 교차 서비스 혼동된 대리자 방지
다음 예제 정책에서는 서비스 위탁자 cloudtrail.amazonaws.com
이 AWS 계정 111122223333을 대신하여 작업하는 경우에만 Amazon S3 버킷(arn:aws:s3:::amzn-s3-demo-bucket1)에 대한 액세스 권한을 해당 서비스 위탁자에 부여합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CloudTrailAclCheck",
"Effect": "Allow",
"Principal": {"Service": "cloudtrail.amazonaws.com"},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::amzn-s3-demo-bucket1
",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "111122223333"
}
}
},
{
"Sid": "AWSCloudTrailWrite",
"Effect": "Allow",
"Principal": {"Service": "cloudtrail.amazonaws.com"},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::amzn-s3-demo-bucket1/[optionalPrefix]/Logs/myAccountID/*
",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "111122223333"
}
}
}
]
}
이 버킷 정책 예제에서는 aws:SourceArn
으로 플릿 ARN을 지정하여 지정된 Amazon AppStream 플릿을 대신해 작업하는 경우에만 s3://amzn-s3-demo-bucket2 내에서 powershell 스크립트 examplefile.psh에 대한 액세스 권한을 서비스 위탁자 appstream.amazonaws.com
에 부여합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"appstream.amazonaws.com"
]
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::amzn-s3-demo-bucket2/examplefile.psh
",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:appstream:us-east-1:111122223333
:fleet/ExampleFleetName
"
}
}
}
]
}
리소스 제어 정책을 사용하여 교차 서비스 혼동된 대리자 방지
리소스 제어 정책(RCP)을 사용하여 지원되는 AWS 서비스의 리소스에 교차 서비스 혼동된 대리자 제어 기능을 적용할 수 있습니다. RCP를 사용하면 리소스에서 교차 서비스 혼동된 대리자 제어 기능을 중앙에서 적용할 수 있습니다. 특정 리소스 기반 정책에 명령문을 추가하지 않고도 조직의 AWS Organizations, 조직 단위(OU) 또는 AWS 계정에 연결된 RCP를 사용하여 aws:SourceOrgId
및 aws:SourceOrgPaths
와 같은 조건 키를 사용할 수 있습니다. RCP 및 지원되는 서비스에 대한 자세한 내용은 AWS Organizations 사용 설명서의 리소스 제어 정책(RCP)을 참조하세요.
다음 예제 RCP에서는 aws:SourceOrgID
가 o-ExampleOrg와 같지 않으면 멤버 계정에 있는 Amazon S3 버킷에 대한 AWS 서비스 위탁자의 액세스를 거부합니다. SourceOrgID가 o-ExampleOrg.S인 AWS 서비스 위탁자를 허용하려면 Amazon S3 버킷의 리소스 기반 정책에 해당 허용이 있어야 합니다.
이 정책은 aws:SourceAccount
키가 있는("Null": {"aws:SourceAccount":
"false"}
) 서비스 위탁자("Bool":
{"aws:PrincipalIsAWSService": "true"}
)의 요청에만 제어를 적용하므로 조건 키를 사용할 필요가 없는 서비스 통합 및 위탁자의 직접 호출에는 영향을 미치지 않습니다. 요청 컨텍스트에 aws:SourceAccount
조건 키가 있는 경우 Null 조건은 true로 평가되어 aws:SourceOrgID
에 적용됩니다. 요청이 조직에 속하지 않은 계정에서 시작된 경우에도 제어가 여전히 적용되도록 Null 조건 연산자에서 aws:SourceOrgID
대신 aws:SourceAccount
를 사용할 수 있습니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RCPEnforceConfusedDeputyProtectionForS3",
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:*"
],
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"aws:SourceOrgID": "o-ExampleOrg
"
},
"Null": {
"aws:SourceAccount": "false"
},
"Bool": {
"aws:PrincipalIsAWSService": "true"
}
}
}
]
}