Protecting APIs on Apigee X Gateway
Learn how to discover, integrate and protect your APIs deployed behind the Apigee X Gateway. In this article, you will create an Apigee X Authorizer in SecureAuth, integrate it with SecureAuth, and configure your Apigee X Gateway.
Prerequisites
Docker and Docker Compose
Access to an SecureAuth tenant
Apigee X account with an active organization
Google Cloud Platform (GCP) access
An organization added to GCP
Privileges necessary to get an authentication key in GCP's Services Accounts
Integrate Apigee X Authorizer with Apigee X GW
Create Apigee X gateway
Log in to your SecureAuth tenant.
Open your authorization server (workspace).
Go to Authorization > Gateways.
Select Create Gateway. A list of available gateways appears.
Select Apigee X. Provide the name and description.
Optionally, enable the Create and bind services automatically check box.
Tip
When enabled, all services protected by your Apigee X instance are discovered and added to the SecureAuth service list automatically when the Apigee authorizer is connected to SecureAuth. Otherwise, you need to add them manually.
Download the authorizer's package from the Quickstart instruction.
Integrate SecureAuth and Apigee X Authorizer
In GCP service accounts for your project, create a new key that you will use for authenticating your authorizer to your Google Cloud organization.
The key should be in the JSON format.
Unzip the package and open the
docker-compose.yaml
file.Move the key that you have created in the first step to your authorizer's directory.
Edit the
docker-compose.yaml
file for your authorizer.Tip
The
APIGEE.ACP_RELOAD_INTERVAL
configuration parameter defines how often SecureAuth tries to discover APIs on your gateway.Add the
GOOGLE_APPLICATION_CREDENTIALS
environment variable under theenvironment
node. The value of your variable should be a path to the JSON file that contains the authentication key from GCP.For example:
environment: - APIGEE.APIGEE_PRODUCT=ApigeeX - APIGEE.ACP_RELOAD_INTERVAL=5s # for demo purposes only, increase for production! - GOOGLE_APPLICATION_CREDENTIALS=/apigee/apigee-integration-sample.json - SHARED_FLOW_PATH=/data/data
Add a
volumes
parameter. For example:volumes: - /Path/To/Your/Authorizer/apigee-x-authorizer:/apigee
volumes
attaches the defined catalog (/Path/To/Your/Authorizer/apigee-x-authorizer
) to your authorizer's docker image and maps it to a catalog that, from now on, exists on your docker image (apigee
). This is the place where your Google Application credentials are stored on your authorizer's docker deployment.Save the
docker-compose.yaml
file once you are done with your changes.
Run the
docker-compose run apigee-authorizer install
command in your terminal.When you run the command, a shared Authorizer flow is created automatically for you in your Apigee X instance. The shared flow consists of two policies:
A JavaScript SecureAuth Authorizer Policy that is responsible for communicating with the Apigee X Authorizer and for blocking/allowing the request depending on the Authorizers decision.
An XML Raise Authorization Error policy that is responsible for delivering the error status as the response to the unauthorized call to the protected API.
Run
docker-compose up
. After a short while, Apigee X authorizer should be running.docker-compose up Starting apigee-x-authorizer ... done Attaching to apigee-x-authorizer apigee-x-authorizer | time="2021-09-28T13:55:28Z" level=info msg="starting apigee authorizer" commit=b132c7c version=1.13.0 apigee-x-authorizer | time="2021-09-28T13:55:29Z" level=info msg="apigee-authorizer listening on https://localhost:8442" apigee-x-authorizer | time="2021-09-28T13:55:34Z" level=info msg="Starting authorizer reload..." apigee-x-authorizer | time="2021-09-28T13:55:36Z" level=info msg="Authorization configuration reloaded (1.0898772s)"
Go to Authorization > Gateways > Your Apigee X instance > APIs. You should see a familiar list of services deployed using Apigee X.
Note
If you do not see a list of services deployed on Apigee X, make sure that at least one API Product is defined in your Apigee X organization with a connected API proxy.
If you need to limit the count of discovered APIs, you can configure
product_name_regexp
orenvironment_name_regexp
. Setting it up will limit discovered APIs to matching names.Select Connect > Create new service on a protected API from the list to add it to the list of SecureAuth-protected services. Give this new SecureAuth service a name when prompted.
Your Apigee X-protected API is now on the list of SecureAuth-protected services.
Note
If you selected the Create and bind services automatically option when creating the gateway, your services are bound already.
Deploy your Apigee X authorizer so that it is available publicly.
Tip
So far, you have only deployed your Apigee X authorizer locally using the Docker image provided by SecureAuth. You must expose it publicly as it is needed later on for the integration to work. For testing purposes, you can use tools like, for example, ngrok that expose local servers behind NATs and firewalls to public internet over secure channels.
Configure Apigee X Gateway
With Apigee X Gateway, you can define policies that are Apigee X components that you can attach to different points in the message flow through your API proxies. Such policies can transform the message format, call remote services, and more. To protect your APIs, elevate the integration between SecureAuth and the Apigee X platform. Doing so allows you to enforce access control using Apigee X policies and SecureAuth authorization policies.
In your Apigee X Proxy settings, go to the DEVELOP tab.
In the Navigator > Policies add a policy of the Flow Callout type.
Tip
You can find the Flow Callout policy type under the EXTENSTION tree node.
Provide a name and a display name for your policy.
As a shared flow, use the Authorizer shared flow.
Your policy is created. It is defined with the following XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <FlowCallout async="false" continueOnError="false" enabled="true" name="Flow-Callout"> <DisplayName>Flow Callout</DisplayName> <FaultRules/> <Properties/> <SharedFlowBundle>Authorizer</SharedFlowBundle> </FlowCallout>
Configure your policy so that it points to your Apigee X authorizer's
/authorize
endpoint that you have deployed in the seventh step of the Integrate SecureAuth and Apigee X sectionFor example:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <FlowCallout async="false" continueOnError="false" enabled="true" name="microPerimeter"> <DisplayName>microPerimeter</DisplayName> <FaultRules/> <Properties/> <Parameters> <Parameter name="authorizer_url">https://yourAuthorizerURL/authorize</Parameter> <Parameter name="proxy_body">false</Parameter> </Parameters> <SharedFlowBundle>Authorizer</SharedFlowBundle> </FlowCallout>
proxy_body Parameter
If the
proxy_body
parameter is set totrue
, the shared flow policy proxies the request body to the authorizer and then to the policies. Thanks to that it is possible to create policies that reject requests based on the request body. The request body must be in the JSON format.The
proxy_body
option is disabled by default to make it possible to use bigger-sized request bodies, for example, for image uploads.Add your new policy as a
<step>
element to your Proxy Endpoints PreFlows.For example:
<PreFlow name="PreFlow"> <Request> <Step> <Name>microPerimeter</Name> </Step> </Request> <Response/> </PreFlow>
Note
You have to add your new policy to your Proxy Endpoints PreFlows, as the authorization must take place before the request reaches to target endpoint.
Select Save.
Apply Sample Policy
In SecureAuth, create a policy.
Select Enforcement > APIs.
Select a service protected by the Apigee X authorizer and any API with authorization status Unrestricted.
In the popup window, select a policy from the dropdown list and click Save to proceed.
Result: You have successfully assigned a policy to your API.
Test Integration
To test if your integration was successfull and that your APIs are protected, you can, for example, create a simple SecureAuth or REGO policy that will always pass. Call your protected endpoint and check if the response contains the successfull status. If yes, change your policy so that it blocks APIs. The next request to your protected enpoint should end with the unauthorized access
error.
Apigee X Authorizer Configuration Refrence
For Apigee X Authorizer, it is possible to adjust its configuration. Below you can see an example of how the reference.yaml
file looks like for both authorizers:
# acp acp: reload_interval: 1m0s # reload interval reload_timeout: 30s # reload configuration timeout issuer_url: https://localhost:8443/sample/system # issuer url client_id: bqesdrc4m4co2s81mpu0 # client id client_secret: LH6mAb6PNljvjYMIF-A5RP2bElA5a5bnQah8sG0fsLA # client secret tenant_id: "" # tenant id server_id: "" # server id # http client http_client: timeout: 10s # http client timeout retry_wait_min: 0s # minimum time to wait between retries retry_wait_max: 0s # maximum time to wait between retries retry_max: 0 # maximum number of retries root_ca: "" # root ca that this client should trust (defaults to system root ca) insecure_skip_verify: false # disable cert verification disable_follow_redirects: false # disable follow redirects disable_retry: true # disable retry # metrics metrics: enabled: false # enable metrics endpoint port: 9000 # metrics endpoint port # analytics analytics: enabled: true # when enabled, events are sent to audit log # event format event_format: include_policy_output: false # when enabled, policy evaluation output is sent to audit log # sampling sampling: probability: 1 # Probability of an event to be published (0.0-1.0) batch_inverval: 1s # Max duration to wait for a batch to publish batch_limit: 100 # Max number of events in a batch limit: 5 # Max number of batches per second to be published timeout: 5s # Timeout for a single batch to send workers: 8 # Number of sending workers # cache cache: ttl: 10s # ttl max_size: 100 # max size # logging config logging: level: info # log level severity # token echange config token_exchange: enabled: false # enable token exchange # cache cache: ttl: 1m0s # ttl max_size: 1000 # max size # inject config (supported only for istio authorizer) inject: mode: "" # Defines what token should be sent to the target service when token is exchanged # headers config headers: exchanged_token: "" # Defines the name of the header that contains an exchanged token. original_token: "" # Defines the name of the header that contains an original token. strip_bearer: false # Allows to strip the bearer prefix in headers # enforcement config enforcement: allow_unknown: false # allow requests with no matching rule # http server http_server: port: 8442 # http port dangerous_disable_tls: false # diables TLS # certificate configuration certificate: password: "" # key passphrase cert_path: "" # path to the certificate PEM file key_path: "" # path to the key PEM file cert: "" # base64 encoded cert PEM key: "" # base64 encoded key PEM generated_key_type: ecdsa # type for generated key if cert and key are not provided (rsa or ecda) client_auth_type: 0 # client auth type # apigee apigee: product_name: ApigeeX # oneof ApigeeX or ApigeeEdge shared_flow_path: data # path to a directory with an apigee shared flow definition # service discovery configuration discovery: enabled: true # when true, API discovery is enabled # filters are used for limiting the number of discovered APIs filters: product_name_regexp: "" # filter discovered APIs by Apigee product name (whitelist) environment_name_regexp: "" # filter discovered APIs by Apigee environment name (whitelist) # apigee edge configuration, leave empty in case of ApigeeX apigee_edge: username: "" # username (email address format) password: "" # password organization_id: "" # organization name base_url: https://api.enterprise.apigee.com # URL of Apigee API token_url: https://login.apigee.com/oauth/token # URL of Apigee Authorization API use_token: true # when true, the client exchanges credentials for the token, when false it uses basic auth debug: false # dumps http traffic to Apigee API, useful for debugging connection issues
You can generate a reference configuration for your authorizer using the docker-compose run apigee-authorizer reference
command.
You can use the reference configuration as a basis for your customization. You can omit settings for which the default configuration is satisfactory, specifying only the required values, which are the client ID, client secret, and issuer URL parameters like it is shown in the example below:
environment: - ACP_RELOAD_INTERVAL=5s - APIGEE_APIGEE_PRODUCT=ApigeeEdge - APIGEE_APIGEE_X_USERNAME=username - APIGEE_APIGEE_X_PASSWORD=password - APIGEE_APIGEE_X_ORGANIZATION_ID=org-id
Tip
Note that nested YAML settings can be accessed by joining uppercased names with underscores, as shown in the example above, where the APIGEE_APIGEE_X_PASSWORD=password
parameter is set.
Run Authorizer with Configuration File
Add a
volumes
parameter to yourdocker-compose.yml
file:volumes: - /Path/To/Your/Authorizer/apigee-{your_authorizer_version}-authorizer:/apigee
The
{your_authorizer_version}
variable can be set to eitherx
oredge
.volumes
attaches the defined catalog (/Path/To/Your/Authorizer/apigee-{your_authorizer_version}-authorizer:/apigee
) to your authorizer's docker image and maps it to a catalog that, from now on, exists on your docker image (apigee
). This is the place where your configuration is stored on your authorizer's docker deployment.Use the
--config
option to specify the YAML file with your configuration. For example, assuming that you have created aapigee_edge_config.yaml
file in your current directory, yourdocker run
command would look like the following:docker-compose run apigee-authorizer --config=/apigee/apigee_edge_config.yaml
Run Authorizer with Environment Variables in the docker-compose Run Command
To run the authorizer without providing the whole configuration file, you can provide the environment variables in your docker-compose run
command. See example below:
docker-compose run apigee-authorizer -e APIGEE_ACP_CLIENT_ID={your_client_id} APIGEE_ACP_CLIENT_SECRET={your_client_secret}