실습 설정 안내 및 요구사항
계정과 진행 상황을 보호하세요. 이 실습을 실행하려면 항상 시크릿 브라우저 창과 실습 사용자 인증 정보를 사용하세요.

Apigee Lab 6: Protecting Against Internal Threats

실습 1시간 30분 universal_currency_alt 크레딧 5개 show_chart 입문
info 이 실습에는 학습을 지원하는 AI 도구가 통합되어 있을 수 있습니다.
이 콘텐츠는 아직 휴대기기에 최적화되지 않음
최상의 경험을 위해 데스크톱 컴퓨터에서 이메일로 전송된 링크를 사용하여 방문하세요.

Overview

Credentials are often necessary when an API proxy communicates with backend or third-party services, and credentials should always be protected when stored in Apigee. Security breaches can occur when internal users get unauthorized access to sensitive data.

In this lab, you use a key value map (KVM) to store backend credentials. Values stored in a KVM are encrypted. You will then use the KeyValueMapOperations policy to retrieve the credentials into private variables and use them to build a Basic Authentication header.

Objectives

In this lab, you learn how to perform the following tasks:

  • Create and populate a key value map (KVM).
  • Use data from a KVM in your proxy.
  • Build a Basic Authentication header.

Setup

For each lab, you get a new Google Cloud project and set of resources for a fixed time at no cost.

  1. Sign in to Google Skills using an incognito window.

  2. Note the lab's access time (for example, 1:15:00), and make sure you can finish within that time. There is no pause feature. You can restart if needed, but you have to start at the beginning.

  3. When ready, click Start lab.

  4. Note your lab credentials (Username and Password). You will use them to sign in to the Google Cloud Console.

  5. Click Open Google Console.

  6. Click Use another account and copy/paste credentials for this lab into the prompts. If you use other credentials, you'll receive errors or incur charges.

  7. Accept the terms and skip the recovery resource page.

Activate Google Cloud Shell

Google 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.

Google Cloud Shell provides command-line access to your Google Cloud resources.

  1. In Cloud console, on the top right toolbar, click the Open Cloud Shell button.

    Highlighted Cloud Shell icon

  2. Click Continue.

It takes a few moments to provision and connect to the environment. When you are connected, you are already authenticated, and the project is set to your PROJECT_ID. For example:

Project ID highlighted in the Cloud Shell Terminal

gcloud is the command-line tool for Google Cloud. It comes pre-installed on Cloud Shell and supports tab-completion.

  • You can list the active account name with this command:
gcloud auth list

Output:

Credentialed accounts: - @.com (active)

Example output:

Credentialed accounts: - google1623327_student@qwiklabs.net
  • You can list the project ID with this command:
gcloud config list project

Output:

[core] project =

Example output:

[core] project = qwiklabs-gcp-44776a13dea667a6 Note: Full documentation of gcloud is available in the gcloud CLI overview guide .

Preloaded assets

These assets have already been added to the Apigee organization:

  • The retail-v1 API proxy
  • The oauth-v1 API proxy (for generating OAuth tokens)
  • The TS-Retail target server in the eval environment (used by retail-v1)

These assets will be added to the Apigee organization as soon as the runtime is available:

  • The API products, developer, and developer app (used by retail-v1)

The highlighted items are used during this lab.

Note: Revision 1 of the retail-v1 proxy is marked as deployed, and is immutable. If you ever make a mistake in your proxy code that you can't recover from, you can select revision 1 and restart editing from there.

Task 1. Modify the retail proxy to use the KVM credentials

In this task, you will use the KeyValueMapOperations policy to extract credentials from the key value map.

The PATCH /products/{id} call to the backend requires that a Basic Authentication header containing the backend credentials be added to the request. We will store these credentials in the KVM.

Note: A KVM cannot be created until the runtime is available. The Apigee organization you use for this lab takes a while to start up, and the runtime is not yet available when you start the lab. In a real-world scenario, you would typically create the KVM before you used it in a proxy.

Pin the Apigee console page

  1. In the Google Cloud console, on the Navigation menu (Navigation menu), look for Apigee in the Favorite Products section.

    The Apigee console page will open.

  2. If Apigee is not listed, search for Apigee in the top search bar and navigate to the Apigee service.

  3. To pin Apigee in the console, click the favorite icon (favorite button for pinned product).

    The Apigee console page will now be listed as a favorite product in the Navigation menu.

