In March of this year, the Istio community announced deprecation for Istio Mixer. The Istio Mixer component is critical for the functioning of this project, so we took the opportunity to rethink and redesign the Istio Adapter to rely only on native Envoy filters for even more flexible deployment of Apigee-integrated authorization, global quota, and analytics.
Apigee announced a beta release of the newly-created Apigee Adapter for Envoy in the blog post Announcing API management for services that use Envoy.
We're also pleased that these features will remain open source:
- https://github.com/apigee/apigee-remote-service-envoy
- https://github.com/apigee/apigee-remote-service-cli
- https://github.com/apigee/apigee-remote-service-golib
Please migrate to the Apigee Adapter for Envoy as soon as possible. For more information, please contact Apigee support.
This is the source repository for Apigee's Istio Mixer Adapter. This allows users of Istio to incorporate Apigee Authentication, Authorization, and Analytics policies to protect and report through the Apigee UI.
A Quick Start Tutorial continues below, but complete Apigee documentation on the concepts and usage of this adapter is also available on the Apigee Adapter for Istio site.
You must have an Apigee Edge account. If needed, you may create one here.
Choose your favorite way of installing Istio.
Important
A key feature of the Apigee adapter that we'll be exploring below is to automatically enforce Apigee policy in Istio
using Istio's Mixer. However, starting in Istio 1.1, policy is not enabled by default. For Apigee policy features to take
effect, policy control must be explicitly enabled in Istio config and the Mixer policy image must be running. See
Enabling Policy Enforcement for more details.
Istio Mixer Adapter releases can be found here.
Download the appropriate release package for your operating system and Istio version and extract it. You should a top-level list similar to:
LICENSE
README.md
samples/
apigee-istio
apigee-istio
(or apigee-istio.exe on Windows) is the Command Line Interface (CLI) for this project.
Add it to your PATH for quick access - or remember to specify the path for the commands below.
The files in the samples/ directory contain sample configuration for Istio and the adapter.
The first thing you'll need to do is provision your Apigee environment to work with the Istio adapter. The provision
command will install a proxy into Apigee if necessary, set up a certificate on Apigee, and generate some credentials the
Adapter will use to securely connect back to Apigee.
Upgrading
By default, running provision
will not attempt to install a new proxy into Apigee if one already exists. If
you are upgrading from a prior release, add the --forceProxyInstall
option to the commands below to ensure that the
latest Apigee proxy is installed for your organization.
OPDK
If you are running Apigee Private Cloud (OPDK), you'll need to also specify your private server's --managementBase
and --routerBase
options in the command. The URIs must be reachable from your Istio mesh.
Credentials
apigee-istio
will automatically pick up the username and password from a
.netrc file in your home directory (or where you specify with the --netrc
option) if you have an entry for machine api.enterprise.apigee.com
(or the host you specified for OPDK).
To create an Istio handler file, run the following:
apigee-istio provision -u {username} -p {password} -o {organization} -e {environment} > samples/apigee/handler.yaml
Once it completes, check your samples/apigee/handler.yaml
file. It should look similar to this:
# Istio handler configuration for Apigee gRPC adapter for Mixer
apiVersion: config.istio.io/v1alpha2
kind: handler
metadata:
name: apigee-handler
namespace: istio-system
spec:
adapter: apigee
connection:
address: apigee-adapter:5000
params:
apigee_base: https://istioservices.apigee.net/edgemicro
customer_base: https://myorg-env.apigee.net/istio-auth
org_name: myorg
env_name: myenv
key: 06a40b65005d03ea24c0d53de69ab795590b0c332526e97fed549471bdea00b9
secret: 93550179f344150c6474956994e0943b3e93a3c90c64035f378dc05c98389633
Istio adapters are run in a separate process from Mixer and Mixer will connect to the adapter
via gRPC to the address specified in the connection.address
property in the Apigee adapter handler config. This
address must be reachable by the Mixer processes in the Istio mesh. If you deploy the adapter to a location other than
the default, just change the connection.address
value as appropriate.
Next, we'll install a simple Hello World service into the Istio mesh as a target. From your Istio directory:
kubectl label namespace default istio-injection=enabled
kubectl apply -f samples/helloworld/helloworld.yaml
You'll also need to add the gateway to reach it from outside the mesh:
kubectl apply -f samples/helloworld/helloworld-gateway.yaml
You should be able to verify two helloworld
instances are running:
kubectl get pods
And you should be able to access the service successfully:
curl http://${GATEWAY_URL}/hello
Note: If you don't know your GATEWAY_URL, you'll need to follow these instructions to set the INGRESS_IP and INGRESS_PORT variables. Then, your GATEWAY_URL can be set with:
export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
Now it's time to install Apigee policy onto Istio.
kubectl apply -f samples/apigee/adapter.yaml
kubectl apply -f samples/apigee/definitions.yaml
kubectl apply -f samples/apigee/handler.yaml
kubectl apply -f samples/apigee/rule.yaml
Istio should now be fully configured for Apigee control - and you should no longer be able to access your target
helloworld
service without authentication. If you curl it:
curl http://${GATEWAY_URL}/hello
You should receive a permission denied error:
PERMISSION_DENIED:apigee-handler.apigee.istio-system:missing authentication
The service is now protected by Apigee. Great! But now you've locked yourself out without a key. If only you had credentials. Let's fix that.
Debugging
If you're certain you've applied everything correctly up to this point but are still able to reach the target service,
please check the Github wiki for troubleshooting tips.
Policy is defined by Apigee API Products and enforced by the Apigee Adapter. Let's create an API Product, Developer, and App to see how this works.
- Create an API Product in your Apigee organization:
- Give the
API Product
definition a name (helloworld
is fine). - Select your environment(s).
- Set the Quota to
5
requests every1
minute
. - Add a Path with the
+Custom Resource
button. Set the path to/
. - Add the service name
helloworld.default.svc.cluster.local
toIstio Services
. - Save
(Note: You can also use the apigee-istio bindings
command to control Istio service bindings.)
-
Create a Developer. Use any values you wish. Be creative!
-
Create an App to grant your Developer access to your API Product:
- Give your
App
a name (helloworld
is fine). - Select the
Developer
you just created above. - Add your
API Product
with the+Product
button. - Save
Still on the App
page, you should now see a Credentials
section. Click the Show
button
under the Consumer Key
heading. That's your API Key. Your Developer includes this key in requests to Apigee to
establish his or her identify. Copy that key!
Now you can access your target service by passing the key you received above by including it in the x-api-key
header:
curl http://${GATEWAY_URL}/hello -H "x-api-key: {your consumer key}"
The call should now be successful. You're back in business and your authentication policy works!
Note
There may be some latency in configuration. The API Product information refreshes from Apigee
every two minutes. In addition, configuration changes you make to Istio will take a few moments to
be propagated throughout the mesh. During this time, you could see inconsistent behavior as it takes
effect.
Remember that API Product Quota you set limiting requests from Developer to 5 requests per minute? Let's max it out.
Make the same authenticated request you did above a few more times:
curl http://${GATEWAY_URL}/hello -H "x-api-key: {your consumer key}"
If you're in a Unix shell, you can use repeat:
repeat 10 curl http://${GATEWAY_URL}/hello -H "x-api-key: {your consumer key}"
Either way, you should see some successful calls... followed by failures like this:
RESOURCE_EXHAUSTED:apigee-handler.apigee.istio-system:quota exceeded
Note
Did you see mixed successes and failures? That's OK. The Quota system is designed to have
very low latency for your requests, so it uses a cache that is eventually consistent with
the remote server. Client requests don't wait for the server to respond and you could have
inconsistent results for a second or two, but it will be worked out quickly and no clients
have to wait in the meantime.
We don't always want to hand out API Keys to developers, they don't expire and require a call to the server to validate. Let's look at using a JWT Token instead.
Update the samples/apigee/authentication-policy.yaml
file to set correct URLs for your environment. The hostname
and ports for these URLs should mirror what you used for customer_base
config above (adjust as appropriate
if you're using OPDK).
peers:
# - mtls: # uncomment if you're using mTLS between services in your mesh
origins:
- jwt:
issuer: https://{your organization}-{your environment}.apigee.net/istio-auth/token
jwks_uri: https://{your organization}-{your environment}.apigee.net/istio-auth/certs
Important
The mTLS authentication settings for your mesh and your authentication policy must match. In other words,
if you set up Istio to use mTLS connections, you must enable mTLS by uncommenting the mTLS the mtls
line in the
authentication-policy.yaml file. (If the policies do not match, you will see errors similar to: upstream connect error or disconnect/reset before headers
.)
Save your changes and apply your Istio authentication policy:
kubectl apply -f samples/apigee/authentication-policy.yaml
Now, calls to helloworld
- even with the API Key:
curl http://${GATEWAY_URL}/hello -H "x-api-key: {your consumer key}"
Should receive an auth error similar to:
Origin authentication failed.
We need a JWT token to succeed. We can use apigee-istio
to get a JWT token:
apigee-istio token create -o {your organization} -e {your environment} -i {your key} -s {your secret}
Or, you can do it yourself through the API:
curl https://{your organization}-{your environment}.apigee.net/istio-auth/token -d '{ "client_id":"your key", "client_secret":"your secret", "grant_type":"client_credentials" }' -H "Content-Type: application/json"
Now, try again with your newly minted JWT token:
curl http://${GATEWAY_URL}/hello -H "Authorization: Bearer {your jwt token}"
This call should now be successful.
One more thing: Let's head back to the Apigee Edge UI.
Click the Analyze
in the menu on the left and check out some of the nifty analytics information on your requests!