Chapter 4. 3scale adapter
4.1. Using the 3scale Istio adapter
The 3scale Istio Adapter is an optional adapter that allows you to label a service running within the Red Hat OpenShift Service Mesh and integrate that service with the 3scale API Management solution. It is not required for Red Hat OpenShift Service Mesh.
4.1.1. Integrate the 3scale adapter with Red Hat OpenShift Service Mesh
You can use these examples to configure requests to your services using the 3scale Istio Adapter.
Prerequisites:
- Red Hat OpenShift Service Mesh 0.12.0+
- A working 3scale account (SaaS or 3scale 2.5 On-Premises)
- Red Hat OpenShift Service Mesh prerequisites
- Ensure Mixer policy enforcement is enabled. Update Mixer policy enforcement provides instructions to check the current Mixer policy enforcement status and enable policy enforcement.
To configure the 3scale Istio Adapter, refer to Red Hat OpenShift Service Mesh custom resources for instructions on adding adapter parameters to the custom resource file.
Pay particular attention to the kind: handler
resource. You must update this with your 3scale credentials and the service ID of the API you want to manage.
Modify the handler configuration with your 3scale configuration.
Handler configuration example
apiVersion: "config.istio.io/v1alpha2" kind: handler metadata: name: threescale spec: adapter: threescale params: service_id: "<SERVICE_ID>" system_url: "https://<organization>-admin.3scale.net/" access_token: "<ACCESS_TOKEN>" connection: address: "threescale-istio-adapter:3333"
Optionally, you can provide a backend_url
field within the params section to override the URL provided by the 3scale configuration. This may be useful if the adapter runs on the same cluster as the 3scale on-premise instance, and you wish to leverage the internal cluster DNS.
Modify the rule configuration with your 3scale configuration to dispatch the rule to the threescale handler.
Rule configuration example
apiVersion: "config.istio.io/v1alpha2" kind: rule metadata: name: threescale spec: match: destination.labels["service-mesh.3scale.net"] == "true" actions: - handler: threescale.handler instances: - threescale-authorization.instance
4.1.1.1. Generating 3scale custom resources
The adapter includes a tool that allows you to generate the handler
, instance
, and rule
custom resources.
Option | Description | Required | Default value |
---|---|---|---|
| Produces help output for available options | No | |
| Unique name for this URL, token pair | Yes | |
| Namespace to generate templates | No | istio-system |
| 3scale access token | Yes | |
| 3scale Admin Portal URL | Yes | |
| 3scale backend URL. If set, it overrides the value that is read from system configuration | No | |
| 3scale API/Service ID | No | |
| 3scale authentication pattern to specify (1=Api Key, 2=App Id/App Key, 3=OIDC) | No | Hybrid |
| File to save produced manifests to | No | Standard output |
| Outputs the CLI version and exits immediately | No |
4.1.1.1.1. Generate templates from URL examples
This example generates templates allowing the token, URL pair to be shared by multiple services as a single handler:
$ 3scale-gen-config --name=admin-credentials --url="https://<organization>-admin.3scale.net:443" --token="[redacted]"
This example generates the templates with the service ID embedded in the handler:
$ 3scale-gen-config --url="https://<organization>-admin.3scale.net" --name="my-unique-id" --service="123456789" --token="[redacted]"
4.1.1.2. Generating manifests from a deployed adapter
Run this command to generate manifests from a deployed adapter in the
istio-system
namespace:$ export NS="istio-system" URL="https://replaceme-admin.3scale.net:443" NAME="name" TOKEN="token" oc exec -n ${NS} $(oc get po -n ${NS} -o jsonpath='{.items[?(@.metadata.labels.app=="3scale-istio-adapter")].metadata.name}') \ -it -- ./3scale-config-gen \ --url ${URL} --name ${NAME} --token ${TOKEN} -n ${NS}
-
This will produce sample output to the terminal. Edit these samples if required and create the objects using the
oc create
command. When the request reaches the adapter, the adapter needs to know how the service maps to an API on 3scale. You can provide this information in two ways:
- Label the workload (recommended)
-
Hard code the handler as
service_id
Update the workload with the required annotations:
NoteYou only need to update the service ID provided in this example if it is not already embedded in the handler. The setting in the handler takes precedence.
$ export CREDENTIALS_NAME="replace-me" export SERVICE_ID="replace-me" export DEPLOYMENT="replace-me" patch="$(oc get deployment "${DEPLOYMENT}" patch="$(oc get deployment "${DEPLOYMENT}" --template='{"spec":{"template":{"metadata":{"labels":{ {{ range $k,$v := .spec.template.metadata.labels }}"{{ $k }}":"{{ $v }}",{{ end }}"service-mesh.3scale.net/service-id":"'"${SERVICE_ID}"'","service-mesh.3scale.net/credentials":"'"${CREDENTIALS_NAME}"'"}}}}}' )" oc patch deployment "${DEPLOYMENT}" --patch ''"${patch}"''
4.1.1.3. Routing service traffic through the adapter
Follow these steps to drive traffic for your service through the 3scale adapter.
Prerequisites
- Credentials and service ID from your 3scale administrator.
Procedure
-
Match the rule
destination.labels["service-mesh.3scale.net/credentials"] == "threescale"
that you previously created in the configuration, in thekind: rule
resource. -
Add the above label to
PodTemplateSpec
on the Deployment of the target workload to integrate a service. the value,threescale
, refers to the name of the generated handler. This handler stores the access token required to call 3scale. -
Add the
destination.labels["service-mesh.3scale.net/service-id"] == "replace-me"
label to the workload to pass the service ID to the adapter via the instance at request time.
4.1.2. Configure the integration settings in 3scale
Follow this procedure to configure the 3scale integration settings.
For 3scale SaaS customers, Red Hat OpenShift Service Mesh is enabled as part of the Early Access program.
Procedure
-
Navigate to [your_API_name]
Integration Configuration. - At the top of the Integration page click on edit integration settings in the top right corner.
- Under the Service Mesh heading, click the Istio option.
- Scroll to the bottom of the page and click Update Service.
4.1.3. Caching behavior
Responses from 3scale System APIs are cached by default within the adapter. Entries will be purged from the cache when they become older than the cacheTTLSeconds
value. Also by default, automatic refreshing of cached entries will be attempted seconds before they expire, based on the cacheRefreshSeconds
value. You can disable automatic refreshing by setting this value higher than the cacheTTLSeconds
value.
Caching can be disabled entirely by setting cacheEntriesMax
to a non-positive value.
By using the refreshing process, cached values whose hosts become unreachable will be retried before eventually being purged when past their expiry.
4.1.4. Authenticating requests
This release supports the following authentication methods:
- Standard API Keys: single randomized strings or hashes acting as an identifier and a secret token.
- Application identifier and key pairs: immutable identifier and mutable secret key strings.
- OpenID authentication method: client ID string parsed from the JSON Web Token.
4.1.4.1. Applying authentication patterns
Modify the instance
custom resource, as illustrated in the following authentication method examples, to configure authentication behavior. You can accept the authentication credentials from:
- Request headers
- Request parameters
- Both request headers and query parameters
When specifying values from headers, they must be lower case. For example, if you want to send a header as User-Key
, this must be referenced in the configuration as request.headers["user-key"]
.
4.1.4.1.1. API key authentication method
Service Mesh looks for the API key in query parameters and request headers as specified in the user
option in the subject
custom resource parameter. It checks the values in the order given in the custom resource file. You can restrict the search for the API key to either query parameters or request headers by omitting the unwanted option.
In this example, Service Mesh looks for the API key in the user_key
query parameter. If the API key is not in the query parameter, Service Mesh then checks the user-key
header.
API key authentication method example
apiVersion: "config.istio.io/v1alpha2" kind: instance metadata: name: threescale-authorization namespace: istio-system spec: template: authorization params: subject: user: request.query_params["user_key"] | request.headers["user-key"] | "" action: path: request.url_path method: request.method | "get"
If you want the adapter to examine a different query parameter or request header, change the name as appropriate. For example, to check for the API key in a query parameter named “key”, change request.query_params["user_key"]
to request.query_params["key"]
.
4.1.4.1.2. Application ID and application key pair authentication method
Service Mesh looks for the application ID and application key in query parameters and request headers, as specified in the properties
option in the subject
custom resource parameter. The application key is optional. It checks the values in the order given in the custom resource file. You can restrict the search for the credentials to either query parameters or request headers by not including the unwanted option.
In this example, Service Mesh looks for the application ID and application key in the query parameters first, moving on to the request headers if needed.
Application ID and application key pair authentication method example
apiVersion: "config.istio.io/v1alpha2" kind: instance metadata: name: threescale-authorization namespace: istio-system spec: template: authorization params: subject: app_id: request.query_params["app_id"] | request.headers["app-id"] | "" app_key: request.query_params["app_key"] | request.headers["app-key"] | "" action: path: request.url_path method: request.method | "get"
If you want the adapter to examine a different query parameter or request header, change the name as appropriate. For example, to check for the application ID in a query parameter named identification
, change request.query_params["app_id"]
to request.query_params["identification"]
.
4.1.4.1.3. OpenID authentication method
To use the OpenID Connect (OIDC) authentication method, use the properties
value on the subject
field to set client_id
, and optionally app_key
.
You can manipulate this object using the methods described previously. In the example configuration shown below, the client identifier (application ID) is parsed from the JSON Web Token (JWT) under the label azp. You can modify this as needed.
OpenID authentication method example
apiVersion: "config.istio.io/v1alpha2" kind: instance metadata: name: threescale-authorization spec: template: threescale-authorization params: Subject: properties: app_key: request.query_params["app_key"] | request.headers["app-key"] | "" client_id: request.auth.claims["azp"] | "" action: path: request.url_path method: request.method | "get" service: destination.labels["service-mesh.3scale.net/service-id"] | ""
For this integration to work correctly, OIDC must still be done in 3scale for the client to be created in the identity provider (IdP). You should create end-user authentication for the service you want to protect in the same namespace as that service. The JWT is passed in the Authorization
header of the request.
In the sample Policy
defined below, replace issuer
and jwksUri
as appropriate.
OpenID Policy example
apiVersion: authentication.istio.io/v1alpha1 kind: Policy metadata: name: jwt-example namespace: bookinfo spec: origins: - jwt: issuer: >- http://keycloak-keycloak.34.242.107.254.nip.io/auth/realms/3scale-keycloak jwksUri: >- http://keycloak-keycloak.34.242.107.254.nip.io/auth/realms/3scale-keycloak/protocol/openid-connect/certs principalBinding: USE_ORIGIN targets: - name: productpage
4.1.4.1.4. Hybrid authentication method
You can choose to not enforce a particular authentication method and accept any valid credentials for either method. If both an API key and an application ID/application key pair are provided, Service Mesh uses the API key.
In this example, Service Mesh checks for an API key in the query parameters, then the request headers. If there is no API key, it then checks for an application ID and key in the query parameters, then the request headers.
Hybrid authentication method example
apiVersion: "config.istio.io/v1alpha2" kind: instance metadata: name: threescale-authorization spec: template: authorization params: subject: user: request.query_params["user_key"] | request.headers["user-key"] | properties: app_id: request.query_params["app_id"] | request.headers["app-id"] | "" app_key: request.query_params["app_key"] | request.headers["app-key"] | "" client_id: request.auth.claims["azp"] | "" action: path: request.url_path method: request.method | "get" service: destination.labels["service-mesh.3scale.net/service-id"] | ""
4.1.5. 3scale Adapter metrics
The adapter, by default reports various Prometheus metrics that are exposed on port 8080
at the /metrics
endpoint. These metrics provide insight into how the interactions between the adapter and 3scale are performing. The service is labeled to be automatically discovered and scraped by Prometheus.