Modify the proxy

  1. On the left navigation menu, select Proxy development > API proxies.

  2. Select the retail-v1 proxy.

  3. Click the Develop tab.

    You are modifying the version of the retail-v1 proxy that was created during Labs 1 through 5.

  4. Select Proxy endpoints > default > updateProductById.

  5. On the Request updateProductById flow, click Add Policy Step (+).

  6. In the Add policy step pane, select Create new policy, and then select Mediation > Key Value Map Operations.

  7. Specify the following values:

    Property Value
    Name KVM-GetCredentials
    Display name KVM-GetCredentials
  8. Click Add.

  9. Click on Policies > KVM-GetCredentials.

  10. Set the policy configuration to:

    <KeyValueMapOperations continueOnError="false" enabled="true" name="KVM-GetCredentials"> <MapName>ProductsKVM</MapName> <ExpiryTimeInSecs>60</ExpiryTimeInSecs> <Get assignTo="private.backendId"> <Key> <Parameter>backendId</Parameter> </Key> </Get> <Get assignTo="private.backendSecret"> <Key> <Parameter>backendSecret</Parameter> </Key> </Get> <Scope>environment</Scope> </KeyValueMapOperations>

    This policy will extract the backendId and backendSecret values from the ProductsKVM into private variables.

    Note: The ExpiryTimeInSecs element is set to 60, causing the policy to automatically cache the values of the KVM for 60 seconds. This helps with proxy performance. If you modify an entry, you'll have to wait 60 seconds for cached values to expire before the change to the KVM entry will be detected.

    The backend ID and secret are loaded into variables with a "private." prefix. These variables will be masked in the debug tool. You must use private variables when retrieving data from a KVM.

Task 2. Add the Basic Authentication header

In this task, you use the BasicAuthentication policy to add a Basic Auth header, using the private variables from the KeyValueMapOperations policy.

  1. Select Proxy endpoints > default > updateProductById.

  2. On the Request updateProductById flow, click Add Policy Step (+).

  3. In the Add policy step pane, select Create new policy, and then select Security > Basic Authentication.

  4. Specify the following values:

    Property Value
    Name BA-AddAuthHeader
    Display name BA-AddAuthHeader
  5. Click Add.

  6. Click on Policies > BA-AddAuthHeader.

  7. Set the policy configuration to:

    <BasicAuthentication continueOnError="false" enabled="true" name="BA-AddAuthHeader"> <Operation>Encode</Operation> <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables> <User ref="private.backendId"/> <Password ref="private.backendSecret"/> <AssignTo createNew="false">request.header.Authorization</AssignTo> </BasicAuthentication>

    This policy will use the backend ID and secret to build a Basic Authentication header for the call to the backend service.

  8. Select Proxy endpoints > default > updateProductById.

    Your updateProductById flow should look like this:

    Request updateProductById flow highlighted with KVM-GetCredentials and BA-AddAuthHeader steps

  9. Click Save, and then click Save as New Revision.

  10. Click Deploy.

  11. To specify that you want the new revision deployed to the eval environment, select eval as the Environment, then click Deploy, and then click Confirm.

Check runtime status

Certain assets, including API products, developers, developer apps, and KVMs, cannot be saved until the runtime is available.

For example, when navigating to the API products page, you might see an error message that reads "Products were not loaded successfully."

This is an error you should see when you are waiting for the runtime instance to be available. Once the runtime is available, refreshing the page will remove the error.

If you get this type of error, you can check the status of provisioning.

Check provisioning status

  • In Cloud Shell, to confirm that the runtime instance has been installed and the eval environment has been attached, run the following commands:

    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 "***ORG IS READY TO USE***";

    When the script returns ORG IS READY TO USE, you can proceed to the next steps.

While you are waiting

While you wait for the new revision to deploy, review the following information:

Task 3. Create a new key value map

In this task, you create a key value map (KVM).

Create the KVM

  1. On the left navigation menu, select Management > Environments.

  2. Click eval, and then click the Key Value Maps tab.

    Note: If you see an error on the page, the runtime instance may not yet be available.
  3. Click +Create Key Value Map:

  4. For Key value map name, specify ProductsKVM, and then click Create.

Learn about key value maps

To learn more about Apigee key value maps, you can use Gemini Cloud Assist in the Google Cloud console.

