Skip to Content
Technical Articles
Author's profile photo Martin Pankraz

SAP private linky swear with Azure – enabling SAP CAP with Azure services without OData APIs using SAP Private Link

This post is part of a series sharing service implementation experience and possible applications of SAP Private Link Service on Azure.

Find the table of contents and my curated news regarding series updates here.

Find the associated GitHub repos here and here.

Dear community,

Continuing with the implementation journey of SAP Private Link Service (PLS) for Azure we will have a closer look at connecting privately to Azure services that don’t have an OData interface today from apps implemented with SAP Cloud Application Programming Model (CAP). You might say that SAP CAP can connect to non-BTP sources via the SAP Cloud SDK or custom coding. However, if an OData API is available, it works out of the box and allows for separation of concerns. Multiple BTP apps may use the same interface without the need for each of them to take a dependency on the Azure SDK.

So, why not meet CAP halfway?

We will do so using a translator app running on Azure App Service in a private virtual network on Azure exposed via SAP Private Link.

The provided translator app is pre-configured to work with Azure Cosmos DB and Azure Blob storage. Its structure is modular and open for you to add any service you desire.

Any scenario top of mind already? Reach out via GitHub or leave a note down below under this post.

Fig.1 Architecture overview depicting the protocol translation and the SAP Private Link exposure.

Let’s take a look under the hood

To replicate the scenario, create a basic private Azure VNet, provision a serverless Azure Cosmos DB for NoSQL instance and windows-based Azure App Service into it. Make sure all resources are in the same region. You may do this via CLI, the Azure portal, bicep, or terraform for instance. See below guidance for the portal-based approach.

Fig.2 Detailed Azure deployment view from the Azure portal

Data setup and integration test

Before we make everything private and troubleshooting becomes harder (would require private VNet access via Azure Bastion service for instance or VPN), let’s verify initial integration.

I am using the famous SAP SFlight demo data set on Cosmos as a sample. It is stored in database “saps4” in container “sflight”.

Fig.3 Screenshot of Sflight data set in Data Explorer of Cosmos DB

You may synch the data from SAP or for the sake of quicker getting started generating it using the Cosmos DB Data Explorer with below steps:

Fig.4 ChatGPT generated guidance to create SFlight data set in Cosmos DB

  "id": "006",
  "carrid": "AA",
  "connid": "64",
  "fldate": "2016-06-17",
  "planetype": "A310-300",
  "seatsmax": 280,
  "seatsocc": 10

Deploy the code for the translator app via the provided script for convenience:

az login
.\publish.bat [your resource group] [name of above created app service]

Once finished call the APIs to verify proper setup with public endpoints still.

Local execution (or from GitHub Codespaces) is also possible at this point:

cd .\GenericODataWebAPI\
dotnet run

Find a sample call library on the repos here.

Call http://localhost:52056/api/odata/Sflight for the integration test. It should look something like this:

Fig.5 Sflight output from local OData request via translator app

So far so good. Now we will inject all services into our private VNet and prepare the SAP Private Link.

Fig.6 Screenshot of Cosmos DB private network setup

Note the associated VNet in above screen and the marked checkbox to retain access to the database via the portal. Believe me been there, done that 😉

Fig.7 Screenshot of App Service private network setup

Inject the Azure App Service into the same VNet as your Cosmos instance. See above for a reference.

Swoosh 🌪️ At this point you can reach the database only via the App Service! Don’t believe me? Go on and check. Trust is good but verification is better as they say🧐

Now onwards to the private link. Collect the resource id of your app service either from the properties pane or my favourite option: From the JSON view of the Overview pane.

Fig.8 Screenshot of App Service resource id retrieval

Login into your BTP subaccount and create a new instance of SAP Private Link called “odata-proxy-pls” providing the required properties for Azure App Service. See the SAP docs for further details.

Fig.9 Screenshot of SAP Private Link create view for Azure App Service

This triggers the connection request on the Azure App Service from your BTP account. Go on hit approve. I will wait ⏳

Fig.10 Screenshot of SAP Private Link approval in Azure

Done? Ok, great. Now we are ready to deploy our CAP app to “seal” the private link and create the Cloud Foundry service binding.

