BTP private linky swear with Azure – connecting to not-yet supported PaaS with Private Link Service for Azure
This post is part of a series sharing service implementation experience and possible applications of BTP Private Link Service on Azure.
Find the table of contents and my curated news regarding series updates here.
Find the associated GitHub repos here.
Continuing with the implementation journey of BTP Private Link Service (PLS) we will have a closer look at integrating services from the Azure PaaS portfolio, that are not yet added by SAP to the BTP solution.
This post builds upon part 6 of the series in terms of SAP Personal Security Environment (PSE).
Fig. 1 Applying PLS for unsupported PaaS leads to cyborg pinkie
As an example for the generalized approach for Azure PaaS, I will use Azure API Management (APIM) today. Azure APIM could be fronting an SAP system like SAP Gateway, S/4HANA, Process Orchestration (PI/PO) or Microsoft services like Azure Functions, Dynamics365 etc. Any REST interface, including the specialized OData standard, would be possible.
In an ideal world, we would architect like so:
Fig.2 ideal world with OData request
Since we can’t establish the link with comfort and ease, we need to check our toolbox and see what else is available.
Mhm, proxies, reverse connect components, web dispatchers, port forwarders… and of course our beloved IaaS component – the virtual machine. Urgh, really? I am afraid so.
Does it work? Yes indeed.
I am describing two concepts that are bearable and easily adaptable if the future brings more native integration.
Fig.3 not as great as true PaaS but gets the job done; source: thecodinglove.com
Let’s look at the moving parts
Before we get started let’s make sure our target PaaS app is VNet integrated and ideally only reachable from within the private VNet. That configuration would be typically in line with deploying a private link in the first place.
|Note: In case you keep APIM Internet-facing but VNet integrated you can skip the DNS or hosts file configs mentioned later.|
Fig.4 Screenshot of private APIM network setting
At the heart of the first option is the SAP Web Dispatcher (WDisp). It allows us to re-use the BTP Private Link service for VM based scenarios and direct certain http requests towards the private Azure APIM next to the configured SAP backends.
Fig.5 PLS architecture with SAP WDisp and Azure APIM
Great, why don’t we do this all the time for PaaS apps?
Because this requires an additional IaaS component, that needs to be managed, patched, considered for disaster recovery, backup, and high availability. The point of private link for managed services was to avoid such things, right 😉. Like I said before “in an ideal world”. Sigh…
Once, we are happy with all of that, we can apply the same steps for the Azure Private Link Service and load balancer that is bound to BTP as described in part 1 of the blog series.
We simply re-use our existing backend pool.
Fig.6 Screenshot from WDisp backend pool
Fig.7 Screenshot from WDisp load balancing rule
In my example I configured port 44399 as inbound rule from BTP. So, to call through this route, we need to adjust our destinations on BTP to use this port. Meaning the hostname on BTP stays the same and the various routings happen through the different ports (e.g., SAP S/4Hana behind the WDisp through 443).
Fig.8 Screenshot from BTP destination with PLS host name and port 44399
The configuration on the SAP WDisp including the hosts file entry on the same VM (consider DNS for a more scalable solution) ensures that the request from BTP gets “forwarded” to the private IP of your Azure APIM instance on the respective standard SSL port.
Fig.9 Screenshot collection of hosts file on WDisp and APIM private IP
Ok great, now on to the WDisp config 😊 We need to add a system target with special SID EXT and configure our APIM target with the mentioned port associated with the load balancing rule behind the private link service (in my case 44399). Additionally, there is the WDisp parameter SRCURL that restricts the rule to specific paths and allows for more complex routing. In my case I used the prefix /api, which is being used by the Java app on BTP.
Fig.10 Screenshot of WDisp Cockpit and parameter config
Finally add a rule (see rules.txt) to override host header, so that APIM accepts the request from BTP (initially supplying host header *sap.pls.internal). See SAP’s docs for additional context around the rules override.
Fig.11 Screenshot of rules.txt file to override host header
I am not going into more detail around PSE at this point for more concise reaeding. Read more about SNI and PSE Management on part 6 of the series.
As a test I pointed my Java app at Azure APIM through PLS hitting the sample Products OData service on SAP.
Fig.12 Screenshot collection from Azure APIM and Java app response
As you can see the request made its way through the described hops and hit the OData service via Azure APIM. At this point you can govern your SAP APIs as well non-SAP APIs in one central place while connecting via private link from BTP. Great, isn’t it? 😊
Not too happy yet?
In case you have customizing nightmares about DNS, hosts files and WDisp, here is option two that you might like a little better then for its BTP connectivity focus and specialized features.
Fig.12 Alternative architecture with SAP Cloud Connector
Falling back to the SAP Cloud Connector (SCC) for the private isolated connectivity is an option. However, you retain the burden of considering maintaining/patching, handling disaster-recovery, backup, and high availability for the VMs hosting the SCC. Also you don’t profit from the Microsoft backbone and the PaaS aspect of the SAP Private Link Service for Azure and require outbound ports open to the Internet.
The only upside is, that this is an SAP native component and lifts the need to make OS level configurations and overrides the WDisp required to route the requests. The SCC does this for you under the hood. You might consider it a fancy BTP-opinionated dispatcher.
Fig.13 Screenshot from SAP Cloud Connector config for Azure APIM
Once configured you once again adjust the destination on BTP to reflect the host mapping. In my example the virtual host expected by the SCC is “azure-apim”.
Fig.14 Screenshot from Destination on BTP
The proxy type OnPremise ensures routing to your registered SCC.
What about the other routing options from the toolbox?
You might be tempted to use a port forwarder instead of the SAP WDisp if you don’t have any. Unfortunately, the target PaaS services expects its known host header (in my example that was my-odata-apim.azure-api.net for instance). Since your request originates from SAP BTP with SAP’s generated domain you will run into connectivity issues.
Port forwarder OUT! What about reverse proxy then?
That would be the same approach as with the SAP WDisp utilizing host header override logic. If you prefer NGINX, Apache or whatever product you run there, you can adapt the approach outlined at the beginning. Key is the DNS resolution of your private Azure APIM instance and host header override.
Thoughts on production readiness
Both approaches – the SAP Web Dispatcher and the SAP Cloud Connector – are established at companies for many years. They differ in scope though. The SCC is primarily and solemnly targeted at opening a secure tunnel (reverse connect) to BTP only. The WDisp is a specialized load balancer for SAP systems for internal and external purposes.
Either way both options are workable, but you might have a preference given your experience and skill set in the team operating the landscape.
- A view on Azure APIM for SAP workloads and C# projects
- A GitHub repo to get you started with SAP specific artifacts for Azure APIM
- How to convert SAP OData to OpenAPI for Azure APIM
Uhh, what a ride. We saw how to go beyond the scope of the BTP Private Link Service (PLS) using two different approaches to add Azure PaaS apps like the Azure API Management to the mix. This might be useful to cover integration targets that are not yet natively supported by the PLS. If you are comfortable with the challenges of a dispatcher and DNS, you can apply the concept to the PLS. In case you want a more SAP native implementation for BTP, SAP Cloud Connector is your friend.
Any further inputs from you @Developers and @Architects?
Find the related GitHub repos here.
#Kudos to Robert Biro, who once more helped me with the final mile on the SAP WDisp 🙂
As always feel free to ask lots of follow-up questions.