Skip to Content
Technical Articles

Writing Function-as-a-Service [10]: Call protected endpoint across Subaccounts

This blog is part of a series of tutorials explaining how to write serverless functions using the Functions-as-a-Service offering in SAP Cloud Platform Serverless Runtime

Quicklinks:
Quick Guide
Sample Code

Introduction

In the previous tutorial we‘ve learned how to call a service which is protected with OAuth and requires a scope.
The challenge was:
-> how can the function possess the scope?
The solution was:
-> configuration of both xs-security.json files

BUT:
There was a precondition:
-> both app and function have to live in the same subaccount

This is necessary because the central XSUAA of the subaccount creates one oauth-client for each instance and assigns the granted scope to the other client.
Thus, it has to resolve the names of the scope and involved clients
This is possible because the name of the scope is made unique and identifiable by adding the variable $XSAPPNAME to the scope name.
As we all know, the value of the variable is not just the same as the name of the property xsappname
The value of $XSAPPNAME is generated at runtime and contains some mystic suffix !t1234

OK.
Today we want to call from the function to a service which lives in a different subaccount.
So now, the XSUAA has to find not only the correct scope and oauth-client.
It has to find it in a different subaccount (identityzone)

How to do it?
-> communicate with the other central XSUAA

How to find that one?
-> By the unique identifier of the subaccount (identityzone)

As such, we have to add the subaccountID to the GRANT statement

And that’s already all for today

Nevertheless, let’s make it real

Overview

In this tutorial, we’re going to learn how to assign a scope to an application in a different subaccount

The scenario is almost the same as in the previous tutorial.
We can either re-use it and do the required little changes
Or create the project as described below, everything based on the previous blog

In the first part of this tutorial, we’re creating a very basic app which exposes an endpoint which is protected with OAuth and which requires a certain scope
In the second part, we’re creating a Function which tries to call that endpoint

Part 1: The Protected App
Create xsuaa, define scope
Create app, check scope

Part 2: The Calling Function
Create xsuaa, define authority
Create Function, do OAuth flow

Prerequisites

  • If you’re new to the topic, the previous tutorial is a prerequisite, along with all its prerequisites and blablabla
  • In addition:
    To follow this tutorial, we need 2 different subaccounts.
    In my example, I’m using my trial account, in addition to my FaaS-account (containing the instance of SAP Cloud Platform serverless runtime)
    Limitation:
    Both accounts have to live in the same data center (in my example, eu10)

Preparation: Create Project Structure

Same preparation like in previous blog: create files and folders

In addition:
We need to find the ID of the FaaS-subaccount.
It is easy to find: just open the subaccount in the cloud cockpit
Which subaccount?
We need the ID of the subaccount where the FaaS is located

Part 1: The Protected App

Almost same as part 1 of previous tutorial
Really only the xs-security.json file is little bit different

1.1. Security Configuration

This is the essential section of this tutorial:
Here we’re using the subaccount ID:
-> grant the scope to an oauth-client living in the specified subaccount

{
  "xsappname" : "xsappforsafeapp",
  "scopes": [{
      "name": "$XSAPPNAME.scopeformysafety",
      "grant-as-authority-to-apps" : [ "$XSAPPNAME(application, 12ab12ab-34cd-56ef-34cd-12ab12ab12ab, xsappforfaas)"]
  }]
}

 

Syntax:

"grant-as-authority-to-apps" : [ 
  "$XSAPPNAME(<service_plan>, <subaccount_id>, < xsappname_of_caller >)"
]

After clarifying the new security descriptor, we create an instance of XSUAA in our Trial account (or whatever account you’ve chosen)

We have to make sure that we’re targeting the different account, e.g. trial
To change location:

cf t -o p123456trial

see:

OK, for your convenience, here’s again the command to create a service instance:
In my example, we jump into C:\tmp_faas_callsafe\safeapp and run the following command

cf cs xsuaa application xsuaaforsafetyapp -c xs-security-safe.json

1.2. Create Application

No change needed to the app.
Just take the sample code (Part 1) from previous tutorial

1.3. Deploy and Run the App

Yapp, just deploy it to the different account.
No need to run it, we did it in the previous torture

1.4. Small Recap

We deploy a protected app to trial account.
We specify that the Function of FAC account is allowed to call us
So we add a statement to grant access to the calling xsapp
And here is the place to enter the ID of the FAC account

Part 2: The Calling Function

Again, all the same as in one of the other boring tutorials

2.1. Security Configuration

In part 1 we learned how to grant a scope to an xsuaa instance in a different subaccount
Now we’re on the receiving side: we receive the granted scope and we need to accept it
In the previous tutorial, we used the following statement:

“authorities”:[“$XSAPPNAME(application,xsappforsafeapp).scopeformysafety”]

