> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maia.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Google Cloud IAM permissions for runner deployment

export const RunnerMetadata = ({runnerType, platforms = []}) => {
  return <div style={{
    background: 'var(--colors-background-light, #f9fafb)',
    border: '1px solid var(--colors-border-default, #e5e7eb)',
    borderRadius: '12px',
    padding: '20px 28px',
    marginBottom: '28px',
    boxShadow: '0 1px 4px rgba(0,0,0,0.10)'
  }}>
      <table style={{
    width: '100%',
    borderCollapse: 'collapse'
  }}>
        <tbody>
          <tr>
            <td style={{
    fontWeight: '600',
    paddingRight: '32px',
    paddingBottom: '14px',
    whiteSpace: 'nowrap',
    verticalAlign: 'middle',
    width: '180px'
  }}>Runner type</td>
            <td style={{
    paddingBottom: '14px',
    verticalAlign: 'middle'
  }}>{runnerType}</td>
          </tr>
          <tr>
            <td style={{
    fontWeight: '600',
    paddingRight: '32px',
    whiteSpace: 'nowrap',
    verticalAlign: 'middle'
  }}>Runner platform</td>
            <td style={{
    verticalAlign: 'middle'
  }}>
              <div style={{
    display: 'flex',
    flexWrap: 'wrap',
    gap: '8px'
  }}>
                {platforms.map((platform, i) => <span key={i} style={{
    background: '#dcfce7',
    color: '#15803d',
    border: '1px solid #bbf7d0',
    borderRadius: '9999px',
    padding: '3px 12px',
    fontSize: '0.85rem',
    fontWeight: '500',
    whiteSpace: 'nowrap'
  }}>
                    {platform} ✅
                  </span>)}
              </div>
            </td>
          </tr>
        </tbody>
      </table>
    </div>;
};

export const m_runner = "Maia runner";

export const maia = "Maia";

<RunnerMetadata runnerType={`${maia} Hybrid`} platforms={["Google Cloud"]} />

This guide lists all Google Cloud IAM roles and permissions required to deploy and run a {m_runner} on Google Kubernetes Engine (GKE). It covers two distinct principals: the Terraform deployer (the human or CI identity running `terraform apply`) and the {m_runner} runtime service accounts, which are automatically provisioned by Terraform.

For the full deployment walkthrough, see the [GKE deployment guide](/docs/guides/gke-deployment-guide).

***

## Required Google Cloud APIs

Enable the following APIs in the target Google Cloud project before running Terraform. Replace `YOUR_PROJECT_ID` with your actual GCP project ID.

```bash theme={null}
gcloud services enable \
  container.googleapis.com \
  compute.googleapis.com \
  secretmanager.googleapis.com \
  storage.googleapis.com \
  iam.googleapis.com \
  cloudresourcemanager.googleapis.com \
  artifactregistry.googleapis.com \
  --project=YOUR_PROJECT_ID
```

| API                                   | Purpose                                                                                          |
| ------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `container.googleapis.com`            | GKE cluster and node pool management.                                                            |
| `compute.googleapis.com`              | VPC network, subnets, Cloud NAT, and firewall rules.                                             |
| `secretmanager.googleapis.com`        | Secret Manager secrets for {m_runner} credentials.                                               |
| `storage.googleapis.com`              | GCS bucket for {m_runner} staging storage.                                                       |
| `iam.googleapis.com`                  | Service account creation and IAM binding (Workload Identity).                                    |
| `cloudresourcemanager.googleapis.com` | Project metadata read access—required by `roles/browser` for the GCP Project ID field in {maia}. |
| `artifactregistry.googleapis.com`     | Pull {m_runner} container images from the Google Cloud Artifact Registry.                        |

***

## Terraform deployer permissions

The identity running `terraform apply` must have the following IAM roles on the target Google Cloud project. These can be granted to a user account, a service account used by CI/CD, or a group.

| IAM role                        | Purpose                                                                                                                                           | Scope   |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `roles/container.admin`         | Create and manage GKE clusters and node pools.                                                                                                    | Project |
| `roles/compute.networkAdmin`    | Create VPC network, subnets, and Cloud NAT.                                                                                                       | Project |
| `roles/iam.serviceAccountAdmin` | Create the GKE node service account and the {m_runner} Workload Identity service account.                                                         | Project |
| `roles/iam.serviceAccountUser`  | Attach service accounts to GKE nodes.                                                                                                             | Project |
| `roles/iam.securityAdmin`       | Grant IAM bindings to service accounts—covers both project-level (`google_project_iam_member`) and SA-level (Workload Identity binding) policies. | Project |
| `roles/storage.admin`           | Create the {m_runner} staging GCS bucket and set bucket-level IAM policies.                                                                       | Project |
| `roles/secretmanager.admin`     | Create the {m_runner} Secret Manager secret and set secret-level IAM policies.                                                                    | Project |
| `roles/artifactregistry.admin`  | Create and manage Artifact Registry repositories (required if creating the repository via Terraform).                                             | Project |
| `roles/logging.admin`           | Create log buckets and sinks (required if managing Cloud Logging resources via Terraform).                                                        | Project |

<Note>
  `roles/owner` or `roles/editor` + `roles/iam.securityAdmin` will also satisfy all requirements. The granular roles above are recommended for production environments, following the principle of least privilege.
</Note>

***

## Maia runner runtime permissions

Terraform automatically creates and configures two service accounts. No manual IAM grants are required for these.

### Maia runner Workload Identity service account

This service account is annotated onto the Kubernetes service account via Workload Identity, so {m_runner} pods authenticate to Google Cloud APIs without any key files. The following roles are granted automatically by Terraform.

| IAM role                                                          | Scope                                 | Why it's needed                                                                                                                                                                   |
| ----------------------------------------------------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `roles/iam.workloadIdentityUser`                                  | Google Cloud service account          | Binds the Kubernetes service account to this Google Cloud service account via Workload Identity Federation—enables secretless pod authentication.                                 |
| `roles/storage.objectAdmin`                                       | Staging GCS bucket                    | Read, write, and delete objects in the {m_runner}'s own staging bucket.                                                                                                           |
| `roles/secretmanager.secretAccessor`                              | Project-wide                          | Read secret values from Secret Manager—required for the {m_runner} to retrieve credentials and for the Matillion UI to read secrets.                                              |
| `roles/secretmanager.viewer`                                      | Project-wide                          | List and get secret metadata—required for the Matillion UI list-secrets functionality.                                                                                            |
| `roles/browser`                                                   | Project-wide                          | Read Google Cloud project metadata—required for the GCP Project ID field when adding secrets in the Matillion UI.                                                                 |
| `roles/secretmanager.secretVersionManager`                        | {m_runner} Secret Manager secret      | Manage versions of the {m_runner}'s own Secret Manager secret.                                                                                                                    |
| `roles/storage.legacyBucketReader` + `roles/storage.objectViewer` | Each additional GCS bucket (optional) | Bucket metadata and object read access—required to download file contents from user-supplied buckets (custom CA certificates, Python extension libraries, external JDBC drivers). |
| `roles/cloudkms.cryptoKeyDecrypter` (optional)                    | Cloud KMS key(s)                      | Decrypt CMEK-encrypted secrets—only required if you use customer-managed encryption keys (CMEK) in Secret Manager.                                                                |

<Note>
  The optional extra GCS bucket permissions (`roles/storage.legacyBucketReader` and `roles/storage.objectViewer`) are only granted when bucket names are supplied via the `runner_gcs_buckets` Terraform variable. Typical use cases include custom CA certificate bundles, Python extension libraries, and external JDBC drivers.
</Note>

### GKE node service account

A separate, least-privilege service account is attached to the GKE nodes for cluster operations. The following roles are granted automatically by Terraform.

| IAM role                        | Scope   | Why it's needed                                                        |
| ------------------------------- | ------- | ---------------------------------------------------------------------- |
| `roles/logging.logWriter`       | Project | Write container and node logs to Cloud Logging.                        |
| `roles/monitoring.metricWriter` | Project | Write node and pod metrics to Cloud Monitoring.                        |
| `roles/monitoring.viewer`       | Project | Read monitoring data for node health checks and autoscaling decisions. |

***

## Pipeline-level permissions

The following permissions are required at pipeline execution time, depending on the data warehouse the {m_runner} connects to. These aren't provisioned by the GKE deployment Terraform—they must be granted separately to the {m_runner} Workload Identity service account, or to a delegated service account.

### BigQuery

| IAM role                         | Scope              | Why it's needed                                                                                   |
| -------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------- |
| `roles/bigquery.jobUser`         | Project (required) | Submit and run BigQuery jobs—must be project-level; can't be scoped to a dataset.                 |
| `roles/bigquery.dataViewer`      | Dataset or project | Read data from BigQuery datasets and tables.                                                      |
| `roles/bigquery.dataEditor`      | Dataset or project | Read and write data—only required if the pipeline writes back to BigQuery.                        |
| `roles/bigquery.readSessionUser` | Project            | Use the BigQuery Storage Read API for efficient large reads—recommended for production workloads. |
| `roles/bigquery.admin`           | Project            | Full administrative access to Google BigQuery resources.                                          |

