Securing targets for configurable proxies

Stay organized with collections Save and categorize content based on your preferences.

You're viewing Apigee X documentation.
View Apigee Edge documentation.

This topic explains how to configure Google authentication for Apigee Configurable API proxies. With this feature, configurable API proxy developers can secure their Google backend services using Google OAuth and automatically grant access to authorized API consumers. This offers the advantage of seamless integration with other Google services, without requiring API producers to manage private keys.

ConfigurablePREVIEW API proxy development is available only to customers with Apigee paid Subscription orgs. Apigee customers with Pay-as-you-go orgs can create programmable API proxies.

Authenticating with Google services

Apigee supports using Google OAuth tokens or OpenID Connect (OIDC) ID tokens to authenticate with Google services, such as Cloud Logging and Secret Manager, and custom services running on certain Google Cloud products, such as Cloud Functions and Cloud Run.

To configure this functionality in configurable API proxies, a service account is attached at the proxy or operation level in the proxy.yaml. When API consumers call the API with suitable credentials, such as a valid API key, the configurable proxy impersonates the specified service account and injects the necessary credentials to forward the request to the upstream target.

Detailed steps for configuring programmable API proxies to use Google authentication are available in Using Google authentication.

Required permissions

As with programmable proxy deployments, users deploying configurable proxies must have permission to act as the service account specified for use with the proxies. This requires that the user have the Service Account User role. More details regarding the required service account permissions can be found in Using Google authentication.

To give the user who will do the deployment (the deployer) the iam.serviceAccounts.actAs permission on the service account, use the following command:

gcloud iam service-accounts add-iam-policy-binding \
  SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
  --member="MEMBER" \
  --role="roles/iam.serviceAccountUser"

Where:

  • SA_NAME is the name you provided when you created the service account.
  • PROJECT_ID is the project ID. This ID should match your organization name.
  • MEMBER is the name of the user granted the permission, in the form user|group|serviceAccount:email or domain:domain.

The service account specified in the configurable proxy must also have the appropriate roles and permissions required to access the Google services. For example, a service account used to generate an OIDC ID token to invoke a Cloud Function must have the Cloud Functions Invoker role (roles/cloudfunctions.invoker). Similarly, the service account used by a configurable proxy to get a Google OAuth access token to access Google APIs must have sufficient permissions to access the API target.

Using service accounts in archive deployments

Configurable proxies utilize Apigee's archive deployment mode. For archive deployments, the service account used for the proxy is specified in the deployments.json file, as shown in the example below:

#deployments.json
{
  "proxies" : [
    {
      "name": "helloworld",
      "serviceAccountName": "foo@bar.iam.gserviceaccount.com"
    },
    {
      "name": "mocktarget"
    }
  ]
}

Service account configuration

The target section of the proxy configuration is used to define how the specified service account is used. However, as with other sections in the proxy.yaml, the proxy's target configuration can be overridden at the operation level.

There are two methods for using the service account for authentication to Google services:

  1. Use the service account to generate Google OAuth tokens for access to Google APIs.
  2. Use the service account to generate OIDC ID Tokens for authenticated access to Google backends, such as Cloud Functions.

These two methods are mutually exclusive; that is, they cannot both be used at the proxy level in the same proxy configuration. It is possible to use an alternate method at the operation level to override the default authentication method for specific operations. Examples for each method, including the use of an override, are provided in the sections below.

Service account generation of Google OAuth access tokens

In the example below, the target section of the proxy.yaml is used to describe the use of the service account to generate a Google OAuth access token:

#proxy.yaml
basepath: "/helloworld"

target: #
    uri: http://mocktarget.apigee.net
    service_account_authentication:
      access_token: # GOOGLE_OAUTH_ACCESS_TOKEN
        scopes:
        - https://www.googleapis.com/auth/cloud-platform

In this example, the target section includes the following fields:

  • uri: Specifies the URL of the backend service.
  • access_token: Specifies the value of the Google OAuth access token.
  • scopes: Specifies the scopes to be included in the Google OAuth access token. If no scope is specified, it will default to one scope: https://www.googleapis.com/auth/cloud-platform. See OAuth 2.0 Scopes for Google APIs for more information.

Service account generation of OIDC ID tokens

In the next example, the target section of the proxy.yaml is used to describe the use of the service account to generate a OIDC ID token:

#proxy.yaml
basepath: "/helloworld"

