
Vertex AI API 및 서비스 계정 인증: 최소 IAM 권한을 확인하는 방법
요약
Vertex AI 사용 시 서비스 계정에 과도한 권한이 부여되지 않도록 최소 권한 원칙(Least Privilege)을 적용하는 방법을 다룹니다. 단순히 성공적인 API 호출을 확인하는 것을 넘어, 불필요한 권한이 없는지 검증하는 엔지니어링 방법론을 제시합니다.
핵심 포인트
- 성공적인 API 호출은 권한의 충분성만 증명할 뿐, 최소성을 보장하지 않음
- 과도한 권한은 보안 사고 발생 시에만 드러나므로 배포 전 검증이 필수적임
- Google Cloud 권장 사항에 따라 사전 정의된 역할 또는 맞춤형 역할을 최소 범위로 적용해야 함
- 허용된 호출과 의도적으로 금지된 호출을 쌍으로 구성하여 권한 상한선을 테스트할 것
올바른 역할(Role)이란 요청을 허용하는 역할이 아니라, 불필요한 요청을 허용하지 않는 역할입니다. 만약 서비스 계정(Service Account)을 설정하고, 모델을 호출하여 200 응답을 받은 뒤 인증 작업을 종료했다면, 당신은 단 한 가지만 확인한 것입니다: 해당 계정이 해야 할 일을 할 수 있다는 사실 말입니다. 당신은 가장 중요한 것, 즉 해당 계정이 하지 말아야 할 일을 할 수 없는지를 확인하지 않았습니다.
이것은 두 가지 서로 다른 진술이며, 보안(Security) 관점에서는 동일하지 않습니다. 성공적인 호출은 필요한 권한이 있음을 확인해 줍니다. 하지만 불필요한 권한이 없는지에 대해서는 아무것도 말해주지 않습니다. roles/aiplatform.admin 역할을 가진 계정 역시 당신의 예측(Predict) 요청을 통과할 것이며, 동시에 엔드포인트(Endpoint)를 삭제하거나, Vertex 리소스의 IAM 정책을 읽고 다시 쓸 수 있으며, 배치 작업(Batch Job)을 실행할 수도 있습니다. "요청이 통과되었다"는 관점에서 보면 두 구성 모두 똑같이 정상(Green)으로 보입니다.
이 차이를 관찰 가능하게 만드는 프로토콜을 살펴보겠습니다: 하나는 허용된 호출이고, 다른 하나는 의도적으로 금지된 학습용 호출인 한 쌍을 구성하며, 각 호출에는 사전에 기록된 예상 상태(Expected Status)를 부여합니다. 이는 Google의 문서화된 절차는 아닙니다. 이는 엔지니어링 방법론이며, 이후 본문에서 문서화된 내용이 끝나고 저의 재구성(Reconstruction)이 시작되는 지점을 명확히 표시하겠습니다.
성공적인 호출이 실제로 증명하는 것은 무엇인가?
이 글이 반박하고자 하는 기본 전제는 다음과 같습니다: "성공적인 인증은 IAM 권한이 올바르게 설정되었음을 의미한다." 실제로는 성공적인 인증이 호출자에게 필요한 권한을 포함하는 역할 바인딩(Role Binding)이 있다는 것을 의미할 뿐입니다. 이는 권한의 상한선을 측정하지 않습니다.
Google Cloud의 공식 보안 권장 사항(docs.cloud.google.com, 2026년 7월 18일 접속)은 작업에 충분한 가장 제한적인 사전 정의된 역할(Predefined Role) 또는 맞춤형 역할(Custom Role)을 부여하고, 가능한 최소한의 리소스 수준에서 이를 적용하며, 서로 다른 권한 세트를 가진 컴포넌트별로 별도의 서비스 계정을 생성할 것을 직접적으로 권고합니다. 이것이 규범적 근거입니다: 단 한 번의 성공적인 호출은 최소 권한 원칙(Least Privilege)의 증거가 될 수 없습니다. 왜냐하면 그것은 최소성이 아니라 충분성을 확인하기 때문입니다.
개발자로서 당신이 거는 판돈은 매우 실질적입니다. 과도한 권한은 배포 후에 발견하기가 더 어렵습니다. 왜냐하면 그것은 작업에 방해가 되지 않고, 테스트 중에 아무것도 망가뜨리지 않으며, 오직 감사(Audit)나 인시던트(Incident)가 발생했을 때만 드러나기 때문입니다. 잘못된 권한 부여 체계는 리뷰 과정에서 발견되어 릴리스를 지연시키거나, 혹은 몇 달 동안 지속되는 조용한 과잉 액세스(Excessive access)를 생성합니다.
만약 요청의 일부가 외부 호환 컨투어(Contour), 예를 들어 provod.ai (OpenRouter의 러시아 대안)로 전송되는 경우를 위한 예외 사항이 있습니다. 그곳의 인증은 키(Key) 기반으로 이루어지며, 귀하의 Google Cloud 프로젝트의 IAM과는 관계가 없습니다. 서비스 계정의 권한 최소성은 이 경로에 대해 대신 확인해주지 않으며 확인해서도 안 됩니다. 두 가지 인증 모델의 차이점에 대해서는 나중에 별도로 다루겠습니다.
어떤 역할(Role)이 Vertex에서 최소한을 제공하고, 어떤 것이 과도한가?
Vertex AI는 aiplatform.* 권한 공간에 사전 정의된 IAM 역할(Role)을 게시합니다. 역할 문서(docs.cloud.google.com, 2026년 7월 18일 접속)에 따르면 roles/aiplatform.admin (Vertex AI / Agent Platform Administrator)은 와일드카드 aiplatform.*를 부여합니다. 이는 에이전트(Agent), 배치 작업(Batch job), 엔드포인트(Endpoint)를 포함한 모든 Vertex 리소스에 대한 전체 액세스와 해당 리소스에 대한 IAM 정책 관리 권한을 의미합니다. 배포된 모델을 호출하기만 하면 되는 서비스 계정에게 이는 명백히 과도합니다.
동일한 작업을 위한 더 좁은 범위의 역할은 roles/aiplatform.user (Vertex AI User)입니다. 이 역할은 aiplatform.endpoints.predict 권한을 포함하며, 추론/예측(Inference/Prediction) 호출에 정확히 필요한 권한입니다. 이것이 테스트의 중심이 되는 최소한의 권한입니다. 즉, 대상 작업인 예측(Predict)은 aiplatform.user 권한으로 통과해야 하지만, 관리자 수준의 불필요한 작업은 통과해서는 안 됩니다.
기본 역할(Basic Roles)에 대해 별도로 설명하겠습니다. Vertex AI의 액세스 제어(access control) 공식 페이지(docs.cloud.google.com, 2026년 7월 18일 접속)에 따르면, 사전 정의된 역할(Predefined Roles)은 프로젝트 수준의 권한을 부여하는 반면, Owner/Editor/Viewer와 같은 기본 역할(Basic Roles)은 더 광범위하며 모든 Google Cloud 서비스에 공통적으로 적용됩니다. 최소 권한 테스트를 수행하기에는 기본 역할이 정의상 적합하지 않습니다. 이 역할들은 Vertex AI만을 위한 것이 아니라 모든 서비스에 적용되기 때문입니다.
또한, 문제 정의 자체에서 발생할 수 있는 혼란을 바로잡아야 합니다. 그렇지 않으면 검증할 대상 자체가 없게 됩니다. 모델 호출에 관한 문서는 vertex ai api 또는 google vertex ai api라는 이름으로 찾을 수 있으며, 이것이 바로 필요한 정보입니다. 반면 vertex ai api key는 Vertex의 서버 측 호출에서는 일반적으로 사용되지 않는 인증 모델을 설명합니다. Vertex의 액세스는 서비스 계정(Service Account)과 IAM 역할(IAM Roles)을 기반으로 구축됩니다. 만약 내부 가이드나 티켓에 "Vertex를 위한 API 키가 필요함"이라고 적혀 있다면, 코드로 구현하기 전에 작업을 재정의해야 합니다. 즉, aiplatform.endpoints.predict 권한을 포함하는 역할을 가진 서비스 계정이 필요하다는 점을 명확히 해야 합니다. API 키 문자열에는 역할(Role)이라는 개념이 없으며, 따라서 범위를 좁힐 대상도 없습니다. 작업의 정의가 잘못되면 검증 대상 자체가 사라지게 됩니다.

"허용 - 차단" 쌍을 어떻게 구성할 것인가?
방법은 간단하며 의도적으로 좁게 설정되었습니다. 역할이 반드시 허용해야 하는 작업 하나와 반드시 차단해야 하는 작업 하나를 선택합니다. 두 작업을 각각 독립적으로 수행한 뒤, 실제 상태를 기대값과 함께 기록합니다. 허용된 호출은 성공을 반환해야 하며, 차단된 호출은 거부(Deny)를 반환해야 합니다. 만약 차단되어야 할 호출이 통과된다면, 역할의 최소성에 대한 가설은 기각됩니다. 이것이 전체 프로토콜의 반증 가능한(falsifiable) 조건입니다.
거부 신호는 정확하게 기록됩니다. IAM 권한 오류에 관한 페이지(docs.cloud.google.com, 2026년 7월 18일 접속)에 따르면, 호출자에게 필요한 권한이 없거나(또는 deny 정책이나 액세스 경계(access boundary)에 의해 차단된 경우) PERMISSION_DENIED가 반환됩니다. REST API는 구체적으로 누락된 권한과 고유한 오류 식별자를 명시하는 구조화된 페이로드 google.rpc.ErrorInfo와 함께 HTTP 403을 반환합니다. 로그에는 바로 이것, 즉 권한 이름과 코드를 기록해야 합니다. 로그에 "무언가 작동하지 않음"이라고 기록하는 것은 무용지물입니다.
상태를 변화시키는(mutating) 실제 호출을 수행하기 전에, 비파괴적인 방식으로 확인하는 것이 유용합니다. testIamPermissions() 메서드(docs.cloud.google.com, 2026년 7월 18일 접속)는 리소스 식별자와 권한 문자열 목록을 인자로 받아 호출자가 실제로 보유하고 있는 부분 집합만을 반환합니다. 즉, 프로그래밍 방식으로 "이 계정이 aiplatform.endpoints.predict 권한을 가지고 있는가?" 그리고 "목록에 있어서는 안 될 불필요한 권한을 가지고 있는가?"를 물어볼 수 있습니다.
아래는 검증을 위한 프레임워크입니다. 이는 메서드의 템플릿이며 즉시 실행 가능한 코드는 아닙니다. 소스에 실제 테스트 실행 로그는 존재하지 않으며, 여기에 제시된 모든 로그는 제안된 샘플입니다.
from google.api_core.exceptions import PermissionDenied
# test_iam_permissions / call_predict / delete_endpoint - Vertex 클라이언트에 대한 사용자 정의 래퍼(wrapper)
...
이 메서드의 핵심적인 제한 사항은 3단계에 직접 명시되어 있습니다: 금지된 호출은 격리된 상태에서 안전한 리소스를 대상으로 수행되어야 합니다. 왜냐하면 그것은 실제 상태를 변화시키는(mutating) 작업이기 때문입니다. 만약 계정에 delete에 대한 불필요한 권한이 있다면, 호출은 이를 실행할 것입니다. 따라서 과도한 권한에 대한 실전 검증은 testIamPermissions()를 통해 수행하는 것이 합리적이며, 실제 부정적 호출(negative call)은 의도적으로 비용이 소모되는 교육용 엔드포인트에서 수행해야 합니다.

이 로그에서는 거부가 성공으로 간주됩니다
로그는 단순히 "모든 것이 정상(all green)"임을 나타내는 보고서가 아닙니다. 로그는 각 작업에 대해 기대되는 상태가 사전에 정의되어 있으며, 실행을 통해 이를 확인하거나 반박하는 표입니다. 불필요한 작업에 대한 거부(Denial)는 테스트의 오류가 아니라 테스트의 성공입니다. 이는 로그의 관습적인 의미를 뒤집는 것이며, 그렇기 때문에 거부 상태를 명확하게 기록해야 합니다. 기록되지 않은 PERMISSION_DENIED는 결과로 간주되지 않습니다.
아래 매트릭스는 aiplatform.user 역할에 대한 교육용 샘플입니다. 여기에는 의도적으로 "범용 역할(universal role)"이 포함되어 있지 않습니다. 작업 세트가 고정되어 있으므로, 최소성에 대한 결론은 해당 범위 내에서만 유효합니다.
| 교육용 작업 | 권한 | aiplatform.user 하에서의 기대 결과 | 거부(Denial)의 의미 |
|---|---|---|---|
| 엔드포인트에서 예측(Predict) 호출 | aiplatform.endpoints.predict | 200 / OK | 403인 경우 - 대상 작업이 역할과 일치하지 않음 |
| ... |
테스트가 실패한 것으로 간주되는 세 가지 조건을 명심해야 합니다: 불필요한 작업이 허용됨; 대상 작업이 역할과 일치하지 않음(반드시 통과해야 하는 곳에서 통과하지 못함); 거부 상태가 기록되지 않음. 첫 번째는 최소성을 부정하고, 두 번째는 충분성을 부정하며, 세 번째는 증거 자체를 상실하게 만듭니다.
확신할 수 있는 범위에 대해 솔직하게 말씀드리겠습니다. 기록된 허용 및 금지된 호출은 확정된 결과입니다. 이들은 로그에 기록되었습니다. 기대된 거부(Expected denials)가 역할의 최소성을 확인한다는 것은 테스트 매트릭스 범위 내에서만 확률적인 결론입니다. 테스트 세트 이외의 향후 시나리오에 대해 이 역할이 충분한지는 알 수 없습니다. 매트릭스는 이를 측정하지 않으며, 이를 보장하지도 않습니다.