<Note>
  Dataset-level grants are preferred for `roles/bigquery.dataViewer` and `roles/bigquery.dataEditor`, to follow the principle of least privilege.
</Note>

### Snowflake via GCS staging

Snowflake access isn't governed by Google Cloud IAM—the {m_runner} authenticates to Snowflake using credentials stored in Secret Manager (key-pair, OAuth, or username/password). However, if Snowflake uses a GCS Storage Integration for staging, the following additional permission is needed on the Snowflake staging bucket:

| IAM role                    | Scope                        | Why it's needed                                                                     |
| --------------------------- | ---------------------------- | ----------------------------------------------------------------------------------- |
| `roles/storage.objectAdmin` | Snowflake staging GCS bucket | Allows the Snowflake GCS integration service account to read and write stage files. |

***

## Workload Identity binding

Workload Identity allows Kubernetes pods to impersonate a Google Cloud service account without storing any key files in the cluster. Terraform configures this binding automatically. It takes the form:

```
serviceAccount:<PROJECT_ID>.svc.id.goog[<K8S_NAMESPACE>/<K8S_SERVICE_ACCOUNT_NAME>]
  → roles/iam.workloadIdentityUser on <RUNNER_GCP_SA>
```

* `K8S_NAMESPACE` defaults to `var.name`. Override with the `k8s_namespace` Terraform variable if your Helm release is deployed into a different namespace.
* `K8S_SERVICE_ACCOUNT_NAME` defaults to `<name>-sa`. Override with `k8s_service_account_name` if your Helm release name differs from `var.name`.

<Warning>
  If the Kubernetes namespace or service account name doesn't match the Workload Identity binding, {m_runner} pods will silently fail to authenticate to Google Cloud APIs. Run `terraform apply` a second time if you see an identity pool race condition error after initial cluster creation.
</Warning>

***

## Quick reference

The following table summarizes all permissions.

| Principal                       | IAM role                                                          | Scope                        | Provisioned by              |
| ------------------------------- | ----------------------------------------------------------------- | ---------------------------- | --------------------------- |
| GKE node SA                     | `roles/logging.logWriter`                                         | Project                      | Terraform                   |
| GKE node SA                     | `roles/monitoring.metricWriter`                                   | Project                      | Terraform                   |
| GKE node SA                     | `roles/monitoring.viewer`                                         | Project                      | Terraform                   |
| {m_runner} Workload Identity SA | `roles/bigquery.dataViewer` / `roles/bigquery.dataEditor`         | Dataset or project           | Manual (BigQuery pipelines) |
| {m_runner} Workload Identity SA | `roles/bigquery.jobUser`                                          | Project                      | Manual (BigQuery pipelines) |
| {m_runner} Workload Identity SA | `roles/browser`                                                   | Project-wide                 | Terraform                   |
| {m_runner} Workload Identity SA | `roles/cloudkms.cryptoKeyDecrypter`                               | Cloud KMS key(s)             | Manual (if CMEK used)       |
| {m_runner} Workload Identity SA | `roles/iam.workloadIdentityUser`                                  | Google Cloud service account | Terraform                   |
| {m_runner} Workload Identity SA | `roles/secretmanager.secretAccessor`                              | Project-wide                 | Terraform                   |
| {m_runner} Workload Identity SA | `roles/secretmanager.secretVersionManager`                        | {m_runner} secret            | Terraform                   |
| {m_runner} Workload Identity SA | `roles/secretmanager.viewer`                                      | Project-wide                 | Terraform                   |
| {m_runner} Workload Identity SA | `roles/storage.legacyBucketReader` + `roles/storage.objectViewer` | Each additional GCS bucket   | Terraform (optional)        |
| {m_runner} Workload Identity SA | `roles/storage.objectAdmin`                                       | Staging GCS bucket           | Terraform                   |
| Terraform deployer              | `roles/artifactregistry.admin`                                    | Project                      | Manual                      |
| Terraform deployer              | `roles/compute.networkAdmin`                                      | Project                      | Manual                      |
| Terraform deployer              | `roles/container.admin`                                           | Project                      | Manual                      |
| Terraform deployer              | `roles/iam.securityAdmin`                                         | Project                      | Manual                      |
| Terraform deployer              | `roles/iam.serviceAccountAdmin`                                   | Project                      | Manual                      |
| Terraform deployer              | `roles/iam.serviceAccountUser`                                    | Project                      | Manual                      |
| Terraform deployer              | `roles/logging.admin`                                             | Project                      | Manual                      |
| Terraform deployer              | `roles/secretmanager.admin`                                       | Project                      | Manual                      |
| Terraform deployer              | `roles/storage.admin`                                             | Project                      | Manual                      |
