Skip to content

Change Terraform over to the new authn-gcp conjur authenticator #15

Description

@cmm-cisco
  • Make sure gcp-hackers has permissions to use it

How To Use The Conjur GCP Authenticator

The GCP authenticator
is a secure method for workloads running on the Google Cloud Platform to
authenticate to Conjur using a unique short-term
identity token,
not an access token, signed for a Google Service Account.

Note

Only Google Service Accounts are supported by this authenticator. It cannot be
used directly by users. You absolutely can impersonate an authorized
service account, with the GCP authenticator provided you have adequate
IAM permissions. This is discussed later.

What is the difference between a Google identity token and an access token?

The easiest way to keep them straight is to remember that one is a ID card
and the other is a Master Key. In Google Cloud, mixing these up is the most
common cause of "401 Unauthorized" or "403 Forbidden" errors. Here is the
breakdown of how they differ and exactly when to use each.

Differences Between Identity Tokens and Access Tokens

Feature Identity Token (ID Token) Access Token
Protocol OpenID Connect (OIDC) OAuth 2.0
Purpose Authentication: "Who are you?" Authorization: "What are you allowed to do?"
Audience Your application (the "Client") The API or Resource (the "Server")
Format Always a JWT (can be decoded) Usually Opaque (looks like gibberish)
Key Info User’s email, name, and unique ID Scopes (permissions like cloud-platform)

When to use an Identity Token

You use an ID Token when your goal is to prove to a service that you (or
your service account) are a specific identity.

Crucial Rule: If you are trying to "log in" or "hit a service URL," like we're
doing with the Conjur GCP Authenticator, you need an ID Token.

When to use an Access Token

You use an Access Token when you want to call a Google API to perform an
action on a resource (like creating a bucket or starting a VM).

Crucial Rule: If you are calling *.googleapis.com, you almost certainly
need an Access Token.

How They Work Together

In a typical Google Cloud environment, a Service Account often needs to all of
these:

  1. Authentication: The service account provides its credentials to Google’s Auth server.
  2. Issuance: Google sends back an ID Token (to identify the service) and an Access Token (to authorize it to work with Google APIs).

Common Gotcha: "The Wrong Audience" and Workaround

An ID Token contains an aud (audience) claim. If you generate an ID token for
"Service A" but try to use it to call "Service B," Google (or Conjur) will
reject it. The token must be minted specifically for the endpoint you are
calling.

Conjur specifically uses the aud claim to prime the GCP authenticator
to expect a specific host principal to grant access.
The validated service
account E-mail in the token paylod and JWT digital signature must validate, or
access is denied and a 401 HTTP error is returned.

Can I create an identity token for my own user and change the audience claim?

The short answer is: No, not directly through the standard Google OAuth 2.0
flow.

If you are using a standard User Account (your @cisco.com,
.web@cisco.com web admin account, .gen@cisco.com generic account)
and performing a typical "Login with Google" flow, Google sets the
aud (audience) to your OAuth 2.0 Client ID. You cannot manually change
this to a custom URL during the standard authorization request.

However, there is a workaround used by developers when they need a user to call
a protected Google Cloud service. That workaround is to impersonate a service
account
.

Why This Limitation Exists

Identity tokens for users are designed for Authentication to an application.
When you create a Client ID in the Google Cloud Console, Google assumes that
that specific application is the audience. Allowing a user to arbitrarily set
the audience would create a security risk called
Token Substitution,
where a malicious site could trick you into signing a token meant for a sensitive
backend service.

The Workaround: Service Account Impersonation

If you are a developer and you need to get an ID token with a specific aud
(like as used for the Conjur GCP Authenticator) while logged in as yourself, you
must impersonate a Service Account.

How to impersonate via gcloud CLI

You can use the gcloud tool to tell Google: "I am [user], but please act as
[service-account] and generate an ID token for [audience]."

gcloud auth print-identity-token \
    --impersonate-service-account="my-service-account@my-project-id.iam.gserviceaccount.com" \
    --audiences="my-audience"

How to retrieve an identity token via cURL

curl -s -X POST \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json; charset=utf-8" \
  --data '{"audience":"my-audience","includeEmail": "true"}' \
  "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/my-service-account@my-project-id.iam.gserviceaccount.com:generateIdToken" |
    jq -r .token

Requirements for this to work:

  1. IAM Role: Your user account must have the roles/iam.serviceAccountTokenCreator
    (or roles/serviceAccountOpenIdTokenCreator) role on that specific service account.
  2. API Enabled: The Service Account Credentials API
    (iamcredentials.googleapis.com) must be enabled in your current project.

To allow a user to impersonate a service account, you must grant them specific
roles on the service account resource itself (or at the project level,
though the service account level follows the principle of least privilege).

Required IAM Roles

Depending on what kind of token you need (as we discussed with Access vs.
Identity tokens), you need one of the following:

Role Name IAM ID Purpose
Service Account Token Creator roles/iam.serviceAccountTokenCreator Most Permissive. Allows the user to generate both OAuth 2.0 access tokens and OIDC identity tokens.
Service Account OpenID Connect Identity Token Creator roles/iam.serviceAccountOpenIdTokenCreator A more restrictive role that only allows creating OIDC identity tokens. Useful to grant authority to create ID tokens without granting access to the service account to make requests of the Google Cloud APIs. Unfortunately, the gcloud CLI needs the broader permissions to impersonate a service account as a user. Using cURL against the API directly doesn't require the broader permissions.

How to Grant the Required IAM Role via CLI

To give yourself permission to impersonate a specific service account, run:

gcloud iam service-accounts add-iam-policy-binding \
    <service-account-email> \
    --member="user:<your-user-id>@cisco.com" \
    --role="roles/iam.serviceAccountTokenCreator"

To verify the change was made:

gcloud iam service-accounts get-iam-policy \
    <service-account-email>

Note

Don't confuse Service Account Token Creators with Service Account Users
There is a common mix-up between Token Creator and Service Account User (roles/iam.serviceAccountUser):

  • Token Creator: Allows you to act as the service account (impersonation).
  • Service Account User: Allows you to attach the service account to a resource (like a VM or a Cloud Run service). It does not let you generate tokens on your local machine.

For Conjur, this format is used for the audience claim:

conjur/<account>/host/<organization>/<namespace-name>/<host-api-principal>

Create a Conjur Access Token

Acting as a Service Account

Putting it all together to swap a GCP service-account identity token for a
Conjur access token and set up the environment:

conjur init -u https://conjur-prod.cisco.com -a cisco --force

export CONJUR_AUTHN_TOKEN=$(curl -s -X POST \
  https://conjur-prod.cisco.com/authn-gcp/cisco/authenticate \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --header 'Accept-Encoding: base64' \
  --data-urlencode "jwt=`gcloud auth print-identity-token \
    --token-format=full \
    --audiences=conjur/cisco/host/sto/asig_le/gcf-by-sa-email`" |
      base64 -d)

conjur whoami
{
  "client_ip": "10.37.64.205",
  "user_agent": "Go-http-client/2.0",
  "account": "cisco",
  "username": "host/sto/asig_le/gcf-by-sa-email",
  "token_issued_at": "2026-03-28T21:37:04.000+00:00"
}

Choose: Secrets Manager Self-Hosted when prompted.

Note

--token-format=full enables inclusion of the email, email_verified and
google objects, which Conjur requires for authentication. It's only used with
Service Accounts. Users impersonating service accounts can't use
--token-format=full. Instead they specify --include-email.

As a Service Account, e.g. running in a GCE instance:

gcloud auth print-identity-token | cut -d '.' -f 2 | base64 -d | jq .
{
  "aud": "32555940559.apps.googleusercontent.com",
  "azp": "102776097938891794166",
  "exp": 1774729480,
  "iat": 1774725880,
  "iss": "https://accounts.google.com",
  "sub": "102776097938891794166"
}
gcloud auth print-identity-token --token-format=full | cut -d '.' -f 2 | base64 -d | jq .
{
  "aud": "32555940559.apps.googleusercontent.com",
  "azp": "102776097938891794166",
  "email": "618440573010-compute@developer.gserviceaccount.com",
  "email_verified": true,
  "exp": 1774729568,
  "google": {
    "compute_engine": {
      "instance_creation_timestamp": 1768105995,
      "instance_id": "2070053074435946989",
      "instance_name": "cmm",
      "project_id": "gcp-asigaurynccigcp-nprd-37319",
      "project_number": 618440573010,
      "zone": "us-east1-c"
    }
  },
  "iat": 1774725968,
  "iss": "https://accounts.google.com",
  "sub": "102776097938891794166"
}

Acting as a User

Swap a GCP user account identity token for a Conjur access token while
impersonating a service account:

conjur init -u https://conjur-prod.cisco.com -a cisco --force

export CONJUR_AUTHN_TOKEN=$(curl -s -X POST \
  https://conjur-prod.cisco.com/authn-gcp/cisco/authenticate \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --header 'Accept-Encoding: base64' \
  --data-urlencode "jwt=`gcloud auth print-identity-token \
    --impersonate-service-account=618440573010-compute@developer.gserviceaccount.com \
    --audiences=conjur/cisco/host/sto/asig_le/gcf-by-sa-email \
    --include-email`" |
      base64 -d)

conjur whoami
{
  "client_ip": "10.26.164.245",
  "user_agent": "Go-http-client/1.1",
  "account": "cisco",
  "username": "host/sto/asig_le/gcf-by-sa-email",
  "token_issued_at": "2026-03-28T21:40:14.000+00:00"
}      

References


Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions