Tokenizing sensitive cardholder data for PCI DSS

Last reviewed 2025-04-28 UTC

This document shows how to set up an access-controlled credit and debit cardtokenization service on Cloud Run functions. To set up the service, the deploymentin this document uses these Google Cloud services:Identity and Access Management (IAM) andCloud Key Management Service (KMS).

Tokenization is the process of substituting a benign placeholder value, ortoken, for sensitive information such as credit card data. Part 3 of the PaymentCard Industry Data Security Standard (PCI DSS) requires that most of the datastored on a credit card be treated as sensitive information.

A token by itself is meaningless except as a means of looking uptokenized data in a particular context. However, you still need to ensure that your tokensdon't contain any user-specific information and that they aren't directlydecryptable. This way, if you lose control over your customers' payment cardtokens, no one can use the tokens to compromise the cardholder data.

A service for handling sensitive information

You have many choices for the platform or service to host your cardholder dataenvironment (CDE). This document guides you through a sample deployment usingCloud Run functions and helps you on the next steps toward aproduction-ready solution.

Cloud Run functions is a serverless platform that hosts and executes code,and it's a convenient place to quickly launch an application that scales withoutintervention. Keep in mind that in a PCI DSS compliant CDE, you must limit allinbound and outbound traffic to authorized connections. Such fine-grainedcontrols are not currently available for Cloud Run functions. Therefore, youmust implement compensating controls elsewhere (such as in your application) orchoose a different platform. The same Tokenization service can be run in acontainerized manner such as an autoscalingmanaged instance group or a Kubernetes cluster. These would be preferable production environments withtheir complete VPC network controls.

Cloud KMS is Google Cloud's key-management service.Cloud KMS hosts your encryption keys,rotates them regularly,and encrypts or decrypts stored account data.

IAM is used in this document to provide tight controls on all ofthe resources used in the tokenization service. You need a special serviceaccount that has frequently expiring tokens to grant access toCloud KMS and to execute the tokenizer.

The following figure illustrates the tokenization app architecture that youcreate in this document.

tokenization app architecture

Objectives

  • Create a service account.
  • Set up Cloud KMS.
  • Create two Cloud Run functions.
  • Create an authentication token.
  • Call the tokenizer.

Costs

In this document, you use the following billable components of Google Cloud:

To generate a cost estimate based on your projected usage, use thepricing calculator.

New Google Cloud users might be eligible for afree trial.

Before you begin

  1. Ensure that you have the Project Creator IAM role (roles/resourcemanager.projectCreator).Learn how to grant roles.
  2. In the Google Cloud console, go to the project selector page.

    Go to project selector

  3. ClickCreate project.

  4. Name your project. Make a note of your generated project ID.

  5. Edit the other fields as needed.

  6. ClickCreate.

  7. Verify that billing is enabled for your Google Cloud project.

  8. Enable the Cloud Build, Cloud Run functions, and Cloud KMS APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains theserviceusage.services.enable permission.Learn how to grant roles.

    Enable the APIs

When you finish the tasks that are described in this document, you can avoid continued billing by deleting the resources that you created. For more information, seeClean up.

Create the service account

Thedefault runtime service account for Cloud Run functions has the Editor role, which allows broad access tomany Google Cloud services. Although this is the fastest way to developfunctions, Google recommends using the default service account only for testingand development. You create a service account to limit the APIs that thefunction can use in accordance with theprinciple of least privilege.To create a service account, do the following:

  1. In the Google Cloud console, go to theService Accounts page.

    Go to Service Accounts

  2. Select your project.

  3. ClickCreate Service Account.

  4. In theService account name field, enterTokenization ServiceUser. The Google Cloud console fills in theService account IDfield based on this name.

  5. Optional: In theService account description field, enter adescription for the service account.

  6. ClickCreate and continue.

  7. ClickSelect a role, and then selectCloud KMS CryptoKey Encrypter/Decrypter.

  8. To finish creating the service account, clickDone.

    You now have a service account user with the following email address:

    tokenization-service-user@YOUR_PROJECT_ID.iam.gserviceaccount.com

Set up Cloud KMS

  1. In the Google Cloud console, openKey Management.

    Go to the Cryptographic Keys page

  2. Click+ Create key ring. In the dialog that appears, do the following:

    1. Name the key ringtokenization-service-kr.
    2. ForKey ring location, selectglobal. This is a common choicethat suffices for this example deployment. Before you make anyproduction architecture decisions, however, make sure you understand thedifferences between the various Cloud KMS locations.
    3. Double-check your choices, because youcan't delete or rename key rings after they are created.
    4. ClickCreate.

    The system creates the key ring and forwards you to the key creation page.

  3. In theCreate key dialog, do the following:

    1. Name the keycc-tokenization.
    2. ForPurpose, selectSymmetric encrypt/decrypt.
    3. SetRotation period to a value you choose, and clickCreate.

      Note: Keep track of your entries here. You need the project name, keyring name, key ring location, and key name to use in theCloud Run functions.

Create Cloud Run functions