Vertex 인증은 외부 API 키와 어떻게 다른가?
여기서 비교를 해보는 것이 유용합니다. Vertex의 인증 모델은 OpenAI 및 Anthropic 호환 서비스에서 익숙한 "하나의 키로 바로 시작하는" 모델과 자주 혼동되기 때문입니다. Vertex에서의 액세스(Access)는 서비스 계정(Service Account)과 리소스 또는 프로젝트 수준의 IAM 역할(Role)의 조합이며, 별도의 권한 세트와 커스텀 서비스 계정(Custom Service Account) 사용 가능성을 포함합니다 (docs.cloud.google.com의 "Use a custom service account" 별도 문서에서 확인 가능, 2026년 7월 18일 접속 기준). 여기서는 역할을 확인하는 것입니다. 문자열(키) 자체는 아무것도 제한하지 않습니다.
OpenAI 및 Anthropic 호환 환경에서는 모델이 다릅니다. 키와 base_url을 변경하면 SDK가 다른 업스트림(Upstream)으로 요청을 보내기 시작합니다. provod.ai도 이와 같이 작동합니다 - 플랫폼에서 사용 가능한 모델들에 대한 하나의 호환 API이며, 해당 프로토콜을 지원하는 클라이언트, 에이전트 또는 IDE가 이 두 가지 값을 교체함으로써 연결됩니다.
겉보기에는 똑같이 "액세스 설정"이라는 작업처럼 보이기 때문에 이 두 모델을 혼동하게 됩니다.
# 외부 호환 환경: 인증 = 키 + base_url
from openai import OpenAI
client = OpenAI(api_key="PROVOD_KEY", base_url="https://api.provod.ai/v1")
...
이 차이는 본 기사의 주제에 있어 근본적입니다. 키를 변경하는 것은 작업 수준에서의 최소 권한(Least Privilege) 제어 수단을 제공하지 않습니다. 당신의 권한 범위는 제공자가 키를 발급할 때 이미 결정되었으며, 이를 개별 호출 수준으로 이동시킬 수 없습니다. 반면 Vertex에는 제어 수단이 있으며, 부정 테스트(Negative Test)가 바로 이를 활용하는 방법입니다. 환경이 다르고 작업이 다르므로, 하나가 다른 하나를 대체할 수 없습니다.
Policy Simulator는 결론을 강화하지만, 사후에만 가능합니다
역할(role)을 확장하기 전에, 변경 사항을 공회전(dry run)시켜 볼 수 있습니다. Policy Simulator (roles/policysimulator.admin, 권한 policysimulator.replays.create/get/list/run)는 Google Cloud의 공식 도구(docs.cloud.google.com, 2026년 7월 18일 기준 접근 가능)로, 제안된 정책 변경 사항에 대해 과거의 액세스 시도들을 재현(replay)하여, 정책 적용 전 어떤 권한이 다시 허용되거나 다시 차단될지를 보여줍니다. "새로운 역할이 의도한 범위를 벗어나지 않을지"를 확인하기 위한 보완적이고 비파괴적인(non-live) 방법입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기