Skip to content

Add GCP onboarding setup scripts - #2269

Draft
MarcoDN wants to merge 2 commits into
mainfrom
gcp-setup-scripts
Draft

Add GCP onboarding setup scripts#2269
MarcoDN wants to merge 2 commits into
mainfrom
gcp-setup-scripts

Conversation

@MarcoDN

@MarcoDN MarcoDN commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Description of the issue

The onboarding setup scripts cover AWS and Azure platforms. The agent now
supports GCE (auto-detected host mode) and GKE (RUN_IN_GKE via the Helm
chart), but there is no scripted onboarding for GCP workloads.

Important

Do not merge until the 1.300073.0 agent release completes its rollout: the
install commands fetch these scripts and the released agent from main /
the release buckets at install time, and GCE auto-detection first ships in
1.300073.0.

Description of changes

Extends the onboarding scripts to GCE VMs (gcp_vm) and GKE clusters
(gcp_gke), mirroring the Azure split:

  • aws/setup.sh: gcp_vm trust federates the IAM role directly with
    accounts.google.com (no OIDC provider resource; Google is a built-in
    web-identity provider), pinning all three Google condition keys: the
    service account unique ID (:sub), the sts.amazonaws.com audience
    (:oaud), and the authorized party (:aud, the unique ID again on
    service-account tokens) - the trust policy form recommended for
    Google-issued tokens (AWS Security Blog).
    The audience condition matches the audience the agent requests for its
    identity tokens and rejects tokens minted for other services being
    replayed against STS, mirroring how the Azure trust policies pin their
    requested audience.
    gcp_gke registers the cluster's OIDC issuer as an IAM OIDC provider and
    trusts the amazon-cloudwatch/cloudwatch-agent service account.
  • gcp/setup.sh: new GCP-side script with the two-mode design keyed on
    CWAGENT_AWS_ROLE_ARN. Identity discovery is read-only: the VM's service
    account unique ID, or the cluster's OIDC issuer URL (constructed under
    locations/ for zonal and regional clusters alike). A VM install pushes
    install.sh over gcloud compute ssh behind a reachability probe,
    printing the command when SSH cannot reach the VM. A GKE install runs the
    CloudWatch Observability Helm chart with k8sMode=GKE when helm,
    kubectl, and gke-gcloud-auth-plugin are present, printing the commands
    otherwise.
  • install.sh: accepts CWAGENT_CLOUD=gcp through the same web-identity
    branch as azure (set-env CWAGENT_ROLE_ARN and AWS_REGION, then
    fetch-config -m auto).
  • setup.sh: dispatcher chain gcp/setup.sh (identity) -> aws/setup.sh
    (trust) -> gcp/setup.sh (install), with the same cross-shell resume flow
    as Azure.
  • README.md: documents the new platforms and flow.

License

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Tests

  • sh -n and shellcheck clean on all touched scripts; make fmt-sh clean.
  • gcp_vm identity verified against a real GCE VM: service account email and
    unique ID discovery, CWAGENT_EMIT_ENV stdout purity, interactive wizard.
  • gcp_vm trust verified against a test account: role create path,
    idempotent re-run ("trust policy up to date"), trust policy content, and
    policy attachment. The generated trust policy was validated end to end
    with a manual sts assume-role-with-web-identity exchange using an
    identity token minted on the VM (credentials returned, subject = the
    service account unique ID). Re-verified after extending the conditions to
    the three-key form: the rendered policy passes the Zelkova automated
    reasoning check (the engine behind IAM Access Analyzer) as not publicly
    assumable, and a fresh role create plus idempotent re-run with the updated
    script succeeded against the same test account.
  • gcp_gke identity and trust verified against a real zonal cluster: issuer
    construction, IAM OIDC provider create path, both trust statements
    coexisting on one role, and the printed helm command matching the chart's
    validated GKE install.
  • Install push verified against a real VM: SSH reachability probe, push,
    remote transcript, and failure propagation. A side-loaded install.sh ran
    through download/install/set-env on Debian 12; the full green install
    completes once the 1.300073.0 agent reaches the release buckets (until
    then fetch-config correctly fails in on-prem mode).

Requirements

  1. make fmt-sh run
  2. shellcheck clean

Extend the onboarding scripts to GCE VMs (gcp_vm) and GKE clusters
(gcp_gke), mirroring the Azure split:

- aws/setup.sh: gcp_vm trust federates the IAM role directly with
  accounts.google.com (no OIDC provider resource; Google is a built-in
  web-identity provider), conditioned on the service account unique ID
  (:sub) and the sts.amazonaws.com audience (:oaud). gcp_gke registers
  the cluster's OIDC issuer as an IAM OIDC provider and trusts the
  amazon-cloudwatch/cloudwatch-agent service account.