target:
  uri: https://mocktarget.apigee.net
  service_account_authentication:
    id_token: # OIDC_ID_TOKEN
      audience: mock
      include_email: true

In this example, the target section includes the following fields:

  • uri: Specifies the URL of the backend service.
  • id_token: Specifies the value of the OIDC ID token.
  • audience: Required. Specifies the full URL of the audience for the token, such as the API or account to which this account grants access.
  • include_email: Specifies whether or not include the service account email in the token. If set to true, the token will contain the email and email_verified claims.

Service account authentication override

In this example, the target section of the proxy.yaml is used to describe the use of the service account to generate an OIDC ID token, but also includes an operation-level target section that specifies the use of the service account to generate a Google OAuth access token for the help operation.

#proxy.yaml
basepath: "/helloworld"

target:
  uri: https://mocktarget.apigee.net
  service_account_authentication:
    id_token: # OIDC_ID_TOKEN
      audience: mock
      include_email: true

operations:  # First match wins
- id: help
  http_match:
  - path_template: "/help"
    method: GET
  target: # This section overrides what is defined at the proxy level.
    uri: http://mocktarget.apigee.net
    service_account_authentication:
      access_token: # GOOGLE_OAUTH_ACCESS_TOKEN
        scopes:
        - https://www.googleapis.com/auth/cloud-platform

Troubleshooting

During this request flow to fetch credentials, the original value of the Authorization header, if any, is placed in the X-Forwarded-Authorization header. The target backend service should look at this header to retrieve the original end user credentials, when service account authentication is used in the proxy

Check for configuration errors

There are a number of reasons why your configurable proxy may fail to deploy when implementing Google authentication. To help determine the cause of the failure, you can check the operation status with the following command:

$ gcloud alpha apigee operations describe OPERATION_ID

In the command above, OPERATION_ID is the ID of the long-running operation.

For example:

$ gcloud alpha apigee operations describe b64c2665-b5ac-43cc-9e2d-232e8895c2ed

You should receive output similar to the following, with the any error message in the response listed:

Using Apigee organization 'myorg'
done: true
metadata:
  '@type': type.googleapis.com/google.cloud.apigee.v1.OperationMetadata
  operationType: INSERT
  state: FINISHED
  targetResourceName: /organizations/{org}/environments/{env}/archiveDeployments/{archive}
name: organizations/myorg/operations/b64c2665-b5ac-43cc-9e2d-232e8895c2ed
organization: myorg
response:
error:
  code: 3
  message: …
  status: INVALID_ARGUMENT
uuid: b64c2665-b5ac-43cc-9e2d-232e8895c2ed

Common errors and responses

Examples of a few common configuration errors and their corresponding error messages are described below.

Service account unauthorized or unauthenticated

If the service account identified in the proxy.yaml is not authorized or authenticated to the backend, calls to the API may result in a 401 or 403 response code.

Service account unspecified while attempting to target authentication

In this example configuration, target authentication is specified at the proxy level, but no service account is provided in the deployments.json:

#proxy.yaml for proxy mocktarget
basepath: "/helloworld"

target:
  uri: https://mocktarget.apigee.net
  service_account_authentication:
    id_token: # mutually exclusive with access_token
      audience: mock
      include_email: true
#deployments.json
{
  [
    {
      "name": "mocktarget"
    }
  ]
}

On deployment, the following error message is received:

...
error:
  code: 3 # INVALID_ARGUMENT
  generic::invalid_argument: failed to validate proxy: invalid proxy "mocktarget": a service account identity is required,
  but none was provided in src/main/apigee/environments/my-env/deployments.json
...

Invalid target authentication configuration

In this example configuration, the audience field contains an invalid URI:

#proxy.yaml for proxy mocktarget
basepath: "/helloworld"

target:
  uri: https://mocktarget.apigee.net
  service_account_authentication:
    id_token: # mutually exclusive with access_token
      audience: https://{invalid-uri}
      include_email: true
#deployments.json
{
  [
    {
      "name": "mocktarget",
      "serviceAccountName": "foo@bar.iam.gserviceaccount.com"
    }
  ]
}

On deployment, the following error message is received:

...
error:
  code: 3 # INVALID_ARGUMENT
  message: generic::invalid_argument: failed to validate proxy: file:config.yaml line:8 column:17 invalid ID token audience "https://{invalid-uri}": parse "https://{invalid-uri}": invalid character "{" in host name
...