GCP IAP를 통한 어플리케이션(Web) 접근관리방안 feat. IAP + Cloud Run + Cloud Storage
IAP란
GCP IAP (Identity-Aware Proxy)는 Google Cloud Platform의 핵심 보안 서비스로, 애플리케이션 수준에서 중앙 집중식 접근 제어를 제공하는 서비스 입니다.
기존의 네트워크 기반 방화벽 대신, 사용자 ID와 컨텍스트(위치, 기기 상태 등)를 기반으로 접근을 허용하거나 거부하여 제로 트러스트 보안 모델을 구현할 수 있습니다.
일부 기능 (컨텍스트)에 대해서는 CEP (chrome enterprise premium ) 유료 서비스를 사용해야됩니다.
배경
GCP의 IAP(Identity-Aware Proxy)는 Google 계정 또는 Google Workspace 계정을 활용하여 중앙 집중식 사용자 인증 및 권한 관리를 제공합니다.
이를 통해 여러 보안 모델을 설계할 수 있으며, 이번 문서에서 작성한 LB → Cloud Run 방안 외에도 App Engine, GCE, GKE와의 연결을 통해서 보안성을 향상시킬 수 있습니다.
테스트 목표
내부 또는 특정 대상만 접근해야 하는 클라우드 애플리케이션에 대한 보안 구현을 테스트하기 위해, 외부 네트워크(인터넷)로부터 Cloud Run 서비스에 직접적인 접근을 차단하고 인증된 사용자만 접근할 수 있도록 하는 방안을 검증하고자 합니다.
기대 효과
이로 인해 얻을 수 있는 부분은 다음과 같습니다.
기존 방화벽 규칙을 통해 IP 기반으로 접근을 제어하는 방식이 아닌, 사용자(ID) 기반으로 접근을 제어할 수 있습니다. 또한 VPN 설정 없이도 사용자가 인터넷을 통해 Cloud Run에 안전하게 접속할 수 있도록 하며, 이는 SSL VPN과 비슷한 효과를 제공합니다.
특히 원격 근무 환경이나 파트너/고객 접근 시 유용할 것으로 생각됩니다.Google 계정(또는 Google Workspace 계정)을 활용하여 중앙 집중식으로 사용자 인증 및 권한을 관리함으로써 접근 관리의 복잡성을 줄일 수 있습니다.
테스트 핵심 사항
최종적으로 이번 테스트를 위해 하고자 하는 부분은 애플리케이션 접근에 대한 보안 수준을 높이는 방안, 즉 외부에서 접근하는 경로에 대한 인증을 IAP가 담당하도록 하는 것입니다.
LB : 지정된 도메인으로 접근할 수 있도록 합니다.
IAP : Google 인증을 받도록처리
Cloud Run : 인증완료 후 웹페이지 확인
Cloud Storage : Cloud Run에서 보여주는 웹페이지 소스 저장소
Cloud Run에서도 바로 IAP가 가능하기는 하지만 아직 Preview단계입니다.
1. Cloud Storage (웹페이지 소스)
아래와 같은 index.html, style.css 파일을 생성합니다.
index.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cloud Run & Cloud Storage 웹페이지</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>안녕하세요, Cloud Run과 Cloud Storage!</h1>
<p>이 페이지는 Cloud Storage에 저장된 정적 파일을 Cloud Run을 통해 제공하고 있습니다.</p>
<p>환영합니다! </p>
</div>
</body>
</html>
style.css 파일
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background-color: #f0f0f0;
color: #333;
}
.container {
text-align: center;
background-color: #fff;
padding: 40px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
h1 {
color: #4285F4; /* Google Blue */
}
p {
line-height: 1.6;
}

외부에서 접근하지 못하도록 Not public 설정도 진행합니다.

2. Cloud Run 설정
본문서의 Cloud Run에서는 IAP로 인증 후 보여주는 페이지로 간단하게 환영인사만 적은 html 을 보여줄 예정입니다.
Cloud Shell에서 디렉토리를 생성한 후
아래 app.py, requirements.txt, Dockerfile 을 생성합니다.
import os
from flask import Flask, send_from_directory, abort
from google.cloud import storage
app = Flask(__name__)
# Cloud Storage 버킷 이름 설정
# 'YOUR_BUCKET_NAME'을 실제 Cloud Storage 버킷 이름으로 변경해주세요.
GCS_BUCKET_NAME = os.environ.get('GCS_BUCKET_NAME', 'YOUR_BUCKET_NAME')
STORAGE_CLIENT = storage.Client()
@app.route('/')
def serve_index():
"""루트 경로 요청 시 index.html 파일을 제공합니다."""
try:
bucket = STORAGE_CLIENT.get_bucket(GCS_BUCKET_NAME)
# Cloud Storage에 업로드된 정적 파일의 경로 (예: static/index.html)
blob = bucket.blob('static/index.html')
return blob.download_as_text(), 200, {'Content-Type': 'text/html'}
except Exception as e:
print(f"Error serving index.html from GCS: {e}")
abort(500, description="Internal Server Error: Could not retrieve index.html")
@app.route('/<path:filename>')
def serve_static(filename):
"""정적 파일 요청 시 Cloud Storage에서 해당 파일을 제공합니다."""
try:
bucket = STORAGE_CLIENT.get_bucket(GCS_BUCKET_NAME)
# Cloud Storage에 업로드된 정적 파일의 경로 (예: static/style.css)
blob = bucket.blob(f'static/{filename}')
if not blob.exists():
abort(404, description="File not found")
# 파일 확장자에 따라 Content-Type 설정
if filename.endswith('.css'):
content_type = 'text/css'
elif filename.endswith('.js'):
content_type = 'application/javascript'
elif filename.endswith('.png'):
content_type = 'image/png'
elif filename.endswith('.jpg') or filename.endswith('.jpeg'):
content_type = 'image/jpeg'
else:
content_type = 'application/octet-stream' # 기본값
return blob.download_as_text(), 200, {'Content-Type': content_type}
except Exception as e:
print(f"Error serving static file {filename} from GCS: {e}")
abort(500, description="Internal Server Error: Could not retrieve static file")
if __name__ == '__main__':
# Cloud Run은 PORT 환경 변수를 사용합니다.
app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))
requirements.txt
Flask==2.3.2
google-cloud-storage==2.10.0
Dockerfile
# 파이썬 런타임 이미지 사용
FROM python:3.9-slim-buster
# 작업 디렉터리 설정
WORKDIR /app
# requirements.txt 복사 및 의존성 설치
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 애플리케이션 코드 복사
COPY . .
# Cloud Run에서 사용할 포트 지정 (기본 8080)
ENV PORT 8080
# 애플리케이션 시작 명령
CMD ["flask", "run", "--host", "0.0.0.0"]
Cloud Run → Cloud Storage 간 권한이 필요합니다.
기본적으로 Cloud Run은 아래의 SA키의 Role을 사용합니다.
Project number-compute@developer.gserviceaccount.com
Cloud Shell에서 배포방안
gcloud run deploy cloudrun서비스명 --source . --region 리전 --allow-unauthenticated (인증없음) --set-env-vars GCS_BUCKET_NAME=버킷네임입력