I provided a repos for this purpose. Find more details on how to deploy via Business Application Studio (BAS) or the likes there too. I ran “cf deploy”.

Fig.11 Screenshot of CAP app config with emphasis on SAP Private Link config

See above the reference on the CAP app binding itself to the SAP Private Link pointing to the Azure App Service.

Be aware that you require an SSH tunnel on BAS for local testing reaching through the private link to Azure. Otherwise only deployed apps have access due to the Cloud Foundry security groups. Find more details here.

With that we can retrieve the hostname to reach the private link and maintain our destination on BTP.

Fig.12 Screenshot of SAP BTP Destination setup using Private Link

For now, I didn’t put authentication on the App Service but is pre-configured to use Azure AD. Have a look here. Once you decided what authentication flow to use adjust the destination above accordingly.

Broke a sweat yet? 🥵

Either way you may be glad to hear we are done 💪Yes, go on call the CAP app URL and marvel and the privately served data from Cosmos DB as OData stream:

Fig.13 Screenshot of SAP CAP app OData output requested from Cosmos DB

Thanks to the translator app we are serving OData from Azure Cosmos DB tapping into the dotnet NoSQL API even though Cosmos DB doesn’t have an OData interface for the NoSQL API. And all of that privately!

Focus of this blog was on advocating for the private link approach and deeper understanding of the setup rather than enterprise scale. However, all steps taken can be accomplished via infrastructure-as-Code. I can highly recommend the Azure Developer CLI (AZD). For BTP components consider the BTP Setup Automator.

In addition to that I am considering adding the AZD configuration to the repos at later point in time. Would appreciate any help from the community!

Thoughts on production readiness

SAP Private Link is generally available and therefore completely ready for prime time (quoting Gowri from the SAP engineering team 😊).

Cosmos DB powers critical globally available solutions like NEXT GAMES apps with real-time leader board requirements or the data hub of Deutsche Börse AG for instance. For additional stories, have a look at the official portal or the nice community offering Azure Charts.

Cosmos DB scales on its own, match that setup for your CF app on BTP where required with the Application Autoscaler.

Azure App Service is a full-blown PaaS offering to run apps, APIs in all major programming languages, with native integration with Azure AD (no need for custom code), Log Analytics, Application Insights, and Key Vault etc. Have a look here for more goodies. You may even run the SAP Cloud SDK on App Service.

Final Words

Alrighty, folks! Today we continued our SAP Private Link with Azure journey to the Azure App Service – a match made in tech-heaven! We took a closer look at how to connect privately to Azure services that don’t offer an OData interface today, using a translator app running on the App Service.

The provided repos is fully operational to translate to OData for Azure Cosmos DB and has the foundation pre-configured for Azure Blob Storage. You need a different service or prefer to private-link directly sacrificing OData? Let me know in the comments or open an Issue on GitHub or go all-in with a Pull-Request 😊

Till then: sit back, relax, and let’s get private linking!

Any comments regarding your individual integration journey with SAP Private Link SAP @Developers and @Architects?

Find the related GitHub repos here and here.

Find your way back to the aggregator blog post here.

As always feel free to ask lots of follow-up questions.


Best Regards


Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Mustafa Bensan
      Mustafa Bensan

      Hi Martin,

      The solution diagram notes "Blending with S4 data" next to the OData connection.  For clarity, can you confirm where the S4 data is coming from as the diagram doesn't show the S4 integration point?



      Author's profile photo Martin Pankraz
      Martin Pankraz
      Blog Post Author

      Good call out Mustafa. The idea was to depict the blending of data on the level of the CAP app without overcomplicating the drawing. I agree it might be misleading. Since the focus is on private connectivity I am dropping the text.


      Author's profile photo Mustafa Bensan
      Mustafa Bensan

      In that case, the architecture could be simplified even further by deploying the CAP app directly on Azure so there  is only one PaaS to manage instead of two 🙂

      Author's profile photo Martin Pankraz
      Martin Pankraz
      Blog Post Author

      Up to the developers and customers to decide where to put their applications. But generally speaking that would be an alternative option (VNet injection required), yes.