Open Gemini Cloud Assist

  1. To open Gemini Cloud Assist, in the Google Cloud console, click Open or close Gemini Cloud Assist chat (Gemini Cloud Assist icon).

  2. If prompted in the Cloud Assist panel, click Get Gemini Cloud Assist.

  3. Optionally view the APIs that are required and recommended to be enabled.

  4. Click Enable Gemini Cloud Assist at no cost.

  5. Click Start chatting.

Prompt Gemini

  1. For the prompt, type:

    In Apigee X, what is a key value map and when should one be used?
  2. Click Send (Send icon).

    Read the response generated by Gemini Cloud Assist.

  3. Optionally, click Show related content to browse the related documentation.

Task 4. Populate the KVM

In this task, you use the Apigee API to populate your KVM.

KVM data is stored in the runtime database, and it can be populated by using the KeyValueMapOperations policy or using the Apigee API. For this lab, you will use the Apigee API.

The keys and values you will load are:

Key Value
backendId svcacct
backendSecret UNdrDxeQ82

Test the API proxy using private DNS

The eval environment in the Apigee organization can be called using the hostname eval.example.com. The DNS entry for this hostname has been created within your project, and it resolves to the IP address of the Apigee runtime instance. This DNS entry has been created in a private zone, which means it is only visible on the internal network.

Cloud Shell does not reside on the internal network, so Cloud Shell commands cannot resolve this DNS entry. A virtual machine (VM) within your project can access the private zone DNS. A virtual machine named apigeex-test-vm was automatically created for this purpose. You can make API proxy calls from this machine.

The curl command will be used to send API requests to an API proxy. The -k option for curl tells it to skip verification of the TLS certificate. For this lab, the Apigee runtime uses a self-signed certificate. For a production environment, you should use certificates that have been created by a trusted certificate authority (CA).

  1. In Cloud Shell, open a new tab, and then open an SSH connection to your test VM:

    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

    The first gcloud command retrieves the zone of the test VM, and the second opens the SSH connection to the VM.

  2. If prompted, type Y to continue.

    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.

Load the KVM entries

  1. In the Cloud Shell SSH session, to load the backendId, run these commands:

    export PROJECT_ID=$(gcloud config list --format 'value(core.project)'); echo "PROJECT_ID=${PROJECT_ID}" curl -X POST "https://apigee.googleapis.com/v1/organizations/${PROJECT_ID}/environments/eval/keyvaluemaps/ProductsKVM/entries" -H "Authorization: Bearer $(gcloud auth print-access-token)" -H "Content-Type: application/json" -d '{ "name": "backendId", "value": "svcacct" }'

    This command returns the key and value when they are created successfully.

  2. Use this curl command to load the backendSecret with an incorrect secret:

    export PROJECT_ID=$(gcloud config list --format 'value(core.project)'); echo "PROJECT_ID=${PROJECT_ID}" curl -X POST "https://apigee.googleapis.com/v1/organizations/${PROJECT_ID}/environments/eval/keyvaluemaps/ProductsKVM/entries" -H "Authorization: Bearer $(gcloud auth print-access-token)" -H "Content-Type: application/json" -d '{ "name": "backendSecret", "value": "ABCD1234" }'

    In the next task you will see that this incorrect secret causes your backend request to fail.

Task 5. Test the retail API

In this task, you validate that the retail API presents the credentials to the backend service and the product overall rating is updated.

The only field in the product that you can update is the overall_rating. It must be updated to another decimal number.

Store the app's key in a shell variable

The API key may be retrieved directly from the app accessible on the Publish > Apps page. It can also be retrieved via Apigee API call.

  • In the Cloud Shell SSH session, run the following command:

    export PROJECT_ID=$(gcloud config list --format 'value(core.project)'); echo "PROJECT_ID=${PROJECT_ID}" export API_KEY=$(curl -q -s -H "Authorization: Bearer $(gcloud auth print-access-token)" -X GET "https://apigee.googleapis.com/v1/organizations/${PROJECT_ID}/developers/joe@example.com/apps/retail-app" | jq --raw-output '.credentials[0].consumerKey'); echo "export API_KEY=${API_KEY}" >> ~/.bashrc; echo "API_KEY=${API_KEY}"

    This command retrieves a Google Cloud access token for the logged-in user, sending it as a Bearer token to the Apigee API call. It retrieves the retail-app app details as a JSON response, which is parsed by jq to retrieve the app's key. That key is then put into the API_KEY environment variable, and the export command is concatenated onto the .bashrc file which runs automatically when starting a the SSH session.

    Note: If you run the command and it shows API_KEY=null, the runtime instance is probably not yet available.

