示例源码与下载#
验证:未记录
- 适用版本
- 未记录
- 验证范围
- 尚未登记验证记录。
下载实验包。包内包含全部实验文档、应用与策略模板,不包含真实凭据。解压后进入 gcp-iam-handson 目录,再按章节执行命令。
网页是主要阅读入口;下载包用于保存和运行代码。文档中的命令不会因浏览页面而自动执行。云端步骤尚未端到端验证。
app/.dockerignore#
.venv
__pycache__
*.pyc
*.envapp/Dockerfile#
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY main.py .
RUN useradd --create-home appuser
USER appuser
CMD ["sh", "-c", "exec gunicorn --bind 0.0.0.0:${PORT:-8080} --workers 1 --threads 4 main:app"]app/main.py#
"""IAM teaching application. Uses ADC; never returns secret contents."""
import csv
import io
import json
import os
import uuid
from decimal import Decimal
from flask import Flask, jsonify
from google.cloud import secretmanager, storage
app = Flask(__name__)
@app.post('/report')
def report():
stage = 'read_input'
request_id = uuid.uuid4().hex
try:
client = storage.Client()
raw = client.bucket(os.environ['INPUT_BUCKET']).blob('input.csv').download_as_text()
rows = list(csv.DictReader(io.StringIO(raw)))
total = sum((Decimal(row['amount']) for row in rows), Decimal('0'))
stage = 'read_secret'
secretmanager.SecretManagerServiceClient().access_secret_version(
request={'name': os.environ['SECRET_VERSION']})
stage = 'write_report'
name = f'reports/{request_id}.json'
result = {'rows': len(rows), 'total': str(total), 'request_id': request_id}
client.bucket(os.environ['OUTPUT_BUCKET']).blob(name).upload_from_string(
json.dumps(result), content_type='application/json', if_generation_match=0)
print(json.dumps({'request_id': request_id, 'stage': 'complete'}), flush=True)
return jsonify({**result, 'object': name})
except Exception as error:
# Record the operation and error class; never log tokens or secret payloads.
print(json.dumps({'request_id': request_id, 'stage': stage,
'error_type': type(error).__name__}), flush=True)
return jsonify(request_id=request_id, stage=stage,
error_type=type(error).__name__), 500
if __name__ == '__main__':
app.run(host='127.0.0.1', port=int(os.environ.get('PORT', '8080')))app/requirements.txt#
Flask>=3.0,<4
gunicorn>=23,<24
google-cloud-storage>=3,<4
google-cloud-secret-manager>=2,<3templates/custom-role.yaml#
title: Lab Object Reader
description: Read a known object in the IAM lab
stage: ALPHA
includedPermissions:
- storage.objects.gettemplates/deny-read.json#
{
"displayName": "IAM lab deny runtime object reads",
"rules": [
{
"denyRule": {
"deniedPrincipals": [
"principal://iam.googleapis.com/projects/-/serviceAccounts/REPLACE_RUNTIME_SA_EMAIL"
],
"deniedPermissions": [
"storage.googleapis.com/objects.get"
]
}
}
]
}templates/lab.env.example#
# 仅供以后在独立实验环境中填写;不含任何真实凭据。
export ORG_ID='REPLACE_ORGANIZATION_ID'
export NONPROD_FOLDER_ID='REPLACE_NONPROD_FOLDER_ID'
export PROJECT_ID='REPLACE_UNIQUE_DEV_PROJECT_ID'
export GOOGLE_CLOUD_PROJECT="$PROJECT_ID"
export REGION='asia-east1'
export ADMIN_EMAIL='REPLACE_LAB_ADMIN_EMAIL'
export DEV_EMAIL='REPLACE_LAB_DEVELOPER_EMAIL'
export QA_EMAIL='REPLACE_LAB_QA_EMAIL'
export DEV_GROUP='REPLACE_DEVELOPERS_GROUP_EMAIL'
export QA_GROUP='REPLACE_QA_GROUP_EMAIL'
export INPUT_BUCKET="${PROJECT_ID}-raw"
export OUTPUT_BUCKET="${PROJECT_ID}-reports"
export APP_SA="report-app@${PROJECT_ID}.iam.gserviceaccount.com"
export DEPLOY_SA="report-deployer@${PROJECT_ID}.iam.gserviceaccount.com"
export SECRET_ID='report-api-key'
export SERVICE='report-api'templates/org-policy-key.yaml#
# 示例:传统约束。先检查有效策略和 managed 约束,填写后才可用于实验。
name: projects/REPLACE_PROJECT_NUMBER/policies/iam.disableServiceAccountKeyCreation
spec:
rules:
- enforce: truetemplates/实验记录.md#
# IAM 实验记录
- 实验章节与时间:
- 状态:未执行 / 推演 / 已验证 / 失败待排查 / 已回滚
- 执行者与实际请求身份:
- 目标资源和权限:
- 前提及变更前状态:
- 本次变更:
- 预期允许的操作及原因:
- 预期拒绝的操作及原因:
- 实际结果与传播等待时间:
- 日志或策略证据:
- 发现的额外授权路径:
- 最小修复及复测:
- 清理内容与恢复状态:
不记录访问令牌、真实 Secret、密钥或个人敏感资料。