Lab / 8 steps
A private bucket behind a load balancer.
The bucket stays private. The load balancer signs every request with a service account’s HMAC key, so only it can read the objects.
- Step 01 · Console · Cloud Storage Private
Lock the bucket
Create the bucket with public access prevention and uniform access control, then upload a file. Nobody outside the project can read it.
Public access prevention: EnforcedAccess control: UniformObject: image.jpg - Step 02 · Console · IAM and Cloud Storage Key ready
Give a service account a key
Create a service account, give it an HMAC key under Cloud Storage → Settings → Interoperability, and grant it Storage Legacy Object Reader on the bucket.
Service account: PRIVATE_GCS_SAHMAC key: HMAC_ACCESS_KEY + HMAC_SECRETBucket role: Storage Legacy Object Reader - Step 03 · Console · Network endpoint groups Backend ready
Point a NEG at the bucket
An internet network endpoint group gives the load balancer a backend outside the VPC: the bucket’s own hostname on port 443.
Name: private-gcs-negType: Internet NEG (Global)Endpoint: [BUCKET_NAME].storage.googleapis.comDefault port: 443 - Step 04 · Console · Load balancing 403 Forbidden
Put a load balancer in front
An HTTPS load balancer with a static IP and certificate, the NEG as backend, Cloud CDN on, and a Host header set to the bucket’s hostname. Requests now reach the bucket, unsigned.
Frontend: HTTPS, static IP, certificateBackend: Internet NEG (private-gcs-neg), HTTPSCloud CDN: enabledHeader: host: [BUCKET_NAME].storage.googleapis.com - Step 05 · Cloud Shell 403 Forbidden
Export the backend service
Private origin authentication is not in the console. Export the backend service to YAML and add the HMAC key under securitySettings.
Terminal window gcloud compute backend-services export --global [Backend Service Name] \--destination=private-gcs.yaml \--project [PROJECT_ID] - Step 06 · private-gcs.yaml 403 Forbidden
Add the HMAC key
awsV4Authentication tells the load balancer to sign each request to the bucket with the service account’s key. Nothing changes until it is imported.
securitySettings:awsV4Authentication:accessKeyId: [HMAC_ACCESS_KEY]accessKey: [HMAC_SECRET]originRegion: [REGION] - Step 07 · Cloud Shell Signing
Import it
Import the edited file. From now on every request the load balancer sends to the bucket is signed.
Terminal window gcloud compute backend-services import --global [Backend Service Name] \--source=private-gcs.yaml \--project [PROJECT_ID] - Step 08 · Any terminal 200 OK
Prove it
Ask the load balancer for the file. The bucket is still private, but the signed request gets 200 OK.
Terminal window curl -X GET -I https://[LOAD_BALANCER_IP]/image.jpgHTTP/1.1 200 OKx-goog-storage-class: STANDARDvia: 1.1 google