AWS AWS 05-1 누가 무엇을 할 수 있나 — IAM·IAM Identity Center·Cognito·Verified Permissions
AWS · 11/17

AWS 05-1 누가 무엇을 할 수 있나 — IAM·IAM Identity Center·Cognito·Verified Permissions

gabury1고친 사람 github-actions[bot]

EC2 에 처음 배포할 때 흔히 이렇게 합니다. IAM 에서 사용자를 하나 만들고, 액세스 키를 발급받아 서버의 .env 에 넣고, 같은 키를 CI 설정에도 붙여 넣습니다. 돌아가기는 합니다. 그런데 AWS 는 이 방법을 권하지 않습니다. 사람은 단일 로그인(한 번 로그인으로 여러 계정에 들어가는 방식)으로 들어오고, 프로그램은 역할을 맡아 몇 시간짜리 임시 자격 증명만 받으라고 합니다.

AWS 에는 「누가 무엇을 할 수 있나」를 다루는 서비스가 넷 있는데, 넷을 가르는 질문은 하나입니다. 누구의 권한인가. AWS 자원을 만지는 프로그램과 사람의 권한은 IAM 과 IAM Identity Center 가, 내 앱에 가입한 사용자의 로그인은 Cognito 가, 그 사용자가 앱 안에서 무엇을 해도 되는지는 Verified Permissions 가 맡습니다.

지도

flowchart TD
    Q{"권한을 받는 쪽이 누구인가"}
    Q -- "AWS 자원을 부르는 프로그램" --> IAM["IAM 역할<br/>임시 자격 증명"]
    Q -- "콘솔·CLI 로 들어오는 직원" --> IDC["IAM Identity Center<br/>여러 계정 단일 로그인"]
    Q -- "내 앱에 가입한 사용자" --> COG["Cognito<br/>가입·로그인·토큰"]
    COG --> Q2{"앱 안의 권한 규칙이<br/>코드에 흩어져 있나"}
    Q2 -- "그렇다" --> AVP["Verified Permissions<br/>Cedar 정책으로 판단"]

IAM·Identity Center·Cognito 는 인증(authentication, 이 요청을 보낸 게 누구인지 확인하는 일)부터 맡고, Verified Permissions 는 인증이 끝난 뒤의 인가(authorization, 그 사람이 이 일을 해도 되는지 판단하는 일)만 맡습니다. IAM 과 Identity Center 가 지키는 대상은 S3 버킷·DynamoDB 테이블 같은 AWS 자원이고, Cognito 와 Verified Permissions 가 지키는 대상은 내 앱의 기능과 데이터입니다. 그림의 Cedar 는 앱의 권한 규칙을 코드 밖에 적는 정책 언어로, 4절에서 봅니다.

1. IAM — 모든 AWS API 호출이 거치는 권한 검사

