Terraform Authentication and Remote State

The deploy account in Cloud Shell, the IAM roles it needs, and the Cloud Storage backend that holds state

Cloud Shell uses the Google account you signed in with in the browser. The account and project in the terminal have to be the same ones the server is built in. Terraform state goes into a Cloud Storage bucket with restricted access.

Prerequisites

The project ID, the billing link, and the budget alert are confirmed, and terraform version runs in Cloud Shell.

The Account and Project in Use Right Now

The project name at the top right of Cloud Shell and the terminal’s own setting can differ. The commands below print the current account and project ID.

Check

gcloud auth list --filter=status:ACTIVE \
  --format="value(account)"
gcloud config get-value project

The first command should print one Google account of yours, and the second the project ID you chose in part 02. If it prints (unset) or a different project, fix it with the next command.

Conditional run: the project differs

gcloud config set project "my-project-id"

Updated property [core/project]. is the normal result. Later commands create resources in this project. If you could not fix the ID, stop here.

Authentication in Cloud Shell Differs from Your Own Computer

Cloud Shell already carries the credentials of the account selected in the browser. Do not run gcloud auth application-default login again there.

Running the same examples on macOS or WSL needs the following order in the local terminal.

Conditional run: not in Cloud Shell

gcloud init
gcloud auth login
gcloud auth application-default login

The last command creates the Application Default Credentials, ADC for short, which the Google provider uses. Do not copy the credentials file into the example directory or push it to Git.

Permissions Required by the Deployment Account

Terraform uses your account to enable APIs and to manage the network, VM, service account, and buckets. IAM is the Google Cloud permission system that decides which account may perform which action. On a practice project you own alone, project Owner is enough to proceed. On a company or shared project, explain the purpose of the following roles to an administrator and request only the scope you need.

RoleWhat it does in this server layout
roles/serviceusage.serviceUsageAdminEnables the required Google APIs
roles/compute.adminManages VPC, firewalls, IPs, disks, and VMs
roles/storage.adminManages the state and backup buckets and bucket IAM
roles/iam.serviceAccountAdminCreates the dedicated Minecraft VM service account
roles/iam.serviceAccountUserAttaches the created service account to the VM
roles/resourcemanager.projectIamAdminBinds the OS Login project role to your account in part 05

Continuing with an account that cannot add roles itself leads to a 403 during plan or apply. On a shared project, do not widen permissions on your own; ask an administrator.

The current billing link is also readable with a read-only command.

Check

export PROJECT_ID="$(gcloud config get-value project)"
gcloud billing projects describe "${PROJECT_ID}" \
  --format="value(billingEnabled)"

A value created with export exists only in the terminal session that is open right now. Cloud Shell disconnects the session after a while of no use, and a new tab or a reconnection loses all of these values. When a command in this series suddenly returns an empty value or an (unset) error, suspect this case first: rerun the export lines from that article from the top, then continue. You can check whether a value is still there at any time with echo, as in echo "${PROJECT_ID}".

True is required before you can create a VM in part 05. This command neither links billing nor creates resources.

Creating a Bucket Just for State

Terraform state holds real resource IDs and configuration. A Cloud Storage backend keeps it after the browser tab closes and locks writes while another operation is updating the state.

On a new project, first make the Cloud Storage API usable.

Run

gcloud services enable storage.googleapis.com \
  --project="${PROJECT_ID}"

Operation ... finished successfully. is the normal result. Storage usage after API activation can incur charges. Local verification did not enable the API.

Bucket names are unique across all of Cloud Storage. Do not put personal names, email addresses, or internal company identifiers in them. The example below appends -tfstate to the project ID. If that name is taken, add a short random string.

Costs money: creating the Cloud Storage state bucket

export STATE_BUCKET="${PROJECT_ID}-tfstate"

gcloud storage buckets create "gs://${STATE_BUCKET}" \
  --project="${PROJECT_ID}" \
  --location="ASIA-NORTHEAST3" \
  --uniform-bucket-level-access

gcloud storage buckets update "gs://${STATE_BUCKET}" \
  --versioning

The first command creates a Cloud Storage resource. Storage volume and operations can carry a small charge. If you have not set up a budget alert, or you want no charges at all, do not run it and stop here. Local verification did not create a bucket.

On success, Creating gs://... appears along with a message that versioning is enabled. A name collision shows as 409. In that case, change the STATE_BUCKET value and run both commands again.

Object Versioning retains previous generations of overwritten or deleted state objects. Those generations consume storage. When server operation ends, Cleaning Up Terraform State and Remaining Google Cloud Costs checks and deletes every generation. For long-running use, define a lifecycle policy and retention period for older generations.

On a project only you use, grant the current account explicit permission to manage state objects.

Run

export ADMIN_ACCOUNT="$(
  gcloud auth list --filter=status:ACTIVE \
    --format="value(account)"
)"

gcloud storage buckets add-iam-policy-binding \
  "gs://${STATE_BUCKET}" \
  --member="user:${ADMIN_ACCOUNT}" \
  --role="roles/storage.objectAdmin"

The normal result shows roles/storage.objectAdmin and the current account. If someone else’s email went in, do not configure the backend; fix the IAM binding first.

Downloading the Example and Configuring the Backend

Download the example into the Cloud Shell home directory.

Run

cd "${HOME}"
curl --fail --location \
  "https://juntiger-assets.pages.dev/minecraft-one-root.zip" \
  --output minecraft-one-root.zip
unzip -q minecraft-one-root.zip
cd minecraft-one-root

If a directory with the same name already exists, do not overwrite it. Decide first whether to continue the earlier work or to extract under a new directory name.

Copy the backend sample and open it in the nano editor. In nano, move with the arrow keys, fix the values, save with Control+O and Enter, and close with Control+X.

Run

cp backend.hcl.example backend.hcl
nano backend.hcl

Put the real state bucket name and a path used only by this server into the file.

bucket = "my-state-bucket-name"
prefix = "minecraft/one-root"

backend.hcl does not go into Git. The bucket name does not need to stay in a public repository either.

Initializing the Remote Backend

Run

terraform init -backend-config=backend.hcl

The first run downloads the provider and creates .terraform.lock.hcl. It succeeds when the following sentence appears at the end.

Terraform has been successfully initialized!

If Failed to get existing workspaces appears, check the bucket name, the signed-in account, and roles/storage.objectAdmin again. In a freshly created directory there is no local state to move, so finishing without any question is normal. If a prompt does ask whether to copy local state to the remote, this directory has been run before. Answer yes only when you can explain what that state is; if you do not remember it, do not answer, stop with Control+C, and find the cause.

Completion Check

Check

terraform providers
gcloud storage ls "gs://${STATE_BUCKET}"

Preparation is done once the Google provider is listed and the bucket listing succeeds. An empty bucket is normal. State objects may appear only after a real plan or apply starts.

After initialization, use Preparing the Minecraft Server JAR and Terraform Inputs to create terraform.tfvars in the same working directory.

References

Comments

Comments

    Image preview