Checkpoints
Create shared flow and flow hook
/ 40
Add a Cloud Armor security policy
/ 40
Wait for instance to be ready
/ 20
Protecting APIs with Apigee X and Cloud Armor
- GSP909
- Overview
- Setup
- Task 1. Create JSON threat protection shared flow
- Task 2. Add a Cloud Armor security policy
- Task 3. Wait for Apigee instance provisioning to complete
- Task 4. Test from an allowed region
- Task 5. Test the security policy from a disallowed region
- Task 6. Explore policy monitoring for Cloud Armor
- Congratulations!
GSP909
Overview
In this lab, you use an Apigee X threat protection policy to protect APIs against content-based threats. You also add Cloud Armor to a global external HTTPS load balancer to provide web application firewall features like distributed denial-of-service (DDoS) protection, OWASP Top 10 risks mitigation, and IP-based and geo-based access control.
A load balancer and managed instance group of bridge VMs have been created to provide access to your runtime instance. The architecture for this configuration is shown here:
Incoming API calls enter the Customer project through a global external HTTPS load balancer. The external HTTPS load balancer cannot forward calls to the tenant project. Instead, the load balancer forwards the request to a managed instance group of bridge VMs in the customer project. These bridge VMs are in the peered network connected to the Apigee runtime instance, allowing the VMs to forward API calls to the runtime instance.
Any HTTP traffic sent to the load balancer will be forwarded on to the bridge VMs and then the Apigee runtime instance. You will add Cloud Armor security policies to block specific traffic from being sent through to the runtime.
JSON and XML attacks use payloads constructed to overwhelm JSON and XML parsers and induce application-level denial-of-service attacks. Cloud Armor does not detect these types of attacks, but Apigee can. The JSONThreatProtection and XMLThreatProtection policies can detect these malicious payloads without loading the payload into a parser. You will use the JSONThreatProtection policy to protect against malformed JSON payloads.
The instructions in this lab are applicable for both paid and evaluation orgs.
Objectives
In this lab, you learn how to perform the following tasks:
- Use Apigee threat protection policies to block malicious JSON and XML payloads
- Create a Cloud Armor policy
- Create Cloud Armor rule for blocking and allowing requests
- Apply a Cloud Armor policy to a load balancer
- Test a Cloud Armor policy using HTTP traffic
Setup
Before you click the Start Lab button
Read these instructions. Labs are timed and you cannot pause them. The timer, which starts when you click Start Lab, shows how long Google Cloud resources will be made available to you.
This hands-on lab lets you do the lab activities yourself in a real cloud environment, not in a simulation or demo environment. It does so by giving you new, temporary credentials that you use to sign in and access Google Cloud for the duration of the lab.
To complete this lab, you need:
- Access to a standard internet browser (Chrome browser recommended).
- Time to complete the lab---remember, once you start, you cannot pause a lab.
How to start your lab and sign in to the Google Cloud console
-
Click the Start Lab button. If you need to pay for the lab, a pop-up opens for you to select your payment method. On the left is the Lab Details panel with the following:
- The Open Google Cloud console button
- Time remaining
- The temporary credentials that you must use for this lab
- Other information, if needed, to step through this lab
-
Click Open Google Cloud console (or right-click and select Open Link in Incognito Window if you are running the Chrome browser).
The lab spins up resources, and then opens another tab that shows the Sign in page.
Tip: Arrange the tabs in separate windows, side-by-side.
Note: If you see the Choose an account dialog, click Use Another Account. -
If necessary, copy the Username below and paste it into the Sign in dialog.
{{{user_0.username | "Username"}}} You can also find the Username in the Lab Details panel.
-
Click Next.
-
Copy the Password below and paste it into the Welcome dialog.
{{{user_0.password | "Password"}}} You can also find the Password in the Lab Details panel.
-
Click Next.
Important: You must use the credentials the lab provides you. Do not use your Google Cloud account credentials. Note: Using your own Google Cloud account for this lab may incur extra charges. -
Click through the subsequent pages:
- Accept the terms and conditions.
- Do not add recovery options or two-factor authentication (because this is a temporary account).
- Do not sign up for free trials.
After a few moments, the Google Cloud console opens in this tab.
Activate Cloud Shell
Cloud Shell is a virtual machine that is loaded with development tools. It offers a persistent 5GB home directory and runs on the Google Cloud. Cloud Shell provides command-line access to your Google Cloud resources.
- Click Activate Cloud Shell
at the top of the Google Cloud console.
When you are connected, you are already authenticated, and the project is set to your Project_ID,
gcloud
is the command-line tool for Google Cloud. It comes pre-installed on Cloud Shell and supports tab-completion.
- (Optional) You can list the active account name with this command:
- Click Authorize.
Output:
- (Optional) You can list the project ID with this command:
Output:
gcloud
, in Google Cloud, refer to the gcloud CLI overview guide.
Open the Apigee UI
The Apigee UI is accessed on a page separate from the Google Cloud Console. This lab has automatically created an Apigee organization that has the same name as the Google Cloud project.
-
Click to open the Apigee UI.
You may also open the Apigee UI from the Google Cloud Console by opening the Navigation menu (
) and selecting Apigee API Management > Apigee.
If you see an error indicating that the project does not have an organization provisioned, the tab might be trying to load the organization for a previous lab.
If you get this error:
-
Click on the organization dropdown.
The organization dropdown should show an organization that has the same name as the Google Cloud project.
The organizations listed are those that are accessible by the logged-in user. For this lab, you should be logged in with the lab credentials provided in the Lab Details panel when you started the lab.
You can navigate the Apigee UI using its left navigation menu. The landing page also shows quick links for navigating to commonly used locations.
Task 1. Create JSON threat protection shared flow
In this task, you create a shared flow with a JSONThreatProtection policy, and then use a flow hook to enable it for all Apigee APIs.
The JSONThreatProtection policy will reject incoming JSON requests that exceed the specified limits. By placing the policy in a shared flow, and attaching the shared flow with a flow hook, the policy can protect any request for all of the proxies deployed to an environment.
Create the shared flow
-
Select the Apigee Console tab in your browser window.
-
Navigate to Develop > Shared Flows.
-
Click Create.
A shared flow can contain a set of policies and conditions, and can be executed in API proxies or other shared flows by using a FlowCallout policy. In this lab, you will use the shared flow in a flow hook, which attaches it to every proxy deployed in the eval org.
-
Name the shared flow
protect-json
, and then click Create. -
If a Switch to Classic link is in the upper right corner, click that link.
-
Click the Develop tab.
-
To add a policy to the shared flow, click +Step.
-
Select JSON Threat Protection, and then set the Display Name and Name to
JTP-Protect
. -
Click Add.
The JSONThreatProtection policy contains several elements that provide limits to incoming JSON requests. You typically set these limits based upon the maximum values of your APIs. In this case, keep the default configuration for the policy.
This policy will only execute if the Content-Type header of the request is set to application/json, indicating that the incoming request has a JSON payload.
-
Click Save.
-
Click Deploy to eval, and then click Deploy.
Attach the shared flow to a flow hook
The shared flow will be attached to the Pre-proxy flow hook so that it is executed before the proxy executes.
-
Navigate to Admin > Environments > Flow Hooks.
-
Hold the pointer over the Pre-proxy row, and then click the edit (pencil) icon (
) on the right side of the row.
-
Select the protect-json shared flow, and then click OK.
You will test this flow hook in a later task.
Click Check my progress to verify the objective.
Task 2. Add a Cloud Armor security policy
In this task, you add a Cloud Armor security policy to protect your load balancer and control access to your APIs.
Cloud Armor is Google Cloud's web application firewall. A single Cloud Armor policy can be specified for a load balancer. In this lab, you will use a Cloud Armor security policy to reject specific traffic before it reaches the Apigee runtime instance, protecting your API.
Create a new security policy
-
In the Cloud Console tab, on the Navigation menu (
), click View all Products, then select Network security in the Networking Section, and then nevigate to Cloud Armor policies.
-
Click Create policy.
-
For Name, specify
protect-apis
.This security policy will use rules to block specific traffic intended for our Apigee APIs.
-
For Default rule action, select Deny.
Users will be denied access to the APIs unless they match a rule that specifically allows the traffic.
-
For the Deny status dropdown, select 403 (Forbidden).
If a request does not match a rule that allows the traffic, a status code of 403 Forbidden will be returned to the user.
-
Click Next Step.
Add a security policy rule to allow requests by origin country code
This rule will allow only requests coming from specified countries.
-
Click Add a Rule.
-
Click Advanced mode.
A Basic mode rule can only specify IP addresses or IP address ranges to match. In this case, you want to specify allowed country codes.
-
For Match, specify the following expression:
origin.region_code == 'US' For Cloud Armor, region_code is specified as an ISO 3166-2 region. This rule matches requests coming from the United States.
-
For Action, specify Allow.
-
Set Priority to
1000
, and then click Done.
Add a rule to block SQL injection attacks
This rule will block requests that have SQL inputs that may result in SQL injection.
-
Click Add a Rule.
-
Click Advanced mode.
-
For Match, specify the following expression:
evaluatePreconfiguredExpr('sqli-stable', ['owasp-crs-v030001-id942251-sqli', 'owasp-crs-v030001-id942420-sqli', 'owasp-crs-v030001-id942431-sqli', 'owasp-crs-v030001-id942460-sqli', 'owasp-crs-v030001-id942421-sqli', 'owasp-crs-v030001-id942432-sqli']) This expression specifies a preconfigured Cloud Armor rule. The preconfigured rules use open source industry standard signatures to detect malicious requests. Specific signatures can be disabled by providing signature names to be turned off.
In this case, signatures at sensitivity level 3 and 4 are turned off. A signature's sensitivity level, also known as its paranoia level, specifies a tradeoff of a higher level of security at the expense of a higher number of false positives.
Level 1 is the default level of security which should rarely, if ever, have false positives. Level 2 adds extra protection against advanced and obfuscated attacks. Signatures at levels 3 and 4 are more aggressive and are significantly more likely to cause false positives. For example, POST requests with simple JSON payloads may be flagged by level 3 or 4 signatures.
-
Leave Action set to Deny, and leave Deny status set to 403 (Forbidden).
-
Set Priority to
500
.When Cloud Armor policy rules are evaluated, the first encountered rule that matches the request specifies the action that will be taken. The check for SQL injection needs to occur before the check for region, because we want to reject requests that come from an allowed region but also contain SQL injection patterns. By choosing a smaller priority number, the SQL injection check will be done before the region check.
-
Click Done.
Look at the summary on the right. The policy contains 3 rules. The rules are evaluated in order of lowest priority number to highest priority number, and the first matching rule will be used.
The first rule denies access if SQL injection patterns are detected.
The second rule allows access if the origin is the United States.
The final rule denies access for all traffic.
-
Click Create policy.
The Policies tab shows that the new protect-apis policy has 0 targets because you haven't attached it to your load balancer yet.
Attach the policy to the load balancer
-
Next to protect-apis, click the policy menu button (
), and then click Apply policy to target.
-
For the Backend Service target 1 dropdown, select apigee-proxy-backend, and then click Add.
The protect-apis policy details page should soon show that the policy applies to 1 target.
Note: It may take a few minutes for Cloud Armor changes to propagate to the target.
Click Check my progress to verify the objective.
Task 3. Wait for Apigee instance provisioning to complete
In this task, you wait for the Apigee evaluation org provisioning to complete.
The Apigee organization provisioning may take quite a while to complete. The org provisioning progress can be monitored by using the Apigee API.
Start monitoring script
-
In the Cloud Shell, verify that the GOOGLE_CLOUD_PROJECT variable contains your project name by using the following command:
echo ${GOOGLE_CLOUD_PROJECT} The variable GOOGLE_CLOUD_PROJECT should contain the name of your project, which is the same as your Apigee organization name.
-
If the GOOGLE_CLOUD_PROJECT variable is not set, set the variable manually using a command that looks like this, replacing {project} with your project name:
export GOOGLE_CLOUD_PROJECT={project} Note: The curly braces should be removed during this step. -
Paste the following command into the Cloud Shell:
export INSTANCE_NAME=eval-instance; export ENV_NAME=eval; export PREV_INSTANCE_STATE=; echo "waiting for runtime instance ${INSTANCE_NAME} to be active"; while : ; do export INSTANCE_STATE=$(curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" -X GET "https://apigee.googleapis.com/v1/organizations/${GOOGLE_CLOUD_PROJECT}/instances/${INSTANCE_NAME}" | jq "select(.state != null) | .state" --raw-output); [[ "${INSTANCE_STATE}" == "${PREV_INSTANCE_STATE}" ]] || (echo; echo "INSTANCE_STATE=${INSTANCE_STATE}"); export PREV_INSTANCE_STATE=${INSTANCE_STATE}; [[ "${INSTANCE_STATE}" != "ACTIVE" ]] || break; echo -n "."; sleep 5; done; echo; echo "instance created, waiting for environment ${ENV_NAME} to be attached to instance"; while : ; do export ATTACHMENT_DONE=$(curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" -X GET "https://apigee.googleapis.com/v1/organizations/${GOOGLE_CLOUD_PROJECT}/instances/${INSTANCE_NAME}/attachments" | jq "select(.attachments != null) | .attachments[] | select(.environment == \"${ENV_NAME}\") | .environment" --join-output); [[ "${ATTACHMENT_DONE}" != "${ENV_NAME}" ]] || break; echo -n "."; sleep 5; done; echo; echo "${ENV_NAME} environment attached, waiting for hello-world to be deployed"; while : ; do export ATTACHMENT_DONE=$(curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" -X GET "https://apigee.googleapis.com/v1/organizations/${GOOGLE_CLOUD_PROJECT}/instances/${INSTANCE_NAME}/attachments" | jq "select(.attachments != null) | .attachments[] | select(.environment == \"${ENV_NAME}\") | .environment" --join-output); [[ "${ATTACHMENT_DONE}" != "${ENV_NAME}" ]] || break; echo -n "."; sleep 5; done; echo "***ORG IS READY TO USE***"; This series of commands uses the Apigee API to determine when the runtime instance has been created and the eval environment has been attached.
-
Wait until the instance is ready.
When the text
***ORG IS READY TO USE***
is printed, the instance is ready.Note: If the command immediately indicates that the org is ready to use, the lab may have been prewarmed before you entered the lab. While you are waiting for the org to be ready, you can explore a Cloud Armor overview, custom rules, and preconfigured rules.
Click Check my progress to verify the objective.
Task 4. Test from an allowed region
In this task, you verify that the Cloud Armor security policy is protecting your APIs but allows acceptable traffic from the allowed region, and that the flow hook protects against JSON threats.
A virtual machine named apigeex-test-vm was automatically created for you. You can use this machine to call the API from the United States.
-
In Cloud Shell, open an ssh connection to your test VM in the United States:
TEST_VM_ZONE=$(gcloud compute instances list --filter="name=('apigeex-test-vm')" --format "value(zone)") gcloud compute ssh apigeex-test-vm --zone=${TEST_VM_ZONE} --force-key-file-overwrite -
If asked to authorize, click Authorize.
-
For each question asked in the Cloud Shell, click Enter or Return to specify the default input.
Your logged in identity is the owner of the project, so SSH to this machine is allowed.
Your Cloud Shell session is now running inside the VM.
-
Verify that the hello-world API proxy is now accessible:
export PREV_STATUS_CODE=; echo "waiting for hello-world to be accessible"; while : ; do export STATUS_CODE=$(curl -k -s -o /dev/null -w "%{http_code}" --max-time 5 -X GET "https://eval.example.com/hello-world"); [[ "${STATUS_CODE}" == "${PREV_STATUS_CODE}" ]] || (echo; echo "STATUS_CODE=${STATUS_CODE}"); export PREV_STATUS_CODE=${STATUS_CODE}; [[ "${STATUS_CODE}" != "200" ]] || break; echo -n "."; sleep 5; done; echo; echo "***HELLO-WORLD IS ACCESSIBLE***"; It may take a short period of time before the hello-world proxy is deployed and the proxy is available through the external load balancer. When these commands return
***HELLO-WORLD IS ACCESSIBLE***
, the hello-world proxy is available. -
Call the deployed hello-world API proxy in the eval environment:
curl -i -k "https://eval.example.com/hello-world" A DNS entry for the hostname eval.example.com has been created with the incoming IP address for your load balancer.
The -i option displays the status code and header for the response.
The -k option skips verification of the TLS certificate of the load balancer, because the TLS certificate used for the load balancer is a self-signed certificate, not a certificate verified by a known certificate authority.
Note: Using the -k option to bypass certificate validation should not be used in a production environment. The VM is located in the United States, so your curl command should successfully return the
Hello, Guest!
response generated by the hello-world proxy:HTTP/2 200 x-powered-by: Apigee access-control-allow-origin: * x-frame-options: ALLOW-FROM RESOURCE-URL x-xss-protection: 1 x-content-type-options: nosniff content-type: text/plain; charset=utf-8 content-length: 13 etag: W/"d-GHB1ZrJKk/wdVTdB/jgBsw" date: Mon, 30 Aug 2021 19:14:45 GMT alt-svc: clear alt-svc: clear x-request-id: b5532b95-c051-4f21-a131-07da1574edc3 server: apigee via: 1.1 google, 1.1 google Hello, Guest! -
Call the hello-world proxy using this command:
curl -i -k -X POST "https://eval.example.com/hello-world" -H "Content-Type: application/json" -d '{ "ThisIsAReallyLongElementNameIMeanReallyReallyReallyLong": 42 }' This request exceeds the ObjectEntryNameLength limit specified in the JSONThreatProtection policy included in the shared flow. The shared flow is attached to all API proxies using the pre-proxy flow hook.
The response should look similar to this:
HTTP/2 500 content-type: application/json x-request-id: 5360a9fb-b0b9-4fce-968c-22c2d3fd57dd content-length: 235 date: Mon, 30 Aug 2021 19:16:17 GMT server: apigee via: 1.1 google alt-svc: clear {"fault":{"faultstring":"JSONThreatProtection[JTP-Protect]: Execution failed. reason: JSONThreatProtection[JTP-Protect]: Exceeded object entry name length at line 1","detail":{"errorcode":"steps.jsonthreatprotection.ExecutionFailed"}}} Note: The default status code returned is 500, indicating a server error. In a production use of this policy, it makes more sense rewrite the error indicating an issue with the request (like 400 Bad Request), not a server error. -
Attempt to call the hello-world API proxy using this command:
curl -i -k "https://eval.example.com/hello-world?item=name'%20OR%20'a'='a" The item query parameter uses a SQL injection pattern that can have unintended consequences if a SQL query is built by concatenating strings.
The SQL injection pattern is successfully detected by Cloud Armor and the request is blocked, returning a 403 Forbidden response:
HTTP/2 403 content-length: 134 content-type: text/html; charset=UTF-8 date: Thu, 22 Jul 2021 18:50:03 GMT alt-svc: clear <!doctype html><meta charset="utf-8"><meta name=viewport content="width=device-width, initial-scale=1"><title>403</title>403 Forbidden Note: It can take a few minutes for Cloud Armor rules to propagate. If the request is not blocked, retry the call until the request is blocked. -
Type
exit
to close the SSH connection to your United States virtual machine.
Task 5. Test the security policy from a disallowed region
In this task, you verify that the Cloud Armor security policy does not allow traffic for a region that has not been allow-listed.
A virtual machine named apigeex-outside-us was automatically created in zone
- In Cloud Shell, open an ssh connection to your test VM outside the United States:
-
If asked to authorize, click Authorize.
-
For each question asked in the Cloud Shell, click Enter or Return to specify the default input.
Your logged in identity is the owner of the project, so SSH to this machine is allowed.
Your Cloud Shell session is now running inside the VM.
-
Call the deployed hello-world API proxy in the eval environment:
curl -i -k "https://eval.example.com/hello-world" The VM is not located in the United States, so Cloud Armor should block the request, returning a 403:
HTTP/2 403 content-length: 134 content-type: text/html; charset=UTF-8 date: Thu, 22 Jul 2021 22:47:06 GMT alt-svc: clear <!doctype html><meta charset="utf-8"><meta name=viewport content="width=device-width, initial-scale=1"><title>403</title>403 Forbidden
Task 6. Explore policy monitoring for Cloud Armor
In this task, you check the Cloud Armor policy dashboard in Cloud Monitoring.
-
In the Cloud Console tab, navigate to Monitoring > Dashboards.
-
Click Network Security Policies.
This dashboard shows you the rate of allowed and blocked requests for all Cloud Armor policies. You currently have only one policy.
-
In the Policies pane, click protect-apis.
This dashboard shows you the rate of allowed and blocked requests for the protect-apis policy.
To log individual request details, you would need to turn on request logging for the load balancer.
Congratulations!
In this lab, you created a Cloud Armor policy and used the policy to reject or allow incoming traffic based on your Cloud Armor rules.
Next steps / Learn more
Google Cloud training and certification
...helps you make the most of Google Cloud technologies. Our classes include technical skills and best practices to help you get up to speed quickly and continue your learning journey. We offer fundamental to advanced level training, with on-demand, live, and virtual options to suit your busy schedule. Certifications help you validate and prove your skill and expertise in Google Cloud technologies.
Manual Last Updated August 07, 2024
Lab Last Tested August 07, 2024
Copyright 2024 Google LLC All rights reserved. Google and the Google logo are trademarks of Google LLC. All other company and product names may be trademarks of the respective companies with which they are associated.