Get the list of products

  1. In the Cloud Shell SSH session, use this curl command to get a list of products:

    curl -k -H "apikey: ${API_KEY}" -X GET "https://eval.example.com/retail/v1/products" | jq

    The response should be a JSON list of products that resembles this:

    { "18841": { "category": "Clothing", "image": "https://cdn.pixabay.com/photo/2016/03/20/13/48/zip-1268656_1280.jpg", "name": "18841", "overall_rating": 0, "product_name": "Roll-Up Denim Bermuda Shorts (Wise) (Regular & Petite)", "short_description": "An essential for kicked-back days, Bermuda-length denim shorts with rolled hems are detailed with whiskering for a comfy worn-in look.\\n15 1/2\" regular inseam (size 8); 13\" petite inseam (size 8P).\\nZip fly with button closure.\\nDark dye may transfer to lighter materials.\\n99% cotton, 1% spandex.\\nMachine wash cold, tumble dry low or lay flat to dry.\\nBy KUT from The Kloth; imported.\\nPoint of View." }, "31001": { "category": "Baby", "image": "https://cdn.pixabay.com/photo/2017/09/11/16/11/ducks-2739503__480.jpg", "name": "31001", "overall_rating": 2.1, "product_name": "Munchkin 'White Hot' Duck Bath Toy", "short_description": "Test the waters with America's #1 Safety Duck. No need to worry that your baby's bath water is too hot to handle. This adorable rubber ducky has our White Hot safety disc at the bottom that tells you when the water is too hot, then lets you know that it's safe to put your baby in." }, "62003": {

    The top-level keys are the IDs (18841, 31001, and 62003 are shown here). Choose any one of the IDs in the entire list.

  2. Create an environment variable with the ID you have chosen, and replace "REPLACE" with the ID you have chosen:

    export PRODUCT_ID=REPLACE

    Replace "REPLACE" with the ID you have chosen.

  3. Look at the current overall_rating for the product, and choose a different positive decimal number. For example, 2.1 is the overall_rating for product 31001 shown above. You might choose to change the rating to 4.5. Create an environment variable with the new rating you have chosen:

    export NEW_RATING=REPLACE

    Again, be sure to replace "REPLACE" with the new rating you have chosen.

  4. Try to make the request using the incorrect backendSecret we loaded earlier by using this curl command:

    curl -k -H "apikey: ${API_KEY}" -X PATCH "https://eval.example.com/retail/v1/products/${PRODUCT_ID}" -H "Content-Type: application/json" -d "{ \"overall_rating\": ${NEW_RATING} }" | jq

    You should get an error that looks like this:

    { "error": "invalid_credentials", "error_description": "Credentials missing or incorrect." }
  5. Use these curl commands to delete the backendSecret and then add it with the correct value:

    export PROJECT_ID=$(gcloud config list --format 'value(core.project)'); echo "PROJECT_ID=${PROJECT_ID}" curl -X DELETE "https://apigee.googleapis.com/v1/organizations/${PROJECT_ID}/environments/eval/keyvaluemaps/ProductsKVM/entries/backendSecret" -H "Authorization: Bearer $(gcloud auth print-access-token)" curl -X POST "https://apigee.googleapis.com/v1/organizations/${PROJECT_ID}/environments/eval/keyvaluemaps/ProductsKVM/entries" -H "Authorization: Bearer $(gcloud auth print-access-token)" -H "Content-Type: application/json" -d '{ "name": "backendSecret", "value": "UNdrDxeQ82" }'
  6. Use this command to update the overall_rating and then retrieve the product to make sure that the overall_rating has changed.

    curl -k -H "apikey: ${API_KEY}" -X PATCH "https://eval.example.com/retail/v1/products/${PRODUCT_ID}" -H "Content-Type: application/json" -d "{ \"overall_rating\": ${NEW_RATING} }" | jq curl -k -H "apikey: ${API_KEY}" -X GET "https://eval.example.com/retail/v1/products/${PRODUCT_ID}" | jq

    The incorrect backendSecret may still be in the cache from the previous request. The KeyValueMapOperations policy specified an expiry time of 60 seconds. If you get an invalid credentials error for the first call, try your requests again until the request succeeds.

    If successful, the first curl command will return the same overall_rating that you used to update it. The second curl command will return the entire product, including the updated overall_rating.

Task 6. Troubleshooting tips

If the response was not successful, read the code and debug the request to determine the issue. Here are some common issues:

  • The KeyValueMapOperations or BasicAuthentication policy is in the wrong flow. The debug tool would show the policies not being called for the PATCH request.

  • Your key value map was not successfully created or did not have the name ProductsKVM.

  • The keys or values in the key value map were not set correctly. There could be leading or trailing spaces.

  • The keys were not specified correctly in the KeyValueMapOperations policy. The private variables wouldn't be populated.

If you get a 401 Unauthorized error that looks like this, your Basic Auth header is probably incorrect:

{ "error": "invalid_credentials", "error_description": "Credentials missing or incorrect." }

To debug an issue with the backendId or backendSecret, you need to assign the values to another variable to be able to see the values. You can create an ExtractVariables policy that follows the BasicAuthentication policy, and set its name to EV-DebugBasicAuth.

  1. Replace the configuration with the following:

    <ExtractVariables continueOnError="false" enabled="true" name="EV-DebugBasicAuth"> <DisplayName>EV-DebugBasicAuth</DisplayName> <Variable name="private.backendId"> <Pattern>{retrievedBackendId}</Pattern> </Variable> <Variable name="private.backendSecret"> <Pattern>{retrievedBackendSecret}</Pattern> </Variable> <Variable name="request.header.Authorization"> <Pattern>{builtAuthHeader}</Pattern> </Variable> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> </ExtractVariables>
  2. Save the proxy and deploy the updated revision. When you debug the proxy, you can see the values that would otherwise be masked:

    EV-DebugBasicAuth variables

    In the picture above, the backend ID and secret look correct. However, if you decode the Base64 value in the Authorization header, you'll see that there is a leading space in the backendId.

  3. Command:

    echo -n "IHN2Y2FjY3Q6VU5kckR4ZVE4Mg==" | base64 --decode

    The output has a leading space:

    svcacct:UNdrDxeQ82 ^-- space

Congratulations!

In this lab, you created a KVM and stored credentials in it. You retrieved the credentials from your retail-v1 proxy, and built a Basic Auth header that gave you access to the backend updateProductById resource.

End your lab

When you have completed your lab, click End Lab. Google Skills removes the resources you’ve used and cleans the account for you.

You will be given an opportunity to rate the lab experience. Select the applicable number of stars, type a comment, and then click Submit.

The number of stars indicates the following:

  • 1 star = Very dissatisfied
  • 2 stars = Dissatisfied
  • 3 stars = Neutral
  • 4 stars = Satisfied
  • 5 stars = Very satisfied

You can close the dialog box if you don't want to provide feedback.

For feedback, suggestions, or corrections, please use the Support tab.

Copyright 2026 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.

시작하기 전에

  1. 실습에서는 정해진 기간 동안 Google Cloud 프로젝트와 리소스를 만듭니다.
  2. 실습에는 시간 제한이 있으며 일시중지 기능이 없습니다. 실습을 종료하면 처음부터 다시 시작해야 합니다.
  3. 화면 왼쪽 상단에서 실습 시작을 클릭하여 시작합니다.

시크릿 브라우징 사용

  1. 실습에 입력한 사용자 이름비밀번호를 복사합니다.
  2. 비공개 모드에서 콘솔 열기를 클릭합니다.

콘솔에 로그인

    실습 사용자 인증 정보를 사용하여
  1. 로그인합니다. 다른 사용자 인증 정보를 사용하면 오류가 발생하거나 요금이 부과될 수 있습니다.
  2. 약관에 동의하고 리소스 복구 페이지를 건너뜁니다.
  3. 실습을 완료했거나 다시 시작하려고 하는 경우가 아니면 실습 종료를 클릭하지 마세요. 이 버튼을 클릭하면 작업 내용이 지워지고 프로젝트가 삭제됩니다.

현재 이 콘텐츠를 이용할 수 없습니다

이용할 수 있게 되면 이메일로 알려드리겠습니다.

감사합니다

이용할 수 있게 되면 이메일로 알려드리겠습니다.

한 번에 실습 1개만 가능

모든 기존 실습을 종료하고 이 실습을 시작할지 확인하세요.

시크릿 브라우징을 사용하여 실습 실행하기

이 실습을 실행하는 가장 좋은 방법은 시크릿 모드 또는 시크릿 브라우저 창을 사용하는 것입니다. 개인 계정과 학생 계정 간의 충돌로 개인 계정에 추가 요금이 발생하는 일을 방지해 줍니다.