如何将带负载均衡的Google后端存储桶限制到特定IP范围?
我完全理解你的困扰——目前Cloud Armor确实无法直接关联到GCS后端存储桶,而GCP的防火墙规则仅作用于虚拟机实例,没法直接管控GCS的公网访问。不过我们可以通过引入一个轻量的中间代理层,结合Cloud Armor来实现你想要的「特定IP白名单匿名只读访问」需求,下面是两种可行的方案:
方案一:Cloud Run + 负载均衡器 + Cloud Armor(推荐轻量场景)
这是最省心的无服务器方案,不需要管理虚拟机:
步骤1:创建Cloud Run代理服务
编写一个简单的HTTP服务,接收客户端的GET请求,代理访问你的GCS桶并返回对象内容。比如用Python写的示例逻辑:from google.cloud import storage from flask import Flask, redirect, abort app = Flask(__name__) storage_client = storage.Client() BUCKET_NAME = "your-bucket-name" @app.route('/<path:object_path>') def serve_object(object_path): try: bucket = storage_client.bucket(BUCKET_NAME) blob = bucket.blob(object_path) # 生成临时签名URL,让客户端直接从GCS下载,节省Cloud Run资源 signed_url = blob.generate_signed_url(expiration=3600) return redirect(signed_url) except Exception as e: abort(404) if __name__ == '__main__': app.run(host='0.0.0.0', port=8080)部署这个服务到Cloud Run,给它的默认服务账号分配
Storage Object Viewer角色,确保它能读取GCS桶内容。步骤2:配置负载均衡器与Cloud Armor
- 创建一个外部HTTP(S)负载均衡器,在后端服务中选择「Serverless」类型,关联你的Cloud Run服务。
- 创建一个Cloud Armor策略,添加两条规则:
- 第一条规则:允许你指定的IP白名单(比如
192.168.1.0/24、203.0.113.5等),优先级设为高。 - 第二条规则:默认拒绝所有其他IP,优先级设为低。
- 第一条规则:允许你指定的IP白名单(比如
- 将这个Cloud Armor策略绑定到负载均衡器的后端服务上。
步骤3:限制GCS桶的直接访问
进入GCS桶的IAM设置,移除allUsers或allAuthenticatedUsers的任何权限,确保只有Cloud Run的服务账号能访问桶内容,避免绕开代理层的直接访问。
方案二:Compute Engine代理 + 负载均衡器 + Cloud Armor(适合自定义需求)
如果需要更多自定义逻辑(比如缓存、复杂路由),可以用VM实例做代理:
步骤1:创建VM实例并配置反向代理
启动一个小型的Compute Engine实例,安装Nginx作为反向代理。配置Nginx转发请求到GCS桶(注意要通过服务账号认证,避免直接公开GCS),示例Nginx配置:server { listen 80; server_name your-lb-domain.com; location / { proxy_pass https://storage.googleapis.com/your-bucket-name/; proxy_set_header Authorization "Bearer $(gcloud auth print-access-token)"; # 可选:添加缓存配置优化访问速度 proxy_cache_valid 200 1h; } }给VM实例的服务账号分配
Storage Object Viewer角色,确保它能读取GCS桶。步骤2:配置负载均衡器与Cloud Armor
- 创建一个外部HTTP(S)负载均衡器,后端服务关联这个VM实例所在的实例组。
- 同样创建Cloud Armor策略,设置IP白名单和默认拒绝规则,绑定到后端服务。
步骤3:限制GCS桶直接访问
同方案一,移除GCS桶的公开访问权限,只允许VM实例的服务账号访问。
关键注意事项
- 确保GCS桶没有任何公开权限,所有访问必须经过代理层,这样IP过滤才会生效。
- Cloud Armor的规则优先级要设置正确,白名单规则的优先级必须高于默认拒绝规则。
- 推荐给负载均衡器配置HTTPS证书,确保传输安全。
内容的提问来源于stack exchange,提问作者Tom Gummery

