Cognito 그룹 역할을 사용할 때 특정 역할에 대한 모든 정책 문서를 가져 오는 AWS IAM SDK
AWS Cognito 사용자 풀 그룹을 사용하여 API Gateway API에 대한 권한을 관리하고 있습니다. 문서에 나와 있듯이 이것이 그룹에 유효한 사용이라고 생각합니다.https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-user-groups.html#using-groups-to-control-permission-with-amazon-api-gateway.
불행히도 문서는 기본적으로이 사용 사례에 대해 내가 말할 수있는 한 존재하지 않습니다 (작은 단락을 제외하고). 사용자 지정 API Gateway 작성자 Lambda 함수에서 이것이 어떻게 작동하는지 알아 내려고합니다. 테스트 역할을 생성하여 Cognito의 테스트 그룹에 할당했습니다. 역할에는 단일 정책이 연결되어 있지만 향후 역할에는 여러 정책이 있습니다.
이제 내 사용자 지정 작성자에서 액세스 토큰 등을 이미 확인 중이며 모두 정상적으로 작동합니다. 이제 그룹 / 역할 / 정책을 사용할 때이 세분화 된 액세스 제어를 추가하려고합니다. IAM SDK를 설치했고 어떤 호출을해야하는지 알아보기 위해 노력했습니다. 역할과 모든 정책을 얻는 쉬운 방법은없는 것 같습니다. 내가 생각 해낸 최고는 다음과 같습니다.
public async Task<IEnumerable<string>> GetGroupPermissionsForUserAsync(Models.User user)
{
if (!user.UserAttributes.TryGetValue(UserAttributeName.UserPoolId, out var userPoolId))
{
return null;
}
var groups = await GetUserGroups(user.Username, userPoolId);
var groupRoleArn = groups.FirstOrDefault()?.RoleArn;
var policies = new List<string>();
if (!string.IsNullOrWhiteSpace(groupRoleArn))
{
var roleName = groupRoleArn.Substring(groupRoleArn.IndexOf('/') + 1);
var rolePoliciesResponse = await _iamClient.ListAttachedRolePoliciesAsync(new ListAttachedRolePoliciesRequest { RoleName = roleName });
foreach (var rolePolicy in rolePoliciesResponse.AttachedPolicies)
{
var policyVersionsResponse = await _iamClient.ListPolicyVersionsAsync(new ListPolicyVersionsRequest
{
PolicyArn = rolePolicy.PolicyArn
});
var latestPolicyVerson = policyVersionsResponse.Versions.OrderByDescending(x => x.CreateDate).LastOrDefault();
var policyVersionResponse = await _iamClient.GetPolicyVersionAsync(new GetPolicyVersionRequest
{
PolicyArn = rolePolicy.PolicyArn,
VersionId = latestPolicyVerson.VersionId
});
if (!string.IsNullOrWhiteSpace(policyVersionResponse?.PolicyVersion.Document))
{
policies.Add(HttpUtility.UrlDecode(policyVersionResponse.PolicyVersion.Document));
}
}
}
return policies;
}
private async Task<IEnumerable<GroupType>> GetUserGroups(string username, string userPoolId)
{
string nextToken = null;
var groups = new List<GroupType>();
do
{
var response = await _cognitoClient.AdminListGroupsForUserAsync(new AdminListGroupsForUserRequest
{
Username = username,
UserPoolId = userPoolId
});
groups.AddRange(response.Groups);
nextToken = response.NextToken;
} while (!string.IsNullOrWhiteSpace(nextToken));
return groups.OrderBy(x => x.Precedence);
}
보시다시피 역할에 대한 정책을 얻기 위해 여러 번 전화를 걸어야합니다.
_cognitoClient.AdminListGroupsForUserAsync
Cognito에서 사용자 그룹을 가져옵니다._iamClient.ListAttachedRolePoliciesAsync
역할과 관련된 정책을 가져옵니다._iamClient.ListPolicyVersionsAsync
각 정책의 버전을 가져옵니다._iamClient.GetPolicyVersionAsync
최종적으로 정책 문서가있는 개별 정책 버전을 가져옵니다.
ListPolicyVersionsAsync
문서 속성이있는 응답을 반환하지만 어떤 이유로 항상 null이므로 추가 GetPolicyVersionAsync
호출 이 필요합니다 .
이 모든 것이 지연을 추가 할뿐만 아니라 (API에 대한 모든 호출이이 코드를 통해 실행되는 권한 부 여자 함수의 문제임), 중복 제거가 필요한 개별 정책이 많이 남게됩니다. API Gateway로 돌아 가기 전에
정말 더 쉽고 빠른 방법이 없나요? 더 적은 호출로이 모든 정보를 얻을 수있는 방법이 있습니까? 그리고 규칙이 겹치는 경우 정책을 평탄화하는 방법이 있습니까?
답변
Cognito 및 API Gateway를 사용하여 권한 부여를 설정하는 방법은 매우 다양하기 때문에 API Gateway 메서드를 통해 액세스하려는 AWS 리소스를 모르고는 어떤 것이 가장 적합한 지 말하기가 어렵습니다. 예를 들어 API Gateway 메서드가 데이터베이스 정보에 액세스하는 람다 메서드와 통합되어 있습니까, 아니면 서비스를 직접 호출합니까?
내가 올바르게 이해했다면 특정 요청에 사용할 단일 권한 집합을 만들기 위해 사용자가 속할 수있는 (잠재적으로) 여러 그룹에 대한 권한을 결합하고 싶습니다. 그렇다면 user
역할이 사용자 데이터에 대한 액세스를 허용 할 수 있고 admin
역할이 다른 관리 엔드 포인트에 대한 액세스를 추가로 확장 할 수 있습니까?
API Gateway 메서드가 데이터베이스와 같은 기본 AWS 리소스에 액세스하는 람다 메서드와 통합되는 매우 표준 시나리오가 있다고 가정하면 다음과 같이 사용자 지정 권한 부여자를 사용할 수 있습니다.
사용자 지정 권한 부여자가 요청 된 API 메서드를 실행하는 데 필요한 권한 만 반환하면 작업이 상당히 단순화됩니다.
{
"principalId": "sub-from-ID-token",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": [
"arn:aws:execute-api:eu-west-1:1234567890:qwerty:prod:GET/user/address"
]
}
]
}
}
표준 시나리오에서 성공적으로 승인 된 요청은 API 로직이 포함 된 람다를 실행합니다. 이 지원 람다는 DynamoDB 테이블의 데이터 등 보호 된 리소스에 액세스 할 수있는 모든 권한을 정의 하는 실행 역할 을 갖습니다 . 따라서 지원 람다가 다른 AWS 리소스에 액세스 할 때마다 권한을 업데이트 할 필요가 없습니다. 여러 그룹 역할이 있지만 대신 시스템의 단일 위치에서 이러한 권한을 관리합니다.
이 설정을 사용하면 보호가 필요한 API의 각 영역에 대해 매우 간단한 사용자 지정 권한 부여자를 가질 수 있습니다.
예를 들어 /user/*
엔드 포인트 를 보호하기 위해 권한 부여 자로 전달 된 ID 토큰user
에 해당 cognito:groups
클레임에 그룹이 포함되어 있는지 확인하는 하나의 사용자 지정 권한 부여자가있을 수 있습니다 . 그렇다면 요청 된 api 메서드 ( execute-api:Invoke
) 를 실행하는 데 필요한 권한을 반환합니다 . 그런 다음 그룹이 ID 토큰의 클레임 등에 /admin/*
있는지 확인 하여 경로 를 보호하는 다른 사용자 지정 권한 부여 자를 가질 수 있습니다 .admin
cognito:groups
사용자 지정 권한 부 여자 응답 캐싱
각 사용자 지정 권한 부 여자에는 응답 (특정 JWT 토큰에 대한)이 캐시되는 기간을 결정하는 선택적 TTL 설정이 있습니다. 이렇게하면 람다 예열 시간 또는 권한 부여 자의 추가 콜 아웃에 걸리는 시간을 줄이는 데 도움이됩니다.
권한 부여자가 여러 메서드를 앞선 경우, 예 :
- / user / address 가져 오기
- POST / 사용자 / 주소
- / 사용자 / 모바일 가져 오기
그런 다음 성공적으로 승인 된 응답은 캐싱 시간이 초과 될 때까지 이러한 모든 메서드에 대해 캐시된다는 점에 유의해야합니다. 따라서 사용자 지정 권한 부여자가 반환 한 정책은 사용자가 실행할 수있는 모든 메서드를 정의하는 리소스 목록을 반환하거나 와일드 카드를 사용해야합니다.
모든 /user/*
경로 를 포함하는 권한 부 여자에 대한 예제 응답
{
"principalId": "sub-from-ID-token",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": [
"arn:aws:execute-api:eu-west-1:1234567890:qwerty:prod:GET/user/address",
"arn:aws:execute-api:eu-west-1:1234567890:qwerty:prod:POST/user/address",
"arn:aws:execute-api:eu-west-1:1234567890:qwerty:prod:GET/user/mobile"
]
}
]
}
}
모든 /user/*
경로 를 포함하는 권한 부 여자에 대한 예제 응답 (와일드 카드 사용)
{
"principalId": "sub-from-ID-token",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": [
"arn:aws:execute-api:eu-west-1:1234567890:qwerty:prod:*/user/*"
]
}
]
}
}