Now we would need to make clear where to find that foreign xsapp
However, I haven’t found a way to add the subaccountID in this statement
OK, no prob.
-> we have to fall back to the generic statement:

“authorities”:[“$ACCEPT_GRANTED_AUTHORITIES”]

Using this statement, we accept all scopes granted by anybody to our app (xsapp, to be more precise)

So now we open the file xs-security-faas.json, in folder unsafefunction and enter the following content

{
  "xsappname" : "xsappforfaas",
  "tenant-mode" : "dedicated",
  "authorities":["$ACCEPT_GRANTED_AUTHORITIES"]
}

Note:
This statement doesn’t apply only for different subaccounts, it can be used in any scenario

As usual. this JSON config can be used to create or update  an instance of XSUAA.

Before executing a command, don’t forget that this time, we have to make sure that we target the subaccount where FaaS is living

To create the XSUAA-instance for FaaS, we jump into the function folder unsafefunction then:

cf cs xsuaa application xsuaaforfaas -c xs-security-faas.json

And create a service key:

cf csk xsuaaforfaas servicekeyforfaas

BUT:
If you have the scenario in place, It is enough to update the existing service:

cf update-service xsuaaforfaas -c xs-security-faas.json

 

 

2.2. Create Function

All the same as in previous hands-on. It shouldn’t be necessary to do any change, register or deploy.
But it might be necessary to repeat steps, if the xsuaa instance was deleted, etc
Or to adapt the code, if the name of the protected app was changed in trial

Otherwise, we can just use the deployed function, if remaining from the previous blog

Or we create everything from scratch, based on the sample code Part 2

 

And then, finally, we invoke the function and are happy to see the same result which we had before
No shame to be happy:
We’ve learned the little trick which enables us to cross the borders of subaccounts

Summary

In this blog we’ve learned almost nothing
Just adding a cryptic guid in the middle of a cryptic statement
Luckily, the blog post hasn’t been too long…

Quick Guide

The protected app which is called by the Function has to grant the scope to the Function
If both are not located in the same subaccount, then the subaccountID of the Function has to be added (ID can be found in the cockpit)

xs-security.json of protected app:

"scopes": [{
      "name": "$XSAPPNAME.scopeformysafety",
      "grant-as-authority-to-apps" : [ 
         "$XSAPPNAME(application, 12345678-abcd-..., xsappforfaas)"


The calling Function has to accept the grant. In case of different subaccounts, the generic statement has to be used to accept all granted scopes

xs-security.json: of Function

 

"authorities":["$ACCEPT_GRANTED_AUTHORITIES"]

Same as in previous tuutorial

Appendix: All Project Files

The whole project can be found in previous tutorial

However, we have to adjust the following files in both projects

Part 1: The Protected App

These files are located in the folder “safeapp”

xs-security-safe.json

{
  "xsappname" : "xsappforsafeapp",
  "tenant-mode" : "dedicated",
  "scopes": [{
      "name": "$XSAPPNAME.scopeformysafety",
      "grant-as-authority-to-apps" : [ 
         "$XSAPPNAME(application, 1a2b3c4d-0000-1111-aaaa-..., xsappforfaas)"
      ]
  }]
}

Part 2: The Calling Function

They are located in the folder “unsafefunction”

xs-security-faas.json

{
  "xsappname" : "xsappforfaas",
  "tenant-mode" : "dedicated",
  "authorities":["$ACCEPT_GRANTED_AUTHORITIES"]
}

 

3 Comments
You must be Logged on to comment or reply to a post.
  • Hi Carlos, great content and great series related to FaaS! But reading this article, I was wondering how we can deal with the subaccount id “hard-coded” in the xs-security.json file in a CI/CD (DevOps) scenario, because if we need to transport the application in a traditional landscape (DEV -> TEST -> PROD), how we can deal with the different subaccount ids and automate the deployment process?

     

    Regards,

    Fabiano Rosa

    • Hello Fabiano Rosa , thanks a lot for the feedback!!

      And for your interesting question. I don’t have an answer, I haven’t found any info about adding dynamic variables to the security descriptot
      What I’m thinking of: is the creation of service instances part of your CI/CD pipeline?
      You could dynamically create the service instance and pass the params with relevant subaccountID from memory.
      Do you know the CF API?
      http://v3-apidocs.cloudfoundry.org/version/3.87.0/index.html#create-a-service-instance

      Hope that helps for your scenario.
      Otherwise, you could post the question at answers.sap.com to let security-experts provide their opinion
      Cheers,
      Carlos

       

      • Hi Carlos, thanks for the feedback, and yes, the security descriptor and the yaml/mta descriptors are part of the pipeline. I’ll try to do some tests with MTA Extension Descriptors and maybe I can address this limitation.

        Thanks!

        Regards,

        Fabiano Rosa