Upstream Authentication

#Upstream GCP Federated Auth Policy

This policy allows you to delegate authentication and authorization to your gateway without writing any code on your origin service by adding an authentication token to outgoing header allowing the service to be secured with GCP IAM.

The tokens are issued using Zuplo's internal OAuth services and exchanged with GCP using Workflow Identity Federation. This allows you to authenticate your Zuplo API to your origin without saving any secrets in Zuplo.

This is a useful means of securing your origin server so that only your Zuplo gateway can make requests against it.

This policy works with GCP Identity Aware Proxy or services like Cloud Run that natively support IAM authorization.

For information on how Google's service based auth works see Authenticating for invocation

Beta

This policy is in beta. You can use it today, but it may change in non-backward compatible ways before the final release.

Enterprise Feature

This policy is only available as part of our enterprise plans. It is free to try only any plan for development only purposes. If you would like to use this in production reach out to us: sales@zuplo.com

#Configuration

The configuration shows how to configure the policy in the 'policies.json' document.

{
  "name": "my-upstream-gcp-federated-auth-inbound-policy",
  "policyType": "upstream-gcp-federated-auth-inbound",
  "handler": {
    "export": "UpstreamGcpFederatedAuthInboundPolicy",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "audience": "https://hello-k7meruiynq-uc.a.run.app",
      "serviceAccountEmail": "zup-api@my-project.iam.gserviceaccount.com",
      "workloadIdentityProvider": "projects/932049231233/locations/global/workloadIdentityPools/my-pool/providers/my-provider"
    }
  }
}
json

#Policy Configuration

  • name <string> - The name of your policy instance. This is used as a reference in your routes.
  • policyType <string> - The identifier of the policy. This is used by the Zuplo UI. Value should be upstream-gcp-federated-auth-inbound.
  • handler.export <string> - The name of the exported type. Value should be UpstreamGcpFederatedAuthInboundPolicy.
  • handler.module <string> - The module containing the policy. Value should be $import(@zuplo/runtime).
  • handler.options <object> - The options for this policy. See Policy Options below.

#Policy Options

The options for this policy are specified below. All properties are optional unless specifically marked as required.

  • audience (required) <string> - The audience for the minted JWT. This is typically the URL of your service. See the document AuthRequirement for details.
  • serviceAccountEmail (required) <string> - The Google Service Account email address.
  • workloadIdentityProvider (required) <string> - No description available.
  • tokenLifetime <number> - The lifetime in seconds of the issued token. Defaults to 3600.
  • tokenRetries <number> - The number of times to retry fetching the token in the event of a failure. Defaults to 3.
  • expirationOffsetSeconds <number> - The number of seconds less than the token expiration to cache the token. Defaults to 300.
  • useMemoryCacheOnly <boolean> - This is an advanced option that should only be used if you do not want to persist information in ZoneCache.

#Using the Policy

Before you can use this policy, you will need to have configured the following:

  • Setup Workload Identity Federation in your GCP project
  • Create a GCP service account with the appropriate permissions.

#Setup GCP Workload Identity Federation

Setting up Workload Identity Federation for Zuplo follows the instructions for setting up a standard OIDC Identity Provider. Refer to Google's Documentation for additional details.

To begin, navigate to the Workload Identity page of Google Cloud Console. You will find this in the IAM section on the menu.

If you don't already have one, create a new Workload Identity Pool. Then create a new provider and select OpenID Connect as the provider type.

Complete the following values in the form:

  • Provider name: Any Value
  • Provider ID: Any Value
  • Issuer (URL): https://dev.zuplo.com/v1/client-auth/auth_o8PUdhKxSTOiB794GWPwLQCD
  • JWK File: Do not set this value, GCP will perform automatic discovery of the OAuth configuration.
  • Audiences: Select "Default Audience"

Copy the URL value for the Default Audience and record it for later use.

Click Continue and set the follow provider attribute mappings.

  • google.subject => "zuplo::" + assertion.account + "::" + assertion.project + "::" + assertion.deployment
  • attributes.account => assertion.account
  • attributes.project => assertion.project
  • attributes.deployment => assertion.deployment

You can read about all the claims in the Zuplo Identity Token documentation.

Set Attribute Conditions

Important Security Step

It is critical that you set at minimum the attribute.account == "my-account" attribute condition. Without this restriction ANY Zuplo API would be able to call your resources.

Set the attribute conditions you want to use to restrict access to this Workload Identity Pool. Generally, you only need to set this to restrict the account. You will use IAM bindings to grant specific permissions in later steps.

To set the account condition set the following value.

attribute.account == "my-account"
plain

If you want to set further conditions, you can do so as desired, for example to restrict access to all environments in a project set the following.

attribute.account == "my-account" && attribute.project == "my-project"
txt

#Create a Service Account

You Zuplo Identity Token will be granted access to act as if it where a service account in your Google project. As such, you will need to create a service account.

You can do so in the Google console or using the Google CLI:

gcloud iam service-accounts create zuplo-api \
  –-description="zuplo api sa"  \
  –-display-name="zuplo-api"
shell

Next you need to create role binding for the Zuplo principal to impersonate the service account:

  • SERVICE_ACCOUNT_EMAIL is the email address of the service account.
  • PROJECT_NUMBER is your numeric Google project number.
  • POOL_ID is the id of the Workload Identity Pool you created earlier, for example zuplo-pool.
  • SUBJECT is the same the concatenated value we set to the value of google.subject earlier. For example, zuplo::my-account::my-project::my-deployment-1235
gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT_EMAIL \
    --role roles/iam.workloadIdentityUser \
    --member "principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/subject/$SUBJECT
shell

Finally, grant your service account the permissions desired. For example, to invoke Cloud Run services grant the roles/run.invoker

  • SERVICE_ACCOUNT_EMAIL is the email address of the service account.
  • SERVICE_NAME is the name of your Cloud Run service.
gcloud run services add-iam-policy-binding $SERVICE_NAME
  --member-"serviceAccount:$SERVICE_ACCOUNT_EMAIL" \
  --role="roles/run.invoker"
shell

#Set the Policy Options

With GCP Workload Federation setup, you can add the policy to your Zuplo API.

  • audience: Set this to the resource you are planning to call, for example, the Cloud Run URL.
  • serviceAccountEmail - Set this value to the email address of the service account previously created.
  • workloadIdentityProvider - Set this to the value that was copied when setting up your Workload Identity Pool (called Default Audience). Remove the beginning https://iam.googleapis.com/ part of the string.
{
  "name": "gcp-federated-auth",
  "policyType": "upstream-gcp-federated-auth-inbound-policy",
  "handler": {
    "module": "$import(@zuplo/runtime)",
    "export": "UpstreamGcpFederatedAuthInboundPolicy",
    "options": {
      "audience": "https://test-basic-vhpkl3cvtq-uc.a.run.app",
      "serviceAccountEmail": "zup-api@my-project.iam.gserviceaccount.com",
      "workloadIdentityProvider": "projects/932049231233/locations/global/workloadIdentityPools/my-pool/providers/my-provider"
    }
  }
}
json

Read more about how policies work