This document assumes you'll be using Cloud Shell. If you use a differentterminal, be sure you have thelatest version of the Google Cloud CLI.

  1. In the Google Cloud console, open Cloud Shell:

    Go to Cloud Shell

  2. Clone the GitHub project repository and move to the working folder:

    gitclonehttps://github.com/GoogleCloudPlatform/communitygcp-communitycdgcp-community/tutorials/pci-tokenizer/

    Thegcs-cf-tokenizer folder contains the fileindex.js, which is thesource for two different Cloud Run functions that you will create. Italso containspackage.json, which tells Cloud Run functions whichpackages to run.

  3. Apply the KMS configuration: copy the config template file and open it forediting:

    cpconfig/default.jsonconfig/local.jsonnanoconfig/local.json

    The Node.js runtimerequires you to explicitly definethe Google Cloud project ID:

    "project_id":              "YOUR_PROJECT_ID"
  4. Find the KMS configuration and apply the KMS values you created in theprevious section:

    "location":                "global","key_ring":                "tokenization-service-kr","key_name":                "cc-tokenization"
  5. Deploy the tokenize function.

    gcloud functions deploy tokenize --runtime=nodejs18 --trigger-http \    --entry-point=kms_crypto_tokenize --memory=256MB \    --service-account=tokenization-service-user@YOUR_PROJECT_ID.iam.gserviceaccount.com \    --no-allow-unauthenticated --source=.

    This function turns the credit card information into a token.

  6. Look for the value of the URL underhttpsTrigger in the output of thegcloud functions deploy command. Store the value of the URLin theTOK_URL environment variable:

    TOK_URL="TOK_URL"

    You will use theTOK_URL environment variable to call thetokenize function.

  7. Deploy the detokenize function in KMS mode.

    gcloud functions deploy detokenize --runtime=nodejs18 --trigger-http \    --entry-point=kms_crypto_detokenize --memory=256MB \    --service-account=tokenization-service-user@YOUR_PROJECT_ID.iam.gserviceaccount.com \    --no-allow-unauthenticated --source=.

    This function reverses the tokenization process.

  8. Look for the value of the URL underhttpsTrigger in the output of thegcloud functions deploy command. Store the value of the URLin theDETOK_URL environment variable:

    DETOK_URL="DETOK_URL"

    You will use theDETOK_URL environment variable to call thedetokenize function.

    You have created two separate Cloud Run functions: one for turningthe card number into a token, and another to reverse the process. Thediffering entry points direct execution to the proper starting function intheindex.js file.

  9. When the functions are deployed, open the Cloud Run functions console.

    Open the Cloud Run functions console

  10. Verify that the functions were created. If all went well, you will see yourtwo functions with a check mark next to each one.

Create an authentication token

Theno-allow-unauthenticated option in thegcloud functions deploy command means that a caller that invokesthe functions must present an authentication token to assert the identity of thecaller. The caller must have thecloudfunctions.functions.invokepermission. The followingpre-defined roles have this permission:Cloud Functions Invoker, Cloud Functions Admin, and Cloud Functions Developer.

  • Create the authentication token:

    AUTH_TOKEN=$(gcloudauthprint-identity-token)echo$AUTH_TOKEN

These commands generate an authentication token string, store it in theenvironment variable$AUTH_TOKEN, and then display the token. Later you callthe Cloud Run functions that you deployed with the token.

Call the tokenizer

  1. Create some sample data to pass to the tokenizer:

    exportTOK_CC=4000300020001000exportTOK_MM=11exportTOK_YYYY=2028exportTOK_UID=543210
  2. Generate an authentication token as described in the previous section, and then callthe tokenizer:

    CC_TOKEN=$(curl -s \-X POST "$TOK_URL" \-H "Content-Type:application/json" \-H "Authorization: Bearer $AUTH_TOKEN" \--data '{"cc": "'$TOK_CC'", "mm": "'$TOK_MM'", "yyyy": "'$TOK_YYYY'", "user_id": "'$TOK_UID'"}' \)echo $CC_TOKEN

    The tokenization string representing the credit card data is displayed. Thisstring has been stored in the environment variableCC_TOK. You canretrieve the card information by invoking the detokenizer.

  3. Reverse the tokenization with the following command.

    DETOK_DATA=$(curl -s \-X POST "$DETOK_URL" \-H  "Content-Type:application/json" \-H "Authorization: Bearer $AUTH_TOKEN" \--data '{"user_id": "'$TOK_UID'", "token": "'$CC_TOKEN'"}' \)echo -e "$DETOK_DATA\n"

    The output looks something like the following:

    {"cc":"4000300020001000","mm":"11","yyyy":"2028","userid":"543210"}

    This data is what was originally sent into the tokenizer, decrypted, andretrieved by your app.

Expand on this example

Thesample code on GitHubis an excellent start, but there is more toconsider before moving to production.

If you choose to use Cloud Run functions for payment card tokenization, youmight need to do more work to satisfy your Qualified Security Assessor orSelf-Assessment Questionnaire. Specifically, PCI DSS sections 1.2 and 1.3require tight controls on inbound and outbound traffic. Cloud Run functionsand App Engine don't offer a two-way configurable firewall, so you must eithercreate compensating controls or deploy the tokenization service onCompute Engine or Google Kubernetes Engine. If you would like to explorecontainerization, the GitHub code is Docker compatible and contains supportingdocumentation.

This sample code also pulls in the npm (Node.js package manager) dependencies ondeployment. In your production environment, always pin dependencies to specificvetted versions. Then bundle these versions with the app itself orserve them from a private and trusted location. Either approach helps you avoiddowntime resulting from an outage at the public npm repository or from asupply-chain attack that infects packages that you assumed were safe. If youpre-build and bundle the complete app, your deployment time typicallydecreases, which means faster launches and smoother scaling.

Clean up

To avoid incurring charges to your Google Cloud account for the resourcesused in this example deployment you can delete the project that contains theresources.

    Caution: Deleting a project has the following effects:
    • Everything in the project is deleted. If you used an existing project for the tasks in this document, when you delete it, you also delete any other work you've done in the project.
    • Custom project IDs are lost. When you created this project, you might have created a custom project ID that you want to use in the future. To preserve the URLs that use the project ID, such as anappspot.com URL, delete selected resources inside the project instead of deleting the whole project.
  1. In the Google Cloud console, go to theManage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then clickDelete.
  3. In the dialog, type the project ID, and then clickShut down to delete the project.

What's next

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-04-28 UTC.