# Securing GCS Bucket Access for GCP VMs: Best Practices Explained

In this lab we will see how to access the GCS bucket data to GCP VM in most secure manner.

# What we’ll cover

* Cloud Storage FUSE
    
* Service Account
    
* Linux User
    
* GCP VM
    
* Cloud KMS
    

# What you’ll need

* Google Cloud Admin access
    
* Access to VM and a Bucket
    
* Cloud KMS access
    

Here is flowchart on this lab

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1766317568819/08419075-bfb4-4c8f-ae63-493a7f313e14.png align="center")

Lets first create the [Cloud KMS](https://docs.cloud.google.com/kms/docs/key-management-service) keyring and Cryptographic Key

### Setup Cloud KMS

Cloud KMS help in building the [**data sovereignty**](https://en.wikipedia.org/wiki/Data_sovereignty) between GCS bucekt and VM, It ensures that even if someone get access to physical disk in Google data’s center, they cannot read your files without your cryptographic keys.

We are using this Cloud KMS to setup most secure infra for our data, from virtual to physical data will be secure in this data transaction

```bash
gcloud kms keyrings create secure-bucket-keyring --location us-central1
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1766316679563/e69c7b4e-3b6d-43b7-aafe-78412f7c0578.png align="center")

This keyring will be use by the Cloud bucket and VM to decrypt the data

### Create Service account to user to use this KMS key

```bash
export SA_NAME="secure-vm-sa"
gcloud iam service-accounts create $SA_NAME --display-name "Secure VM Access"
```

![Service account](https://cdn.hashnode.com/res/hashnode/image/upload/v1766320619644/e4189818-964b-46b2-8691-66d3bbd1153e.png align="center")

Grant permission to us Cloud KMS key

```bash
export REGION="us-central1"
export KEY_RING="secure-bucket-keyring"
export KEY_NAME="secure-vm-bucket-key"
export SA_EMAIL="$SA_NAME@$PROJECT_ID.iam.gserviceaccount.com"
gcloud kms keys add-iam-policy-binding $KEY_NAME \
    --location $REGION \
    --keyring $KEY_RING \
    --member "serviceAccount:$SA_EMAIL" \
    --role "roles/cloudkms.cryptoKeyEncrypterDecrypter"
```

Now will grant the bucket to access the Cloud KMS key

```bash
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
export STORAGE_AGENT="service-$PROJECT_NUMBER@gs-project-accounts.iam.gserviceaccount.com"
gcloud kms keys add-iam-policy-binding $KEY_NAME \
    --location $REGION \
    --keyring $KEY_RING \
    --member "serviceAccount:$STORAGE_AGENT" \
    --role "roles/cloudkms.cryptoKeyEncrypterDecrypter" 
```

![Cloud KMS Decrypter](https://cdn.hashnode.com/res/hashnode/image/upload/v1766321507665/a2c27d47-9662-4ea1-999a-319efa53601b.png align="center")

Now we will create Bucket

---

## Bucket setup

We will apply four security layers in a single command:

1. **Enforce Public Access Prevention:** Hard block on "allUsers" (internet).
    
2. **Uniform Bucket-Level Access:** Disables messy ACLs (Access Control Lists); forces strict IAM usage.
    
3. **Default CMEK Encryption:** Forces your KMS key on every file immediately.
    
4. **Versioning:** Protects against ransomware or accidental deletion (you can "undelete" files).
    

---

```bash
BUCKET_NAME="secure-bucket-lab-2025"
REGION="us-central1"
PROJECT_ID=$(gcloud config get-value project)
KMS_KEY="projects/$PROJECT_ID/locations/$REGION/keyRings/secure-bucket-keyring/cryptoKeys/secure-vm-bucket-key"
```

> Note: Create a bucket with unique name please don’t use this name

Now let create secure bucket with Cloud KMS key, remove public access, and add uniform bucket level access and enable versioning

```bash
gcloud storage buckets create gs://$BUCKET_NAME \
    --location=$REGION \
    --project=$PROJECT_ID \
    --public-access-prevention \
    --uniform-bucket-level-access \
    --default-encryption-key=$KMS_KEY
```

Enable versioning to bucket

```bash
gcloud storage buckets update gs://$BUCKET_NAME --versioning
```

Grant a service account access to bucket

```bash
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_NAME \
    --member "serviceAccount:$SA_EMAIL" \
    --role "roles/storage.objectUser"
```

![Bucket access](https://cdn.hashnode.com/res/hashnode/image/upload/v1766322283657/366a0379-f839-4428-9456-c60b9753837f.png align="center")

Now we will create the VM

```bash
VM_NAME="secure-vm"
ZONE="us-central1-a"
PROJECT_ID=$(gcloud config get-value project)
SA_EMAIL="secure-vm-sa@$PROJECT_ID.iam.gserviceaccount.com"

gcloud compute instances create $VM_NAME \
    --zone=$ZONE \
    --machine-type=e2-medium \
    --image-family=ubuntu-2204-lts \
    --image-project=ubuntu-os-cloud \
    --service-account=$SA_EMAIL \
    --scopes=cloud-platform \
    --shielded-secure-boot \
    --shielded-vtpm \
    --shielded-integrity-monitoring \
    --tags=secure-ssh
```

We added these thing to make it more secure

* `--shielded-secure-boot`: Ensures the OS hasn't been tampered with before it loads.
    
* `--service-account`: It never uses the "Default" editor account, only your restricted one.
    
* `--tags=secure-ssh`: We will use this tag to create a specific firewall rule next.
    

Now secure the Firewall to allow access with only Cloud IAP

```bash
gcloud compute firewall-rules create allow-ssh-ingress-from-iap \
    --direction=INGRESS \
    --action=allow \
    --rules=tcp:22 \
    --source-ranges=35.235.240.0/20 \
    --target-tags=secure-ssh
```

Use this ssh command to access the VM in Cloud IAM ssh tunnel

```bash
gcloud compute ssh $VM_NAME --zone=$ZONE --tunnel-through-iap
```

### Install Dependencies on VM

Google [Cloud Storage FUSE](https://docs.cloud.google.com/storage/docs/cloud-storage-fuse/overview)

```bash
export GCSFUSE_REPO=gcsfuse-`lsb_release -c -s`
echo "deb https://packages.cloud.google.com/apt $GCSFUSE_REPO main" | sudo tee /etc/apt/sources.list.d/gcsfuse.list
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

sudo apt-get update
sudo apt-get install -y gcsfuse
```

Check your user id

```bash
id <username>
```

Create new users and group then

```bash
sudo groupadd -g 2000 app_group
sudo useradd -u 2000 -g 2000 -m -s /bin/bash app_user
```

create secure folder and give access to the particular user

```bash
sudo mkdir -p /home/app_user/secure_data
sudo chown app_user:app_group /home/app_user/secure_data
sudo chmod 700 /home/app_user/secure_data
```

User mount to fuse.conf file

```bash
sudo sed -i 's/#user_allow_other/user_allow_other/g' /etc/fuse.conf
```

Mount the bucket data to persistent volume

```bash
BUCKET_NAME="secure-bucket-lab-2025" 
echo "$BUCKET_NAME /home/app_user/secure_data gcsfuse rw,_netdev,allow_other,implicit_dirs,uid=2000,gid=2000,file_mode=600,dir_mode=700,noexec,nosuid,nodev 0 0" | sudo tee -a /etc/fstab
sudo mount -a
```

Now switch to user and verify the folder

```bash
sudo su - app_user
ls -ld secure_data/
```

This will the folder **secure\_data** with ***drwx------ 1 app\_user app\_group 0***

Now verify the mount volume

```bash
df -h /home/app_user/secure_data
```

Here you can see the avail size 1.0P which is significant saying Google Storage bucket in petabyte of storage

# Test data access

Push object into bucket

![Cloud Storage Bucket](https://cdn.hashnode.com/res/hashnode/image/upload/v1766325169949/83cb758a-6d10-4114-b22a-f70498f8886c.png align="center")

Now ***ls*** inside the **secure\_data** folder

![GCP VM](https://cdn.hashnode.com/res/hashnode/image/upload/v1766325133539/82e434fe-8f0a-4343-8ac1-fca758ae04d5.png align="center")

---

> In this lab, we explore securing data access between Google Cloud Storage (GCS) buckets and Google Cloud Platform (GCP) virtual machines (VMs) using Cloud Key Management Service (KMS) and other security measures. Key steps include setting up a KMS keyring and cryptographic key, creating a service account for secure VM access, configuring a secure bucket with four layers of security (preventing public access, enforcing uniform bucket-level access, default CMEK encryption, and versioning), and setting up the VM with specific security configurations. We also cover using Cloud Storage FUSE for data access, creating secure user groups, and mounting the bucket data as a persistent volume. Finally, we verify data accessibility and security configurations on the VM.