그리고 해당되는 웹페이지가 정상적으로 뜨는지 URL에 있는 부분을 클릭하여 확인합니다.
웹페이지가 잘 뜨는지 확인 후에는 “Networking”탭의 Ingress에서 Internal 트래픽만 허용 및 ALB는 허용할 수 있는 옵션을 선택하여 접속합니다.
이렇게 되면 Cloud Run은 연결된 VPC와 ALB외에는 접속이 불가합니다.
3. Load Balancing 설정
Cloud Run에 연결할 Load Balancing을 설정합니다.
- Frontend
https, http로 통신하기에 도메인이 필요합니다.
도메인의 경우 ( https://seonggi.kr/217 ) 가이드를 따라서 별도 발급하거나, 기존 테스트할 도메인이 있다면 LB의 공인 IP로 설정 후 GCP관리인증서를 사용하겠습니다.
본문서의 에서는 test.seonggi.kr을 사용하여 테스트 진행하였습니다.
global external Application Load Balancer 를 생성 진행하면서 Frontend 부분에서 IP를 신규로 생성합니다.
사용하는 DNS 업체에서 아래와 같이 GCP LB에서 발급받은 공인 IP을 입력합니다.
대부분의 업체가 메뉴가 대동소이 하니 A레코드 값을 변경하는 부분에서 입력합니다.
http에서 온 트래픽도 https로 리다이렉트 하기 위한 옵션도 체크합니다.
- backend 설정
Backend Service를 생성 진행합니다.
Backend type을 “Serverless network endpoint group” 선택합니다.
endpoint group 생성을 진행하면서 Name, Region과 Cloud Run을 선택하면 먼저 생성했던 Cloud Run 서비스가 표시됩니다.
IAP에서는 CDN을 지원하지 않으므로 CDN 옵션은 체크 해지합니다.
이후 backend service를 생성하고 Routing rules 설정을 진행합니다.
Routing Rules의 경우 현재는 테스트부분이기 때문에 기본으로 진행하여도 무방합니다.
필요하다면 각 Path에 따라 접속 Backend service를 변경하도록 설정합니다.
LB 설정이 완료되면 http to https Rediect를 설정하였기 때문에 2개의 LB가 생성됩니다.
http LB가 뒤에 -redirect가 붙어서 생성됩니다.
LB에서 설정될 인증서, Backend service가 잘되었는지 확인합니다.
4. IAP 설정
본문서에서의 LB에 대한 IAP 설정은 매우 간단합니다.
Security → Identity-Aware Proxy 메뉴로 이동 후 “Applications” 탭을 보면 생성된 LB가 보이며, IAP 탭을 활성화 해줍니다.
약 5분 ~ 10분정도의 적용시간이 있으며, Status 가 Ok임을 확인합니다.
5. IAP IAM 권한 부여
IAP가 사용설정 되었지만, IAP을 이용하여 접속하는 권한을 설정해주어야합니다.
위와 동일한 메뉴에서 LB를 선택 후 오른쪽 상단 “show info panel” 을 선택합니다.
권한을 줄 수 있는 부분입니다.
“add principal” 선택 후 권한을 부여합니다.
인증을 받고 접속하기 위해서는 “IAP-Secured Web APP User” 권한이 필요합니다.
권한 부여 후 조금의 시간이 지나면 적용이 완료됩니다.
6. 테스트
테스트한 주소로 접속을 진행하면 Google Login을 요구합니다.
위의 IAP-Secured Web App User 권한이 없는 경우 아래와 같이 access 가 거부됩니다.
IAP-secured Web App User권한이 주어진 Google ID (Gmail, GWS, Cloud ID)는 아래와 같이 IAP인증을 받았으므로 웹페이지에 접속할 수 있습니다.
인증을 받고 내부 그룹웨어, 웹페이지등으로 접속하는 구성도 가능합니다.