AWS 의 API 호출은 콘솔 클릭이든 SDK 호출이든 전부 IAM 을 거칩니다. 요청을 보내는 쪽을 주체(principal)라 하고, IAM 에서 주체가 되는 것은 IAM 사용자와 역할입니다. IAM 은 주체를 확인한 뒤 거기 붙은 정책(policy)을 읽어 허용할지 정합니다. 정책은 「어떤 동작(s3:GetObject)을 어떤 자원(arn:aws:s3:::my-bucket/*)에 대해 허용 또는 거부한다」를 적은 JSON 문서입니다.

두 주체는 자격 증명을 들고 있는 방식이 다릅니다. IAM 사용자는 비밀번호나 액세스 키(프로그램이 AWS 를 부를 때 쓰는 키 ID 와 비밀 키 한 쌍)를 오래 들고 있습니다. 역할은 비밀번호도 액세스 키도 없고, 누군가 역할을 맡으면(assume) AWS STS(Security Token Service, 임시 자격 증명을 발급하는 서비스)가 만료 시각이 박힌 임시 자격 증명을 내줍니다. 역할을 맡은 세션은 역할 설정에 따라 최대 12시간까지 갑니다(IAM roles). 그룹(group)은 주체가 아니라 사용자 여럿을 묶어 정책을 한 번에 붙이는 단위입니다.

왜 역할이 기본인가

액세스 키는 누가 지우기 전까지 유효합니다. .env 가 깃 저장소에 한 번 올라가거나 CI 로그에 한 번 찍히면, 그 키는 발견될 때까지 계속 쓰입니다. 임시 자격 증명은 새어 나가도 몇 시간 뒤면 스스로 죽습니다. 그래서 AWS 는 사람에게는 ID 공급자(IdP, identity provider, 직원 계정과 로그인을 맡는 시스템)를 거친 임시 자격 증명을, 프로그램에게는 IAM 역할의 임시 자격 증명을 쓰라고 권합니다(Security best practices in IAM). IAM 사용자는 역할을 못 쓰는 외부 도구나, IdP 가 멈췄을 때 쓰는 비상 접근용처럼 예외적인 경우에만 만듭니다(IAM roles).

역할에 붙는 두 정책

역할에는 정책이 두 개 붙습니다. 신뢰 정책(trust policy)은 누가 이 역할을 맡을 수 있나를 적고, 권한 정책(permissions policy)은 역할을 맡은 주체가 무엇을 할 수 있나를 적습니다. 문으로 치면 신뢰 정책은 누구에게 열쇠를 주느냐이고, 권한 정책은 그 열쇠로 어느 방까지 들어가느냐입니다. 둘 중 하나만 맞으면 아무 일도 안 됩니다.

정책 평가 — 명시적 거부가 이긴다

요청 하나에 정책이 여러 개 걸리면 IAM 은 흔히 이 순서로 판단합니다.

flowchart TD
    R["요청 도착"] --> D{"걸린 정책 가운데<br/>Deny 가 맞는 것이 있나"}
    D -- "있다" --> N1["거부<br/>명시적 거부"]
    D -- "없다" --> B{"상한 정책이 있으면<br/>그 안에 드나"}
    B -- "벗어난다" --> N3["거부<br/>상한 밖"]
    B -- "든다" --> A{"Allow 가 맞는 것이 있나"}
    A -- "있다" --> Y["허용"]
    A -- "없다" --> N2["거부<br/>기본값"]

아무것도 허용하지 않았으면 기본은 거부이고, 어디서든 "Effect": "Deny" 가 맞으면 다른 정책의 허용과 상관없이 거부입니다. 같은 계정 안에서는 주체에 붙은 정책과 S3 버킷 정책 같은 자원 기반 정책(자원 쪽에 붙어 「누가 나를 쓸 수 있나」를 적는 정책) 가운데 하나만 허용해도 통과합니다(Policy evaluation logic). 그림의 상한 정책은 권한 경계(permissions boundary, 한 역할이 받을 수 있는 권한의 상한)와, 여러 계정을 묶은 조직이 계정 전체에 거는 SCP(서비스 제어 정책, 10편)입니다. 상한은 대개 허용 여부와 따로 한 번 더 걸립니다. 다만 같은 계정의 자원 기반 정책이 역할 세션을 직접 지목해 허용하면 권한 경계에 묶이지 않는 예외가 있습니다(Permissions boundaries for IAM entities). 「권한을 줬는데 왜 안 되지」는 대개 상한 정책이나 어딘가의 명시적 거부에서 답이 나옵니다.

EC2·Lambda 에 역할을 붙인다

AWS 안에서 도는 코드는 키를 들고 있을 필요가 없습니다. EC2 는 인스턴스 프로파일(instance profile, 역할 하나를 담아 인스턴스에 넘기는 IAM 객체)로 역할을 받습니다. 인스턴스 안의 코드가 인스턴스 메타데이터 서비스(IMDS, 인스턴스가 자기 정보를 조회하는 내부 주소)에서 임시 자격 증명을 꺼내 쓰고, AWS SDK 와 CLI 는 이 과정을 알아서 합니다. 자격 증명은 만료 최소 5분 전에 새것으로 바뀝니다(Retrieve security credentials from instance metadata). Lambda 는 함수마다 실행 역할(execution role)을 붙이고, 이 역할의 신뢰 정책에는 Lambda 서비스(lambda.amazonaws.com)가 들어갑니다. 콘솔로 함수를 만들면 CloudWatch Logs 에 로그를 쓰는 최소 권한만 가진 역할이 같이 생깁니다(Defining Lambda function permissions with an execution role).

밖에서 역할을 맡는다 — GitHub Actions 와 OIDC

AWS 밖의 GitHub Actions 가 배포하려면 예전에는 액세스 키를 저장소 시크릿에 넣었습니다. 지금은 OIDC(OpenID Connect, 로그인한 주체가 누구인지 서명된 토큰으로 증명하는 표준)로 키 없이 역할을 맡습니다. 먼저 IAM 에 GitHub 을 ID 공급자(token.actions.githubusercontent.com)로 등록합니다. 워크플로가 실행되면 GitHub 이 「이 실행은 어느 저장소 어느 브랜치에서 왔다」는 토큰을 발급합니다. STS 는 그 토큰을 확인하고 역할의 임시 자격 증명을 내줍니다. 누가 역할을 맡을 수 있는지는 신뢰 정책의 조건이 정합니다.

JSON
"Condition": {
  "StringEquals": {
    "token.actions.githubusercontent.com:aud":
      "sts.amazonaws.com",
    "token.actions.githubusercontent.com:sub":
      "repo:my-org/my-repo:ref:refs/heads/main"
  }
}
  • aud — 토큰을 받을 대상입니다. AWS STS 로 고정합니다
  • sub — 토큰을 요청한 저장소와 브랜치입니다. 이 예에서는 main 브랜치에서 온 실행만 역할을 맡습니다

sub 을 좁히지 않으면 남의 GitHub 저장소에서 돈 워크플로도 이 역할을 맡을 수 있습니다. 그래서 IAM 은 GitHub 을 신뢰하는 정책을 만들거나 고칠 때 sub 조건이 있는지, 값이 와일드카드뿐이 아닌지 검사하고 어기면 저장을 거부합니다(Create a role for OpenID Connect federation). GitHub OIDC 로 역할을 맡아 이미지를 ECR 에 올리고 ECS 에 배포하기까지를 끝까지 따라가는 설명은 조합 편 25(배포 파이프라인)에서 합니다.

IAM 역할이 맞는 곳

IAM 자체 요금은 0원입니다(IAM FAQs). 치르는 것은 돈이 아니라 수고입니다. 프로그램마다 역할과 정책을 따로 만들어야 권한이 좁게 유지되고, 앞의 sub 처럼 조건 하나를 잘못 쓰면 남이 역할을 맡습니다.

이럴 때 맞다 이럴 때 안 맞다 대신 치르는 것
EC2·Lambda 에서 도는 코드가 S3·DynamoDB 를 부른다 역할을 맡을 수 없는 외부 도구가 AWS 를 부른다 코드마다 역할과 정책을 따로 만들어야 권한이 좁게 유지된다
GitHub Actions 처럼 OIDC 를 지원하는 CI 가 배포한다 OIDC 를 지원하지 않는 CI 가 배포한다 신뢰 정책의 sub 조건을 저장소·브랜치까지 좁혀 관리한다

표의 안 맞는 두 경우에는 IAM 사용자의 액세스 키를 쓰되, 그 도구에만 주고 주기적으로 바꿉니다. 사람이 콘솔로 들어오는 일은 2절의 Identity Center 로, 고객의 로그인은 3절의 Cognito 로 갑니다.

2. IAM Identity Center — 직원이 여러 계정에 한 번에 들어온다

개발·스테이징·운영을 계정 셋으로 나누고 개발자가 다섯 명이면, IAM 사용자로는 15개를 만들고 비밀번호·MFA·퇴사 처리를 계정마다 따로 해야 합니다. MFA(다중 인증)는 비밀번호에 더해 휴대폰 앱의 코드 같은 두 번째 확인을 받는 방식입니다. IAM Identity Center 는 이 일을 한곳으로 모으는 단일 로그인(SSO, single sign-on) 서비스이고, 추가 요금이 없습니다(IAM Identity Center FAQs). 2022-07-26 에 AWS Single Sign-On 에서 지금 이름으로 바뀌었습니다(What is IAM Identity Center?).

직원은 AWS 액세스 포털(access portal, 내게 배정된 계정과 역할이 나열된 웹 페이지)에 한 번 로그인하고 계정과 역할을 골라 들어갑니다. CLI 는 aws configure sso 로 같은 로그인을 씁니다. 무엇을 할 수 있는지는 권한 세트(permission set)가 정합니다. 권한 세트는 IAM 정책 묶음의 틀이고, 이를 계정에 배정하면 Identity Center 가 그 계정마다 IAM 역할을 만들어 정책을 붙이고 관리합니다. 결국 들어간 직원이 받는 것도 역할의 임시 자격 증명입니다. 한 번 들어간 세션은 기본 1시간, 최대 12시간이고, 포털 로그인은 기본 8시간 유지됩니다. 권한 세트에는 AWS 관리형 정책, 직접 만든 정책, 권한 경계를 담을 수 있습니다. 역할의 신뢰 정책이나 태그까지 직접 정해야 하면 권한 세트로는 안 되고, 이미 만든 IAM 역할을 IAM 의 account access manager 로 직원에게 배정합니다(Manage AWS accounts with permission sets). 사용자 명단은 Identity Center 안에 직접 만들 수도 있고, 회사가 이미 쓰는 IdP 에 붙일 수도 있습니다. 구글 워크스페이스·Microsoft Entra ID·Okta 는 SAML(IdP 가 「이 사람은 로그인했다」는 서명된 확인서를 넘겨주는 표준)로 로그인을 넘기고, SCIM(외부 디렉터리의 사용자·그룹을 자동으로 옮겨 오는 표준)으로 입사·퇴사를 따라옵니다(IAM Identity Center identity source tutorials). 구글 워크스페이스에서 퇴사자를 막으면 AWS 접근도 같이 끊깁니다.

계정이 하나뿐이라면

개발자 다섯이 계정 하나를 쓰는 작은 팀도 흔합니다. 이때도 Identity Center 를 쓰려면 AWS Organizations(여러 계정을 한 조직으로 묶는 서비스, 10편)가 필요합니다. Identity Center 를 켠 단위를 인스턴스라 부르는데(EC2 인스턴스와는 관계없습니다), AWS 계정 접근을 나눠 줄 수 있는 것은 Organizations 관리 계정에서 켠 조직 인스턴스뿐입니다. 계정 하나에 묶인 계정 인스턴스는 AWS 가 관리하는 애플리케이션 로그인만 다루고, AWS 계정 접근은 못 줍니다(Organization and account instances of IAM Identity Center). 그렇다고 계정을 늘릴 필요는 없습니다. 조직에 속하지 않은 계정에서 조직 인스턴스를 켜면, 콘솔이 그 계정을 관리 계정으로 하는 조직을 새로 만듭니다. 조직에 계정이 하나뿐이어도 되고, Organizations 도 추가 요금이 없습니다(AWS Organizations FAQs). 다만 프리 티어 계정이면 조직을 만드는 순간 유료 요금제로 바뀌고 남은 프리 티어 크레딧이 바로 사라집니다(Enable IAM Identity Center).

사람 관리를 한곳에 모으는 대가는 Organizations 를 먼저 세우는 것과, 로그인 경로 하나에 모두가 기대는 것입니다.

이럴 때 맞다 이럴 때 안 맞다 대신 치르는 것
사람이 콘솔·CLI 로 AWS 계정에 들어온다 프로그램이 AWS 를 부른다(→ IAM 역할) 계정이 하나여도 Organizations 조직을 만들어야 한다(0원)
회사 구글 워크스페이스·Entra ID 로 직원 로그인을 통일한다 앱 고객의 로그인(→ Cognito) IdP 가 멈추면 AWS 로그인도 멈추므로 비상용 IAM 사용자를 따로 둔다
직무별 권한을 여러 계정에 같은 모양으로 배정한다 역할마다 신뢰 정책·태그를 따로 정해야 한다 그런 역할은 account access manager 로 따로 배정한다

3. Cognito — 내 앱 사용자의 가입과 로그인

여기서부터는 AWS 계정이 없는 사람, 곧 내 앱에 가입한 고객의 이야기입니다. 로그인을 직접 만들면 비밀번호 해싱, 이메일 인증, 비밀번호 재설정, MFA, 구글 로그인 연동, 토큰 서명과 만료까지 전부 내 코드가 됩니다. Cognito 는 이 묶음을 맡는 서비스입니다.

사용자 풀 — 가입·로그인·토큰

사용자 풀(user pool)은 앱 사용자 명단이자 로그인 서버입니다. 아이디·비밀번호 가입, 구글·페이스북·애플·Login with Amazon 같은 소셜 로그인, 회사 SAML·OIDC IdP 연동을 한 풀에 모아 둡니다(Using social identity providers with a user pool). 로그인 화면은 두 가지로 만듭니다. Cognito 가 띄워 주는 관리형 로그인(managed login) 페이지를 쓰면 색·로고 같은 모양은 바꿀 수 있지만 단계는 Cognito 가 정합니다. SDK 로 화면을 직접 그려도 비밀번호 확인·MFA 같은 인증 단계는 Cognito API 의 흐름을 따르고, 끼어들 수 있는 것은 Lambda 트리거(단계 사이에 내 함수를 부르는 기능)까지입니다(User pool feature plans). 로그인이 끝나면 사용자 풀은 OAuth 2.0·OIDC 표준대로 토큰 셋을 내줍니다. 누가 로그인했는지 담은 ID 토큰, API 호출을 허락받는 데 쓰는 액세스 토큰, 둘이 만료되면 새로 받는 데 쓰는 리프레시 토큰입니다.

토큰 담는 것 쓰는 곳 수명
ID 토큰 이름·이메일 같은 사용자 정보 앱이 「누가 로그인했나」를 알 때 기본 1시간, 5분 ~ 1일
액세스 토큰 사용자 그룹과 스코프(허용된 작업 범위) API 호출을 허락받을 때 기본 1시간, 5분 ~ 1일
리프레시 토큰 암호화되어 앱이 못 읽는 값 만료된 두 토큰을 새로 받을 때 기본 30일, 60분 ~ 10년

ID 토큰과 액세스 토큰은 JWT(서명이 붙은 JSON 토큰)라서 받는 서버가 서명만 확인하면 Cognito 에 다시 묻지 않고 믿을 수 있습니다. 수명은 사용자 풀에 등록한 앱마다 따로 정합니다(CreateUserPoolClient). 관리형 로그인을 쓰면 로그인 쿠키가 1시간 유지되므로, 두 토큰을 1시간보다 짧게 잡아도 그 1시간 동안은 다시 로그인하지 않고 새 토큰을 받습니다(Understanding the access token). API 앞에 세우는 관문 서비스 API Gateway(04-2편)는 액세스 토큰 검증을 설정만으로 해 줍니다.

자격 증명 풀 — 앱 사용자에게 AWS 임시 권한을

모바일 앱이 사진을 서버를 거치지 않고 S3 에 바로 올리게 하려면, 앱 사용자가 AWS 자격 증명을 가져야 합니다. 앱에 액세스 키를 넣으면 누구나 앱을 뜯어 키를 꺼냅니다. 자격 증명 풀(identity pool)은 사용자 풀 토큰이나 소셜 로그인 토큰을 받아 IAM 역할의 임시 자격 증명으로 바꿔 줍니다. 로그인 안 한 게스트에게 좁은 역할을, 로그인한 사용자에게 넓은 역할을 줄 수 있고, 자격 증명 풀 자체에는 요금이 없습니다(Amazon Cognito identity pools). 사용자 풀이 「누구인가」를 답하고, 자격 증명 풀이 그 답을 IAM 의 언어로 옮기는 셈입니다.

요금 — 월간 활성 사용자와 요금 등급

Cognito 는 월간 활성 사용자(MAU, monthly active users)로 받습니다. 한 달 동안 그 사용자에 관한 인증 작업이 한 번이라도 있으면 셉니다. 가입·로그인·로그아웃·비밀번호 재설정은 물론, 관리자가 사용자를 만들거나 속성을 바꾸거나 한 사람의 상세 정보를 조회한 것도 들어갑니다. 그달 한 번도 건드리지 않은 사용자는 세지 않습니다(Quotas in Amazon Cognito). 사용자 풀마다 요금 등급 Lite · Essentials · Plus 가운데 하나를 고르고, 새 풀의 기본값은 Essentials 입니다. Lite 는 가입·로그인·소셜 로그인과 SMS·인증 앱 MFA 까지 담습니다. Essentials 는 여기에 패스키(비밀번호 대신 기기에 저장한 암호 키로 로그인하는 방식), 비밀번호 없는 로그인, 이메일 MFA, 액세스 토큰 사용자 지정을 더합니다. Plus 는 유출된 비밀번호 사용과 낯선 곳에서의 로그인 같은 위협을 잡고 그 기록을 남깁니다(User pool feature plans). 등급마다 사용자 한 명의 값이 이렇게 갈립니다. 요금은 전부 2026-09-24 서울(ap-northeast-2) 기준입니다.

Cognito 사용자 풀 · 서울 · 2026-09-24
직접·소셜 로그인 사용자, MAU 한 명당
  무료        Lite·Essentials 합쳐 월 1만 명
  Lite        무료 뒤 9만 명 $0.0055, 그다음 $0.0046 …
  Essentials  무료 뒤 전부   $0.015
  Plus        무료 없음      $0.020

회사 SAML·OIDC IdP 로 들어온 사용자
  월 50명 무료, 그 뒤 한 명당 $0.015 (등급 무관)
  • 무료 한도는 계정(또는 조직)마다 적용되고, 12개월 프리 티어와 달리 기한이 없습니다
  • 가입 확인·MFA 용 SMS 와 이메일 발송비는 따로 냅니다(SMS 는 SNS, 이메일은 SES 요금)
  • 사용자 없이 서버끼리 호출하는 데 쓰는 토큰(M2M)은 요청 건마다 따로 받습니다. 처음 25만 건은 건당 $0.00225 입니다(Amazon Cognito Pricing)

1만 명과 10만 명 — Cognito 와 직접 운영하는 인증 서버

그럼 MAU 가 늘면 얼마나 나오고, 직접 만든 인증 서버와 비교하면 어떨까요. 직접 운영하는 구성은 t4g.small(AWS 가 설계한 Arm 프로세서 Graviton 을 쓰는 vCPU 2 · 2 GiB 인스턴스) 두 대를 ALB(Application Load Balancer, 요청을 여러 서버에 나눠 주는 부하 분산기) 뒤에 두고, 사용자 명단은 가장 작은 RDS PostgreSQL 에 두는 최소 구성으로 잡았습니다.

Cognito · 서울 · 한 달
  MAU 1만     Lite $0       Essentials $0       Plus $200
  MAU 10만    Lite $495     Essentials $1,350   Plus $2,000
    Lite        (10만 − 1만) × $0.0055 = $495
    Essentials  (10만 − 1만) × $0.015  = $1,350
    Plus         10만        × $0.020  = $2,000

직접 운영 · 서울 · 한 달(730시간)
  t4g.small 두 대      2 × $0.0208 × 730 = $30.37
  ALB 시간 요금            $0.0225 × 730 = $16.43
  ALB 처리량(LCU 평균 1)   $0.008  × 730 =  $5.84
  RDS db.t4g.micro         $0.025  × 730 = $18.25
    PostgreSQL 단일 AZ
  RDS gp3 20 GB            $0.131  × 20  =  $2.62
  합계                                   = $73.50
  • 합계는 반올림 전 값으로 더했습니다
  • LCU(Load Balancer Capacity Unit)는 ALB 가 처리한 연결·트래픽 양에 매기는 단위입니다. 평균 1개로 잡았습니다
  • RDS 저장소는 gp3 최소 크기인 20 GB 입니다(Amazon RDS DB instance storage). 백업·메일·SMS 발송비는 두 구성 모두 뺐습니다

1만 명까지는 Lite·Essentials 모두 0원이라 직접 만들 이유가 없습니다. 10만 명이면 Essentials 월 $1,350 은 직접 운영하는 서버 값 $73.50 의 약 18배이고, Lite 로 내리면 $495 로 약 6.7배입니다. 판단 기준은 그 차액과, 비밀번호 저장·패스키·토큰 서명 키 교체·유출 비밀번호 대응을 직접 짜고 지키는 개발자의 한 달 시간을 견주는 것입니다. 시간 값이 더 크면 Cognito 에 남고, 차액이 더 크면 직접 운영을 봅니다. 한 가지 더 걸리는 것은 명단을 옮겨 나가기가 쉽지 않다는 점입니다. Cognito 는 비밀번호를 사용자마다 다른 솔트를 섞은 해시로만 저장해서 꺼낼 수 없고, 다른 곳으로 옮기면 사용자가 비밀번호를 다시 정해야 합니다(Guidance for User Profiles Export with Amazon Cognito). 사용자 관리를 통째로 맡기는 대신 요금은 사용자 수를 따라 오르고, 인증 단계와 명단이 Cognito 에 묶입니다.

이럴 때 맞다 이럴 때 안 맞다 대신 치르는 것
웹·모바일 앱에 가입·로그인·소셜 로그인이 필요하다 로그인 단계 자체를 Cognito 에 없는 방식으로 짜야 한다 화면은 바꿔도 인증 단계는 Cognito API 흐름과 Lambda 트리거 안에서만 바꾼다
MAU 1만 명 이하에서 시작한다 MAU 가 커서 요금이 개발자 시간보다 비싸졌다 MAU 에 비례해 요금이 오른다
앱 사용자에게 S3 같은 AWS 자원을 직접 열어 준다(자격 증명 풀) 모든 파일 접근을 내 서버가 검사하고 넘겨야 한다 게스트·로그인 사용자 역할의 정책을 IAM 으로 좁게 관리한다

MAU 가 커서 요금이 부담이면 Keycloak 같은 오픈소스 인증 서버를 직접 운영하는 길로 갑니다. 로그인은 Cognito 에 맡겼는데 「이 문서를 이 사람이 고쳐도 되나」 같은 판단이 코드 곳곳에 흩어진다면 다음 절로 갑니다.

4. Verified Permissions — 앱 안의 권한 판단을 밖으로 뺀다

로그인은 「누구인가」까지만 답합니다. 문서 공유 앱이라면 그다음 질문이 줄을 섭니다. 이 사용자가 이 문서를 볼 수 있나, 고칠 수 있나, 지울 수 있나. 보통은 코드 안의 if 문이 답합니다. 「주인이거나 관리자면 고칠 수 있다」는 규칙이면 이렇습니다.

Java
if (!doc.getOwnerId().equals(user.getId())
        && !user.isAdmin()) {
    throw new ForbiddenException();
}

처음엔 괜찮은데, 규칙이 늘면 이런 if 가 컨트롤러·서비스·배치 곳곳에 복사됩니다. 「퇴사 예정자는 공유 금지」 하나를 더하려면 그 복사본을 다 찾아야 하고, 지금 누가 무엇을 할 수 있는지는 코드를 다 읽어야 압니다.

Verified Permissions 는 이 판단을 Cedar 라는 정책 언어로 써서 서비스에 맡기게 합니다. Cedar 는 권한 정책을 쓰고 판단하는 오픈소스 언어이고, 정책은 정책 저장소(policy store, 앱 하나의 정책과 스키마를 담는 단위)에 둡니다. 앱은 요청마다 「이 주체가 이 동작을 이 자원에 해도 되나」를 API(IsAuthorized)로 묻고, Allow 나 Deny 를 받아 따릅니다(What is Amazon Verified Permissions?). 위의 if 문과 같은 규칙을 Cedar 로 쓰면 정책 둘이 됩니다.

permit (
  principal,
  action == Action::"EditDocument",
  resource
)
when { resource.owner == principal };

permit (
  principal in Group::"admins",
  action == Action::"EditDocument",
  resource
);

판단 규칙은 IAM 과 닮았습니다. 맞는 permit 이 없으면 기본은 거부이고, 맞는 forbid 가 하나라도 있으면 permit 을 이깁니다(Amazon Verified Permissions and Cedar policy language terms and concepts). 「퇴사 예정자는 공유 금지」는 코드를 안 고치고 forbid 정책 하나로 더합니다. 그룹으로 권한을 주는 역할 기반 접근 제어와, 문서 주인·부서 같은 속성으로 따지는 속성 기반 접근 제어를 한 정책에 섞을 수 있고, 정책 저장소를 만들 때 Cognito 사용자 풀을 사용자 출처로 바로 연결할 수 있습니다. 요금은 판단을 몇 번 물었느냐로 받습니다. 판단을 하나씩 묻는 단건 호출과, 한 주체나 한 자원에 대한 판단을 30건까지 한 번에 묻는 묶음 호출(BatchIsAuthorized)이 값이 다릅니다(BatchIsAuthorized).

Verified Permissions · 서울 · 2026-09-24
  단건 판단(IsAuthorized)   100만 건당 $5
  묶음 판단 호출 100만 번당
    첫 4,000만 번 $150 · 다음 6,000만 번 $75
    그 뒤 $40
  정책 만들기·고치기·조회   100만 건당 $40

  API 요청 월 1,000만 건에 한 번씩 판단
    1,000만 × $0.000005 = $50

무료 한도와 최소 요금은 없습니다(Amazon Verified Permissions pricing). 묶음 호출이 비싸 보이는 것은 호출 하나에 판단이 30건까지 들어가기 때문입니다. 꽉 채우면 $150 ÷ 30 = 판단 한 건 $5 로 단건과 같습니다. 호출 수는 줄어도 판단 한 건 값은 그대로라서, 문서 목록 300건에 권한을 하나씩 매기면 목록을 한 번 보여 줄 때마다 판단 300건 값이 나갑니다. 규칙이 한곳에 모이는 대신 요청마다 네트워크 호출이 하나 늘고, 판단 건수만큼 돈이 나갑니다.

이럴 때 맞다 이럴 때 안 맞다 대신 치르는 것
역할·소유자·공유 범위가 얽힌 규칙이 여러 서비스에 흩어져 있다 「로그인했나」와 관리자 여부 정도만 따진다 요청마다 판단 호출 한 번의 지연이 붙는다
문서 한 건을 열거나 고칠 때 권한을 묻는다 목록 수천 건을 한 번에 권한으로 걸러야 한다 판단 건수에 비례해 요금이 나간다
고객사마다 규칙이 달라 정책 저장소를 고객사별로 나눈다 모든 고객사가 같은 규칙을 쓰고 거의 바뀌지 않는다 Cedar 와 스키마를 새로 익혀야 한다

규칙이 단순하면 코드 안의 검사나 액세스 토큰의 그룹 클레임으로 충분합니다. 판단 호출이 부담이면 오픈소스 Cedar 라이브러리를 앱 안에 넣어 같은 정책을 네트워크 없이 평가하는 길도 있습니다.

요청 하나가 거치는 권한 판단

한 요청 안에서는 Cognito·Verified Permissions·IAM 세 서비스가 차례로 만납니다. 문서 앱 사용자가 「저장」을 누른 순간을 따라가면 이렇습니다.

flowchart TD
    U["사용자가 로그인"] --> C["Cognito 사용자 풀<br/>ID·액세스 토큰 발급"]
    C --> G["API Gateway<br/>액세스 토큰 서명·만료 확인"]
    G --> L["Lambda 함수"]
    L --> V{"Verified Permissions<br/>이 문서를 고쳐도 되나"}
    V -- "Deny" --> X["403 반환"]
    V -- "Allow" --> R["실행 역할의 임시 자격 증명으로<br/>DynamoDB 호출"]
    R --> I{"IAM 정책 평가"}
    I -- "허용" --> OK["저장 완료"]

Cognito 와 Verified Permissions 가 따지는 것은 앱 사용자의 권한이고, 마지막 IAM 평가가 따지는 것은 Lambda 라는 프로그램의 권한입니다. 사용자가 누구든 DynamoDB 를 부르는 주체는 Lambda 의 실행 역할입니다. Identity Center 는 이 요청 흐름에 끼지 않고, 이 코드를 배포하고 운영하는 개발자가 콘솔에 들어올 때 거칩니다.

이럴 땐 무엇

지도가 「누구의 권한인가」로 네 서비스를 갈랐다면, 이 표는 실제로 자주 만나는 상황에서 거꾸로 찾는 용도입니다.

상황 서비스 이유
EC2·Lambda·컨테이너가 S3·DynamoDB 를 부른다 IAM 역할 키 없이 임시 자격 증명, 자동 교체
GitHub Actions 에서 배포한다 IAM OIDC 공급자 + 역할 저장소 시크릿에 키를 안 둔다. sub 조건 필수
개발자 여럿이 계정 여럿에 들어온다 IAM Identity Center 한 번 로그인, 권한 세트, 추가 요금 없음
개발자 다섯이 계정 하나를 쓴다 Identity Center 조직 인스턴스 계정 하나로 조직을 만들면 된다. Organizations 도 0원
회사 구글 계정으로 AWS 에 로그인 Identity Center + 구글 워크스페이스(SAML·SCIM) 퇴사하면 AWS 접근도 같이 끊긴다
앱에 가입·로그인·소셜 로그인 Cognito 사용자 풀 직접·소셜 로그인 MAU 1만 명까지 0원
앱 사용자가 S3 에 직접 올린다 Cognito 자격 증명 풀 토큰을 IAM 임시 자격 증명으로 바꾼다
문서·프로젝트 단위 권한 규칙이 코드에 흩어졌다 Verified Permissions Cedar 정책 한곳, forbid 가 이긴다

자주 붙는 서비스는 STS(임시 자격 증명), Organizations(여러 계정 묶기, 10편), CloudTrail(누가 어떤 API 를 불렀나 기록, 06편), API Gateway(토큰 검증), Secrets Manager 와 KMS(비밀값 보관과 암호화 키 관리, 05-2편)입니다. 여러 서비스를 엮어 끝까지 따라가는 설명은 조합 편(이 시리즈 20번대)에서 합니다.

한 장 요약

「누가 무엇을 할 수 있나」는 누구의 권한이냐로 갈립니다. AWS 자원을 부르는 프로그램은 IAM 역할의 임시 자격 증명으로, 직원은 Identity Center 의 단일 로그인으로 들어오고, 둘 다 추가 요금이 없습니다. 앱 사용자의 가입·로그인은 Cognito 가 맡으며 서울에서 MAU 1만 명까지 0원, 10만 명이면 Essentials 월 $1,350 입니다. 앱 안의 세밀한 권한 규칙은 Verified Permissions 에 Cedar 로 모으고 판단 100만 건당 $5 를 냅니다.

관련 항목

누가 무엇을 할 수 있나를 나눠 맡는 서비스

AWS IAM · IAM Identity Center · Amazon Cognito · Amazon Verified Permissions · AWS STS

IAM 을 이루는 신원과 정책

IAM 역할 · IAM 사용자 · IAM 정책 · 신뢰 정책 · 자원 기반 정책 · 권한 경계 · 서비스 제어 정책 · 임시 자격 증명 · 액세스 키 · 인스턴스 프로파일 · 인스턴스 메타데이터 서비스 · Lambda 실행 역할

외부 신원을 AWS 로 들이는 표준

OpenID Connect · OAuth 2.0 · SAML · SCIM · ID 공급자 · 단일 로그인 · GitHub Actions

Cognito 가 주고받는 토큰과 단위

JWT · ID 토큰 · 액세스 토큰 · 리프레시 토큰 · 스코프 · 사용자 풀 · 자격 증명 풀 · 월간 활성 사용자 · 패스키 · 다중 인증 · Keycloak

앱 안의 권한 판단을 짜는 방식

인증과 인가 · Cedar · 정책 저장소 · 역할 기반 접근 제어 · 속성 기반 접근 제어 · 최소 권한 · 정책 결정 지점

권한 판단과 같이 쓰는 서비스

AWS Organizations · AWS CloudTrail · API Gateway · AWS Lambda · Amazon S3 · Amazon DynamoDB · Amazon RDS · 감사 로그