- gcp/setup.sh: new GCP-side script with the two-mode design keyed on
  CWAGENT_AWS_ROLE_ARN. Identity discovery is read-only: the VM's
  service account unique ID, or the cluster's OIDC issuer URL,
  constructed under locations/ for zonal and regional clusters alike.
  A VM install pushes install.sh over gcloud compute ssh behind a
  reachability probe, printing the command when SSH cannot reach the
  VM. A GKE install runs the CloudWatch Observability Helm chart with
  k8sMode=GKE when helm, kubectl, and gke-gcloud-auth-plugin are
  present, printing the commands otherwise.
- install.sh: accept CWAGENT_CLOUD=gcp through the same web-identity
  branch as azure (set-env CWAGENT_ROLE_ARN and AWS_REGION, then
  fetch-config -m auto).
- setup.sh: dispatcher chain gcp/setup.sh (identity) -> aws/setup.sh
  (trust) -> gcp/setup.sh (install) with the same cross-shell resume
  flow as Azure.
- README.md: document the new platforms and flow.
Comment thread scripts/aws/setup.sh Outdated
Extend the gcp_vm trust conditions from :sub + :oaud to
:aud + :sub + :oaud, the recommended trust policy form for
Google-issued tokens. On service-account identity tokens the azp
claim (matched by :aud) carries the service account unique ID, so
the added key pins the authorized party alongside the subject and
the requested audience, keeping the policy provably scoped to a
single Google identity under automated policy analysis.
Comment thread scripts/gcp/setup.sh
Comment on lines +257 to +260
# Describe doubles as the existence and access check, like the Azure
# script's scoped account show.
gcloud projects describe "${PROJECT}" --format='value(projectId)' >/dev/null 2>&1 ||
die "cannot access project ${PROJECT} (run 'gcloud auth login'; check 'gcloud projects list')"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normalize PROJECT to the project ID. We're using it directly in the GKE OIDC issuer URL, which needs it to be the project ID to match the issued token, but CWAGENT_GCP_PROJECT could come in as a project number.

The current describe call can take in either the ID or the number (https://docs.cloud.google.com/sdk/gcloud/reference/projects/describe) and it already is set to output the project ID. Capture the value and replace the PROJECT with it.

Suggested change
# Describe doubles as the existence and access check, like the Azure
# script's scoped account show.
gcloud projects describe "${PROJECT}" --format='value(projectId)' >/dev/null 2>&1 ||
die "cannot access project ${PROJECT} (run 'gcloud auth login'; check 'gcloud projects list')"
# Describe doubles as the existence and access check, like the Azure
# script's scoped account show.
_resolved_project=$(gcloud projects describe "${PROJECT}" --format='value(projectId)' 2>/dev/null) ||
die "cannot access project ${PROJECT} (run 'gcloud auth login'; check 'gcloud projects list')"
PROJECT="${_resolved_project}"

Comment thread scripts/gcp/setup.sh
# gcloud config default is used when unset)
# CWAGENT_EMIT_ENV When set (1/true/yes/on), print eval-able KEY='value'
# lines on stdout and route all logging to stderr
# gcp_vm:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to gcp_gce to match aws_ec2. Azure VM was azure_vm because they don't have a separate product name.

Rename the related functions as well.

Comment thread scripts/gcp/setup.sh
# CWAGENT_EMIT_ENV When set (1/true/yes/on), print eval-able KEY='value'
# lines on stdout and route all logging to stderr
# gcp_vm:
# CWAGENT_GCP_ZONE Zone the VM lives in

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to collapse the CWAGENT_GCP_ZONE and CWAGENT_GCP_LOCATION into a single CWAGENT_GCP_LOCATION?

Both of the variable names read as generic GCP, so users may end up using either on either platform. If I were trying to set up a zonal GKE cluster, I would expect CWAGENT_GCP_ZONE to work and if I were trying to set up a GCE instance, I may expect CWAGENT_GCP_LOCATION to work as well.

Since zone is a valid location, one variable covers both cleanly:

  • gcp_gce passes it as --zone, so a region fails the describe and the script's die points at the zone
$ gcloud compute instances describe <instance_name> --zone us-east1 --project <project_id> --format 'value(serviceAccounts[0].email)' 2>&1
ERROR: (gcloud.compute.instances.describe) Could not fetch resource:
 - Invalid value for field 'zone': 'us-east1'. Unknown zone.

$ echo $?
1
  • gcp_gke passes it as --location

Would help to remove some confusion.

Comment thread scripts/gcp/setup.sh
# lines on stdout and route all logging to stderr
# gcp_vm:
# CWAGENT_GCP_ZONE Zone the VM lives in
# CWAGENT_GCP_VM_NAME VM name

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: GCP refers to their VMs as Instances. Consider renaming to CWAGENT_GCP_INSTANCE_NAME.

https://docs.cloud.google.com/sdk/gcloud/reference/compute/instances/describe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants