Add documentation for Google WIF Integration

This commit is contained in:
Yuan Gao
2025-09-20 16:43:22 -07:00
parent cd266ebec9
commit cc7b5c1a14
7 changed files with 297 additions and 106 deletions

View File

@@ -184,7 +184,7 @@ perform these steps and then retry the create project command.
## Authorize Service Account Key Uploads
*IMPORTANT:* Google best practice is to NOT use service account keys. Rather than overriding Google's default policy please consider [Running GAM7 securely on a Google Compute Engine](https://github.com/GAM-team/GAM/wiki/Running-GAM7-securely-on-a-Google-Compute-Engine) so that service account keys are not necessary.
*IMPORTANT:* Google best practice is to NOT use service account keys. Rather than overriding Google's default policy please consider [Running GAM7 securely on a Google Compute Engine](https://github.com/GAM-team/GAM/wiki/Running-GAM7-securely-on-a-Google-Compute-Engine) (if running in Google Cloud) or [Workload Identity Federation](https://github.com/GAM-team/GAM/wiki/Using-GAM7-with-keyless-authentication-Workload-Identity-Federation) (if running outside Google Cloud) so that service account keys are not necessary.
If you try to create a project and get an error saying that Constraint `constraints/iam.disableServiceAccountKeyUpload violated for service account projects/gam-project-xxxxx`,
perform these steps and then you should be able to authorize and use your project.

View File

@@ -5,6 +5,8 @@
## Introduction
GAM7 can run on a Linux or Windows [Google Compute Engine (GCE)](https://cloud.google.com/products/compute) virtual machine and use the attached service account to access Google Workspace APIs. The advantage of this configuration is that no service account private key is accessible to GAM7 directly and [there is no risk of the key being stolen/lost](https://cloud.google.com/iam/docs/best-practices-for-managing-service-account-keys#alternatives).
**Note**: This method is recommended when running GAM **inside** Google Cloud. If you're running GAM **outside** Google Cloud (on-premises, other cloud providers, CI/CD systems), consider [Workload Identity Federation](https://github.com/GAM-team/GAM/wiki/Using-GAM7-with-keyless-authentication-Workload-Identity-Federation) instead - Google's officially recommended keyless authentication method for external environments.
## Setup Steps
1. Create a [GCP project](https://cloud.google.com/resource-manager/docs/creating-managing-projects).

View File

@@ -5,6 +5,8 @@
- [FAQs](#faqs)
- [Setup Steps](#setup-steps)
**Alternative Approach**: For enhanced security and simplified operations when running GAM outside Google Cloud, consider [Workload Identity Federation](https://github.com/GAM-team/GAM/wiki/Using-GAM7-with-keyless-authentication-Workload-Identity-Federation) - Google's recommended keyless authentication method that eliminates the need for managing any long-lived credentials. If running GAM in Google Cloud, use [attached service accounts on GCE](https://github.com/GAM-team/GAM/wiki/Running-GAM7-securely-on-a-Google-Compute-Engine) instead.
## Thanks
Thanks to Jay Lee for the original version of this document.
@@ -69,4 +71,4 @@ gam user admin@example.com check serviceaccount
```
and see the YubiKey lights flash as the YubiKey interacts with GAM7 to sign the GAM7 authentication requests. If you look at the oauth2service.json file, you'll see it contains some new fields like yubikey_serial and yubikey_pin but no longer contains the private_key field where GAM7 would normally store the private key data.
7. As a last step, since YubiKey-stored private keys do not need to be and should not be rotated, you can remove the service account's permissions to change it's own key. Navigate to the [Cloud Console](https://console.cloud.google.com/iam-admin/serviceaccounts) select the correct project and service account and on the Permissions tab, edit and remove the "Service Account Key Admin" permission that the service account has to itself.
7. As a last step, since YubiKey-stored private keys do not need to be and should not be rotated, you can remove the service account's permissions to change it's own key. Navigate to the [Cloud Console](https://console.cloud.google.com/iam-admin/serviceaccounts) select the correct project and service account and on the Permissions tab, edit and remove the "Service Account Key Admin" permission that the service account has to itself.

View File

@@ -0,0 +1,290 @@
# Using GAM7 with Keyless Authentication - Workload Identity Federation
**Important**: This method is designed for running GAM7 **outside** of Google Cloud (on-premises, other cloud providers, CI/CD systems). If you're running GAM7 **inside** Google Cloud, use [attached service accounts on Google Compute Engine](Running-GAM7-securely-on-a-Google-Compute-Engine) instead, which provides the same keyless benefits with simpler configuration.
This guide explains how to configure GAM7 to use Google Cloud's Workload Identity Federation for keyless authentication. **This is Google's officially recommended authentication method** for enhanced security and simplified credential management.
## Table of Contents
- [Overview](#overview)
- [Prerequisites](#prerequisites)
- [Setup Steps](#setup-steps)
- [1. Enable Required APIs](#1-enable-required-apis)
- [2. Create Workload Identity Pool](#2-create-workload-identity-pool)
- [3. Create or Use Existing Service Account](#3-create-or-use-existing-service-account)
- [4. Grant Required Permissions](#4-grant-required-permissions)
- [AWS Configuration](#aws-configuration)
- [1. Create Workload Identity Provider for AWS](#1-create-workload-identity-provider-for-aws)
- [2. Allow AWS Identity to Impersonate Service Account](#2-allow-aws-identity-to-impersonate-service-account)
- [3. Create Credential Configuration File](#3-create-credential-configuration-file)
- [4. Configure GAM7 Environment for AWS](#4-configure-gam7-environment-for-aws)
- [5. Initialize GAM7](#5-initialize-gam7)
- [GitHub Actions Configuration](#github-actions-configuration)
- [1. Create Workload Identity Provider for GitHub Actions](#1-create-workload-identity-provider-for-github-actions)
- [2. Allow GitHub Actions to Impersonate Service Account](#2-allow-github-actions-to-impersonate-service-account)
- [3. GitHub Actions Workflow Configuration](#3-github-actions-workflow-configuration)
- [Clean Up](#clean-up)
- [Security Best Practices](#security-best-practices)
- [Troubleshooting](#troubleshooting)
- [Benefits](#benefits)
- [References](#references)
## Overview
Workload Identity Federation allows GAM7 to authenticate to Google Cloud services without storing long-lived service account keys. Instead, it uses short-lived tokens from external identity providers like AWS, Azure, or GitHub Actions, eliminating the security risks associated with managing static credentials.
## Prerequisites
- GAM7 [installed and configured](https://github.com/GAM-team/GAM/wiki/How-to-Install-GAM7)
- Run `gam config` to generate the `gam.cfg` file
- Run `gam create/use project` to generate the `oauth2service.json` file
- Optionally enable [DASA](https://github.com/GAM-team/GAM/wiki/Using-GAM7-with-a-delegated-admin-service-account) `gam config enable_dasa true admin_email admin@domain.com customer_id domain domain.com save`
- Google Cloud CLI (gcloud) installed and configured
- [Install gcloud CLI](https://cloud.google.com/sdk/docs/install)
- Run `gcloud auth login` to authenticate
- Run `gcloud config set project PROJECT_ID` to set your project
- **Alternative**: Use the [Google Cloud Console](https://console.cloud.google.com) web interface to perform the same operations
- Google Cloud project with appropriate APIs enabled
- External identity provider (AWS, Azure, GitHub Actions, etc.)
- Appropriate permissions to create Workload Identity Pools and manage IAM
## Setup Steps
### 1. Enable Required APIs
```bash
gcloud services enable iamcredentials.googleapis.com
gcloud services enable sts.googleapis.com
```
### 2. Create Workload Identity Pool
```bash
gcloud iam workload-identity-pools create POOL_ID \
--location="global" \
--description="Pool for GAM authentication"
```
### 3. Create or Use Existing Service Account
You can either create a new service account or reuse an existing one that has the necessary permissions.
#### Option A: Create New Service Account
```bash
gcloud iam service-accounts create SERVICE_ACCOUNT_ID \
--description="Service account for GAM operations" \
--display-name="GAM Service Account"
```
#### Option B: Use Existing Service Account
If you already have a service account with appropriate Google Workspace permissions (typically the one created during GAM7 initial setup), you can reuse it. Just note the service account email for the next steps.
```bash
# List existing service accounts to find the one you want to use
gcloud iam service-accounts list
```
### 4. Grant Required Permissions
```bash
# Grant necessary Google Workspace permissions
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \
--role="roles/iam.serviceAccountTokenCreator"
```
## AWS Configuration
### 1. Create Workload Identity Provider for AWS
```bash
gcloud iam workload-identity-pools providers create-aws PROVIDER_ID \
--workload-identity-pool="POOL_ID" \
--account-id="YOUR_AWS_ACCOUNT_ID" \
--location="global"
```
### 2. Allow AWS Identity to Impersonate Service Account
```bash
gcloud iam service-accounts add-iam-policy-binding \
SERVICE_ACCOUNT_EMAIL \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.aws_role/arn:aws:sts::YOUR_AWS_ACCOUNT:assumed-role/YOUR_ROLE_NAME"
```
### 3. Create Credential Configuration File
Create a JSON file with your Workload Identity Federation configuration:
#### For AWS [IMDSv1](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html#instance-metadata-retrieval-examples-imdsv1)
```bash
gcloud iam workload-identity-pools create-cred-config \
projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID \
--service-account=SERVICE_ACCOUNT_EMAIL \
--service-account-token-lifetime-seconds=SERVICE_ACCOUNT_TOKEN_LIFETIME \
--aws \
--output-file=FILEPATH.json
```
#### For AWS [IMDSv2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html#instance-metadata-retrieval-examples)
```bash
gcloud iam workload-identity-pools create-cred-config \
projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID \
--service-account=SERVICE_ACCOUNT_EMAIL \
--aws \
--enable-imdsv2 \
--output-file=FILEPATH.json
```
### 4. Configure GAM7 Environment for AWS
Set the environment variable to use the credential file:
```bash
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/credential-configurations.json"
```
Open the `oauth2service.json` file, and set the `key_type` to `signjwt`.
```
...
"key_type": "signjwt",
...
```
### 5. Initialize GAM7
```bash
gam version
gam info user
```
## GitHub Actions Configuration
### 1. Create Workload Identity Provider for GitHub Actions
```bash
gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID \
--workload-identity-pool="POOL_ID" \
--issuer-uri="https://token.actions.githubusercontent.com" \
--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" \
--attribute-condition="assertion.repository_owner=='YOUR_GITHUB_ORGANIZATION'"
--location="global"
```
### 2. Allow GitHub Actions to Impersonate Service Account
```bash
gcloud iam service-accounts add-iam-policy-binding \
SERVICE_ACCOUNT_EMAIL \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.repository/YOUR_GITHUB_ORG/YOUR_REPO"
```
### 3. GitHub Actions Workflow Configuration
.github/workflows/example.yml
```yaml
name: GAM Operations
on: [push]
jobs:
gam-job:
runs-on: ubuntu-24.04
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v3
- name: Download and install GAM
run: |
bash <(curl -s -S -L https://git.io/gam-install) -l
- name: Copy GAM configs into target dir
# Make sure to remove the private key from oauth2service.json and set `key_type` to `signjwt`
run: |
cp ./gam.cfg ~/.gam/gam.cfg
cp ./oauth2service.json ~/.gam/oauth2service.json
# # For debugging GitHub identity tokens
# - name: Print out GitHub OIDC token
# uses: github/actions-oidc-debugger@2e9ba5d3f4bebaad1f91a2cede055115738b7ae8
# with:
# audience: https://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID
- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v1'
with:
create_credentials_file: true
workload_identity_provider: 'projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID'
service_account: 'SERVICE_ACCOUNT_EMAIL'
- name: Run GAM commands
run: |
~/bin/gam7/gam info user
```
## Clean Up
After verifying that gam is working as expected, delete the old key if it's no longer in use.
```bash
gcloud iam service-accounts keys delete KEY_ID --iam-account=SERVICE_ACCOUNT_EMAIL
```
Also remove it from the `oauth2service.json` file.
```
...
"private_key": "",
"private_key_id": "",
...
```
## Security Best Practices
1. **Principle of Least Privilege**: Grant only necessary permissions to the service account
2. **Attribute Conditions**: Use attribute conditions to restrict access based on specific criteria
3. **Regular Auditing**: Regularly review and audit Workload Identity Federation configurations
4. **Token Lifetime**: Configure appropriate token lifetimes for your use case
## Troubleshooting
### Common Issues
1. **Authentication Errors**
- Verify the audience URL matches your Workload Identity Pool
- Check that the external identity has permission to impersonate the service account
2. **Permission Denied**
- Ensure the service account has necessary Google Workspace permissions
- Verify domain-wide delegation is configured if required
3. **Token Expiration**
- Tokens are automatically refreshed by the Google Auth libraries
- Check network connectivity to Google STS endpoints
### Debug Commands
```bash
# Test authentication
gcloud auth print-access-token
# Verify service account impersonation
gcloud auth print-access-token --impersonate-service-account=SERVICE_ACCOUNT_EMAIL
# Check GAM authentication
gam info user
```
## Benefits
- **Reduced Attack Surface**: Short-lived tokens minimize exposure window if compromised
- **Reduced Operational Cost**: Eliminates the overhead of managing and rotating service account keys
- **Improved Scalability**: Easily scale across multiple environments without distributing keys
- **Better Integration**: Native integration with cloud provider identity systems (AWS IAM, GitHub OIDC)
- **Compliance**: Meets security requirements for keyless authentication
## References
- [Google Cloud Workload Identity Federation](https://cloud.google.com/iam/docs/workload-identity-federation)
- [Workload Identity Federation With Other Clouds](https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds)
- [Authenticate to Google Cloud from GitHub Actions](https://github.com/google-github-actions/auth/blob/main/README.md)
- [Service Account Impersonation](https://cloud.google.com/iam/docs/impersonating-service-accounts)

View File

@@ -22,6 +22,7 @@ Configuration
* [Multiple Users-Projects on One Computer](https://github.com/GAM-team/GAM/wiki/gam.cfg#multiple-users-projects-on-one-computer)
* [Running GAM7 securely on a Google Compute Engine](Running-GAM7-securely-on-a-Google-Compute-Engine)
* [Using GAM7 with a delegated admin service account](Using-GAM7-with-a-delegated-admin-service-account)
* [Using GAM7 with keyless authentication - Workload Identity Federation](Using-GAM7-with-keyless-authentication-Workload-Identity-Federation)
* [Using GAM7 with a YubiKey](Using-GAM7-with-a-YubiKey)
* [GAM with minimal GCP rights](GAM-with-minimal-GCP-rights)
@@ -203,4 +204,3 @@ GAM Tutorials
* [Unmanaged Users and Invitations](l-UnmanagedUsersExamples)
* [User Email Settings](l-ExamplesEmailSettings)
* [User Security Settings](l-SecurityExamples)

View File

@@ -1,54 +0,0 @@
# Intro
GAM can run on a Linux or Windows Google Compute Engine (GCE) VM and use the attached service account to access Google Workspace APIs. The advantage of this configuration is that no service account private key is accessible to GAM directly and there is no risk of the key being stolen/lost. To use GAM on GCE with a service account:
1. Create a [GCP project](https://cloud.google.com/resource-manager/docs/creating-managing-projects).
2. Create [a service account](https://cloud.google.com/iam/docs/creating-managing-service-accounts) which will be used by GAM. Continue steps 2 and 3 without granting the new service account any special access to the project and without granting users access to the service account.
3. Grant the service account rights to generate authentication tokens.
* go to [console.cloud.google.com](https://console.cloud.google.com).
* go to "IAM & Admin" > Service accounts
* click on the service account you created (not the default service account).
* copy the email address of your service account to the clipboard.
* click on the Permissions tab.
* click "Grant Access".
* In the "New principals text box, paste the service account email you copied.
* Give your service account the "Service Account Token Creator" and "View Service Accounts" roles.
4. [Create a Windows or Linux virtual machine](https://cloud.google.com/compute/docs/instances/create-start-instance).
* You can choose a region physically close to you though you may be limited in your choices if you want to use the free tier.
* GAM can run on the minimal `e2-micro` [free tier VM](https://cloud.google.com/free/docs/free-cloud-features#compute) though performance may suffer. If you are performing batch operations, raising the CPU count will help performance. If you have a very large and busy Workspace instance downloading reports or Drive file lists may require more RAM.
* [DO NOT use the default service account](https://cloud.google.com/iam/docs/best-practices-service-accounts#single-purpose). Choose the service account you created above instead.
* GAM does not use a significant amount of storage, unless you have specific storage needs the default disk size should suffice.
* leave other VM instance settings at their defaults unless you know what you are doing.
5. Install GAM on the VM with the command:
```
bash <(curl -s -S -L https://git.io/gam-install) -l
```
the `-l` argument causes GAM to be installed and SKIP the normal setup wizard.
6. Logout and log back in to the VM, you should now be able to run GAM commands like:
```
gam version
```
7. Create the special `oauth2service.json` file GAM will use:
```
gam create signjwtserviceaccount
```
If you'd like, take a look at the generated ```oauth2service.json``` file with:
```
cat ~/bin/gam/oauth2service.json
```
you'll notice that while the file has some fields similar to a normal service account file, there is no `private_key` attribute containing an RSA private key.
8. Enable the Google APIs GAM will use:
```
gam enable apis
```
you are given the option to enable them automatically or manually. Automatic enablement will ask you to authenticate to GAM. You should authenticate as a user with rights to manage project APIs, probably a project owner. If you are not the project owner you can choose manual enablement and GAM will provide two or more URLs which you can send to the project owner. When the owner opens these URLs, they'll be prompted to enable all the APIs GAM needs.
9. GAM is now installed, the last steps are to grant GAM permissions to your Google Workspace domain.
* If you want to manage user data, run ```gam user you@example.com check serviceaccount``` and follow the instructions to perform domain-wide delegation.
* If you want to perform admin actions (manage users, groups, etc) [you can configure delegated admin service account (DASA)](https://github.com/GAM-team/GAM/wiki/Using-GAM-with-a-delegated-admin-service-account-(DASA)).

View File

@@ -1,49 +0,0 @@
## Description
GAM supports using a [YubiKey](https://www.yubico.com/products/yubikey-5-overview/) to generate and store the service account's private RSA key. Private keys generated by the YubiKey cannot be exported even to the computer running GAM. When compared to the plain text oauth2service.json file with the private key stored in text, the YubiKey offers a more secure option that prevents digital theft and copying of the private key. Instead of reading the private key from the oauth2service.json file and signing requests itself, GAM will simply send signing requests to the YubiKey and get back the signature.
## FAQs
### Can I use a Google Titan or other brand security key?
No, while Titan keys are great as security keys / U2F / 2SV, that is not the protocol being used by GAM here. GAM uses the PIV app of YubiKeys to work with service accounts. You need to use [a genuine Yubikey.](https://yubico.com/genuine/).
### Does this protect the admin credentials GAM stores in oauth2.txt?
No, the admin credentials GAM stores in oauth2.txt are not protected by the YubiKey as they are not using RSA private keys. Only the service account credentials normally stored in oauth2service.json are protected. The service account credentials are used for domain-wide delegation operations like managing Workspace user data in Drive, Gmail and Calendar. Note that GAM also has the ability to perform admin actions as a delegated admin service account (DASA). See [instructions for setting up DASA](https://github.com/GAM-team/GAM/wiki/Using-GAM-with-a-delegated-admin-service-account-(DASA)) when DASA is setup, GAM will use the service account to authenticate which can be protected by the YubiKey.
### What if someone physically steals the YubiKey?
The YubiKey can be configured with a PIN that must be entered in order for it to sign data with the private key. GAM stores this PIN string in the oauth2service.json file so it can use it as needed. What this means is that an attacker would need to steal *both* the physical YubiKey and the PIN stored in oauth2service.json. The recommendation is to store oauth2service.json and the rest of the GAM directory on an encrypted partition. The YubiKey itself should also be kept in a secure location.
### Can I require a physical touch of the YubiKey before the private key can be used?
Yes but in practice this does not work very well with GAM. The YubiKey will need to be touched every time there is a GAM command running which for batch or cron jobs may be constant. GAM can use a PIN configured on the YubiKey in order to offer an additional layer of protection.
### If I use a YubiKey, do I need to rotate the private key regularly?
No, because the YubiKey generated the private key it cannot be digitally exported from the YubiKey so there is not chance for it to be copied and stolen. Instead you should physically secure the YubiKey from theft.
### What data does the service account private key have access to?
When using domain-wide delegation with GAM, the service account and anyone possessing the service account private key oauth2service.json file has access to the Gmail, Drive and Calendar data of ALL Workspace users in your domain. For this reason, whether using a YubiKey or not, you should take strong measures to protect the service account private key.
## Setup Steps
1. Upgrade to at least GAM 6.07. Best practice is to always use the [latest version of GAM](https://github.com/GAM-team/GAM).
2. Setup GAM according to the [Quick Start Guide](https://github.com/GAM-team/GAM#quick-start). Once setup you will have a service account created and it's private key credentials in the oauth2service.json file.
3. **If you are using a new YubiKey or don't care about the PIV app data on the YubiKey**
1. Tell GAM to reset and configure the PIV app data on the YubiKey. This wipes all existing keys and config and then configures a private key and PIN for GAM. Run:
```gam yubikey reset_piv```
2. During the PIV reset, GAM will print out a PIN for the private key, record this key.
4. **OR If you are already using the YubiKey and wish to preserve the PIV app data and keys**
1. You need to configure one of the PIV slots for a private key and certificate GAM can use. The full steps here are beyond this guide's scope but might include:
```
ykman piv keys generate -P some_pin --pin-policy ALWAYS --touch-policy NEVER --algorithm RSA2048 9c new_pubkey.txt
ykman piv certificates generate -P some_pin --subject "GAM Service Account" -d 36500 9c new_pubkey.txt
```
5. Now that you have a private key on your YubiKey, tell GAM to use that instead of the private_key stored in oauth2service.json. We can do that by rotating the key:
```
gam rotate sakey yubikey yubikey_pin yubikey_slot AUTHENTICATION
```
The yubikey argument tells GAM to use a private key on a plugged in YubiKey. The yubikey_pin argument tells GAM to prompt you to input the PIN that was set in the previous step. The yubikey_slot argument tells GAM which PIV slot to use on the YubiKey.
6. Now you should be able to run GAM commands like:
```
gam user admin@example.com check serviceaccount
```
and see the YubiKey lights flash as the YubiKey interacts with GAM to sign the GAM authentication requests. If you look at the oauth2service.json file, you'll see it contains some new fields like yubikey_serial and yubikey_pin but no longer contains the private_key field where GAM would normally store the private key data.
7. As a last step, since YubiKey-stored private keys do not need to be and should not be rotated, you can remove the service account's permissions to change it's own key. Navigate to the [Cloud Console](https://console.cloud.google.com/iam-admin/serviceaccounts) select the correct project and service account and on the Permissions tab, edit and remove the "Service Account Key Admin" permission that the service account has to itself.