https://raw.githubusercontent.com/ajmaradiaga/feeds/main/scmt/topics/SAP-Connectivity-service-blog-posts.xml SAP Community - SAP Connectivity service 2024-05-20T11:12:36.375557+00:00 python-feedgen SAP Connectivity service blog posts in SAP Community https://community.sap.com/t5/technology-blogs-by-sap/surviving-and-thriving-with-the-sap-cloud-application-programming-model/ba-p/13570264 Surviving and Thriving with the SAP Cloud Application Programming Model: Deployment to SAP BTP, Kyma runtime 2023-03-07T15:51:05+01:00 maxstreifeneder https://community.sap.com/t5/user/viewprofilepage/user-id/95 Greetings and salutations, fellow CAP enthusiasts! We're back with another episode of "Surviving and thriving with the SAP Cloud Application Programming Model" (<A href="https://blogs.sap.com/tag/captricks/" target="_blank" rel="noopener noreferrer">#CAPTricks</A>). Last time, we covered the wild and bumpy ride of getting your app up and running on your local machine, complete with all the twists and turns of talking to on-premise systems via the Cloud Connector and whatnot.<BR /> <BR /> But now, I've been experimenting with the SAP BTP, Kyma runtime, and wanted to see just how quick and easy it is to take our "trusty old CAP app" from the Cloud Foundry environment over to the Kyma landscape - it's been quite a journey for me personally. Now, if you're still thinking this series is going to be a neat and tidy chronology, I hate to disappoint - I just write about what pops up on my radar. (But don't worry, I've got much more like integration and UI tests on the horizon, I just need to do some more research before I feel confident enough to share my findings. <span class="lia-unicode-emoji" title=":winking_face:">😉</span>)<BR /> <BR /> I've been primarily working with the SAP BTP, Cloud Foundry runtime, but we have seen a growing demand and need for applications to be deployed and running on Kubernetes. SAP provides a managed Kubernetes-based runtime called SAP BTP, Kyma runtime which has started as the open-source project <A href="https://kyma-project.io/" target="_blank" rel="nofollow noopener noreferrer">Kyma</A>. With loads of discussions on which SAP BTP environment to choose, this blog post will dive into the technical aspects of deploying a CAP application on the SAP BTP, Kyma runtime.<BR /> <BR /> Full disclosure as usual: I'm not exactly a Kubernetes pro, especially not in a production setting or within the context of SAP. My experience has mostly been limited to playing around with hosting dedicated GitHub Actions runners for small projects or doing "Hello World" stuff. But, the recent changes in the CAP on Kyma movement caught my eye because it involves a new approach to deployment and service binding. That's why I decided to dive a little deeper and learn more about it.<BR /> <H3 id="toc-hId-1092917699"><STRONG>Common Ground: SAP BTP, Cloud Foundry runtime and SAP BTP, Kyma runtime</STRONG></H3><BR /> I'm not here to delve into the differences between SAP BTP, Kyma runtime and SAP BTP, Cloud Foundry runtime or to argue for one over the other. Instead, my focus is on the technical aspects of deploying a CAP application to Kubernetes.<BR /> <BR /> Kubernetes? Yes, the SAP BTP, Kyma runtime is essentially "<EM>a fully managed Kubernetes runtime based on the open-source project "Kyma". This cloud-native solution allows the developers to extend SAP solutions with serverless Functions and combine them with containerized microservices. The offered functionality ensures smooth consumption of SAP and non-SAP applications, running workloads in a highly scalable environment, and building event- and API-based extensions</EM>", so the <A href="https://discovery-center.cloud.sap/serviceCatalog/kyma-runtime?region=all" target="_blank" rel="nofollow noopener noreferrer">service description in the SAP Discovery Center</A>.<BR /> <BR /> To gain a better understanding, I recommend checking out available resources such as the SAP Community Call with <SPAN class="mention-scrubbed">piotr.tesny</SPAN> and <SPAN class="mention-scrubbed">jamie.cawley</SPAN> titled "<A href="https://www.youtube.com/watch?v=RhSF9ZBcHsg" target="_blank" rel="nofollow noopener noreferrer">Understand the value proposition of SAP BTP, Kyma runtime by example</A>," or the "<A href="https://www.youtube.com/playlist?list=PL6RpkC85SLQCwaJ54TAAHMvSl5wpVPrai" target="_blank" rel="nofollow noopener noreferrer">2 Minutes of Cloud Native</A>" playlist by my friend and former colleague, <SPAN class="mention-scrubbed">kevin.muessig</SPAN>. You could also start with some <A href="https://kubernetes.io/training/" target="_blank" rel="nofollow noopener noreferrer">well-known Kubernetes courses</A>.<BR /> <BR /> Before discussing the differences between the runtimes, let's first highlight their similarities. Both runtimes operate on the SAP Business Technology Platform and have an entry point in the platform, making this their commonality.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/02/btp-cockpit.png" /></P><BR /> &nbsp;<BR /> <BR /> At first glance, both platforms may appear similar, as they provide an abstraction layer for developers to focus on application development and deployment, without the need to worry about the underlying infrastructure. Additionally, both platforms support containerization, allowing applications to be packaged in a consistent and portable way, making them easier to manage and deploy.<BR /> <H3 id="toc-hId-896404194"><STRONG>Deployment differences:&nbsp;SAP BTP, Cloud Foundry runtime and SAP BTP, Kyma runtime</STRONG></H3><BR /> Let's talk about the deployment differences between SAP BTP, Cloud Foundry runtime and SAP BTP, Kyma runtime. Obviously, the command line tools to interact with the environments are different. While the Cloud Foundry CLI was the go-to tool to interact with the SAP BTP, Cloud Foundry runtime, kubectl is the tool you'll need to get cozy with in the world of SAP BTP, Kyma runtime.<BR /> <BR /> So, let's quickly recap how you'd deploy a CAP application to SAP BTP, Cloud Foundry runtime:<BR /> <OL><BR /> <LI>Develop your CAP Full-Stack application (often underrated in the whole process <span class="lia-unicode-emoji" title=":winking_face:">😉</span>)</LI><BR /> <LI>Build an mta.yaml deployment descriptor with the help of <STRONG>cds add mta</STRONG></LI><BR /> <LI>Create an MTA archive with the <A href="https://sap.github.io/cloud-mta-build-tool/" target="_blank" rel="nofollow noopener noreferrer">Cloud MTA Build Tool: </A><STRONG>mbt build</STRONG></LI><BR /> <LI>Deploy the MTA archive using a<I>&nbsp;</I>CF CLI plugin called <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/27f3af39c2584d4ea8c15ba8c282fd75.html" target="_blank" rel="noopener noreferrer">multiapps</A>: <STRONG>cf deploy</STRONG></LI><BR /> </OL><BR /> The <A href="https://help.sap.com/docs/btp/sap-business-technology-platform/multitarget-applications-in-cloud-foundry-environment" target="_blank" rel="noopener noreferrer">MTA (Multi-Target Application)</A> is <A href="https://www.youtube.com/watch?v=Bo5qtTsmObY" target="_blank" rel="nofollow noopener noreferrer">technically just a ZIP file</A> that the SAP BTP, Cloud Foundry runtime (specifically the deploy service) picks up and generates the container for you. The platform takes care of managing the service instances, like creating, updating, and deleting them as needed. As a developer, all you have to do is provide a properly structured ZIP file - the MTA archive. The SAP BTP, Cloud Foundry runtime and its components create the container and the image (<A href="https://docs.cloudfoundry.org/concepts/diego/diego-architecture.html" target="_blank" rel="nofollow noopener noreferrer">Diego cells and droplets</A>) automatically for you.<BR /> <BR /> The deployment of applications to Kubernetes-based environments (like SAP BTP, Kyma runtime) is a little different but provides more flexibility. However, as they say, <A href="https://en.wikipedia.org/wiki/With_great_power_comes_great_responsibility" target="_blank" rel="nofollow noopener noreferrer">with great power comes great responsibility.</A> In a nutshell:<BR /> <OL><BR /> <LI>Develop your CAP Full-Stack application</LI><BR /> <LI>Add a Helm Chart configuration for a common CAP application with the help of <STRONG>cds add helm</STRONG></LI><BR /> <LI>Configure the right values for the provided Helm Chart of a common CAP application</LI><BR /> <LI>Create the needed Docker Images with the help of Paketo: <STRONG>pack build</STRONG></LI><BR /> <LI>Install the Helm Chart to the Kubernetes Cluster: <STRONG>helm install</STRONG></LI><BR /> </OL><BR /> Paketo, Helm? You might be wondering about Paketo and Helm. Don't worry; we'll cover that in a bit. The main difference is that with Kubernetes-based environments, you're responsible for creating the application (Docker) image and not any platform. Kubernetes picks up the Docker images and creates the container, while Cloud Foundry takes care of the entire process from the MTA archive to running a container.<BR /> <BR /> At first, this might sound complicated (it did for me!) but it's not as tough as it seems. Let's dive into the two tools, Paketo and Helm, that will help with your deployment tremendously.<BR /> <H3 id="toc-hId-699890689">What's Paketo?</H3><BR /> Before we dive into Paketo in detail, let's take a step back to better understand where it's coming from. When a developer deploys an application to Cloud Foundry, the container and image to run the application are created by Cloud Foundry, using buildpacks. So, what exactly are buildpacks? According to the official Cloud Foundry documentation: <A href="https://docs.cloudfoundry.org/buildpacks/" target="_blank" rel="nofollow noopener noreferrer">The official Cloud Foundry documentation</A> states the following:<BR /> <BLOCKQUOTE><EM>"Buildpacks provide framework and runtime support for apps. Buildpacks typically examine your apps to determine what dependencies to download and how to configure the apps to communicate with bound services.</EM><BR /> <BR /> <EM>When you push an app, Cloud Foundry automatically detects an appropriate buildpack for it. This buildpack is used to compile or prepare your app for launch."</EM></BLOCKQUOTE><BR /> In short: You provide the application. Cloud Foundry does the rest to figure out what's needed and creates the container and image to run your stuff.<BR /> <BR /> Kubernetes, on the other hand, relies on Docker images to run applications or workloads in general. This means that the responsibility shifts to you, as the developer, to build the Dockerfile. While this is manageable, there are more convenient ways. And that's where Paketo comes in. Paketo provides buildpacks without actually using Cloud Foundry.<BR /> <BR /> Built by the Cloud Foundry buildpacks team, Paketo allows you to build Docker images with a single command and without any additional configuration. Using the Paketo CLI, called pack, you can quickly create Docker images for your application. Want to see it in action? Here we go:<BR /> <PRE class="language-bash"><CODE>pack build ghcr.io/maxstreifeneder/verificationapp-srv:test --path gen/srv \ <BR /> --builder paketobuildpacks/builder:base \<BR /> --publish</CODE></PRE><BR /> The command "pack build" is used to create a Docker image. The command specifies the following options:<BR /> <UL><BR /> <LI><EM>ghcr.io/maxstreifeneder/verificationapp-srv:test</EM> is the name and tag of the Docker image that will be created.</LI><BR /> <LI><EM>--path gen/srv</EM> specifies the path where the application artifacts are located (cds build --production has generated the needed artefacts in there)</LI><BR /> <LI><EM>--builder paketobuildpacks/builder:base</EM> specifies which builder to use for the image. In this case, the "base" builder is being used from the Paketo Buildpacks project. (basically, which base OS to pick)</LI><BR /> <LI>--publish specifies that the image should be published to the specified container registry after it is built.</LI><BR /> </UL><BR /> The command will analyse the contents of the specified path ("gen/srv"), and will use the Paketo builder to determine which dependencies are required to run the application. Once the dependencies have been determined, the necessary packages will be installed and the Docker image will be created.<BR /> <BR /> After the image is created, it will be tagged with "ghcr.io/maxstreifeneder/verificationapp-srv:test" and published to the specified container registry.<BR /> <BR /> Initially, pack analyses the type of project that needs to be handled:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/packeto_analyze.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">pack cli detected which buildpacks are needed</P><BR /> <P style="overflow: hidden;margin-bottom: 0px">Given that the analysis has determined this to be a node-based project, the pack CLI will then examine the package.json file to determine the specific version of Node.js that needs to be installed:</P><BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/node_version.png" /><BR /> <BR /> After determining that this is a node-based project, pack examines the package.json file to determine which version of node needs to be installed. There are various ways to install dependencies, and pack ensures to choose the most suitable one based on the available files and directories. For example, it checks if a node_modules directory already exists with the dependencies installed, or if npm ci is a viable option due to the presence of a package-lock.json file.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/npm_install.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">pack cli detected npm install as the best dependency installation process</P><BR /> <BR /> <DIV><BR /> <DIV><BR /> <DIV><BR /> <DIV><BR /> <DIV><BR /> <DIV><BR /> <BR /> While there are various aspects to consider, such as the configuration of the operating system and setting environment variables, it can be unclear what the resulting Docker image will look like. To shed some light on this, I like to reverse engineer things whenever possible. But how can you reverse engineer a Docker image to <A href="https://docs.docker.com/storage/storagedriver/#images-and-layers" target="_blank" rel="nofollow noopener noreferrer">its individual layers</A> or even a Dockerfile? Although Paketo's methodology may pose some limitations, you can still deconstruct the image into its layers using tools like <A href="https://github.com/wagoodman/dive" target="_blank" rel="nofollow noopener noreferrer">dive</A>.<BR /> <BR /> </DIV><BR /> </DIV><BR /> </DIV><BR /> </DIV><BR /> </DIV><BR /> </DIV><BR /> It's relatively simple:<BR /> <PRE class="language-bash"><CODE>dive image-name:image-tag</CODE></PRE><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/dive_paketo1.gif" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic;font-family: 'SAPRegular', 'Helvetica Neue', Arial, sans-serif">dive tool in action</P><BR /> In the GIF above, you can see the layers of the image on the left side and the impact of each layer on the file system (highlighted in yellow) on the right side. This provides a good idea of what Paketo does in general and gives one the opportunity to further inspect the built Docker image - for instance its different layers. If you find the previous method too detailed or excessive, pack CLI also offers a simpler alternative to inspect the built Docker image at a higher level:<BR /> <PRE class="language-bash"><CODE>pack inspect-image &lt;image-name&gt;:&lt;tag&gt;</CODE></PRE><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/pack_inspect.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic;font-family: 'SAPRegular', 'Helvetica Neue', Arial, sans-serif">pack inspect to see the buildpack details (also remote vs. local)</P><BR /> You can use this feature to view the list of buildpacks that have been identified and will be included in the Docker image you have built. This Docker image can then be deployed to the SAP BTP, Kyma runtime.<BR /> <BR /> All of these Docker images will later on end up in your values.yaml file for the Helm chart (next paragraph <span class="lia-unicode-emoji" title=":winking_face:">😉</span>) and are picked up by the SAP BTP, Kyma runtime to run the application.<BR /> <BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/valuesyaml_image.png" /><BR /> <BR /> You can apply the same approach to deploy SAP HANA artifacts: use the pack CLI to build the corresponding Docker image and then include its reference in the <EM>values.yaml</EM> file for the Helm installation.<BR /> <BR /> Installation of pack cli: <A href="https://buildpacks.io/docs/tools/pack/" target="_blank" rel="nofollow noopener noreferrer">https://buildpacks.io/docs/tools/pack/</A><BR /> Paketo homepage: <A href="https://paketo.io/" target="_blank" rel="nofollow noopener noreferrer">https://paketo.io/</A><BR /> pack build: <A href="https://buildpacks.io/docs/tools/pack/cli/pack_build/" target="_blank" rel="nofollow noopener noreferrer">https://buildpacks.io/docs/tools/pack/cli/pack_build/</A><BR /> pack inspect: <A href="https://buildpacks.io/docs/tools/pack/cli/pack_inspect/" target="_blank" rel="nofollow noopener noreferrer">https://buildpacks.io/docs/tools/pack/cli/pack_inspect/</A><BR /> dive tool: <A href="https://github.com/wagoodman/dive" target="_blank" rel="nofollow noopener noreferrer">https://github.com/wagoodman/dive</A><BR /> <H3 id="toc-hId-503377184">What's Helm?</H3><BR /> "The package manager for Kubernetes", so the short description on <A href="https://helm.sh/" target="_blank" rel="nofollow noopener noreferrer">helm.sh.</A><BR /> <BR /> Helm is a package manager for Kubernetes, which makes it easy to install, upgrade, and manage applications and services in a Kubernetes cluster. When it comes to SAP Cloud Application Programming Model, Helm can be used to package and deploy CAP applications to a Kubernetes environment like SAP BTP, Kyma runtime.<BR /> <BR /> Using Helm to deploy CAP applications to Kubernetes offers numerous benefits. Firstly, it simplifies the deployment process by automating the installation and configuration of applications and services, reducing the amount of manual work required. Additionally, it enables version control, so you can track changes and rollback to previous versions if necessary.<BR /> <BR /> Deploying a CAP application without Helm would typically involve writing a complete Kubernetes manifest to create the corresponding resources. However, using Helm's templating function, you can avoid doing that for every single CAP application. Do you want to do that for every single CAP application? My rough guess: Most likely not. The CAP team has already taken good care of the common configuration with the help of <A href="https://helm.sh/docs/chart_template_guide/functions_and_pipelines/" target="_blank" rel="nofollow noopener noreferrer">Helm template functions</A> and much more, so you only need to focus on the specifics for your application.<BR /> <BR /> Here's a concrete example:<BR /> <BR /> Let's take a <A href="https://github.com/SAP-samples/btp-build-resilient-apps/blob/main/chart/values.yaml" target="_blank" rel="nofollow noopener noreferrer">values.yaml</A> file in one of my <A href="https://github.com/SAP-samples/btp-build-resilient-apps" target="_blank" rel="nofollow noopener noreferrer">sap-samples repositories</A>. The values.yaml file only contains a basic configuration about the application itself and which service instances and bindings are needed and is the key file in your deployment configuration. With <STRONG>helm install</STRONG> you could already install this chart on your SAP BTP, Kyma runtime but you won't really find out what exactly you are deploying. I wanted to know more. I know that Kubernetes resource definitions are by far more complex than this particular values.yaml file for Helm - so where's the magic happening that generates a Kubernetes resource out of that Helm chart? Here's my Helm chart (<A href="https://github.com/SAP-samples/btp-build-resilient-apps/blob/main/chart/values.yaml" target="_blank" rel="nofollow noopener noreferrer">Link</A><span class="lia-unicode-emoji" title=":disappointed_face:">😞</span><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/values_yaml.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">values.yaml file</P><BR /> When you run <STRONG>cds add helm</STRONG>, it generates more than just the <EM>values.yaml</EM> file for your CAP application. It also creates several <STRONG>.tpl</STRONG> files that contain template helpers/functions used to generate various Kubernetes/Kyma resoucres, such as APIRules and Deployments, in addition to the basic CAP application.<BR /> <BR /> To see the complete deployment configuration, you can use <STRONG>helm template &lt;directory&gt;</STRONG>. This command takes the template helpers (.tpl files) into account and renders the chart to standard Kubernetes resource templates. You could basically use these templates with <STRONG>kubectl apply -f &lt;helm-template-result-file&gt;</STRONG> without using Helm, but you won't get the benefits of Helm. I've shared the results of running "helm template" <STRONG><A href="https://gist.github.com/maxstreifeneder/0b4f369e414639ce42953e7867f29ebe" target="_blank" rel="nofollow noopener noreferrer">here</A></STRONG>.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/helm_template_result.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">part of the result for helm template</P><BR /> Why write hundreds of lines of Kubernetes resource definitions when you can do it all with just a few dozen lines in a Helm chart for your CAP application? That's the power of using Helm. And if you've already installed a Helm chart and want to see what you've got, just use <STRONG>helm get manifest &lt;release name&gt;</STRONG> to get the full installation manifest. It's that simple!<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/helm_get_manifest.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">part of the result for helm get manifest</P><BR /> Adding a new service instance is as easy as creating a new key in the <STRONG>values.yaml</STRONG> file and filling in the required properties (such as serviceInstanceFullname, serviceOfferingName, servicePlanName, etc.).<BR /> <BR /> If you're familiar with SAP BTP, Cloud Foundry runtime, you'll recognise these properties, as <EM>ServiceInstances</EM> and <EM>ServiceBindings</EM> work on the same principle in both environments - thanks to the <A href="https://blogs.sap.com/2022/07/12/the-new-way-to-consume-service-bindings-on-kyma-runtime/" target="_blank" rel="noopener noreferrer"><STRONG>SAP BTP Service operator</STRONG></A>!<BR /> <BR /> You can find a list of possible properties for creating ServiceInstances and ServiceBindings in the <A href="https://github.com/SAP/sap-btp-service-operator#reference-documentation" target="_blank" rel="nofollow noopener noreferrer">GitHub repository of the SAP BTP service operator.</A><BR /> <BR /> Lastly, create a new <EM>.yaml</EM> file with the name of the key you provided in the values.yaml file. The file's content is simply "{{- include "cap.service-instance" . }}", and one of the Helm template helpers provided by CAP will pick it up and recognise it as a ServiceInstance and ServiceBinding.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/cap_serviceinstances-1.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">template/_helpers.tpl picks up the yaml files</P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/yaml-services.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">How the required yaml file per ServiceInstance should look like</P><BR /> In other words, the name you choose for the key in the values.yaml file to define a service instance can be anything you like, as long as you create a corresponding file with that name in the directory, and include the phrase I mentioned earlier. The whole process of using template functions, different yaml files, and getting the desired results can be a bit overwhelming at first, but once you've got the hang of it... <span class="lia-unicode-emoji" title=":winking_face:">😉</span><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/Helm_deployment_flow.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Helm flow (source: opensource.hcltechsw.com)</P><BR /> Overall, using Helm to deploy CAP applications to Kubernetes can save time and effort, improve consistency and reliability and makes it easier to manage.<BR /> <H3 id="toc-hId-306863679">How do I deploy my application now?</H3><BR /> <OL><BR /> <LI>Create a namespace in your Kyma cluster. (<EM>kubectl create namespace)</EM></LI><BR /> <LI>Make sure that you have created your SAP HANA Cloud instance before and have mapped it to your namespace using the SAP HANA Cloud tools: <A href="https://blogs.sap.com/2022/12/15/consuming-sap-hana-cloud-from-the-kyma-environment/" target="_blank" rel="noopener noreferrer">https://blogs.sap.com/2022/12/15/consuming-sap-hana-cloud-from-the-kyma-environment/&nbsp;</A></LI><BR /> <LI>Add a Helm chart and the required helpers with <STRONG>cds add helm</STRONG></LI><BR /> <LI>Use Paketo to build the Docker images for your db and srv artefacts</LI><BR /> <LI>Deploy the UI bits to the HTML5 Application Repository with a provided Docker image from the responsible team: <A href="https://hub.docker.com/r/sapse/html5-app-deployer/tags" target="_blank" rel="nofollow noopener noreferrer">sapse/html5-app-deployer</A>. An example of how that could work is part of the sample repository I've provided: <A href="https://github.com/SAP-samples/btp-build-resilient-apps/tree/main/app/html5-deployer" target="_blank" rel="nofollow noopener noreferrer">Dockerfile</A> and <A href="https://github.com/SAP-samples/btp-build-resilient-apps/blob/main/package.json#L106" target="_blank" rel="nofollow noopener noreferrer">preparation scripts&nbsp;</A></LI><BR /> <LI>In case you are publishing your Docker images to a private Container registry, make sure you create secret in your <A href="https://blogs.sap.com/2022/12/04/sap-btp-kyma-kubernetes-how-to-pull-from-private-repository/" target="_blank" rel="noopener noreferrer">Kyma cluster</A> and provide in the <A href="https://github.com/SAP-samples/btp-build-resilient-apps/blob/main/chart/values.yaml#L3" target="_blank" rel="nofollow noopener noreferrer">Helm chart&nbsp;</A></LI><BR /> <LI>Use Helm upgrade &lt;release name&gt; &lt;chart directory&gt; --install --debug to start the deployment (in helm jargon installation)</LI><BR /> </OL><BR /> That's it in a nutshell.<BR /> <BR /> Helm: <A href="https://helm.sh/" target="_blank" rel="nofollow noopener noreferrer">https://helm.sh/</A><BR /> Helm template functions: <A href="https://helm.sh/docs/chart_template_guide/functions_and_pipelines/" target="_blank" rel="nofollow noopener noreferrer">https://helm.sh/docs/chart_template_guide/functions_and_pipelines/&nbsp;</A><BR /> CAP with Helm: <A href="https://cap.cloud.sap/docs/guides/deployment/deploy-to-kyma#deploy-using-cap-helm-chart" target="_blank" rel="nofollow noopener noreferrer">https://cap.cloud.sap/docs/guides/deployment/deploy-to-kyma#deploy-using-cap-helm-chart</A><BR /> <H3 id="toc-hId-110350174">Can I use the Cloud Connector with SAP BTP, Kyma Runtime?</H3><BR /> Yes, you can use the Cloud Connector with SAP BTP's, Kyma Runtime, but the Connectivity Service operates slightly different than for SAP BTP's, Cloud Foundry runtime. In Kyma, the Connectivity Proxy (read more about it in one of <A href="https://blogs.sap.com/2023/02/02/surviving-and-thriving-with-the-sap-cloud-application-programming-model-local-development-hurdles/#connectivity" target="_blank" rel="noopener noreferrer">my previous blog posts</A>) is created per cluster, whereas in Cloud Foundry, it already exists per region.<BR /> <BR /> The Kyma reconciler, which is a scheduled job that runs frequently, checks if you have created a ServiceInstance and ServiceBinding for the Connectivity Service. The Connectivity Proxy will be provisioned into the kyma-system namespace in the runtime but only once - so don't create more than one ServiceInstance and ServiceBinding for the Connectivity service! It can be accessed from within the Kyma runtime using the URL <STRONG>connectivity-proxy.kyma-system.svc.cluster.local:20003</STRONG>. By using <STRONG>cds add connectivity</STRONG>, the Helm chart <A href="https://cap.cloud.sap/docs/releases/feb23#connectivity-service" target="_blank" rel="nofollow noopener noreferrer">is updated with the necessary secrets</A> for the Connectivity Proxy as volumes, so that the CAP application knows how to access the on-premise system through the SAP Cloud Connector using the Connectivity Service and its Connectivity Proxy.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/connectivity-proxy.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">connectivity-proxy-0 is the Pod name in namespace kyma-system</P><BR /> When creating the ServiceInstance and ServiceBinding for the Connectivity Service, it's crucial to ensure that this process isn't part of any app deployment, as it's a one-time job and secret rotation (caused by multiple ServiceBindings) could cause inconsistencies for the Connectivity Proxy Pod. Additionally, it's important to make sure that only one connectivity-proxy Pod exists in the kyma-system namespace, as this can impact connectivity to the on-premise system. If issues arise, the Container Logs of this Pod can provide useful insights.<BR /> <BR /> <STRONG>Important:</STRONG> It's also worth noting that Istio injection must be enabled in the namespace where the ServiceInstance and ServiceBinding are created, which can be done with the command<BR /> <PRE class="language-bash"><CODE>kubectl label namespace &lt;namespace&gt; istio-injection=enabled</CODE></PRE><BR /> <H3 id="toc-hId--86163331">How does CAP know where to get the service binding information from?</H3><BR /> <P style="overflow: hidden;margin-bottom: 0px">On a slightly different note, as someone who has worked with the SAP BTP, Cloud Foundry runtime for quite some time, I'm well acquainted with VCAP_SERVICES. This environment variable is set for each app instance and contains all service binding information as a JSON. Many SDKs heavily rely on fetching this information to establish connections with specific backing services. Initially, in the early days of SAP BTP, Kyma runtime, and CAP, faking the VCAP_SERVICES environment variable was necessary to allow CAP to access the necessary credentials to connect to other services.</P><BR /> <P style="overflow: hidden;margin-bottom: 0px">However, thanks to the SAP BTP Service operator, this is no longer necessary. Secrets and ConfigMaps are now automatically provided as volumes, eliminating the need to fake the VCAP_SERVICES environment variable.</P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/secrets-as-volumes.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">the deployment configuration after running helm template</P><BR /> Ok, fair. Since I always like to understand how things work actually - where's the piece of code that differentiates between apps running on SAP BTP, Cloud Foundry runtime and apps running on SAP BTP, Kyma runtime? Basically, if there's no VCAP_SERVICES it's going to read the service information from the mounted volume path:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/read-service-bindings.png" /></P><BR /> As I said, little excursion <span class="lia-unicode-emoji" title=":winking_face:">😉</span><BR /> <H3 id="toc-hId--282676836">SAP Event Mesh and SAP S/4HANA on-premise - little detour needed</H3><BR /> If you need to receive events from an SAP S/4HANA on-premise system in your CAP application, there are several configuration steps and artefacts required on the SAP S/4HANA on-premise side to enable this connection. Fortunately, there's a simplified process offered through a dedicated transaction called <STRONG>/IWXBE/CONFIG</STRONG>.<BR /> <BR /> In essence, you just need a service key and copy its contents to this transaction, and all the necessary artefacts are automatically created for you. The service key contains information about authorization, applied namespaces, and effective endpoints for the SAP Event Mesh instance. However, this only applies to service keys created in the SAP BTP, Cloud Foundry runtime. For the SAP BTP, Kyma Runtime, which uses Kubernetes Secrets as its service key equivalent, an additional step is required to transform it into the correct format.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/03/eventmesh-secret.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Secret for the SAP Event Mesh service binding</P><BR /> <A href="https://stedolan.github.io/jq/" target="_blank" rel="nofollow noopener noreferrer"><STRONG>jq</STRONG></A> to the rescue! Since the output of the above shown secret can be formatted as json, we can make use of <EM>jq</EM> to transform it into the right format again. The jq call is slightly too complex for a one-liner (for instance not all of the properties of that secrets are needed, base64 decoding is required, etc.), that's why I've put into a dedicated file:<BR /> <PRE class="language-bash"><CODE>#!/usr/bin/env jq<BR /> <BR /> def props: "^(management|messaging|tags|uaa)$";<BR /> <BR /> .data | with_entries(select(.key != ".metadata") |<BR /> .value|=@base64d<BR /> | if .key | test(props) then .value |= fromjson else . end<BR /> ) </CODE></PRE><BR /> So, to get the right JSON for the SAP S/4HANA on-premise transaction, you can simply execute:<BR /> <PRE class="language-bash"><CODE>kubectl get secrets/your-messaging-secret -o json | jq -f ./kyma/eventmeshkey.jq </CODE></PRE><BR /> As usual, the above shown <EM>jq</EM> file is also part of the repository I'm currently working on: <A href="https://github.com/SAP-samples/btp-build-resilient-apps/blob/main/kyma/eventmeshkey.jq" target="_blank" rel="nofollow noopener noreferrer">Enhance core ERP business processes with resilient applications on SAP BTP</A><BR /> <H3 id="toc-hId--479190341">Mind your DB Pool configuration!</H3><BR /> I didn't want to dedicate a whole paragraph to it, since I can barely explain the background - my application didn't contain a pool configuration. It worked on SAP BTP, Cloud Foundry but it didn't on SAP BTP, Kyma runtime. Please make sure that you provide a proper <A href="https://github.com/SAP-samples/btp-build-resilient-apps/blob/main/package.json#L131-L144" target="_blank" rel="nofollow noopener noreferrer">DB Pool configuration</A>, otherwise your CAP application might not be able to establish connections to your SAP HANA Cloud instance and something like this might appear in your application logs:<BR /> <PRE class="language-bash"><CODE>TimeoutError: Acquiring client from pool timed out. Please review your system setup, transaction handling, and pool configuration. Pool State: borrowed: 0, pending: 0...</CODE></PRE><BR /> I have no idea why that happens on SAP BTP, Kyma runtime and not on SAP BTP, Cloud Foundry (same application, just packaged differently - Paketo instead of MTA), but my rough guess would be that it has to do with the buildpacks being used and a different default configuration for the underlying npm module <A href="https://www.npmjs.com/package/generic-pool" target="_blank" rel="nofollow noopener noreferrer">generic-pool</A>. I couldn't figure it out, I'm sorry. <span class="lia-unicode-emoji" title=":winking_face:">😉</span><BR /> <BR /> <HR /><BR /> <BR /> Thank you so much for taking the time to read my blog post! Although I'm a big fan of the simplicity of the SAP BTP, Cloud Foundry runtime, I'm thoroughly enjoying my experience with SAP BTP, Kyma runtime. This post is not meant to be a pro-contra comparison, but rather a collection of my thoughts and observations while working on some sample repositories.<BR /> <BR /> I welcome any comments and feedback you may have, whether it's questions, personal experiences, or just your thoughts. Let's continue the conversation in the comments! 2023-03-07T15:51:05+01:00 https://community.sap.com/t5/technology-blogs-by-sap/sap-data-intelligence-python-operators-and-cloud-connector-tcp/ba-p/13550389 SAP Data Intelligence Python Operators and Cloud Connector – TCP 2023-04-14T09:20:38+02:00 felixbartler https://community.sap.com/t5/user/viewprofilepage/user-id/4997 The Transmission Control Protocol (TCP) is a widely used protocol that provides a reliable and ordered delivery of data between applications running on different hosts. It serves as the foundation for many technologies and plays a crucial role in modern IT infrastructure.<BR /> <BR /> SAP Data Intelligence is a powerful platform that allows you to integrate various systems and data sources to gain insights and make informed decisions. Its custom Python operators offer even more flexibility, enabling you to connect to systems beyond what the standard shipped operators support.<BR /> <BR /> In this blog post, we'll guide you through the steps to establish connectivity to an on-premises TCP-based system using Python in SAP Data Intelligence.<BR /> <H2 id="toc-hId-961988966">Access TCP-based resources:</H2><BR /> Scenario: We aim to establish a connection with a TCP-based system using the Python operator in SAP Data Intelligence. Many databases but also other protocols like SFTP etc. are based on TCP. To achieve this, we will configure the cloud connector, which involves a series of steps. For the purposes of this demonstration, we will use an example of a "Hello TCP" server that is running on my local computer. The ultimate objective is to access this server from within SAP Data Intelligence using the Cloud Connector.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/architecture-data-intelligence-tcp.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Szenario Architecture</P><BR /> <BR /> <H3 id="toc-hId-894558180">Prerequisite:</H3><BR /> Before proceeding with the steps outlined in this guide, it is essential to have an instance of the SAP Cloud Connector installed. While it is possible to install the cloud connector on a server, for the purposes of this demonstration, we will be using a Windows machine. We recommend following the instructions provided in this blog (<A href="https://blogs.sap.com/2021/09/05/installation-and-configuration-of-sap-cloud-connector/" target="_blank" rel="noopener noreferrer">https://blogs.sap.com/2021/09/05/installation-and-configuration-of-sap-cloud-connector/</A>) to install and configure the cloud connector.<BR /> <BR /> The second requirement is a BTP subaccount with a Data Intelligence cluster. To this Subaccount we will connect the Cloud Connector.<BR /> <H3 id="toc-hId-698044675">1. Configuration:</H3><BR /> The first step is to create a configuration in the Cloud Connector that connects to our subaccount and exposes the TCP resource. For the purpose of this demonstration, I ran a small Node.js server on my Windows machine that outputs <A href="https://gist.github.com/fyx99/cb6389e3c1942729cdbfc7ad3a9e1c71" target="_blank" rel="nofollow noopener noreferrer">"Hello TCP!"</A>.<BR /> <PRE class="language-python"><CODE>telnet localhost 4444<BR /> Connecting to localhost ...<BR /> Hello TCP!</CODE></PRE><BR /> To create the configuration, navigate to the admin interface for the cloud connector and create a "Cloud to On-Premise" configuration.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/cloud-to-onpremise-configuration-tcp-1.png" /></P><BR /> <P class="image_caption" style="font-style: italic;font-family: SAPRegular, 'Helvetica Neue', Arial, sans-serif;text-align: center">Cloud Connector configuration</P><BR /> In the screenshot above, you can see that I exposed the internal host "localhost" with port 4444 via a virtual host called "virtualhost". This virtual host is the host that we will be requesting from the BTP side. Compared to HTTP resources, we do not need to explicitly expose paths.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/btp-registered-cloud-connectors-tcp.png" /></P><BR /> <P class="image_caption" style="font-style: italic;font-family: SAPRegular, 'Helvetica Neue', Arial, sans-serif;text-align: center">BTP Cockpit Cloud Connector Resources</P><BR /> On the BTP end, we can check the cockpit and the connected cloud connectors in the respective menu tab. If you cannot see this tab, you may be missing some roles. It is important to note that we see the LocationID "FELIXLAPTOP", which is an identifier that distinguishes multiple cloud connectors connected to the same subaccount.<BR /> <H3 id="toc-hId-501531170">2. Creating a Data Intelligence Connection:</H3><BR /> For our purposes, we do not want to hard-code the connection details, because we need a little help from the connection management to access the Connectivity Service of BTP. In the Connection Management application from SAP Data Intelligence we can create connections of all types. We create a connection of type HTTP with host, port and SAP Cloud Connector as the gateway.<BR /> <BR /> Note: Not all connection types allow you to access via the Cloud Connector. See the official product documentation for details.<BR /> <H3 id="toc-hId-305017665">3. Developing a Custom Operator:</H3><BR /> In the operators menu of Data Intelligence we create a new custom operator based on the Python3 operator.<BR /> <P style="overflow: hidden;margin-bottom: 0px;text-align: left"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/python-operator-creation-1.png" /></P><BR /> <P class="image_caption" style="font-style: italic;font-family: SAPRegular, 'Helvetica Neue', Arial, sans-serif;text-align: center">Creating Custom Python Operator</P><BR /> We than change the configSchema.json of this operator to accept an HTTP Connection as a parameter. This file can be found in the repository under the following path.<BR /> <BR /> <STRONG style="color: #252525">Note: This is a bit hacky. </STRONG>Data Intelligence proxies the Connectivity Service from the BTP internally. We can reach it using the internal host provided in the connection details ("connectivity-proxy-service") of a HTTP Connection (because this connection supports the SAP Cloud Connector as a gateway - other connection types might work as well). It is important to notice that the behavior of this proxy is exactly the same as that of the Connectivity Service. In other environments, like Cloud Foundry, you can bind an instance of the Connectivity Service to your application and access the service that way. Data Intelligence also helps us with the authentication flow; in the connection details, we will find a valid JWT token to authenticate against the Connectivity Proxy.<BR /> <PRE class="language-python"><CODE>vflow\subengines\com\sap\python36\operators\PythonCloudConnector\configSchema.json</CODE></PRE><BR /> The JSON file looks like this:<BR /> <PRE class="language-javascript"><CODE>{<BR /> "$schema": "http://json-schema.org/draft-06/schema#",<BR /> "$id": "http://sap.com/vflow/PythonCloudConnector.configSchema.json",<BR /> "type": "object",<BR /> "properties": {<BR /> "codelanguage": {<BR /> "type": "string"<BR /> },<BR /> "scriptReference": {<BR /> "type": "string"<BR /> },<BR /> "script": {<BR /> "type": "string"<BR /> },<BR /> "http_connection": {<BR /> "title": "HTTP Connection",<BR /> "description": "HTTP Connection",<BR /> "type": "object",<BR /> "properties": {<BR /> "configurationType": {<BR /> "title": "Configuration Type",<BR /> "description": "Configuration Type",<BR /> "type": "string",<BR /> "enum": [<BR /> " ",<BR /> "Configuration Manager",<BR /> "Manual"<BR /> ]<BR /> },<BR /> "connectionID": {<BR /> "title": "Connection ID",<BR /> "type": "string",<BR /> "format": "com.sap.dh.connection.id"<BR /> },<BR /> "connectionProperties": {<BR /> "title": "Connection Properties",<BR /> "description": "Connection Properties",<BR /> "$ref": "http://sap.com/vflow/com.sap.dh.connections.http.schema.json",<BR /> "sap_vflow_constraints": {<BR /> "ui_visibility": [<BR /> {<BR /> "name": "configurationType",<BR /> "value": "Manual"<BR /> }<BR /> ]<BR /> }<BR /> }<BR /> }<BR /> }<BR /> },<BR /> "required": [<BR /> "http_connection"<BR /> ]<BR /> }</CODE></PRE><BR /> In the Python Operator we will be using the <STRONG>sapcloudconnectorpythonsocket</STRONG> library I created for this purpose. This needs to be installed in a custom Dockerfile. The reason we cannot use standard librarys like PySocks to connect to the connectivity service, is the <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/using-tcp-protocol-for-cloud-applications" target="_blank" rel="noopener noreferrer">custom authentication flow used</A>.<BR /> <BR /> This post will not elaborate further on how to link the Dockerfile to the Custom Operator using tags.<BR /> <PRE class="language-javascript"><CODE>FROM $com.sap.sles.base<BR /> <BR /> RUN python3 -m pip --no-cache-dir install 'sapcloudconnectorpythonsocket' --user</CODE></PRE><BR /> And finally, the actual script looks straightforward:<BR /> <PRE class="language-python"><CODE>from sapcloudconnectorpythonsocket import CloudConnectorSocket<BR /> <BR /> tcp_connection = api.config.http_connection<BR /> <BR /> api.logger.info(str(tcp_connection))<BR /> <BR /> def gen():<BR /> api.logger.info("Generator Start")<BR /> <BR /> cc_socket = CloudConnectorSocket()<BR /> cc_socket.connect(<BR /> dest_host=tcp_connection["connectionProperties"]["host"], <BR /> dest_port=tcp_connection["connectionProperties"]["port"], <BR /> proxy_host=tcp_connection["gateway"]["host"], <BR /> proxy_port=20004, <BR /> token=tcp_connection["gateway"]["authentication"],<BR /> location_id="FELIXLAPTOP"<BR /> )<BR /> <BR /> cc_socket.send(b"")<BR /> <BR /> response = cc_socket.recv(4096)<BR /> api.logger.info(response)<BR /> <BR /> api.logger.info("Generator End")<BR /> <BR /> api.add_generator(gen)</CODE></PRE><BR /> First we take the connection details from the api.config.http_connection object. Then we hand those credentials to the library to connect a socket via the Cloud Connector proxy to our destination server. The logs reveal the various fields that are accessible.<BR /> <PRE class="language-javascript"><CODE>{<BR /> "configurationType":"Configuration Manager",<BR /> "connectionID":"TCP_ONPREM_SYSTEM",<BR /> "connectionProperties":{<BR /> "authenticationType":"NoAuth",<BR /> "host":"virtualhost",<BR /> "port":4444,<BR /> "protocol":"HTTP"<BR /> },<BR /> "connectionType":"HTTP",<BR /> "gateway":{<BR /> "authentication":"&lt;token&gt;",<BR /> "host":"connectivity-proxy-service",<BR /> "locationId":"",<BR /> "password":"",<BR /> "port":20003,<BR /> "subaccount":"2343242-b1ea-415c-9a50-46347c32fa2a",<BR /> "user":""<BR /> },<BR /> "type":"HTTP"<BR /> }</CODE></PRE><BR /> One thing to keep in mind here. Instead of the standard HTTP proxy port of the connectivity service, we use the SOCKS5 proxies port. Looking at a regular service key of a connectivity service instance will make things clearer:<BR /> <PRE class="language-javascript"><CODE>{<BR /> "clientid": "&lt;clientid&gt;",<BR /> "clientsecret": "&lt;clientsecret&gt;",<BR /> "url": "https://&lt;subaccount&gt;.authentication.sap.hana.ondemand.com",<BR /> "identityzone": "&lt;subaccount&gt;",<BR /> "tenantid": "&lt;tenantid&gt;",<BR /> "tenantmode": "dedicated",<BR /> "verificationkey": "&lt;verificationkey&gt;",<BR /> "xsappname": "iueniuerncoirencorencercer!b3008|connectivity!b137",<BR /> "uaadomain": "authentication.sap.hana.ondemand.com",<BR /> "credential-type": "binding-secret",<BR /> "onpremise_proxy_host": "connectivityproxy.internal.cf.sap.hana.ondemand.com",<BR /> "onpremise_proxy_http_port": "20003",<BR /> "onpremise_proxy_ldap_port": "20001",<BR /> "onpremise_proxy_port": "20003",<BR /> "onpremise_proxy_rfc_port": "20001",<BR /> "onpremise_socks5_proxy_port": "20004",<BR /> "token_service_domain": "authentication.sap.hana.ondemand.com",<BR /> "token_service_url": "https://&lt;subaccount&gt;.authentication.sap.hana.ondemand.com"<BR /> }</CODE></PRE><BR /> We find the classic XSUAA style clientid, clientsecret and token_service_url to retrieve a token in the client credential flow (Data Intelligence does that for us). Plus, one can also see the different ports exposed by the Connectivity Service.<BR /> <UL><BR /> <LI>HTTP: 20003</LI><BR /> <LI>SOCKS5/TCP: 20004</LI><BR /> </UL><BR /> This is why we specify the SOCKS5 port specifically in the opening of the socket.<BR /> <BR /> With the successful opening of a socket, we are now able to send requests to the TCP server. In the example I am sending a request with an empty body, my local server returns "Hello Tcp!" to every request.<BR /> <H3 id="toc-hId-108504160">4. Testing the Custom Operator:</H3><BR /> Finally we can put the new operator in a empty graph and fill the http_connection parameter. In this instance, I provide the Connection ID of the connection I created previously.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/python-operator-configuration.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Python Operator Parameters</P><BR /> When executing the graph we can have a look at the console and see the following entries:<BR /> <PRE class="language-python"><CODE>Generator Start<BR /> Hello TCP!<BR /> Generator End</CODE></PRE><BR /> That means we were successful and the operator was able to request the local TCP server on my windows machine.<BR /> <BR /> Hope you find the content of this blog helpful. Feel free to comment for further clarifications. 2023-04-14T09:20:38+02:00 https://community.sap.com/t5/technology-blogs-by-sap/sftp-via-cloud-connector-python-operator-in-sap-data-intelligence/ba-p/13551278 SFTP via Cloud Connector Python Operator in SAP Data Intelligence 2023-04-14T13:00:08+02:00 felixbartler https://community.sap.com/t5/user/viewprofilepage/user-id/4997 The (Secure) File Transfer Protocol is still a very common way to integrate files from different sources. SAP Data Intelligence supports many source systems for file operations out of the box. To allow for even more flexibility in the connection to SFTP servers, this blog post shows how to use the Python library Paramiko to read, write, list or delete files on remote sources. Even through the infamous Cloud Connector.<BR /> <H2 id="toc-hId-962017764">Connect Python Operator to SFTP via Cloud Connector:</H2><BR /> Szenario: This blog post aims at establishing a connection to an on-premises SFTP server. We will show how to establish a TCP socket and use Paramiko to read, list, write or delete files. The TCP connection socket is the basis for this blog and I recommend my previous blog about the basics of establishing a TCP Socket from a python custom operator and a detailed explaination on the role of the Connectivity Service. <A href="https://blogs.sap.com/2023/04/14/sap-data-intelligence-python-operators-and-cloud-connector-tcp/" target="_blank" rel="noopener noreferrer">https://blogs.sap.com/2023/04/14/sap-data-intelligence-python-operators-and-cloud-connector-tcp/</A><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/architecture-data-intelligence-sftp.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Szenario Architecture</P><BR /> <BR /> <H3 id="toc-hId-894586978">Prerequisite:</H3><BR /> All prerequisites from the previous blog post apply.<BR /> <BR /> For this case, we additionally need a SFTP server running on the same host as the Cloud Connector. To establish a local test setup on my Windows machine, I use a very simple dockerized SFTP server. It exposes a SFTP server on the localhost on port 22. With the user foo and the password pass we are allowed to interact with the contents of the folder /upload.<BR /> <PRE class="language-python"><CODE>docker run -p 22:22 -d atmoz/sftp foo:pass:::upload</CODE></PRE><BR /> <H3 id="toc-hId-698073473">1. Configuration:</H3><BR /> The very first step in the integration is to configure the Cloud Connector to expose the SFTP server to the respective BTP subaccount. The configuration looks as follows:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/cloud-to-onpremise-configuration-sftp-1.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Cloud To On-premises Configuration</P><BR /> The localhost:22 is exposed to a virtual host that we can see in the BTP Cockpit.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/btp-registered-cloud-connectors-sftp.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">BTP Cockpit Cloud Connector Resources</P><BR /> <BR /> <H3 id="toc-hId-501559968">2. Creating a Data Intelligence Connection:</H3><BR /> For our purposes, we do not want to hard-code the connection details, because we need a little help from the connection management to access the Connectivity Service of BTP. In the Connection Management Application from SAP Data Intelligence we can create connections of all kinds of types. We create a connection of type HTTP with out host, port and we specify SAP Cloud Connector as gateway.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/sftp-connection.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Data Intelligence Connection Management</P><BR /> Note: Not all connection types allow you to access through the Cloud Connector. See the official product documentation for details.<BR /> <H3 id="toc-hId-305046463">3. Developing a Custom Operator:</H3><BR /> We use Paramiko and the sapcloudconnectorpythonsocket library. They need to be installed in a Dockerfile and added to the custom operator. Paramiko is a python library that helps to communicate with the SFTP server. The sapcloudconnectorpythonsocket library helps us to open a socket via the Cloud connector.<BR /> <PRE class="language-python"><CODE>FROM $com.sap.sles.base<BR /> <BR /> RUN python3 -m pip --no-cache-dir install 'sapcloudconnectorpythonsocket' --user<BR /> RUN python3 -m pip --no-cache-dir install 'paramiko' --user</CODE></PRE><BR /> &nbsp;<BR /> <BR /> Finally, let's have a look at the actual custom script. The first important part is opening the TCP socket as described in the previous blog. This TCP socket can be passed to Paramiko SSHClient to establish the connection. Since we do keep this really simple we put some Paramiko policies in to ignore the missing host keys. With the open ftp client, we can interact with the file server.<BR /> <BR /> For the purpose of demonstration, we create a file in the /upload directory, called test_create_file.txt. We then create a new directory, list the contents of the /upload directory, read the content of the created file and remove it again.<BR /> <BR /> Paramiko can do a lot more than the shown file operations, it implements the SSHv2 Protocol and can be used to execute shell commands remotely. Thus opening a big door for hacky integration scenarios - even fully on-prem <span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span> <span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span><BR /> <BR /> Check out the <A href="https://docs.paramiko.org/en/stable/" target="_blank" rel="nofollow noopener noreferrer">Paramiko documentation</A> for more details.<BR /> <PRE class="language-python"><CODE>import paramiko<BR /> import io<BR /> from sapcloudconnectorpythonsocket import CloudConnectorSocket<BR /> <BR /> sftp_connection = api.config.http_connection<BR /> <BR /> api.logger.info(str(sftp_connection))<BR /> <BR /> def gen():<BR /> api.logger.info("Generator Start")<BR /> <BR /> cc_socket = CloudConnectorSocket()<BR /> cc_socket.connect(<BR /> dest_host=sftp_connection["connectionProperties"]["host"], <BR /> dest_port=sftp_connection["connectionProperties"]["port"], <BR /> proxy_host=sftp_connection["gateway"]["host"], <BR /> proxy_port=20004, <BR /> token=sftp_connection["gateway"]["authentication"],<BR /> location_id="FELIXLAPTOP"<BR /> )<BR /> <BR /> ssh_client = paramiko.SSHClient()<BR /> ssh_client.load_system_host_keys()<BR /> ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())<BR /> <BR /> ssh_client.connect(<BR /> sftp_connection["connectionProperties"]["port"], <BR /> username=sftp_connection["connectionProperties"]["user"],<BR /> password=sftp_connection["connectionProperties"]["password"],<BR /> sock=cc_socket<BR /> )<BR /> <BR /> sftp = ssh_client.open_sftp()<BR /> <BR /> api.logger.info("SFTP Client open")<BR /> <BR /> file = sftp.file("/upload/test_create_file.txt", "a", -1)<BR /> file.write("Hello SFTP.!\n")<BR /> file.flush()<BR /> <BR /> sftp.mkdir("/upload/testdir")<BR /> <BR /> dir_objects = sftp.listdir_attr("/upload")<BR /> file_names = [e.filename for e in dir_objects]<BR /> api.logger.info(file_names)<BR /> <BR /> file_obj = io.BytesIO()<BR /> sftp.getfo("/upload/test_create_file.txt", file_obj)<BR /> api.logger.info(str(file_obj.getvalue()))<BR /> <BR /> sftp.remove("/upload/test_create_file.txt")<BR /> <BR /> api.logger.info("Generator End")<BR /> <BR /> api.send("file", api.Message(file_obj.getvalue(), {"file":{"path": f"/shared/pythoncloudconnector/test_create_file.txt"}, "file_name": "test_create_file.txt"}))<BR /> <BR /> <BR /> api.add_generator(gen)</CODE></PRE><BR /> &nbsp;<BR /> <H3 id="toc-hId-108532958">4. Testing the Custom Operator:</H3><BR /> To test the new custom SFTP operator, we create a Data Intelligence graph. In the example, I added an output port of type message.file to the custom operator. It connects to the write file operator, which is configured to write to the DI_DATA_LAKE. For the SFTP operator we add the Connection ID we created before as a parameter.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/sftp-graph.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Data Intelligence Graph</P><BR /> In the logs of the Graph execution, we can see how the file and directory are created on the SFTP server. Additionally, we can also retrieve the file content "Hello SFTP.!".<BR /> <PRE class="language-python"><CODE>Generator Start <BR /> SFTP Client open <BR /> ['testdir', 'test_create_file.txt'] <BR /> b'Hello SFTP.!\n' <BR /> Generator End </CODE></PRE><BR /> At last we can check the Metadata Explorer and see the newly imported file.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/sftp-datalake-result.png" /></P><BR /> Looking at the file content, we can see it worked well! We are able to connect to the SFTP server and integrate files with the standard operators.<BR /> <PRE class="language-python"><CODE>Hello SFTP.!</CODE></PRE><BR /> Hope you find the content of this blog helpful. Feel free to comment for further clarifications. 2023-04-14T13:00:08+02:00 https://community.sap.com/t5/technology-blogs-by-sap/proxy-third-party-python-library-traffic-using-sap-cloud-connector-in-sap/ba-p/13557501 Proxy Third-Party Python Library Traffic - Using SAP Cloud Connector in SAP Data Intelligence Python Operators 2023-04-24T12:50:54+02:00 felixbartler https://community.sap.com/t5/user/viewprofilepage/user-id/4997 Custom Python operators are the most convenient way to develop non-standard integrations in SAP Data Intelligence. The vast range of Python libraries available is virtually unlimited. In this blog post, I will demonstrate how to proxy TCP traffic of third-party libraries through the SAP Cloud Connector, enabling the integration of on-premises systems to be as effortless as internet-accessible ones.<BR /> <BR /> Please note that this blog post is a continuation of my previous post, "<A href="https://blogs.sap.com/2023/04/21/proxy-third-party-python-library-traffic-general/" target="_blank" rel="noopener noreferrer">Proxy Third-Party Python Library Traffic - General</A>", where I provided a more comprehensive explanation of the approach and libraries used.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/architecture-postgres.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Szenario Architecture</P><BR /> Szenario: In this example, I will show how to connect to a PostgreSQL database via the Cloud Connector. The database is running on my Windows machine, and the Cloud Connector is connected to that machine. This replicates a real world on-premises setup.<BR /> <H3 id="toc-hId-1091281888">Prerequisite:</H3><BR /> Before proceeding with the steps outlined in this guide, it is essential to have an instance of the SAP Cloud Connector installed. While it is possible to install the cloud connector on a server, for the purposes of this demonstration, we will be using a Windows machine. We recommend following the instructions provided in this blog (<A href="https://blogs.sap.com/2021/09/05/installation-and-configuration-of-sap-cloud-connector/" target="_blank" rel="noopener noreferrer">https://blogs.sap.com/2021/09/05/installation-and-configuration-of-sap-cloud-connector/</A>) to install and configure the cloud connector.<BR /> <BR /> The second requirement is a BTP subaccount with a Data Intelligence cluster. To this subaccount, we will connect the Cloud Connector.<BR /> <H3 id="toc-hId-894768383">1. Configuration:</H3><BR /> The first step is to create a configuration in the Cloud Connector that connects to our subaccount and exposes the PostgreSQL host as a TCP resource.<BR /> <BR /> &nbsp;<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/cloud-to-onpremise-configuration-postgres.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Cloud Connector configuration</P><BR /> On the BTP end, we can check the cockpit and the connected cloud connectors in the respective menu tabs. If you cannot see this tab, you may be missing some roles. It is important to note that we see the LocationID “FELIXLAPTOP”, which is an identifier that distinguishes multiple cloud connectors connected to the same subaccount.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/btp-registered-cloud-connectors-postgres.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Registered Cloud Connector Resources</P><BR /> <BR /> <H3 id="toc-hId-698254878">2. Creating a Data Intelligence Connection:</H3><BR /> For our purposes, we do not want to hard-code the connection details, because we need a little help from the connection management to access the Connectivity Service of BTP. In the Connection Management application from SAP Data Intelligence we can create connections of all types. We create a connection of type HTTP with host, port and SAP Cloud Connector as the gateway.<BR /> <BR /> In there we specify the internal host of the Cloud Connector resource, its port and the Postgres username and password.<BR /> <BR /> &nbsp;<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/postgres-connection.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Connection with Cloud Connector Gateway</P><BR /> Note: Not all connection types allow you to access via the Cloud Connector. See the official product documentation for details.<BR /> <H3 id="toc-hId-501741373">3. Developing a Custom Operator:</H3><BR /> In the operators menu of Data Intelligence we create a new custom operator based on the Python3 operator.<BR /> <BR /> We build a custom Dockerfile with the required libraries. We use psycopg2 to connect to Postgres, SocketSwap as a local proxy, and sapcloudconnectorpythonsocket to open a socket via the Cloud Connector.<BR /> <PRE class="language-python"><CODE>FROM $com.sap.sles.base<BR /> <BR /> RUN python3 -m pip --no-cache-dir install 'psycopg2-binary' --user<BR /> RUN python3 -m pip --no-cache-dir install 'sapcloudconnectorpythonsocket' --user<BR /> RUN python3 -m pip --no-cache-dir install 'SocketSwap' --user</CODE></PRE><BR /> Now to the key part, the custom script:<BR /> <PRE class="language-python"><CODE>import psycopg2<BR /> from SocketSwap import SocketSwapContext<BR /> import multiprocessing<BR /> from operators.&lt;your_operator&gt;.socket_factory import socket_factory<BR /> <BR /> multiprocessing.set_start_method("spawn") # needed because DI Python Operator is itself executed in Threads<BR /> <BR /> postgres_connection = api.config.http_connection<BR /> <BR /> api.logger.info(str(postgres_connection))<BR /> <BR /> <BR /> def connect_postgres():<BR /> """<BR /> This function demos how to easily setup the local proxy using the SocketSwapContext-Manager.<BR /> It exposes a local proxy on the localhost 127.0.0.1 on port 2222<BR /> The connection factory is provided to handle the creation of a socket to the remote target<BR /> """<BR /> <BR /> with SocketSwapContext(socket_factory, [postgres_connection], "127.0.0.1", 2222):<BR /> api.logger.info("Proxy started!")<BR /> # Set up a connection to the PostgreSQL database<BR /> conn = psycopg2.connect(<BR /> host="127.0.0.1",<BR /> database="postgres",<BR /> user="postgres",<BR /> password="password",<BR /> port=2222<BR /> )<BR /> api.logger.info("Postgres connected successfully!")<BR /> <BR /> # Create a cursor object to execute SQL queries<BR /> cur = conn.cursor()<BR /> <BR /> # Execute a SELECT query to retrieve data from a table<BR /> cur.execute("SELECT CURRENT_TIMESTAMP;")<BR /> <BR /> # Fetch all the rows returned by the query<BR /> rows = cur.fetchall()<BR /> <BR /> # Print the rows to the console<BR /> for row in rows:<BR /> api.logger.info(str(row))<BR /> <BR /> # Close the cursor and connection<BR /> cur.close()<BR /> conn.close()<BR /> <BR /> <BR /> def gen():<BR /> api.logger.info("Generator Start")<BR /> <BR /> connect_postgres()<BR /> <BR /> <BR /> api.add_generator(gen)</CODE></PRE><BR /> And we need a second file in which we put the function we are passing into the SocketSwap Proxy. Note: This function is placed in a seperate file on the top level, to make it pickleable.<BR /> <PRE class="language-python"><CODE>from sapcloudconnectorpythonsocket import CloudConnectorSocket<BR /> <BR /> def socket_factory(postgres_connection):<BR /> cc_socket = CloudConnectorSocket()<BR /> cc_socket.connect(<BR /> dest_host=postgres_connection["connectionProperties"]["host"], # virtualhost<BR /> dest_port=postgres_connection["connectionProperties"]["port"], # 5432<BR /> proxy_host=postgres_connection["gateway"]["host"], # connectivity-service-proxy<BR /> proxy_port=20004, # 20004 SOCKS5 Proxy Port of connectivity service<BR /> token=postgres_connection["gateway"]["authentication"], # auth token<BR /> location_id="FELIXLAPTOP"<BR /> )<BR /> return cc_socket</CODE></PRE><BR /> In the custom operator, script we just use a generator to start the connect_postgres function. Inside that function, we use the standard psycopg functions to make a small SQL query to the database. The only difference here: We wrap it in the SocketSwapContext to redirect its traffic through a CloudConnectorSocket.<BR /> <BR /> Note: The SocketSwapContext takes mainly 3 arguments: A socket_factory, a callable that returns a connected socket, socket_factory_args, the local proxy host and its port. As we can see in the example, I pass the socket_factory function to the context manager. This function uses the already introduced CloudConnectorSocket functionality to open a Python socket using the Cloud Connector as proxy server. <A href="https://blogs.sap.com/2023/04/14/sap-data-intelligence-python-operators-and-cloud-connector-tcp/" target="_blank" rel="noopener noreferrer">Check out my previous post about TCP and the SAP Cloud Connector</A> to learn more details about this.<BR /> <BR /> The local proxy is setup automatically in a background daemon process and listens to the given host, port. Usually this will be the localhost and a free port. In your third-party library you can then connect to that proxy and its traffic will be redirected automatically to the address specified as destination in the cloud connector socket.<BR /> <H2 id="toc-hId-176145149">4. Test the custom operator:</H2><BR /> We can wrap the new operator in a Data Intelligence Graph and fill the configuration parameter with the POSTGRES_ONPREM_SYSTEM connection ID.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/operator.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Custom Operator Parameters</P><BR /> In this example, we can check the logs and see the following:<BR /> <PRE class="language-python"><CODE>Generator Start <BR /> Proxy started! <BR /> Postgres connected successfully! <BR /> (datetime.datetime(2023, 4, 24, 10, 10, 52, 593842, tzinfo=datetime.timezone.utc),) </CODE></PRE><BR /> The proxy registered successfully and was able to redirect the traffic coming to localhost:2222 to the on-premises PostgreSQL. As a result of the query, we get the current_timestamp in the python datetime object.<BR /> <BR /> I hope this blog gave you a perspective of the possibilities you have even through the Cloud Connector to interact with any system. If you have any questions of scenarios for the <A href="https://github.com/fyx99/SocketSwap" target="_blank" rel="nofollow noopener noreferrer">SocketSwap</A> package, feel free to leave a comment.<BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp; 2023-04-24T12:50:54+02:00 https://community.sap.com/t5/technology-blogs-by-sap/surviving-and-thriving-with-cap-destinations-and-the-transparent-proxy-for/ba-p/13555822 Surviving and Thriving with CAP: Destinations and the Transparent Proxy for Kubernetes 2023-05-04T09:07:02+02:00 maxstreifeneder https://community.sap.com/t5/user/viewprofilepage/user-id/95 In my last blog post, I've written about how I prepared an existing app that was already running on SAP BTP, Cloud Foundry to be deployed on SAP BTP, Kyma runtime. Along the way, I got to know and appreciate some new tools like helm/paketo and kubectl and the entire Kubernetes ecosphere which is quite eye-opening. I had some "touch barrier" for a long time, which may be why it took me a while to dive into the topic more deeply.<BR /> <BR /> <SPAN class="mention-scrubbed">jan.schaffner</SPAN>'s recent post on <A href="https://www.linkedin.com/feed/update/urn:li:activity:7044960441281728513/" target="_blank" rel="nofollow noopener noreferrer">LinkedIn</A> drew my attention to the <STRONG>Transparent Proxy for Kubernetes</STRONG>. As usual, I had to take a closer look at the topic and try it out myself to really understand what it is and how it works.<BR /> <BR /> The Transparent Proxy is a software component designed for Kubernetes, which means it can also be used with SAP BTP, Kyma runtime. This tool simplifies the process of calling SAP BTP Destinations for developers. I was impressed with how the Transparent Proxy seamlessly integrates with SAP BTP's, Kyma runtime, and it definitely exceeded my expectations in terms of the benefits it offers.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/loiod4060b6fc6444d48931ecb9b20032ed5_LowRes.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Transparent Proxy for Kubernetes (help.sap.com)</P><BR /> Before diving into the steps for using the Transparent Proxy and its inner workings, I think it's important to first discuss SAP BTP Destinations in general. While these destinations are incredibly useful, they can also cause challenges if you're not using the correct libraries and SDKs. Luckily, SAP provides various SDKs and frameworks (spoiler: but not for all languages) that make using Destinations on SAP BTP a lot easier. Throughout this process, we'll explore the existing SDKs and frameworks by SAP and how they help us in using Destinations.<BR /> <H4 id="toc-hId-1220307971"><STRONG>It's about CAP because it's not about CAP</STRONG></H4><BR /> You're right, it may seem like this blog post isn't directly related to CAP but once you've chosen a blog series title (#<A href="https://blogs.sap.com/tag/captricks/" target="_blank" rel="noopener noreferrer">CAPTricks</A>), you have to stick to it, right? <span class="lia-unicode-emoji" title=":winking_face:">😉</span> However, that's only half of the truth. In this post, I intentionally set aside CAP code to focus on the real problem that the Transparent Proxy solves. Additionally, by the end of the post, readers will hopefully see (again) how CAP simplifies the use of SAP BTP Destination service as a whole.<BR /> <BR /> To provide some context, CAP aims to simplify many essential and repetitive processes. According to the CAP documentation, it can significantly accelerate development, minimize boilerplate code, and improve overall quality by providing single points to fix and optimize. One such process is connecting to remote services or making API calls, which is precisely what this blog post will cover.<BR /> <BR /> In SAP Business Technology Platform (SAP BTP), there's a service called Destination service that stores information about remote services.<BR /> <P style="text-align: left">Before I'll explain the concept of the Destination service, how about asking the most prominent assistant these days?</P><BR /> <BR /> <BLOCKQUOTE><BR /> <P style="text-align: center"><STRONG>ChatGPT, what's the purpose of SAP BTP Destinations?&nbsp;</STRONG></P><BR /> </BLOCKQUOTE><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/purpose_destinations.png" /></P><BR /> &nbsp;<BR /> <BR /> The Destination service in SAP BTP provides a centralized way to store information about remote services, including the URL, port number, HTTP headers, and authentication information. This approach offers a significant advantage by allowing updates to the Destination information on SAP BTP, rather than modifying the service information in every single application that wants to connect. This saves time and effort and ensures that all applications are updated at once, resulting in increased quality and minimized errors.<BR /> <BR /> As the SAP BTP Destination service is part of your SAP BTP sub-account, not everyone can connect to it. To use the information about a particular Destination in your application, you first need to go through OAuth2 authentication to retrieve the information from the SAP BTP service. While constructing the subsequent call to the actual remote service is not difficult, it can still be challenging, particularly if the actual API is also secured by OAuth2 or if the API is an on-premise system behind an SAP Cloud Connector or SAP Private Link service. Additionally, token handling, such as refreshing them, is a common task that needs to be tackled.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/mermaid-diagram-2023-04-24-182449.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">very high level flow of calling a remote service/API using the SAP BTP Destination service</P><BR /> To handle these challenges, several SDKs and frameworks offer support for Destination handling, including the SAP Cloud SDK and the SAP Cloud Application Programming Model (CAP). CAP probably handles Destinations in the most convenient way.<BR /> <BR /> We'll have a look at different scenarios peu a peu with more help of SDKs or services, but the common ground for all the following paragraphs is the Destination service on SAP BTP. We'll not going to move this out of this scenario. I'll only provide the configuration &amp; code examples for Node.js for the sake of not bloating up this blog post. If you closely look at the endpoint we are using for the example code: Yes, it's basically an OData endpoint that I'm treating as a plain REST endpoint. Also, the examples below do not contain any kind of authentication or SAP Cloud Connector which makes the scenario by far more complex (and realistic, to be honest but less readable in this blog post).<BR /> <BR /> This is the destination we'll be using throughout this blog post:<BR /> <BR /> &nbsp;<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/destination-1-1.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic"><A href="https://services.odata.org/v4/northwind/northwind.svc/" target="test_blank" rel="nofollow noopener noreferrer">https://services.odata.org/v4/northwind/northwind.svc/</A></P><BR /> <BR /> <H4 id="toc-hId-1023794466"><STRONG>Destination usage with plain Node.js with <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1387241">@Sap</a>/xsenv</STRONG></H4><BR /> When connecting to a remote service through the SAP BTP Destination service, you need to provide your service instance information, including service credentials, to your application. This can be achieved through various methods:<BR /> <UL><BR /> <LI>By providing environment variables using <EM>.env</EM> / <EM>default-env.json</EM> files for local development</LI><BR /> <LI>On SAP BTP, Cloud Foundry runtime: Either via the SAP BTP Cockpit, the CF CLI or in the MTA descriptor</LI><BR /> <LI>on SAP BTP, Kyma runtime: <A href="https://github.com/SAP/sap-btp-service-operator#reference-documentation" target="_blank" rel="nofollow noopener noreferrer">Via ServiceInstance and a ServiceBinding</A></LI><BR /> </UL><BR /> This injects the service information (where and how to reach the SAP BTP Destination service and the SAP Connectivity service) either as an environment variable (in case of local development and SAP BTP, Cloud Foundry runtime) or as an <A href="https://cap.cloud.sap/docs/node.js/cds-connect#in-kubernetes-kyma" target="_blank" rel="nofollow noopener noreferrer">mounted Volume</A> for the respective runtime. CAP itself knows how to grab that information and uses it to connect to the SAP BTP Destination service make the subsequent call to the actual remote service.<BR /> <BR /> <SPAN id="autocomplete"><SPAN id="autocomplete-delimiter">In the following code, the only SAP-provided helper is the <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1387241">@Sap</a>/xsenv package. This package serves as a "<A href="https://www.npmjs.com/package/@sap/xsenv" target="_blank" rel="nofollow noopener noreferrer">utility for easily reading application configurations for bound services and certificates in the SAP BTP, Cloud Foundry environment, SAP XS advanced model, and Kubernetes (K8S)</A>". It is used to read environment variables based on the three options mentioned earlier in the text, enabling the application to retrieve the service instance information necessary to connect to the SAP BTP Destination service and call the Destination itself. The package reads environments variables based on the three above provided options.&nbsp;</SPAN></SPAN><BR /> <PRE class="language-javascript"><CODE>const request = require("request-promise");<BR /> const env = require("@sap/xsenv");<BR /> env.loadEnv();<BR /> const destinationService = env.getServices({<BR /> dest: { tag: "destination" },<BR /> }).dest;<BR /> const xsuaaService = env.getServices({ uaa: { tag: "xsuaa" } }).uaa;<BR /> const xsuaaCreds = `${destinationService.clientid}:${destinationService.clientsecret}`;<BR /> const destinationName = "northwind";<BR /> <BR /> async function getNorthwindExampleData() {<BR /> try {<BR /> const tokenResponse = await request({<BR /> uri: `${xsuaaService.url}/oauth/token`,<BR /> method: "POST",<BR /> headers: {<BR /> Authorization: `Basic ${Buffer.from(xsuaaCreds).toString("base64")}`,<BR /> "Content-type": "application/x-www-form-urlencoded",<BR /> },<BR /> form: {<BR /> client_id: destinationService.clientid,<BR /> grant_type: "client_credentials",<BR /> },<BR /> });<BR /> const token = JSON.parse(tokenResponse).access_token;<BR /> <BR /> const destinationResponse = await request({<BR /> uri: `${destinationService.uri}/destination-configuration/v1/destinations/${destinationName}`,<BR /> headers: {<BR /> Authorization: `Bearer ${token}`,<BR /> },<BR /> });<BR /> const oDestination = JSON.parse(destinationResponse);<BR /> <BR /> const result = await request({<BR /> method: "GET",<BR /> uri: `${oDestination.destinationConfiguration.URL}Employees?$top=10&amp;$select=FirstName`,<BR /> });</CODE></PRE><BR /> As you may have noticed, calling the SAP BTP Destination service yourself, including authentication and token handling, and then making the call to the actual remote service can be quite challenging. In the example shown above, the remote service is not secured, making it relatively simple. However, handling token refresh and managing authentication makes the flow more complex. As you can see and most likely know or can even imagine: quite some effort and headache.<BR /> <BR /> If you want to know more about it, <SPAN class="mention-scrubbed">carlos.roggan</SPAN> has written a blog post about the details of calling an on-premise API using plain Node.js <A href="https://blogs.sap.com/2020/08/07/sap-cloud-platform-how-to-call-onprem-system-from-node.js-app-via-cloud-connector/" target="_blank" rel="noopener noreferrer">How to call – onPrem System – from Node.js app – via Cloud Connector</A>.<BR /> <H4 id="toc-hId-827280961"><STRONG>Destination usage with the SAP Cloud SDK for JavaScript</STRONG></H4><BR /> If we want to avoid the headaches and problems associated with the manual handling of SAP BTP Destination service authentication and remote service calls, one option is to use the SAP Cloud SDK for JavaScript. According to the SDK's landing page on <A href="https://sap.github.io/cloud-sdk/" target="_new" rel="noopener nofollow noreferrer">https://sap.github.io/cloud-sdk/</A>: "The SAP Cloud SDK for JavaScript helps you build cloud-based apps and extensions to SAP solutions using the power and flexibility of Node.js and its ecosystem."<BR /> <BR /> While the application still requires service credentials for the SAP BTP Destination service, the SDK makes connecting to the service and calling the remote service much more convenient and robust, with all the necessary handling taken care of.<BR /> <BR /> Below is an example of how to use the SAP Cloud SDK for JavaScript to connect to a remote service.<BR /> <PRE class="language-javascript"><CODE>import { executeHttpRequest } from '@sap-cloud-sdk/http-client';<BR /> import xsenv from '@sap/xsenv';<BR /> xsenv.loadEnv();<BR /> const destinationName = 'northwind';<BR /> async function getNorthwindExampleData() {<BR /> const result = await executeHttpRequest(<BR /> {<BR /> destinationName: destinationName,<BR /> },<BR /> {<BR /> url: 'Employees?$top=10&amp;$select=FirstName',<BR /> },<BR /> {<BR /> fetchCsrfToken: false,<BR /> }<BR /> <BR /> }<BR /> </CODE></PRE><BR /> &nbsp;<BR /> <H4 id="toc-hId-630767456"><STRONG>Destination usage with SAP Cloud Application Programming Model (CAP) - Node.js &amp; Java</STRONG></H4><BR /> Next, let's look at how to use SAP Cloud Application Programming Model (CAP) to call a remote service using Destinations. In essence, calling the remote service with CAP is not much different from using the SAP Cloud SDK, especially when it comes to the example request we are trying to accomplish here. You can read more about the similarities and differences between the two in <SPAN class="mention-scrubbed">milton</SPAN>'s blog post: <A href="https://blogs.sap.com/2023/04/04/sap-cloud-sdk-and-its-relationship-with-sap-cloud-application-programming-model/" target="_blank" rel="noopener noreferrer">SAP Cloud SDK and its relationship with SAP Cloud Application Programming Model</A>.<BR /> <BR /> One advantage of using CAP is that the CDS cli provides additional convenience, such as the ability to mock remote services or a protocol agnostic query language like <A href="https://cap.cloud.sap/docs/cds/cql" target="_blank" rel="nofollow noopener noreferrer">CQL</A>. Another benefit is that you can provide the necessary service binding for local development using <A href="https://cap.cloud.sap/docs/advanced/hybrid-testing#bind-to-cloud-services" target="_blank" rel="nofollow noopener noreferrer">cds bind</A>, which eliminates the need for manual configuration.<BR /> <BR /> When it comes to configuring Destinations with CAP, there isn't much that needs to be done. You simply need to pass the Destination name to cds and call the remote service in your custom handlers.<BR /> <BR /> <STRONG>cds configuration in package.json or cdsrc.json:</STRONG><BR /> <PRE class="language-javascript"><CODE>{<BR /> "cds": {<BR /> "requires": {<BR /> "MyRemoteService": {<BR /> "kind": "rest",<BR /> "credentials": {<BR /> "destination": "northwind"<BR /> }<BR /> }<BR /> }<BR /> }<BR /> }</CODE></PRE><BR /> With that you can simply connect to the remote service using the following lines of code:<BR /> <PRE class="language-javascript"><CODE>const myRemoteServiceObject = await cds.connect.to('MyRemoteService');<BR /> const employees = await myRemoteServiceObject.get('/Employees?$top=10&amp;$select=FirstName');<BR /> </CODE></PRE><BR /> That's all. CAP takes care of the details about how to connect to that service. May it be the specifics of an on-premise system with the detour via the SAP Connectivity Service, or Principal Propagation and so on. CAP handles all of these scenarios for the developer, making it easier to focus on building the application logic instead of worrying about the details of connecting to the remote service.<BR /> <H4 id="toc-hId-434253951"><STRONG>So, Max, what's the Transparent Proxy for Kubernetes and why should I use it?</STRONG></H4><BR /> Let's talk about the Transparent Proxy for Kubernetes and why it's beneficial to use. I apologize for the detour in explaining how the SAP BTP Destination service is typically used in Node.js or Java (even though I haven't provided the corresponding samples) projects, but it's important to understand the sweet spot of the Transparent Proxy.<BR /> <BR /> Consider a scenario where you don't have access to SDKs or frameworks like CAP for whatever reason. Perhaps you're using a programming language that doesn't have such tools available, like Python, Go, Rust, or others. In such a case, wouldn't it be great if there was a mechanism that could take away the responsibility of handling destination specifics from the developer, using an infrastructure mechanism to "intercept" calls and adjust them based on the configuration of the actual destination on SAP BTP?<BR /> <BR /> The Transparent Proxy for Kubernetes does exactly that. Once the Transparent Proxy is installed in SAP BTP, Kyma runtime, or any Kubernetes cluster, developers only need to consider two key aspects:<BR /> <BR /> A custom Kubernetes resource of kind <STRONG>destination.connectivity.api.sap </STRONG>that you need to apply:<BR /> <PRE class="language-javascript"><CODE>---<BR /> apiVersion: destination.connectivity.api.sap/v1<BR /> kind: Destination<BR /> metadata:<BR /> name: tproxydestination<BR /> spec:<BR /> destinationRef:<BR /> name: "northwind"</CODE></PRE><BR /> With that, one can easily make a call to the actual remote service by using the name of the destination resource defined above - TProxyDestination. To better understand it, a curl example beautifully demonstrates it (though escaping might make it a bit less pretty <span class="lia-unicode-emoji" title=":winking_face:">😉</span>).<BR /> <PRE class="language-python"><CODE>curl tproxydestination/Employees?$top=10&amp;$select=FirstName</CODE></PRE><BR /> Impressive, right? However, this was just a basic example using an unsecured public endpoint. The true power of the Transparent Proxy lies in its ability to handle secured remote services protected by OAuth and likely hidden behind a SAP Cloud Connector. By taking over the responsibility of handling destination specifics, the Transparent Proxy saves developers from dealing with cumbersome configurations and adjustments.<BR /> <H4 id="toc-hId-237740446"><STRONG>How can I use it and how does it work?&nbsp;</STRONG></H4><BR /> If you're interested in using the Transparent Proxy and want to know how it works, here's a brief overview. To get started, you'll need to configure the SAP-provided Helm Chart with information specific to your environment, such as the service details for the SAP BTP Destination service and the location of the Transparent Proxy Docker image. The instructions for setting up the Transparent Proxy with the Repository-Based Shipment Channel (RBSC) can be found on <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/transparent-proxy-lifecycle-management" target="_blank" rel="noopener noreferrer">help.sap.com</A>, but let's take a closer look at the step-by-step setup process.<BR /> <BR /> 1. <A href="https://help.sap.com/docs/RBSC/0a64be17478d4f5ba45d14ab62b0d74c/7e83dfc309834942b441fc2106c5b7f5.html?locale=en-US" target="_blank" rel="noopener noreferrer">Create a technical user for SAP Repositories Management</A><BR /> <BR /> 2. Create a secret for that technical user in your namespace<BR /> <PRE class="language-python"><CODE>kubectl create secret docker-registry docker-secret --docker-server=73554900100900006891.dockersrv.cdn.repositories.cloud.sap --docker-username=&lt;rbsc-user&gt; --docker-password=&lt;password&gt;</CODE></PRE><BR /> 3. Create a ServiceInstance and ServiceBinding for the SAP BTP Destination service, either using the <A href="https://help.sap.com/docs/btp/sap-business-technology-platform/using-sap-btp-services-in-kyma-environment" target="_blank" rel="noopener noreferrer">SAP BTP, Kyma runtime Dashboard</A> or kubectl:<BR /> <PRE class="language-javascript"><CODE>apiVersion: services.cloud.sap.com/v1<BR /> kind: ServiceInstance<BR /> metadata:<BR /> name: transparent-proxy-dest<BR /> spec:<BR /> serviceOfferingName: destination<BR /> servicePlanName: lite<BR /> ---<BR /> apiVersion: services.cloud.sap.com/v1<BR /> kind: ServiceBinding<BR /> metadata:<BR /> name: transparent-proxy-dest-binding<BR /> spec:<BR /> serviceInstanceName: transparent-proxy-dest</CODE></PRE><BR /> 4. In case you want to use the SAP Cloud Connector, please <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/connectivity-proxy-for-kubernetes" target="_blank" rel="noopener noreferrer">enable the Connectivity Proxy in your cluster</A>.<BR /> <BR /> 5. Configure the necessary values in the <CODE>values.yaml</CODE> file. An example configuration that I have used is shown below, while a comprehensive list of all available properties, including the required ones, can be found on <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/transparent-proxy-configuration-guide" target="_blank" rel="noopener noreferrer">help.sap.com</A>.<BR /> <PRE class="language-javascript"><CODE>config:<BR /> integration:<BR /> destinationService:<BR /> serviceCredentials:<BR /> secretName: transparent-proxy-dest-binding<BR /> platform:<BR /> region: us20<BR /> security:<BR /> communication:<BR /> internal:<BR /> encryptionEnabled: false<BR /> accessControl:<BR /> destinations:<BR /> defaultScope: namespaced<BR /> <BR /> deployment:<BR /> image:<BR /> registry: 73554900100900006891.dockersrv.cdn.repositories.cloud.sap<BR /> repository: com.sap.core.connectivity.transparent-proxy<BR /> pullSecret: docker-secret<BR /> </CODE></PRE><BR /> &nbsp;<BR /> <UL><BR /> <LI><STRONG>config.integration.destinationService.serviceCredentials.secretName:</STRONG> refers to the secret that has been created by creating the ServiceBinding resource.</LI><BR /> <LI><STRONG>config.platform.region:</STRONG> refers to the region of your SAP BTP subaccount (regions on <A href="https://help.sap.com/docs/btp/sap-business-technology-platform/regions?locale=en-US" target="_blank" rel="noopener noreferrer">help.sap.com</A>)</LI><BR /> <LI><STRONG>deployment.image.registry:</STRONG> refers to the image registry. remains the same for all installations since this is the registry SAP uses to distribute the Transparent Proxy</LI><BR /> <LI><STRONG>deployment.image.pullSecret:</STRONG> refers to the secret name you have created in one of the earlier steps using kubectl</LI><BR /> </UL><BR /> 6. Once you've completed the previous configuration steps, you're ready to install the Transparent Proxy in your cluster using Helm. Simply reference the values.yaml file you configured in the earlier steps, and the installation process will use your customized settings.<BR /> <BR /> &nbsp;<BR /> <PRE class="language-python"><CODE>helm install transparent-proxy transparent-proxy-helm/transparent-proxy --version=1.2.0 --namespace &lt;yournamespace&gt; -f values.yaml</CODE></PRE><BR /> What you get as a result is a set of pods (as part of a Deployment that you can scale using ReplicaSets) that seamlessly manage the entire lifecycle of Destinations as a crucial component of the Transparent Proxy solution.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/pods_deployment.png" /></P><BR /> 7. Create a Destination as a custom Kubernetes resource in the SAP BTP, Kyma runtime cluster:<BR /> <PRE class="language-javascript"><CODE>---<BR /> apiVersion: destination.connectivity.api.sap/v1<BR /> kind: Destination<BR /> metadata:<BR /> name: tproxydestination<BR /> spec:<BR /> destinationRef:<BR /> name: "northwind"</CODE></PRE><BR /> The Transparent Proxy's reconciler will detect the Destination resource and generate a Kubernetes Service with the name specified in metadata.name. Once a Kubernetes Service is established, it is allocated a DNS name in the cluster's DNS service. This DNS name is derived from the Service name and its associated namespace, allowing it to be accessed from within the cluster.<BR /> <BR /> By using the name of a Kubernetes Service to call it, Kubernetes will automatically resolve the DNS name to the Service's virtual IP address. This results in the request being directed to the appropriate Pod through its load balancing mechanism, and this Pod is one of the Pods created by the Helm chart installation as you can see below.<BR /> <BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/service-pods-ip.png" /><BR /> <H4 id="toc-hId-41226941"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/05/mermaid-flow1.png" /></H4><BR /> <H4 id="toc-hId--155286564">Takeaway:</H4><BR /> <SPAN id="autocomplete"><SPAN id="autocomplete-delimiter">Sometimes it's easy to forget just how complex it can be to call remote services and APIs, especially if you don't have the right tools at your disposal. While the SAP Cloud SDK and CAP do an excellent job for Node.js and Java, the Transparent Proxy is a great solution for taking the responsibility of low-level API calls away from developers in other languages. </SPAN></SPAN><BR /> <BR /> To be very clear: This blog post is not specifically about CAP and the Transparent Proxy is only available for Kubernetes.<BR /> <BR /> <SPAN id="autocomplete"><SPAN id="autocomplete-delimiter">If you're interested in learning more about the goal and features of the Transparent Proxy, I recommend reading <SPAN class="mention-scrubbed">iliyanvidenov9</SPAN>'s blog post</SPAN></SPAN><SPAN id="autocomplete"><SPAN id="autocomplete-delimiter">: <A href="https://blogs.sap.com/2022/11/29/transparent-consumption-of-connectivity/" target="_blank" rel="noopener noreferrer">Transparent Consumption of Connectivity</A>.&nbsp;</SPAN></SPAN><BR /> <BR /> <HR /><BR /> <BR /> Slightly off-topic: In my recent blog post, I explored SAP BTP's, Kyma runtime and its various capabilities, benefits, and challenges. I realized that the world of Kubernetes is extensive and offers far more opportunities for software development than traditional deployment methods like "cf push/cf deploy" in Cloud Foundry. As a result, it can be challenging to compare the two runtimes. However, factors like the need for a service mesh, control over application distribution, and flexibility in tool selection often lead developers to choose SAP BTP's, Kyma runtime. It's important to remember that this discussion is not about comparing the two runtimes, but rather explaining the technical topic of the Transparent Proxy for Kubernetes.<BR /> <BR /> If you're interested in learning more about the similarities and differences between SAP BTP's, Cloud Foundry and Kyma Runtimes, I highly recommend reading <SPAN class="mention-scrubbed">alperdedeoglu</SPAN>'s blog post: <A href="https://blogs.sap.com/2023/04/28/developing-an-application-on-sap-cloud-foundry-runtime-and-sap-kyma-runtime-a-comparative-analysis/" target="_blank" rel="noopener noreferrer">Developing an Application on SAP Cloud Foundry Runtime and SAP Kyma Runtime: A Comparative Analysis</A>.<BR /> <BR /> &nbsp; 2023-05-04T09:07:02+02:00 https://community.sap.com/t5/technology-blogs-by-sap/consuming-a-rest-service-from-a-cap-application/ba-p/13568197 Consuming a REST service from a CAP application 2023-06-06T10:50:16+02:00 Chandan https://community.sap.com/t5/user/viewprofilepage/user-id/8875 In this blog post, we will deep dive into the process of constructing a comprehensive use case using the powerful capabilities of the SAP Cloud Application Programming Model (CAP).<BR /> <BR /> Our focus will be on consuming a REST service within CAP, and I draw inspiration from a highly informative <A href="https://blogs.sap.com/2020/12/27/consuming-a-rest-service-with-the-sap-cloud-application-programming-model/" target="_blank" rel="noopener noreferrer">blog</A> by Robert Witt that greatly helped me in developing this application.<BR /> <BR /> Let's provide a summary of the exciting journey that lies ahead of us. <I>“I can’t wait&nbsp;</I><span class="lia-unicode-emoji" title=":beaming_face_with_smiling_eyes:">😁</span><I>”</I><BR /> <H2 id="toc-hId-963148922"><STRONG>Use Case</STRONG></H2><BR /> In our application, I have defined a data model consisting of two main entities: Customers and Locations. A single customer can operate in multiple locations, and each location has an attribute called "temperature." Our goal is to ensure that this attribute is regularly updated with the current temperature for each respective city.<BR /> <BR /> To achieve this, we require a service capable of providing us with the latest temperature data. Fortunately, there are several services available for this purpose, and for our use case, we will be utilizing the <A href="https://openweathermap.org/api" target="_blank" rel="nofollow noopener noreferrer">OpenWeatherMap</A> service.<BR /> <BR /> Also, we will explore how to develop an action within CAP that will interact with the OpenWeatherMap REST service. This action will retrieve the current temperature information and subsequently update our data model with the latest temperature values.<BR /> <BR /> Now, let's dive into the process of building this application, starting with the definition of our data model.<BR /> <H2 id="toc-hId-766635417">Data Model</H2><BR /> <PRE class="language-javascript"><CODE>type Coordinates : {<BR /> longitude : Decimal(9,6);<BR /> latitude : Decimal(9,6);<BR /> };<BR /> <BR /> entity Customer {<BR /> <BR /> key name : String(20);<BR /> <BR /> }<BR /> <BR /> entity Location {<BR /> <BR /> key city : String(20);<BR /> coordinates : Coordinates;<BR /> temperature : Decimal;<BR /> temp_unit : String(2); <BR /> }<BR /> <BR /> entity OperatedIn {<BR /> <BR /> key customer : Association to one Customer not null;<BR /> location : Association to one Location not null;<BR /> }</CODE></PRE><BR /> We have a straightforward data model that revolves around two primary entities: Customer and Location. Additionally, we have a local type known as "Coordinates," which is declared within the same service.<BR /> <BR /> The Location entity has an attribute called "temperature." This attribute holds the current temperature specifically associated with each location. It allows us to store and track the temperature data effectively.<BR /> <H2 id="toc-hId-570121912">Service</H2><BR /> <PRE class="language-javascript"><CODE>using { OperatedIn as OperatedIn } from '../db/schema.cds';<BR /> <BR /> service sensorData {<BR /> <BR /> @readonly entity CustomerLocations as select *, location.temperature from OperatedIn;<BR /> <BR /> // Take the City as input and call the weather API to update the current temperature<BR /> action updateTemperature(city: String(20)) returns Decimal;<BR /> <BR /> }</CODE></PRE><BR /> Within our service, we have an unbound action called "updateTemperature". This action is responsible for handling the process of calling the OpenWeatherMap service to update the temperature data.<BR /> <BR /> The updateTemperature action accepts the location name as input. It then reads the database to retrieve the geo-coordinates associated with that specific location. With the acquired coordinates, the action proceeds to invoke the OpenWeatherMap REST service.<BR /> <H2 id="toc-hId-373608407">Consuming the REST Service</H2><BR /> In the package.json you have mentioned the service details.<BR /> <PRE class="language-abap"><CODE>"cds": {<BR /> "requires": {<BR /> "weatherservice": {<BR /> "kind": "rest",<BR /> "credentials": {<BR /> "url": "https://api.openweathermap.org",<BR /> "requestTimeout": 30000<BR /> }<BR /> }<BR /> }<BR /> }</CODE></PRE><BR /> <H2 id="toc-hId-177094902">Custom Handler</H2><BR /> <PRE class="language-javascript"><CODE>// Take the City as input and call the weather API to update the current temperature <BR /> srv.on('updateTemperature', async (req) =&gt; {<BR /> <BR /> const {city} = req.data;<BR /> <BR /> const db = await cds.connect.to ('db');<BR /> let {Location} = db.entities;<BR /> <BR /> let results = await db.read(Location,["city","coordinates_longitude as longitude","coordinates_latitude as latitude"]).where({city:city});<BR /> <BR /> const weatherAPI = await cds.connect.to("weatherservice");<BR /> // Using template literals<BR /> let res = weatherAPI.tx(req).get(`/data/2.5/weather?units=metric&amp;appid=&lt;ApiID&gt;&amp;lat=${results[0].latitude}&amp;lon=${results[0].longitude}`);<BR /> <BR /> let final_data =<BR /> res.then( async (data) =&gt; {<BR /> let results1 = await db.update(Location).set({temperature: data.main.temp}).where({city:city});<BR /> return data.main.temp;<BR /> });<BR /> <BR /> return final_data;<BR /> <BR /> });</CODE></PRE><BR /> When the action is invoked, this custom handler comes into play. It performs a sequence of operations to ensure the successful retrieval and update of temperature data.<BR /> <BR /> Firstly, it reads the coordinates associated with the input location from the database. Then it calls the designated service for temperature data retrieval. Once the temperature is obtained, it is both updated in the database and returned as the current temperature.<BR /> <BR /> It is important to note that, you need to obtain an API ID from the OpenWeatherMap website. Kindly replace "&lt;ApiID&gt;" with your unique API ID provided by OpenWeatherMap.<BR /> <BR /> If you are wondering how to use the OpenWeatherMap services then please refer to its documentation <A href="https://openweathermap.org/api" target="_blank" rel="nofollow noopener noreferrer">API doc</A>.<span class="lia-unicode-emoji" title=":smiling_face_with_smiling_eyes:">😊</span><BR /> <H2 id="toc-hId--19418603">Summary</H2><BR /> Key Takeaways from this Use Case:<BR /> <OL><BR /> <LI>Understanding the process of consuming a REST service within CAP.</LI><BR /> <LI>Learning how to effectively read and update the database.</LI><BR /> <LI>Implementing an action in CAP to perform specific tasks.</LI><BR /> </OL><BR /> Note:<span class="lia-unicode-emoji" title=":memo:">📝</span> The codes in this example are purely for illustrative purposes. No performance testing has been done. There may be alternative approaches for optimization.<BR /> <BR /> Thank you. Hope you enjoyed this blog! Please feel free to leave a comment or question below. 2023-06-06T10:50:16+02:00 https://community.sap.com/t5/technology-blogs-by-members/easy-way-to-access-destinations-in-sap-btp-cloud-foundry-via-node-js/ba-p/13547880 Easy way to access destinations in SAP BTP cloud foundry via Node.js 2023-06-28T20:34:00+02:00 kallolathome https://community.sap.com/t5/user/viewprofilepage/user-id/14879 <H2 id="toc-hId-961278778">Introduction</H2><BR /> I've checked blog-posts for accessing the destinations having authentication <SPAN style="font-size: 1rem"><STRONG>OAuth2ClientCredentials </STRONG></SPAN>in Cloud Foundry via <STRONG>Node.js</STRONG> <SPAN style="font-size: 1rem">. But I didn't find any code working properly. </SPAN><BR /> <BR /> <SPAN style="font-size: 1rem">Then I came across <SPAN class="mention-scrubbed">iobert</SPAN>'s blog post about </SPAN><A href="https://blogs.sap.com/2018/10/08/using-the-destination-service-in-the-cloud-foundry-environment/" target="_blank" rel="noopener noreferrer">Using the Destination service in SAP BTP, Cloud Foundry Environment</A>. The blog-post is really very nice and helpful. But there was one problem. The library: <A href="https://www.npmjs.com/package/request" target="_blank" rel="nofollow noopener noreferrer"><SPAN class="_50685029 truncate" title="request">request</SPAN></A> used is deprecated.<BR /> <BR /> So, thought of rewriting the code using the <A href="https://www.npmjs.com/package/axios" target="_blank" rel="nofollow noopener noreferrer">axios</A> library. The sample code snippet is provided below for reference.<BR /> <BR /> <STRONG>Pre-requisites:</STRONG> &nbsp;Please bind your application with the instances of <STRONG>Destination Service</STRONG> &amp;<STRONG> Authorization and Trust Management Service</STRONG> respectively.<BR /> <H2 id="toc-hId-764765273">Solution</H2><BR /> <PRE class="language-javascript"><CODE>// imports<BR /> const express = require("express");<BR /> const cfenv = require('cfenv');<BR /> const axios = require("axios");<BR /> <BR /> const app = express();<BR /> const PORT = process.env.PORT || 4000;<BR /> <BR /> const getProjectDef = async (req, res) =&gt; {<BR /> <BR /> const MAX_ROWS = "1000";<BR /> <BR /> // Get the UAA and destination services<BR /> const UAA_SERVICE = cfenv.getAppEnv().getService('UAA_INSTANCE_NAME');<BR /> const DESTINATION_SERVICE = cfenv.getAppEnv().getService('DESTINATION_SERVICE_NAME');<BR /> <BR /> // Combine the client ID and secret for the UAA service into a single string<BR /> const UAA_CREDENTIALS = DESTINATION_SERVICE.credentials.clientid + ':' + DESTINATION_SERVICE.credentials.clientsecret;<BR /> <BR /> // Set the name of the destination to retrieve and the endpoint to call<BR /> const DESTINATION_NAME = 'DESTINATION_NAME';<BR /> const END_POINT = 'END_POINT_URL';<BR /> <BR /> // Set the payload for the POST request to the UAA to get a token<BR /> const post_payload = {<BR /> 'client_id': DESTINATION_SERVICE.credentials.clientid,<BR /> 'grant_type': 'client_credentials'<BR /> };<BR /> <BR /> // Set the configuration options for the POST request to the UAA<BR /> const post_config = {<BR /> method: 'POST',<BR /> url: UAA_SERVICE.credentials.url + '/oauth/token',<BR /> headers: {<BR /> 'Authorization': 'Basic ' + Buffer.from(UAA_CREDENTIALS).toString('base64'), // Encode the client ID and secret as base64<BR /> 'Content-type': 'application/x-www-form-urlencoded'<BR /> },<BR /> data: new URLSearchParams(post_payload).toString() // Encode the payload as x-www-form-urlencoded<BR /> };<BR /> <BR /> // Make the POST request to the UAA to get a token<BR /> axios(post_config)<BR /> .then((response) =&gt; {<BR /> if (response.status === 200) {<BR /> const token = response.data.access_token; // Get the token from the response data<BR /> // Set the configuration options for the GET request to the destination service<BR /> const get_config = {<BR /> method: 'GET',<BR /> url: DESTINATION_SERVICE.credentials.uri + '/destination-configuration/v1/destinations/' + DESTINATION_NAME,<BR /> headers: {<BR /> 'Authorization': 'Bearer ' + token // Include the token in the authorization header of the GET request<BR /> }<BR /> };<BR /> <BR /> // Make the GET request to the destination service to retrieve the destination configuration<BR /> axios(get_config)<BR /> .then((response) =&gt; {<BR /> const DESTINATION = response.data; // Get the destination configuration from the response data<BR /> <BR /> // Get the auth token from the destination configuration<BR /> const token = DESTINATION.authTokens[0];<BR /> <BR /> // Set the configuration options for the POST request to the endpoint of the destination service<BR /> // a CPI is built over the BAPI: BAPI_PROJECTDEF_GETLIST with OAuth2ClientCredentials authentication<BR /> const options = {<BR /> method: 'POST',<BR /> url: DESTINATION.destinationConfiguration.URL + END_POINT,<BR /> headers: {<BR /> 'Authorization': `${token.type} ${token.value}` // Include the auth token in the authorization header of the GET request<BR /> },<BR /> data: {<BR /> MaxRows: MAX_ROWS,<BR /> ProjectDefinitionRange: {<BR /> item: [<BR /> {<BR /> Sign: req.data.sign,<BR /> Option: req.data.option,<BR /> Low: req.data.low,<BR /> High: req.data.high,<BR /> },<BR /> ],<BR /> },<BR /> }<BR /> };<BR /> <BR /> // Make the GET request to the endpoint of the destination service<BR /> axios(options)<BR /> .then((response) =&gt; {<BR /> res.send(response.data); // Return data<BR /> })<BR /> .catch((error) =&gt; {<BR /> res.send(error); // Return error<BR /> });<BR /> })<BR /> .catch((error) =&gt; {<BR /> res.send(error); // Return error<BR /> });<BR /> }<BR /> })<BR /> .catch((error) =&gt; {<BR /> res.send(error); // Return error<BR /> });<BR /> console.log('Exit :-------&gt;');<BR /> };<BR /> <BR /> // endpoint<BR /> app.get("/getProjectDef", getProjectDef);<BR /> <BR /> app.listen(PORT),<BR /> () =&gt; {<BR /> console.log(`Listnening to the PORT: ${PORT}`);<BR /> };</CODE></PRE><BR /> &nbsp;<BR /> <BR /> <STRONG>N.B:</STRONG> This code snippet can be easily used in the CAPM(Node.js) applications. There is another library named <A href="https://www.npmjs.com/package/sap-cf-axios" target="_blank" rel="nofollow noopener noreferrer">sap-cf-axios</A> which can be used if you want to code less.<BR /> <BR /> &nbsp;<BR /> <BR /> Happy Coding! 2023-06-28T20:34:00+02:00 https://community.sap.com/t5/technology-blogs-by-sap/integration-architecture-for-enterprise-agility-powered-by-sap-btp/ba-p/13551112 Integration Architecture For Enterprise Agility Powered By SAP BTP 2023-07-05T04:43:33+02:00 Avinash_Vaidya https://community.sap.com/t5/user/viewprofilepage/user-id/120687 <H2 id="toc-hId-962016611">Introduction</H2><BR /> While working with customers on different solutioning and implementation projects, one of the most important area zeroes down to - <STRONG>Integration</STRONG>.<BR /> <BR /> As the enterprises, grow in size and scale, many custom applications and processes are created which are required to be connected to maintain consistency and data integrity.<BR /> <BR /> In this blog, I have come up with a integration architecture leveraging SAP BTP services which will help to make an enterprise connect the dots and function intelligently and seamlessly. In this article, I am focusing on a use case where the customer's ERP is either on premise or on private cloud. Ofcourse, this is based on my experience and can differ based on scenarios, but I think it at least will give you a starting point.<BR /> <BR /> I will break down this blog into 2 parts<BR /> <OL><BR /> <LI>Design thinking - Integration Architecture</LI><BR /> <LI>Explore BTP services used in the Integration Architecture</LI><BR /> </OL><BR /> Let's dive into the details.<BR /> <H3 id="toc-hId-894585825">1. Design thinking - Integration Architecture</H3><BR /> <TABLE style="border-collapse: collapse;width: 100%" border="1"><BR /> <TBODY><BR /> <TR><BR /> <TD style="width: 100%"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/SAP-Integration-Architecture.drawio-5.png" /></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Integration Architecture</P><BR /> <BR /> <H3 id="toc-hId-698072320">2. Explore BTP services used in the Integration Architecture</H3><BR /> In this section, I will go through some of the important cloud services available on SAP BTP which are shown in the above integration architecture.<BR /> <OL><BR /> <LI><BR /> <H4 id="toc-hId-630641534">SAP Integration Suite</H4><BR /> <UL><BR /> <LI>Cloud Integration</LI><BR /> <LI>API Management</LI><BR /> <LI>Open Connectors</LI><BR /> </UL><BR /> </LI><BR /> <LI><BR /> <H4 id="toc-hId-434128029">Event Driven Architecture</H4><BR /> <UL><BR /> <LI>Event Mesh</LI><BR /> <LI>Advanced Event Mesh</LI><BR /> </UL><BR /> </LI><BR /> <LI><BR /> <H4 id="toc-hId-237614524">Connectivity</H4><BR /> <UL><BR /> <LI>Cloud Connector</LI><BR /> </UL><BR /> </LI><BR /> </OL><BR /> The intent here is to give a starting point and then help you navigate to the details of each topic.<BR /> <OL><BR /> <LI><STRONG>SAP Integration Suite</STRONG> is an iPaaS – <STRONG>Integration Platform as a Service.&nbsp;</STRONG>It offers a suite of cloud services enabling organizations and development teams to create production grade integration flows. This helps to connect heterogenous systems, interfaces, services, cloud based or on premise applications and data. SAP Integration Suite provides lot of great capabilities but in this blog, I will be covering few of them as mentioned below<BR /> <OL><BR /> <LI><STRONG>Cloud Integration (CI) -</STRONG> Cloud integration capability provides a working environment and a development studio where you can discover existing integration flows provided by SAP and also design new integration flows based on business requirements. It also the place where you can monitor the integrations and manage the tenant.</LI><BR /> <LI><STRONG>API Management -&nbsp;</STRONG>API management gives you ability to wrap your integration flows, ODATA services or open connectors instances to the external world. You can also configure certificates, API keys. Using API management you can monetize your APIs.</LI><BR /> <LI><STRONG>Open Connectors -&nbsp;</STRONG>SAP Open Connectors&nbsp;is a suite of 150+ connectors for integration with non SAP applications. For example – TWILIO, STRIPE etc.</LI><BR /> </OL><BR /> </LI><BR /> <LI><STRONG>Event Driven Architecture -&nbsp;</STRONG>As number of software applications grow, organization must develop a communication strategy without overhead on the systems and the underlying infrastructure. As systems evolve, point to point communication can become bottleneck in many scenarios. Decoupled/Asynchronous communication helps to improve the performance and scale the software landscape. SAP BTP provides services which will help you start with your journey of Event Driven Architecture.<BR /> <OL><BR /> <LI><STRONG>Event Mesh - </STRONG>SAP Event Mesh capability has been available for quite some time on SAP BTP and suffices to notably lower performance thresholds than SAP Advanced Event Mesh. The maximum message size is 1 MB for all messaging protocols.The maximum storage space for all messages in all the queues per subaccount is 10 GB. SAP Event mesh is deployed centrally and does not offer distributed deployment option.</LI><BR /> <LI><STRONG>Advanced Event Mesh - </STRONG>It provides a complete event streaming, management and monitoring platform designed with higher performance threshold in mind. The maximum message size is 30 MB for all messaging protocols.The maximum storage space for all messages in all the queues per subaccount is 1TB. This is highly attractive solution for high volume real time business processes. On top of it, it has a ability to deploy event brokers at the edge of the business network which is close to the source of events. Both the event meshes may coexist based on use case. SAP Event mesh can subscribe to events published from SAP Advanced event mesh.</LI><BR /> </OL><BR /> </LI><BR /> <LI><STRONG>Connectivity</STRONG> - SAP BTP provides a connectivity service through cloud connector. Cloud connector is an application that can be installed on customer's operating system which creates a secure tunnel between SAP BTP and customers on premise or private cloud landscape.</LI><BR /> </OL><BR /> <H2 id="toc-hId--217064419">Conclusion</H2><BR /> As I always say Enterprise Architecture is full of constraints. Every customer landscape is different, processes are different.<BR /> <BR /> But with the help of SAP BTP Integration capabilities you can navigate through the constraints effectively.<BR /> <BR /> This is just a glimpse of wide set of capabilities offered by SAP Integration Suite. Stay curious! Keep learning!<BR /> <BR /> To get more updates about this topic, please follow the below pages<BR /> <OL><BR /> <LI><A href="https://help.sap.com/docs/integration-suite?locale=en-US" target="_blank" rel="noopener noreferrer">SAP Integration Suite</A></LI><BR /> <LI><A href="https://blogs.sap.com/tags/73554900100800003241/" target="_blank" rel="noopener noreferrer">Blogs</A></LI><BR /> <LI><A href="https://answers.sap.com/tags/73554900100800003241" target="_blank" rel="noopener noreferrer">Q&amp;A</A></LI><BR /> </OL><BR /> <STRONG>Feel free to “<EM>like</EM>“, “<EM>Share</EM>“, “<EM>Add a Comment</EM>” and to get more updates about my next blogs follow me –&nbsp;<SPAN class="mention-scrubbed">avinash.vaidya</SPAN></STRONG> 2023-07-05T04:43:33+02:00 https://community.sap.com/t5/technology-blogs-by-sap/next-in-the-sap-garage-build-events-to-business-actions-apps-with-sap-btp/ba-p/13573044 Next in the SAP Garage – Build Events-to-Business Actions Apps with SAP BTP and MS Azure/AWS. 2023-08-01T06:53:14+02:00 gauravdey https://community.sap.com/t5/user/viewprofilepage/user-id/183532 <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/Screenshot-2023-08-01-100924.png" /></P><BR /> In the August 2023 edition of SAP Garage we feature this use case that highlights event-to-action framework and SAP BTP services for developing, deploying and monitoring the solution like the CAP framework, SAP Event Mesh, SAP Connectivity Service, SAP Private Link Service, SAP Business Rules.<BR /> <BR /> The demo will focus on consuming events from the Microsoft Azure IoT Platform and AWS IoT and based on business rules in SAP BTP, actions are triggered in the SAP S/4HANA system. Then the app can be customized to any event integrating from any source system to any SAP LoB systems.<BR /> <UL><BR /> <LI><SPAN data-contrast="auto">Date of the session</SPAN><SPAN data-ccp-props="{}">&nbsp;–&nbsp;<STRONG>August 2nd, 2023, Wednesday</STRONG></SPAN></LI><BR /> <LI data-leveltext="" data-font="Symbol" data-listid="1" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-aria-posinset="2" data-aria-level="1"><SPAN data-contrast="auto">SAP Discovery Center mission to be featured :&nbsp;<STRONG><A href="https://discovery-center.cloud.sap/missiondetail/4172/4422/" target="_blank" rel="noopener nofollow noreferrer">Build Events-to-Business Actions Apps with SAP BTP and MS Azure/AWS</A></STRONG></SPAN></LI><BR /> </UL><BR /> <A href="https://webinars.sap.com/2023-01-01-sap-ie-btp-garage-webinar-series/en/registration.aspx" target="_blank" rel="noopener noreferrer"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2022/07/Register.png" /></A><BR /> <BR /> <B><SPAN data-contrast="none">Meet the Experts:</SPAN></B><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/Picture1.jpg" height="180" width="176" /></P><BR /> <SPAN class="mention-scrubbed">praveenpadegal</SPAN>, working as a Development Expert in SAP BTP Platform Adoption &amp; Advisory team to increase the adoption of SAP Business Technology Platform by building, enabling and validating use-cases that demonstrates value to customers and partners. He has 12+ Years of IT industry experience in different phases of software development, especially in building Industry 4.0 cloud products, publishing reference architectures, technical blogs and enablement sessions.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/Ajit.jpg" height="180" width="176" /></P><BR /> <SPAN class="mention-scrubbed">ajitkpanda</SPAN>, working as an Architect in SAP BTP Platform Adoption &amp; Advisory team to increase the adoption of SAP Business Technology Platform by building, enabling and validating use-cases that demonstrates value to customers and partners. With 10+ years of experience in design and development of application and integration of SAP systems he has lead discovery conversations, architect, and build end to end applications, tools using different programming technologies like SAPUI5, NodeJS, CAPM, SAP Build and BTP services in conjunction with hyperscaler services.<BR /> <BR /> <B><SPAN data-contrast="none">Missed our last call?</SPAN></B><BR /> <BR /> No worries you can revisit the session with details below –<BR /> <UL><BR /> <LI data-leveltext="" data-font="Symbol" data-listid="3" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-aria-posinset="1" data-aria-level="1"><SPAN data-contrast="auto">Topic :&nbsp;<A href="https://discovery-center.cloud.sap/missiondetail/4163/4406/" target="_blank" rel="noopener nofollow noreferrer">Extend SAP S/4HANA with SAP Build Process Automation</A></SPAN></LI><BR /> <LI data-leveltext="" data-font="Symbol" data-listid="3" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-aria-posinset="2" data-aria-level="1"><SPAN data-contrast="auto">Speakers</SPAN><SPAN data-ccp-props="{}"> : Syed Ejazuddin, Senior BTP Product Specialist</SPAN></LI><BR /> <LI data-leveltext="" data-font="Symbol" data-listid="3" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-aria-posinset="3" data-aria-level="1">Link to&nbsp;<A href="https://www.youtube.com/watch?v=4T0xUkGA57I" target="_blank" rel="noopener nofollow noreferrer">Recording</A></LI><BR /> </UL><BR /> <B><SPAN data-contrast="none">Join us.&nbsp;</SPAN></B><BR /> <BR /> <SPAN data-contrast="auto">Thank you for all of the positive feedback we continue to receive about the SAP Garage series. We are thrilled to bring you top SAP BTP use cases and demos directly from the experts. If you haven’t already,&nbsp;</SPAN><A href="https://webinars.sap.com/2023-01-01-sap-ie-btp-garage-webinar-series/en/registration.aspx" target="_blank" rel="noopener noreferrer"><SPAN data-contrast="none"><STRONG>subscribe</STRONG></SPAN></A><SPAN data-contrast="auto">&nbsp;to the series, bring your curiosity, your questions, and join us as we cover key SAP Business Technology Platform topics and use cases!</SPAN> 2023-08-01T06:53:14+02:00 https://community.sap.com/t5/technology-blogs-by-sap/next-release-of-the-cloud-connector-is-available-2-16-0/ba-p/13575684 Next release of the Cloud Connector is available: 2.16.0 2023-08-07T12:43:38+02:00 MarcoErtel https://community.sap.com/t5/user/viewprofilepage/user-id/6305 We again have released a new version of the cloud connector with interesting new features. A lot happened under the hood to ensure the highest security levels but that is not all.<BR /> <BR /> Let me start with the installation (which of course can be found <A href="https://tools.hana.ondemand.com/#cloud" target="_blank" rel="nofollow noopener noreferrer">here</A>) where we've added two more platforms to give you more flexibility for selecting the best platform:<BR /> <UL><BR /> <LI>Oracle Linux 9</LI><BR /> <LI>macOS aarch64 (native support of the M1/M2 processors)</LI><BR /> </UL><BR /> If you are using an ABAP System in the cloud and need more security for classic RFC endpoints, you should check the new feature to use SNC:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/SNC.png" /></P><BR /> More about that can be found in the <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/configure-service-channel-for-rfc" target="_blank" rel="noopener noreferrer">documentation</A>.<BR /> <BR /> Not for all users but at least for some it might be helpful that you're able to change now the login procedure from user and password to a client certificate. This works also for the REST APIs. But here we have to say that (in the version 2.16) we unfortunately have the restriction to setups without a shadow instance. This will of course change in the future. If you still want to use it or at least try it out find more <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/logon-to-cloud-connector-via-client-certificate" target="_blank" rel="noopener noreferrer">here</A>.<BR /> <BR /> On the logging and monitoring we’ve worked on two features:<BR /> <UL><BR /> <LI>getting more insights for TCP and TCP SSL connections as you now see them also in the Back-end connections and in the usage statistics.</LI><BR /> <LI>adding a csv export to the Audit Log to give you more transparency which modifications on the cloud connector setup had been done:</LI><BR /> </UL><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/audit.png" /></P><BR /> Additionally, under the hood we've updated lots of libraries to the most recent versions, cleaned up features which are no longer needed and improved the performance of the login procedure for some installations.<BR /> <BR /> Therefore: don't wait and update your Cloud Connector as soon as possible (and have a look at the official <A href="https://help.sap.com/whats-new/cf0cb2cb149647329b5d02aa96303f56?Component=Connectivity&amp;locale=en-US&amp;version=Cloud" target="_blank" rel="noopener noreferrer">release notes</A>)! 2023-08-07T12:43:38+02:00 https://community.sap.com/t5/technology-blogs-by-members/sap-btp-client-certificate-destination-for-an-ibp-communication-scenario/ba-p/13575649 SAP BTP client certificate destination for an IBP communication scenario: side-by-side extensibility 2023-08-07T14:29:10+02:00 alespad https://community.sap.com/t5/user/viewprofilepage/user-id/141302 Hello community,<BR /> <BR /> after several years, I am returning to write a blog. For almost a year now, I start a new professional adventure with my fellow adventures <SPAN class="mention-scrubbed">177ce313868444f78e8b2470e82a23d6</SPAN> ,&nbsp;&nbsp;<SPAN class="mention-scrubbed">sergio_ferrari</SPAN>&nbsp;&nbsp;and other friends. I feel a renewed enthusiasm in writing and sharing my experiences, especially regarding the BTP platform .<BR /> <BR /> The journey from 2010s Netweaver blogs to the new BTP era. So, I hope that this will be the first blog of a new long series.<BR /> <BR /> In this blog, I want to describe how to set up a secure connection based on X.509 certificate from BTP to SAP IBP (<STRONG>SAP Integrated Business Planning for Supply Chain)</STRONG> within the context of side-by-side extensibility.<BR /> <BR /> You can find detailed explanations about this process in the official documentation at the following link: <A href="https://help.sap.com/docs/SAP_INTEGRATED_BUSINESS_PLANNING/feae3cea3cc549aaa9d9de7d363a83e6/21f637e22dab41599b2a5334ff9908f7.html?locale=en-US" target="_blank" rel="noopener noreferrer">https://help.sap.com/docs/SAP_INTEGRATED_BUSINESS_PLANNING/feae3cea3cc549aaa9d9de7d363a83e6/21f637e22dab41599b2a5334ff9908f7.html?locale=en-US</A>.<BR /> <BR /> <STRONG>Important</STRONG>: Of course, this approach is applicable to any context of an ABAP environment and a communication scenario where we want to establish a connection via a certificate. In the blog, I will describe it focused on a specific communication scenario of SAP IBP.<BR /> <H1 id="toc-hId-834905003">Introduction</H1><BR /> I am not an IBP consultant, and I won't go too deep into product-specific details.<BR /> <BR /> The side-by-side extensibility scenario, as described in the link, involves a custom algorithm implemented in BTP / CAP, using the OData services exposed by SAP IBP for both reading and writing Master Data and Key Figures.<BR /> <BR /> The communication arrangement used in this context is SAP_COM_0720, and you can find a detailed explanation of the OData services in this blog:&nbsp;<A href="https://blogs.sap.com/2022/06/20/integrate-sap-ibp-key-figure-delta-%CE%B4-data-with-external-systems/" target="_blank" rel="noopener noreferrer">https://blogs.sap.com/2022/06/20/integrate-sap-ibp-key-figure-delta-%CE%B4-data-with-external-systems/</A><BR /> <BR /> I will describe how to configure a connection between BTP and SAP IBP using X.509 certificates, allowing a seamless integration of your custom algorithm with SAP IBP's OData services.<BR /> <BR /> As we can see in the image below, OAuth 2.0 is not supported as an Inbound Authentication Method for the Communication Arrangement Managed by SAP<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/1-15.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">IBP Communication Scenario</P><BR /> &nbsp;<BR /> <BR /> We could generate a password for the user defined in IBP and use the simpler basic authentication. However, as we already know, and as emphasized in the IBP documentation "Secure Communication for Inbound Integration" <A href="https://help.sap.com/docs/SAP_INTEGRATED_BUSINESS_PLANNING/685fbd2d5f8f4ca2aacfc35f1938d1c1/37bcbb7616734a22ada7122e06654e90.html?locale=en-US" target="_blank" rel="noopener noreferrer">https://help.sap.com/docs/SAP_INTEGRATED_BUSINESS_PLANNING/685fbd2d5f8f4ca2aacfc35f1938d1c1/37bcbb7616734a22ada7122e06654e90.html?locale=en-US</A>&nbsp;the "Certificate-based authentication" option is highly recommended.<BR /> <BR /> By opting for certificate-based authentication, we ensure a more robust and secure connection between BTP and SAP IBP.<BR /> <BR /> &nbsp;<BR /> <H1 id="toc-hId-638391498">Generate and download the Certificate via Connectivity service</H1><BR /> With reference to the Connectivity service documentation (<A class="notion-link-token notion-focusable-token notion-enable-hover" href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/use-destination-certificates" rel="noopener noreferrer" data-token-index="1" target="_blank"><SPAN class="link-annotation-unknown-block-id-1352430029"></SPAN></A><A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/use-destination-certificates" target="test_blank" rel="noopener noreferrer">https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/use-destination-certificates</A>), navigate to the "Destinations" section of your subaccount and select the "Certificates" option. From here, you can generate a new SAP Cloud PKI Infrastructure Certificate. In this example, I am generating a PEM certificate, setting a password, and configuring it to be valid for one year.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/2-12.png" height="202" width="542" /><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/3-11.png" height="413" width="498" /></P><BR /> Once the certificate has been generated, it will be listed among the available certificates. However, as mentioned in the highlighted message, downloading the certificate is only possible through the REST API.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/4-11.png" /></P><BR /> To identify the API for accessing certificates within the subaccount, we can leverage the SAP Business Accelerator HUB. In our case, we want to access the certificates associated with the subaccount using the relevant API <A class="notion-link-token notion-focusable-token notion-enable-hover" href="https://api.sap.com/api/SAP_CP_CF_Connectivity_Destination/resource/Certificates_on_Subaccount_Level" rel="noopener noreferrer" data-token-index="1" target="_blank"><SPAN class="link-annotation-unknown-block-id-1640785536"></SPAN></A><A href="https://api.sap.com/api/SAP_CP_CF_Connectivity_Destination/resource/Certificates_on_Subaccount_Level" target="test_blank" rel="noopener noreferrer">https://api.sap.com/api/SAP_CP_CF_Connectivity_Destination/resource/Certificates_on_Subaccount_Level</A><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/5-6.png" /></P><BR /> Let's proceed to use Postman. If you haven't done so already, you can create a new instance of the "Destination Service" and generate a key to obtain the client ID / client secret pair required to invoke the API from Postman.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/6-6.png" height="357" width="511" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/7-4.png" height="169" width="539" /></P><BR /> In Postman, we have to use the Grant Type “Client Credentials” where:<BR /> <UL><BR /> <LI>Access Token Url is the url of the key plus /oauth/token</LI><BR /> <LI>Client ID and Client Secret the corresponding values from your key.</LI><BR /> </UL><BR /> The endpoint we are going to use to access the certificates of the subaccount is <EM><A href="https://destination-configuration.cfapps.eu20.hana.ondemand.com/destination-configuration/v1/subaccountCertificates" target="test_blank" rel="nofollow noopener noreferrer">https://destination-configuration.cfapps.eu20.hana.ondemand.com/destination-configuration/v1/subaccountCertificates</A></EM><BR /> <BR /> Once we obtain the OAuth token and send the request, we receive the list of certificates along with their corresponding content in Base64 encoding.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/8-5.png" /></P><BR /> I’m a windows user , so to decode the Content from base64 to a file, I used Powershell but you can use the tool (or online tool) you prefer<BR /> <PRE class="language-javascript"><CODE>$base64String = "pasteYourBase64Content"<BR /> $decodedString = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64String))<BR /> $decodedString | Set-Content -Path "C:\your\path\your_certificate.pem"</CODE></PRE><BR /> Now you have your .pem certificate containing both public cert and key.<BR /> <BR /> pem can be opened with a text editor and splitted in 2 new files:<BR /> <BR /> content between<BR /> <BR /> ----BEGIN ENCRYPTED PRIVATE KEY---—<BR /> <BR /> ----END ENCRYPTED PRIVATE KEY---—<BR /> <BR /> in a .key and the fullchain starting from ----BEGIN CERTIFICATE---— in a .crt file<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/9-3.png" height="106" width="157" /><BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <H1 id="toc-hId-441877993">Upload the Certificate in Target System (SAP IBP in our scenario)</H1><BR /> The certificate (.crt) must be uploaded in the “Communication User” Fiori App. This is the communication user will be used in the Communication Arrangement.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/10-3.png" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/11-4.png" /></P><BR /> &nbsp;<BR /> <BR /> Now you can test the certificate with a request in Postman. In Settings, it’s possible to add key,crt , the host of your target system and the password you specified during the creation of PEM.<BR /> <BR /> Additional details can be found here <A href="https://learning.postman.com/docs/sending-requests/certificates/#adding-client-certificates" target="_blank" rel="nofollow noopener noreferrer">https://learning.postman.com/docs/sending-requests/certificates/#adding-client-certificates</A><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/12-2.png" /></P><BR /> &nbsp;<BR /> <BR /> Now we can create the destination that will use the certificate to authenticate towards IBP. However, before that, we need to upload the key that will be referenced during the definition phase. We can generate the key in .p12 format using OpenSSL (I'm not an OpenSSL expert). The command that can be used to generate it is:<BR /> <PRE class="language-javascript"><CODE>openssl pkcs12 -export -in IBP_EXT.crt -inkey IBP_EXT.key -out IBP_EXT.p12</CODE></PRE><BR /> Go again in the “Certificates” of the subaccount and upload the .p12 file<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/13.png" /></P><BR /> <BR /> <H1 id="toc-hId-245364488">Create the Destination</H1><BR /> Now we are ready to create the destination with Authentication: <STRONG>ClientCertificateAuthentication</STRONG><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/14.png" height="217" width="603" /></P><BR /> where URL is your IBP OData Endpoint of the communication arrangement <EM><A href="https://youribphostname-api.scmibp.ondemand.com/sap/opu/odata/IBP" target="test_blank" rel="nofollow noopener noreferrer">https://youribphostname-api.scmibp.ondemand.com/sap/opu/odata/IBP</A></EM><BR /> <BR /> Key Store Location your .p12 and Key Store Password is your password<BR /> <H1 id="toc-hId-48850983">Side By Side: Test the destination in CAP / Application router</H1><BR /> There are several ways to test the functionality of the destination to ensure it works correctly. We could create a CAP project or a project using the Productivity Tools within the space.<BR /> <BR /> However, I believe the simplest and fastest way to test the routing and proper functioning of a destination is to define a custom app router that forwards inbound requests to the destination.<BR /> <BR /> This tech byte perfectly explains how to define a custom app router for this purpose. The only adjustments I had to make compared to the template were to update the Node version, OAuth redirect-uris in xs-security.json and add a basic auth in order to easily test the application router's endpoint from Postman<BR /> <P class="style-scope ytd-watch-metadata"><STRONG>Tutorial - Testing SAP BTP Destinations </STRONG><A href="https://www.youtube.com/watch?v=0zzFCfuUIbs" target="_blank" rel="nofollow noopener noreferrer">https://www.youtube.com/watch?v=0zzFCfuUIbs</A></P><BR /> my repository can be found here <A href="https://github.com/alespad/ibptestdestination" target="_blank" rel="nofollow noopener noreferrer">https://github.com/alespad/ibptestdestination</A><BR /> <BR /> Once the Node app is deployed, we can open the link of the application router and append the relevant OData path for the master data (or key figure) we want to test.<BR /> <BR /> At this point, we can verify that the OData service is correctly consumed using the routing destination.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/15.png" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/16.png" /></P><BR /> &nbsp;<BR /> <H3 id="toc-hId-110502916">Appendix</H3><BR /> The list of SAP IBP trusted root CAs is available in SAP Note&nbsp;<A href="https://help.sap.com/docs/link-disclaimer?site=https://launchpad.support.sap.com/#/notes/2801396" target="_blank" rel="noopener noreferrer">2801396</A> &nbsp;(SAP Global Trust List). SAP is not in the list but I suppose it’s “trusted” by default (also used for Cloud Connector). If you have some useful additional info about this, please add your comment<BR /> <BR /> &nbsp; 2023-08-07T14:29:10+02:00 https://community.sap.com/t5/technology-blogs-by-sap/next-in-the-sap-garage-integrate-sap-s-4hana-with-microsoft-teams-via-sap/ba-p/13576419 Next in the SAP Garage – Integrate SAP S/4HANA with Microsoft Teams via SAP Business Technology Platform. 2023-09-05T14:40:09+02:00 gauravdey https://community.sap.com/t5/user/viewprofilepage/user-id/183532 <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/09/Screenshot-2023-09-05-172942.png" height="347" width="693" /></P><BR /> In the September 2023 edition of SAP Garage we feature this use case that highlights how to extend the business processes in SAP S/4HANA to the Microsoft Teams app, by using the SAP BTP Bridge Framework.<BR /> <BR /> The demo will focus on how to use the Bridge Framework to view the SAP S/4HANA purchase order data, update purchase order data if needed, and perform the release purchase order process in the Microsoft Teams.<BR /> <UL><BR /> <LI><SPAN data-contrast="auto">Date of the session</SPAN><SPAN data-ccp-props="{}">&nbsp;–&nbsp;<STRONG>September 6th, 2023, Wednesday</STRONG></SPAN></LI><BR /> <LI data-leveltext="" data-font="Symbol" data-listid="1" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-aria-posinset="2" data-aria-level="1"><SPAN data-contrast="auto">SAP Discovery Center mission to be featured :&nbsp;<STRONG><A href="https://discovery-center.cloud.sap/missiondetail/4164/4408/" target="_blank" rel="noopener nofollow noreferrer">Integrate SAP S/4HANA with Microsoft Teams via SAP Business Technology Platform</A></STRONG></SPAN></LI><BR /> </UL><BR /> <A href="https://webinars.sap.com/2023-01-01-sap-ie-btp-garage-webinar-series/en/registration.aspx" target="_blank" rel="noopener noreferrer"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2022/07/Register.png" /></A><BR /> <BR /> &nbsp;<BR /> <BR /> <B><SPAN data-contrast="none">Meet the Experts:</SPAN></B><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/09/v.jpg" height="180" width="176" /></P><BR /> <SPAN class="mention-scrubbed">viancu</SPAN>, is a Developer for the Strategic Customer Engagements team of SAP Platform Adoption and Advisory. He works alongside fellow developers, designers, and data scientists to harness the power of SAP BTP to deliver innovative solutions to customers. He began his SAP journey during college as a frontend development intern for SAP Ariba’s Guided Buying team. Since then, his fulltime role has expanded to include full-stack development centered around SAP BTP and the broader SAP Ecosystem. Victor’s most recent work has focused on bringing two worlds—SAP and Microsoft Teams—closer together through an integration solution on BTP.”<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/09/a.png" height="180" width="176" /></P><BR /> Alex Bishka, a Developer in the Strategic Customer Engagements team of SAP Platform Adoption and Advisory. Alex started at SAP under the SAP Next Talent program. Since joining the team, Alex has focused on full stack development and automation around SAP BTP technologies: specifically on his current project which aims to bridge the gap between SAP and Microsoft Teams by implementing an integration solution via BTP.<BR /> <BR /> &nbsp;<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/09/w.jpg" height="180" width="176" /></P><BR /> Weikun Liu, a Software Developer from SAP T&amp;I Strategic Customer Engagements team.​ He is an experienced software development engineer with 4+ years 'experience on crafting efficient and scalable back-end distributed systems within cloud environments. As a Software Developer at SAP Labs, Palo Alto, he collaborated closely with customers, orchestrating the development and delivery of systems for combining SAP Business Technology Platform (BTP) and other hyperscaler services.<BR /> <BR /> <B><SPAN data-contrast="none">Missed our last call?</SPAN></B><BR /> <BR /> No worries you can revisit the session with details below –<BR /> <UL><BR /> <LI data-leveltext="" data-font="Symbol" data-listid="3" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-aria-posinset="1" data-aria-level="1"><SPAN data-contrast="auto">Topic :&nbsp;<A href="https://discovery-center.cloud.sap/missiondetail/4172/4422/" target="_blank" rel="noopener nofollow noreferrer">Build Events-to-Business Actions Apps with SAP BTP and MS Azure/AWS</A></SPAN></LI><BR /> <LI data-leveltext="" data-font="Symbol" data-listid="3" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-aria-posinset="2" data-aria-level="1"><SPAN data-contrast="auto">Speakers</SPAN><SPAN data-ccp-props="{}"> :&nbsp;</SPAN>Praveen Kumar Padegal, Development Expert &amp; Ajit Kumar Panda, Architect, Platform Adoption &amp; Advisory team</LI><BR /> <LI data-leveltext="" data-font="Symbol" data-listid="3" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-aria-posinset="3" data-aria-level="1">Link to&nbsp;<A href="https://youtu.be/NrJXjWVg6c4" target="_blank" rel="noopener nofollow noreferrer">Recording</A></LI><BR /> </UL><BR /> <B><SPAN data-contrast="none">Join us.&nbsp;</SPAN></B><BR /> <BR /> <SPAN data-contrast="auto">Thank you for all of the positive feedback we continue to receive about the SAP Garage series. We are thrilled to bring you top SAP BTP use cases and demos directly from the experts. If you haven’t already,&nbsp;</SPAN><A href="https://webinars.sap.com/2023-01-01-sap-ie-btp-garage-webinar-series/en/registration.aspx" target="_blank" rel="noopener noreferrer"><SPAN data-contrast="none"><STRONG>subscribe</STRONG></SPAN></A><SPAN data-contrast="auto">&nbsp;to the series, bring your curiosity, your questions, and join us as we cover key SAP Business Technology Platform topics and use cases!</SPAN> 2023-09-05T14:40:09+02:00 https://community.sap.com/t5/technology-blogs-by-members/easy-way-to-provide-schema-access-to-a-btp-hana-cloud-standard-user/ba-p/13576462 Easy way to provide schema access to a BTP HANA Cloud Standard User 2023-10-05T22:04:35+02:00 kallolathome https://community.sap.com/t5/user/viewprofilepage/user-id/14879 <H2 id="toc-hId-964015646">Problem</H2><BR /> While working with the CAP applications, I have came across a situation that a standard HANA cloud user used in CPI cannot perform direct CRUD operations on the tables via the JDBC driver. The CPI will throw the error: insufficient privileges.&nbsp; So, I am writing the blogpost for reference purpose.<BR /> <H2 id="toc-hId-767502141">Solution</H2><BR /> Please follow the below mentioned steps:<BR /> <OL><BR /> <LI>Open the <STRONG>SQL Console</STRONG> of the <STRONG>BTP HANA Cloud</STRONG> by selecting the <STRONG>DBADMIN</STRONG> node.<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/8-8.png" /></LI><BR /> <LI><SPAN class="ui-provider ec bsg brz bsh bsi bsj bsk bsl bsm bsn bso bsp bsq bsr bss bst bsu bsv bsw bsx bsy bsz bta btb btc btd bte btf btg bth bti btj btk btl btm" dir="ltr"><SPAN class="ui-provider ec bsg brz bsh bsi bsj bsk bsl bsm bsn bso bsp bsq bsr bss bst bsu bsv bsw bsx bsy bsz bta btb btc btd bte btf btg bth bti btj btk btl btm" dir="ltr">Create the User group:</SPAN></SPAN><BR /> <PRE class="language-markup"><CODE>CREATE USERGROUP USERGROUP_NAME</CODE></PRE><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/9-6.png" /></P><BR /> </LI><BR /> <LI><SPAN class="ui-provider ec bsg brz bsh bsi bsj bsk bsl bsm bsn bso bsp bsq bsr bss bst bsu bsv bsw bsx bsy bsz bta btb btc btd bte btf btg bth bti btj btk btl btm" dir="ltr"><SPAN class="ui-provider ec bsg brz bsh bsi bsj bsk bsl bsm bsn bso bsp bsq bsr bss bst bsu bsv bsw bsx bsy bsz bta btb btc btd bte btf btg bth bti btj btk btl btm" dir="ltr">Creating the User &amp; assigning it to the group: USER_01</SPAN></SPAN><BR /> <PRE class="language-markup"><CODE>CREATE USER USER_01 PASSWORD Password1111 NO FORCE_FIRST_PASSWORD_CHANGE SET USERGROUP USERGROUP_NAME</CODE></PRE><BR /> </LI><BR /> <LI><SPAN class="ui-provider ec bsg brz bsh bsi bsj bsk bsl bsm bsn bso bsp bsq bsr bss bst bsu bsv bsw bsx bsy bsz bta btb btc btd bte btf btg bth bti btj btk btl btm" dir="ltr"><SPAN class="ui-provider ec bsg brz bsh bsi bsj bsk bsl bsm bsn bso bsp bsq bsr bss bst bsu bsv bsw bsx bsy bsz bta btb btc btd bte btf btg bth bti btj btk btl btm" dir="ltr">Grant the User: <STRONG>USER_01</STRONG> operator of the group: <STRONG>USERGROUP_NAME</STRONG></SPAN></SPAN><BR /> <PRE class="language-markup"><CODE>GRANT USERGROUP OPERATOR ON USERGROUP USERGROUP_NAME TO USER_01</CODE></PRE><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/10-6.png" /></P><BR /> </LI><BR /> <LI>If there is already a user present then please ignore the above steps.</LI><BR /> <LI>Now, its time to check the <STRONG>SCHEMA_OWNER</STRONG>.<BR /> <OL><BR /> <LI>Get the SCHEMA name. Add the instance by selecting <STRONG>Instance Type</STRONG>: HDI Container.<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/1-33.png" /></LI><BR /> <LI>Expand &amp; click on the <STRONG>Tables</STRONG>. Select any table &amp; then double click to <STRONG>open</STRONG>. You will get the <STRONG>SCHEMA</STRONG> name.</LI><BR /> <LI><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/2-16.png" /></LI><BR /> </OL><BR /> </LI><BR /> <LI>Go to the <STRONG>SAP HANA Cockpit</STRONG>.<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/5-10.png" /></LI><BR /> <LI>Click on the drop down list &amp; select <STRONG><STRONG style="font-size: 1rem">Security and User Management</STRONG><SPAN style="font-size: 1rem">.</SPAN><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/6-13.png" /></STRONG></LI><BR /> <LI>Under the <STRONG>User &amp; Role Management</STRONG> tile, select the <STRONG>Role Assignment</STRONG> option.<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/7-11.png" /></LI><BR /> <LI>Select <STRONG>Assign roles to a user</STRONG>. Enter the <STRONG>user</STRONG>.<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/11-4.png" /></LI><BR /> <LI>Click on the <STRONG>EDIT</STRONG> button &amp; add the roles by providing the <STRONG>SCHEMA</STRONG> name.<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/12-3.png" /></LI><BR /> <LI>Select &amp; add the role you want. Then, save it.</LI><BR /> <LI>Click on the added role to check more details.<BR /> <OL><BR /> <LI><STRONG>Object Privilege<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/13-5.png" /></STRONG></LI><BR /> <LI><STRONG>Assigned Users<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/14-2.png" /></STRONG></LI><BR /> </OL><BR /> </LI><BR /> <LI>Now, the user is having access to the <STRONG>SCHEMA</STRONG>.</LI><BR /> <LI>That's it.</LI><BR /> </OL><BR /> &nbsp;<BR /> <BR /> Now you can use the same user in the CPI for <STRONG>CRUD</STRONG> operations.<BR /> <BR /> &nbsp;<BR /> <BR /> If you want to learn more about the <STRONG>privileges</STRONG> then please check this <A href="https://help.sap.com/docs/SAP_HANA_ONE/1c837b3899834ddcbae140cc3e7c7bdd/fb0f9b103d6940f28f3479b533c351e9.html" target="_blank" rel="noopener noreferrer">link</A>.<BR /> <BR /> &nbsp;<BR /> <DIV><BR /> <DIV><BR /> <DIV><BR /> <DIV>If I have missed something, please feel free to add it in the comment section so that, this post can be useful to others.</DIV><BR /> </DIV><BR /> </DIV><BR /> </DIV><BR /> <DIV></DIV><BR /> &nbsp;<BR /> <DIV><BR /> <DIV><BR /> <DIV><BR /> <DIV></DIV><BR /> </DIV><BR /> </DIV><BR /> </DIV><BR /> <H3 id="toc-hId-700071355"><SPAN style="font-size: 1rem">References:</SPAN></H3><BR /> <DIV><BR /> <OL><BR /> <LI class="style-scope ytd-watch-metadata"><A href="https://www.youtube.com/watch?v=aK4Pd8KKBQE&amp;t=600s" target="_blank" rel="nofollow noopener noreferrer">SAP HANA Cloud User Management</A></LI><BR /> <LI><BR /> <DIV data-v-b0cfaade=""><BR /> <BR /> <A href="https://help.sap.com/docs/SAP_HANA_ONE/1c837b3899834ddcbae140cc3e7c7bdd/bb37a9f2caf7438ca7332ceb3c5dc4d9.html" target="_blank" rel="noopener noreferrer">SAP HANA One Administration Guide</A><BR /> <BR /> </DIV><BR /> <DIV data-v-b0cfaade=""><BR /> <DIV data-v-5c31d43f="" data-v-b0cfaade=""><BR /> <DIV data-v-5c31d43f=""></DIV><BR /> </DIV><BR /> </DIV></LI><BR /> </OL><BR /> </DIV><BR /> <DIV><BR /> <DIV></DIV><BR /> </DIV> 2023-10-05T22:04:35+02:00 https://community.sap.com/t5/technology-blogs-by-members/sap-btp-destinations-in-a-nutshell-part-3-oauth-2-0-client-credentials/ba-p/13577101 SAP BTP Destinations in a nutshell Part 3 - OAuth 2.0 Client Credentials 2023-10-08T09:15:07+02:00 JakobFra https://community.sap.com/t5/user/viewprofilepage/user-id/178619 <H1 id="toc-hId-834959648">Introduction</H1><BR /> The goal of this series is to introduce the different destination types of the SAP BTP, to show how they work and also to make them tangible with basic and easy to execute code examples. In parts one and two of this series, I looked at the basics, as well as the simplest destination types, NoAuthentication and BasicAuthentication. In this part, I'll dive into a more complex topic for the first time: I'll show you how to implement an OAuth 2.0 client credentials flow using Destination.<BR /> <H1 id="toc-hId-638446143">OAuth 2.0</H1><BR /> <P id="ember595" class="ember-view reader-content-blocks__paragraph">Before I turn to the concrete scenario and implementation, I will first take a closer look at the topic of OAuth. Most people in the IT environment have come across this term before, and a majority is still able to provide information when it comes to explaining at a high-level what it is and what it is used for. But as soon as it comes to the technical details, the exact workings of the protocols, the different authentication flows, etc., many (including me) quickly get tripped up. But fortunately I'm not alone in providing the most important information about OAuth, because there are also a large number of wonderful people who have a very deep understanding of the subject and are willing to document this knowledge and make it digitally available to their fellow world in an easy to understand way. One resource I came across a couple of years ago that has helped sharpen my understanding of this topic is this talk by Nate Barbettini:&nbsp;<A href="https://www.youtube.com/watch?v=996OiexHze0" target="_blank" rel="nofollow noopener noreferrer">https://www.youtube.com/watch?v=996OiexHze0</A>&nbsp;I can highly recommend this video to anyone who would like to learn more about OAuth 2.0 (and for good measure, OIDC) or is looking for a simple yet solid introduction to the topic. The investment of this one hour is definitely worth it.</P><BR /> <P id="ember596" class="ember-view reader-content-blocks__paragraph">For those who are in a hurry, here is the most important information in a nutshell:</P><BR /> <P id="ember597" class="ember-view reader-content-blocks__paragraph">OAuth 2.0 is an open protocol that allows standardized, secure API authorization for desktop, web and mobile applications. This also covers the scenario of access delegation, i.e. that an application gets access to certain data or functionalities of another application with the permission of the user. Classic example: an application is granted permission by a user to send posts on Facebook or read contact data on their behalf.</P><BR /> <BR /> <H2 id="toc-hId-571015357">4 Roles</H2><BR /> <P id="ember599" class="ember-view reader-content-blocks__paragraph"><STRONG>Resource Owner</STRONG>&nbsp;- The owner of a resource (data). As a rule, this is simply a user, i.e. the person sitting in front of the computer / smartphone / tablet / ...</P><BR /> <P id="ember600" class="ember-view reader-content-blocks__paragraph"><STRONG>Resource Server</STRONG>&nbsp;- This is the application that stores the resources (data) of the resource owner (user)</P><BR /> <P id="ember601" class="ember-view reader-content-blocks__paragraph"><STRONG>Client</STRONG>&nbsp;- The client is the third-party application that wants to access resources (data) of the resource server on behalf of the resource owner (user) and needs a token for authentication that contains the corresponding authorization grant (so to speak, the proof that the client has received permission from the resource owner to access the resource server)</P><BR /> <P id="ember602" class="ember-view reader-content-blocks__paragraph"><STRONG>Authorization Server</STRONG>&nbsp;- The Authorization Server is the instance that manages Authorization grants and issues the tokens (these are usually JWT (JSON Web Tokens), i.e. JSON objects that contain the relevant token information) that authorize the client to access the Resource Server on behalf of the Resource Owner. In some cases, Resource Server and Authorization Server are identical, but often they are separate instances</P><BR /> <BR /> <H2 id="ember603" class="ember-view" id="toc-hId-374501852">Client Credentials Flow</H2><BR /> Depending on the specific use case, there are different flows in the OAuth 2.0 standard. In this part of the series, we will look at the client credentials flow. In order for a client to access a resource server, it must be registered with the Authorization Server, for each registered client there are client credentials, these are ultimately username and password. In the client credentials flow, the client also acts as the resource owner, because it does not obtain delegated access to the resource server, but instead requests a token for itself from the authentication server (using basic authentication with the client credentials) in order to then authenticate itself to the resource server with its own (technical) identity outside of a user context.<BR /> <H1 id="ember605" class="ember-view" id="toc-hId-48905628">XSUAA</H1><BR /> <BLOCKQUOTE>The XSUAA service, inside of the SAP BTP, handles the authorization flow between users, identity providers, and the applications or services. The XSUAA service is an internal development from SAP dedicated for the SAP BTP. In the Cloud Foundry project, there is an open-source component called UAA. UAA is an OAuth provider which takes care of authentication and authorization. SAP used the base of UAA and extended it with SAP specific features to be used in SAP BTP.</BLOCKQUOTE><BR /> <A href="https://learning.sap.com/learning-journey/discover-sap-business-technology-platform/illustrating-sap-authorization-and-trust-management-service-xsuaa-_b9fde282-4cff-4dca-b146-7c8f8dde9955" target="test_blank" rel="noopener noreferrer">https://learning.sap.com/learning-journey/discover-sap-business-technology-platform/illustrating-sap-authorization-and-trust-management-service-xsuaa-_b9fde282-4cff-4dca-b146-7c8f8dde9955</A><BR /> <BR /> In the context of OAuth 2.0, XSUAA is acting as the authentication server, i.e. it manages authorization grants and issues and validates JWT tokens. Important to know is, that there is always one XSUAA service instance per subaccount. As you will also later see in the concrete example, it is best practice to bind a dedicated XSUAA "service" resource to every application service (in our example: Client and Server). It took me a while to understand that those XSUAA services are not real running services in terms of a deployed container or something similar, but actually this are "only" pairs of Client ID and Client Secret (plus some additional meta information) that are injected into the application environment variables (VCAP_SERVICES). I.e. this binding represents a client in the sense of OAuth 2.0 terminology.<BR /> <H1 id="ember609" class="ember-view" id="toc-hId--147607877">Cloud 2 Cloud - OAuth 2.0 Client Credentials</H1><BR /> <A href="https://github.com/jfranken/sap-btp-destinations/tree/cloud-2-cloud-oauth2-client-credentials" target="test_blank" rel="nofollow noopener noreferrer">https://github.com/jfranken/sap-btp-destinations/tree/cloud-2-cloud-oauth2-client-credentials</A><BR /> <BR /> This all sounds rather abstract so far, so at this point I will fall back on our well-known example from the previous parts of this series to illustrate the use case:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/Bildschirmfoto-2023-10-03-um-17.09.00.png" /></P><BR /> In this scenario, the BTP Destinations Enthusiast acts as the resource owner, the server app is the resource server, and XSUAA represents the authorization server. When the user calls the client/helloWorldClientPlain(), the client app subsequently attempts to access the /server/helloWorldServer() endpoint upon execution, but not on behalf of the user, but in this scenarios by means of technical client credentials. This endpoint is secured using XSUAA, which means that the server app expects a JWT token in the request header, which is issued and validated by XSUAA. To obtain this token, the client makes use of an according OAuth2ClientCredentials destination in the destination service.<BR /> <H2 id="ember614" class="ember-view" id="toc-hId--215038663">Server Implementation</H2><BR /> <P id="ember615" class="ember-view reader-content-blocks__paragraph">At first, I will show you the basics of the implementation of the server app.</P><BR /> <P id="ember616" class="ember-view reader-content-blocks__paragraph">To be able to secure any endpoint of this service via XSUAA, we need to establish a binding between server app and XSUAA. This is done in the mta.yaml file that we use for the server app deployment:</P><BR /> <BR /> <PRE class="language-javascript"><CODE>...<BR /> resources:<BR /> ... <BR /> - name: xsuaa-server-service<BR /> type: org.cloudfoundry.managed-service<BR /> parameters:<BR /> service: xsuaa<BR /> service-plan: application<BR /> service-name: xsuaa-server-service</CODE></PRE><BR /> In addition, it is required to enable JWT authentication. With SAP CAP, this is pretty staightforward within the cds configuration, which is located in the .cdsrc.js:<BR /> <PRE class="language-javascript"><CODE>{<BR /> "requires": {<BR /> "auth": {<BR /> "kind": "jwt-auth"<BR /> },<BR /> "uaa": {<BR /> "kind": "xsuaa"<BR /> }<BR /> }<BR /> }</CODE></PRE><BR /> Authentication checks can be added by means of annotations which can be added in the service CDS files (the example below shows the server-service.cds file), either on service level or for single entities / functions / actions. In the given example, I only add a very rudimentary check that requires nothing else than the caller to be authenticated at all (i.e. sending a valid JWT token, authenticated-user is an according pseudo role). It is also possible to check for concrete role assignments within the annotation, which is in real world scenarios normally the case, however, since this series aims at keeping the focus on the pure communication flow between the different instances, I try to keep it as simple as possible:<BR /> <PRE class="language-javascript"><CODE>service ServerService @(requires: 'authenticated-user') {<BR /> function helloWorldServer() returns String;<BR /> }</CODE></PRE><BR /> The service implementation within the file server-service.js isn't very spectacular and should be familiar to the attentive readers of the first two parts of the series:<BR /> <PRE class="language-javascript"><CODE>module.exports = async (srv) =&gt; {<BR /> srv.on('helloWorldServer', async (req) =&gt; {<BR /> return 'Hello World from Server'<BR /> })<BR /> }</CODE></PRE><BR /> <H2 id="ember620" class="ember-view" id="toc-hId--411552168">Destination</H2><BR /> As described above, the client app needs to use a destination to obtain a valid JWT token that allows access to the endpoint of the server app, which is secured via XSUAA. The most important aspect here is that I store the client credentials from the XSUAA binding of the&nbsp;<STRONG>server app</STRONG>&nbsp;in the destination, because these represent the OAuth 2.0 client that is authorized to access the server app. The destination configuration in detail is as follows:<BR /> <UL><BR /> <LI>Name: Server</LI><BR /> <LI>Type: HTTP</LI><BR /> <LI>URL:&nbsp;https://${SERVER_APP_ROUTE}/server/helloWorldServer()</LI><BR /> <LI>ProxyType: Internet</LI><BR /> <LI>Authentication: OAuth2ClientCredentials</LI><BR /> <LI>Client ID: Server XSUAA Client ID from Service Binding</LI><BR /> <LI>Client Secret: Server XSUAA Client Secret from Service Binding</LI><BR /> <LI>Token Service URL:&nbsp;https://????????trial.authentication.????.hana.ondemand.com/oauth/token</LI><BR /> </UL><BR /> Please check the README.md file in the github repo. There you find a detailed description how you can find the concrete URLs and credentials via the BTP Cockpit and the Cloud Foundry CLI.<BR /> <H2 id="ember624" class="ember-view" id="toc-hId--608065673">Client Implementation</H2><BR /> As always, the client includes two alternative implementations. On the one hand, the server call via Cloud SDK, and on the other hand, a plain variant that illustrates the communication processes step by step.<BR /> <H3 id="toc-hId--675496459"><STRONG>Cloud SDK</STRONG></H3><BR /> <PRE class="language-javascript"><CODE>srv.on('helloWorldClientCloudSDK', async () =&gt; {<BR /> return executeHttpRequest({ <BR /> destinationName: 'Server' <BR /> }).then((response) =&gt; response.data)<BR /> })</CODE></PRE><BR /> <H3 id="toc-hId--947241333">Plain</H3><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/Bildschirmfoto-2023-09-27-um-07.45.19.png" /></P><BR /> First, the client authenticates against XSUAA with the client credentials from the destination service binding. I.e. here we already have the first client credentials flow to obtain a token that allows the client app to access the destination service. Afterwards, the client app requests the destination "Server" from the destination service, which is described in the chapter above. During this call, the destination service executes another client credentials flow and adds the token into the response which is then sent back to the client app. This could already be used to access the endpoint of the server app. However, for demonstration purposes, the client app implementation triggers another client credentials flow against XSUAA with the client credentials of the destination configuration.<BR /> <PRE class="language-javascript"><CODE>srv.on('helloWorldClientPlain', async () =&gt; {<BR /> // get all the necessary destination service parameters from the <BR /> // service binding in the VCAP_SERVICES env variable<BR /> const vcapServices = JSON.parse(process.env.VCAP_SERVICES)<BR /> const destinationServiceUrl =<BR /> vcapServices.destination[0].credentials.uri + <BR /> '/destination-configuration/v1/destinations/'<BR /> const destinationServiceClientId = <BR /> vcapServices.destination[0].credentials.clientid<BR /> const destinationServiceClientSecret = <BR /> vcapServices.destination[0].credentials.clientsecret<BR /> const destinationServiceTokenUrl = <BR /> vcapServices.destination[0].credentials.url + <BR /> '/oauth/token?grant_type=client_credentials'<BR /> <BR /> // before we can fetch the destination from the destination <BR /> // service, we need to retrieve an auth token<BR /> const token = await axios.post(<BR /> destinationServiceTokenUrl, <BR /> null, <BR /> {<BR /> headers: {<BR /> authorization: 'Basic ' + <BR /> Buffer.from(<BR /> destinationServiceClientId + <BR /> ':' + <BR /> destinationServiceClientSecret'<BR /> ).toString('base64'),<BR /> },<BR /> }<BR /> )<BR /> const destinationServiceToken = token.data.access_token<BR /> <BR /> // with this token, we can now request the "Server" destination <BR /> // from the destination service<BR /> const headers = {<BR /> authorization: 'Bearer ' + destinationServiceToken,<BR /> }<BR /> const destinationResult = await axios.get(<BR /> destinationServiceUrl + 'Server', <BR /> { headers }<BR /> )<BR /> const destination = destinationResult.data<BR /> <BR /> // now, we use the retrieved the destination information to send <BR /> // a HTTP request to the token service endpoint;<BR /> // to authenticate, we take the Client ID attribute and the <BR /> // Client Secret attribute from the destination,<BR /> // encode ClientId:ClientSecret to Base64 and send the resulting <BR /> // string prefixed with "Basic " as Authorization<BR /> // header of the request;<BR /> // as a response, we receive a JWT token that we can then use to <BR /> // authenticate against the server<BR /> // alternatively, the JWT token could directly be fetched from <BR /> // destination.authTokens[0].value<BR /> const jwtTokenResponse = await axios.get(<BR /> destination.destinationConfiguration.tokenServiceURL + <BR /> '?grant_type=client_credentials', <BR /> {<BR /> headers: {<BR /> Authorization: 'Basic ' +<BR /> btoa(destination.destinationConfiguration.clientId + <BR /> ':' + <BR /> destination.destinationConfiguration.clientSecret),<BR /> }<BR /> }<BR /> )<BR /> const jwtToken = jwtTokenResponse.data.access_token<BR /> <BR /> // here we call the server instance with the bearer token we <BR /> // received from the token service endpoint<BR /> const destinationResponse = await axios.get(<BR /> destination.destinationConfiguration.URL, <BR /> {<BR /> headers: {<BR /> Authorization: 'Bearer ' + jwtToken,<BR /> },<BR /> }<BR /> )<BR /> return destinationResponse.data<BR /> })</CODE></PRE><BR /> <H2 id="toc-hId--850351831">Execution</H2><BR /> Once the client and server are deployed and the destination is configured correctly, calls to both client endpoints should return the following result:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/1684662117403.png" /></P><BR /> That's it! In the next part of this series, I will go one step further. Instead of using technical client credentials, I will show you how you can use OAuth2TokenExchange destinations with authorization delegation. The client app will call the server app by propagating the identity of the user who calls the client endpoint in the beginning, i.e. we will cover one of the core scenarios for which OAuth 2.0 has been invented.<BR /> <H1 id="toc-hId--753462329">Disclaimer</H1><BR /> The code examples provided are&nbsp;<STRONG>not suitable</STRONG>&nbsp;to be transferred 1:1 into productive implementations, but they only serve to illustrate the functioning of destinations and Destination Service. In some cases, the interaction with the Destination Service is deliberately implemented in a “cumbersome” manner in order to illustrate the communication processes as explicitly and in detail as possible. SAP CAP and the SAP Cloud SDK provide various functionality to simplify and abstract the use of destinations. However, this would be more of a hindrance than a benefit to the purpose of the illustration. 2023-10-08T09:15:07+02:00 https://community.sap.com/t5/technology-blogs-by-sap/tell-us-about-your-experience-with-sap-btp-connectivity/ba-p/13577270 Tell us about Your Experience with SAP BTP Connectivity 2023-10-18T23:22:32+02:00 frank_mueller https://community.sap.com/t5/user/viewprofilepage/user-id/223421 Have you ever been in touch with the Connectivity service or the Destination service for SAP Business Technology Platform (SAP BTP)?<BR /> <BR /> For example, creating or configuring a destination in the BTP cockpit, or doing some connectivity configuration in your app code?<BR /> <BR /> If so, let us know about your experience.<BR /> <BR /> There's a really short survey (5 minutes or less) that will help us improve SAP BTP Connectivity components according to your feedback.<BR /> <BR /> You can find the survey <A href="https://sapinsights.eu.qualtrics.com/jfe/form/SV_7VZeDjYI5FSHJCS?source=blog" target="_blank" rel="nofollow noopener noreferrer">here</A>.<BR /> <BR /> &nbsp;<BR /> <BR /> Thank you! 2023-10-18T23:22:32+02:00 https://community.sap.com/t5/technology-blogs-by-sap/it-has-never-been-easier-connecting-cloud-apps-to-internet-and-on-premises/ba-p/13578208 It has never been easier! Connecting cloud apps to Internet and on-premises systems using SAP BTP Connectivity 2023-11-14T21:29:59+01:00 ManolV https://community.sap.com/t5/user/viewprofilepage/user-id/181738 It is a common scenario that cloud applications need to connect to remote systems to fulfil the business goals of their creators and those of their end users. This is essential for enterprise applications, which are generally complex and consume data from and/or push data to a variety of sources or destinations – systems that are directly accessible, systems hosted in <A href="https://en.wikipedia.org/wiki/Cloud_computing" target="_blank" rel="nofollow noopener noreferrer">public or private cloud</A>, or such that are hosted in the&nbsp;<A href="https://en.wikipedia.org/wiki/On-premises_software" target="_blank" rel="nofollow noopener noreferrer">customer premises</A>. This use case is called hybrid connectivity.<BR /> <BR /> Sounds complex, right?! With this blog post, I show you that it has never been easier to solve this problem. Let’s get started and see how&nbsp;<A href="https://help.sap.com/docs/connectivity" target="_blank" rel="noopener noreferrer">SAP BTP Connectivity</A>&nbsp;can help with this challenge, more specifically, in <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/d1abd18556f24fb091d081b2e3454b8b.html" target="_blank" rel="noopener noreferrer">SAP BTP Kyma environment</A>.<BR /> <H2 id="toc-hId-964073126">Prerequisites</H2><BR /> Well, complex things cannot be made simple without proper preparation work. Therefore, I need to setup the environment. For the purposes of this blog post, I don’t get into details on how each step is done, if interested, you can follow the links:<BR /> <OL><BR /> <LI>Setup the cloud environment:<BR /> <OL><BR /> <LI>Create a <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/144e1733d0d64d58a7176e817fa6aeb3.html" target="_blank" rel="noopener noreferrer">SAP BTP subaccount</A> - the <A href="https://en.wikipedia.org/wiki/Platform_as_a_service" target="_blank" rel="nofollow noopener noreferrer">PaaS</A> context in the domain of <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/6a2c1ab5a31b4ed9a2ce17a5329e1dd8.html" target="_blank" rel="noopener noreferrer">SAP BTP</A>, i.e., an account enabled to instantiate cloud application development environments, create and manage service instances, etc.</LI><BR /> <LI>Enable <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/d1abd18556f24fb091d081b2e3454b8b.html" target="_blank" rel="noopener noreferrer">Kyma environment</A> - the cloud-native application hosting environment<BR /> <OL><BR /> <LI>Enable <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/0c035010a9d64cc8a02d872829c7fa75.html" target="_blank" rel="noopener noreferrer">Connectivity Proxy</A> for cloud to premise technical connectivity, an <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/0c035010a9d64cc8a02d872829c7fa75.html" target="_blank" rel="noopener noreferrer">integrated component in Kyma environment</A></LI><BR /> <LI>Enable <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/1700cfe070704d2e80aa76de1033a6c4.html" target="_blank" rel="noopener noreferrer">Transparent Proxy</A> for unified, virtually transparent technical connectivity to any destination or data source, an <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/1b548e9ad4744b978b8b595288b0cb5c.html" target="_blank" rel="noopener noreferrer">integrated module in Kyma environment</A></LI><BR /> </OL><BR /> </LI><BR /> </OL><BR /> </LI><BR /> <LI>Setup the local environment<BR /> <OL><BR /> <LI>Install <A href="https://kubernetes.io/docs/reference/kubectl/" target="_blank" rel="nofollow noopener noreferrer">Kubectl</A> - the command line interface for <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/3e25944e491049b2aeec68c562a5ee48.html" target="_blank" rel="noopener noreferrer">connecting to and interacting with the Kyma instance</A></LI><BR /> <LI>Install <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/e6c7616abb5710148cfcf3e75d96d596.html" target="_blank" rel="noopener noreferrer">Cloud Connector</A> for <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/f42fe4471d6a4a5fb09b7f3bb83c66a4.html" target="_blank" rel="noopener noreferrer">controlled and secure exposure concrete systems or resources</A>, hosted in a <A href="https://en.wikipedia.org/wiki/Virtual_private_cloud" target="_blank" rel="nofollow noopener noreferrer">VPC</A> on <A href="https://en.wikipedia.org/wiki/Hyperscale_computing" target="_blank" rel="nofollow noopener noreferrer">Hyperscalers</A> or <A href="https://en.wikipedia.org/wiki/On-premises_software" target="_blank" rel="nofollow noopener noreferrer">on-premises</A> - in my case, on my PC.</LI><BR /> </OL><BR /> </LI><BR /> <LI>For each scenario use case, <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/84e45e071c7646c88027fffc6a7bb787.html" target="_blank" rel="noopener noreferrer">create the relevant destinations in SAP Destination service</A> using <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/4e750660b72e4fd6b2485ffb0b3cbdca.html" target="_blank" rel="noopener noreferrer">SAP BTP cockpit</A>.</LI><BR /> </OL><BR /> <H2 id="toc-hId-767559621">Overview of the scenario</H2><BR /> Image: <EM>Scenario Schematic Overview</EM><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/uc-tp-kyma-blog-scenario-schematic-overview.png" /></P><BR /> This solution diagram depicts the high-level architecture and layout of the SAP BTP tools, software components, services listed above in the <STRONG>Prerequisites</STRONG> section. The focus on the scenario is on the <STRONG>Application</STRONG> side. The rest is depicted for completeness and better end-to-end understanding.<BR /> <BR /> In this blog, I showcase how I can connect my cloud application to the following <STRONG>target systems</STRONG>. I start with the <STRONG>trivial</STRONG> and then continue with the more <STRONG>advanced</STRONG> use cases:<BR /> <OL><BR /> <LI><STRONG><EM>Google</EM></STRONG> - direct connectivity <SPAN style="text-decoration: underline">without</SPAN> using any of the SAP BTP Connectivity software and services</LI><BR /> <LI><STRONG><EM>Google via destination</EM></STRONG> - direct connectivity <SPAN style="text-decoration: underline">with</SPAN> usage of SAP BTP Connectivity software and services</LI><BR /> <LI><STRONG><EM>Google via destination and Cloud Connector</EM></STRONG> - indirect cloud to premise connectivity - in my setup Google is directly accessible via my local Cloud Connector<BR /> <UL><BR /> <LI><EM><SPAN style="text-decoration: underline">Note</SPAN></EM>: this use case is presented only for the purpose of showcase and ease the perception of the reader, it is not expected to be done in production</LI><BR /> </UL><BR /> </LI><BR /> <LI><STRONG><A href="https://help.sap.com/docs/btp/sap-business-technology-platform/access-sap-authorization-and-trust-management-service-apis" target="_blank" rel="noopener noreferrer">SAP Authorization and Trust Management Service (XSUAA)</A> via destination</STRONG> - OAuth based REST API</LI><BR /> <LI><STRONG><EM>An HTTP system hosted on-premises</EM></STRONG> <EM><STRONG>via destination and Cloud Connector </STRONG></EM>- indirect cloud to premise connectivity</LI><BR /> <LI><STRONG><EM>An HTTPS system hosted on-premises</EM> <EM>via destination and Cloud Connector </EM></STRONG>- indirect cloud to premise connectivity with <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/c84d4d0b12d34890b334998185f49e88.html" target="_blank" rel="noopener noreferrer">Principal Propagation</A> enabled, i.e., end-to-end secure user context propagation, a.k.a <A href="https://en.wikipedia.org/wiki/Single_sign-on" target="_blank" rel="nofollow noopener noreferrer">Single Sign On (SSO)</A>.</LI><BR /> </OL><BR /> I pick those systems to showcase what I claimed in the begging of this blog - <STRONG>It has never been easier!</STRONG><BR /> <BR /> <SPAN style="text-decoration: underline">Note</SPAN>: For the creation of the destination pointing to XSUAA in step 4 of the scenario, I followed these two simple steps in <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/4e750660b72e4fd6b2485ffb0b3cbdca.html" target="_blank" rel="noopener noreferrer">BTP cockpit</A>:<BR /> <OL><BR /> <LI><A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/8221b7434d8e484fab5ec5d219b7bf64.html" target="_blank" rel="noopener noreferrer">Create a service instance</A> of <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/ebc9113a520e495ea5fb759b9a7929f2.html" target="_blank" rel="noopener noreferrer">service "xsuaa", plan "apiaccess"</A></LI><BR /> <LI><A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/685f383cebb54c009b2fac633b32c90f.html" target="_blank" rel="noopener noreferrer">Create a destination pointing to the service instance via destinations UI</A> - just a few clicks job!</LI><BR /> </OL><BR /> <H2 id="toc-hId-571046116">Configure the scenario</H2><BR /> To get the scenario in action, at first I need to configure the target systems as technical connection configurations, a.k.a. destinations. In this way I control to which systems the application has access to and can switch the used technical authentication and authorisation mechanisms on the fly – changing the destination attributes without affecting the experience of the end user, and without affecting the lifecycle of the application.<BR /> <H3 id="toc-hId-503615330">Expose the on-premises system to the cloud</H3><BR /> For the destinations pointing to systems hosted in the customer premises (points 5 and 6 of the scenario overview), I need to securely expose those to the cloud.<BR /> <BR /> You guessed it, for this I configure the respective <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/f42fe4471d6a4a5fb09b7f3bb83c66a4.html" target="_blank" rel="noopener noreferrer">Access Controls</A> in my <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/e6c7616abb5710148cfcf3e75d96d596.html" target="_blank" rel="noopener noreferrer">SAP Cloud Connector</A>:<BR /> <BR /> Image: <EM>Access Control entries in Cloud Connector</EM><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/scc-access-controls-1.png" /></P><BR /> In this example, the two systems hosted in the on-premises are simple HTTP and HTTPS servers:<BR /> <UL><BR /> <LI>System #1:<STRONG><EM> localhost:8000</EM></STRONG> - serves <EM>HTTP</EM>, returns status code: <STRONG><EM>200&nbsp;</EM></STRONG>with the received HTTP request line as a message.</LI><BR /> </UL><BR /> <UL><BR /> <LI>System #2:<STRONG><EM> localhost:9000</EM></STRONG> - serves <EM>HTTP<STRONG>S</STRONG></EM>, returns status code: <EM><STRONG>200</STRONG></EM> with the received HTTP request line as a message, and&nbsp;the subject common name (CN) of the received <SPAN style="font-size: 1rem">X.509 client certificate as part of the HTTP request - the user context propagated from the cloud, achieving Single Sign-On (SSO).</SPAN></LI><BR /> </UL><BR /> <H3 id="toc-hId-307101825">Manage the technical connection configurations</H3><BR /> One of the best practices for cloud-native applications is to externalise any configuration and avoid coupling it with the lifecycle of the application, e.g. via hard-coding it. I use <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/7e306250e08340f89d6c103e28840f30.html" target="_blank" rel="noopener noreferrer">Destination service</A>&nbsp;for&nbsp;<A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/84e45e071c7646c88027fffc6a7bb787.html" target="_blank" rel="noopener noreferrer">managing the technical connection configurations (a.k.a. destinations)</A>, as guided by the Golden Path defined in&nbsp;<A href="https://cap.cloud.sap/docs/about/" target="_blank" rel="nofollow noopener noreferrer">Cloud Application Programming</A>&nbsp;model of&nbsp;<A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/6a2c1ab5a31b4ed9a2ce17a5329e1dd8.html" target="_blank" rel="noopener noreferrer">SAP BTP</A>.<BR /> <BR /> In the context of my&nbsp;<A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/144e1733d0d64d58a7176e817fa6aeb3.html" target="_blank" rel="noopener noreferrer">SAP BTP subaccount</A>, I create the following destinations, pointing to the variety of systems I’ll connect my cloud app workload running in my Kyma instance.<BR /> <BR /> Image: <EM>Destinations in BTP cockpit</EM><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/BTP-cockpit-destinations.png" /></P><BR /> <BR /> <H3 id="toc-hId-110588320">Expose the destinations in the Kyma instance</H3><BR /> To allow an application to consume the defined destinations, I declaratively expose only those I'm interested in, and are specific for this particular use case. For this, I <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/c5257cf110bf4b7b9054eab74ededff4.html" target="_blank" rel="noopener noreferrer">create specific Destination Custom Resources</A>, a <A href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/" target="_blank" rel="nofollow noopener noreferrer">common practice for cloud-native applications based on Kubernetes</A>. In Kyma environment, I can do this either via <A href="https://kyma-project.io/#/01-overview/ui/README?id=kyma-dashboard" target="_blank" rel="nofollow noopener noreferrer">Kyma Dashboard</A>, or via command-line using <A href="https://kubernetes.io/docs/reference/kubectl/" target="_blank" rel="nofollow noopener noreferrer">Kubectl</A>.<BR /> <BR /> Image: <EM>Creation of a Destination CR in Kyma Dashboard</EM><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/DestinationCRs-create-CR.png" /></P><BR /> Shortly after the&nbsp;<A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/c5257cf110bf4b7b9054eab74ededff4.html" target="_blank" rel="noopener noreferrer">Destination CR</A>&nbsp;is created,&nbsp;<A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/acc64ada71e34f98867f16fbcc471b5e.html" target="_blank" rel="noopener noreferrer">Transparent Proxy</A>&nbsp;process it and updates the status of the Destination CR with a message that the technical connectivity is successfully configured, and this destination is ready to be consumed.<BR /> <BR /> Image: <EM>Status of a Destination CR in Kyma Dashboard</EM><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/DestinationCR-ConfigurationSuccessful.png" /></P><BR /> Using the same approach, I expose all the destinations required specifically for this use case.<BR /> <BR /> Image: <EM>Destination CRs in Kyma&nbsp;</EM><I>Dashboard</I><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/DestinationCRs.png" /></P><BR /> It's all set now, let's play with the application.<BR /> <H2 id="toc-hId--215007904">Scenario in action: Connect the application to the remote systems</H2><BR /> As described in the status message of the&nbsp;<A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/c5257cf110bf4b7b9054eab74ededff4.html" target="_blank" rel="noopener noreferrer">Destination CR</A>, the&nbsp;<A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/acc64ada71e34f98867f16fbcc471b5e.html" target="_blank" rel="noopener noreferrer">Transparent Proxy</A>&nbsp;exposed the referenced <STRONG>destination</STRONG> via the specified name in the form of <STRONG>locally accessible host</STRONG>, leveraging the concept of&nbsp;<A href="https://kubernetes.io/docs/concepts/services-networking/service/" target="_blank" rel="nofollow noopener noreferrer">Kubernetes Service</A>.<BR /> <BR /> As a result, it’s&nbsp;<EM>trivial</EM>&nbsp;for the application to connect to those local hosts, and this is the only task needed to be performed. It’s that easy!<BR /> <BR /> For simplicity and versatility reasons, my application is represented by a local terminal attached to a container running in a&nbsp;<A href="https://kubernetes.io/docs/concepts/workloads/pods/" target="_blank" rel="nofollow noopener noreferrer">Kubernetes Pod</A>&nbsp;in the Kyma Instance. Then I use&nbsp;<A href="https://en.wikipedia.org/wiki/CURL" target="_blank" rel="nofollow noopener noreferrer">cURL</A>&nbsp;command-line tool for executing HTTP requests towards the target systems.<BR /> <BR /> How it’s done? Once connected to the Kyma instance via Kubectl, I run a sample&nbsp;<A href="https://hub.docker.com/r/curlimages/curl" target="_blank" rel="nofollow noopener noreferrer">cURL image</A>&nbsp;as a&nbsp;<A href="https://kubernetes.io/docs/concepts/workloads/pods/" target="_blank" rel="nofollow noopener noreferrer">Kuberenetes Pod</A>&nbsp;and open a terminal session via the following command:<BR /> <PRE class="language-abap"><CODE>kubectl run mycurlpod -n sap-transp-proxy-system --image=curlimages/curl -i --tty -- sh</CODE></PRE><BR /> &nbsp;<BR /> <H3 id="toc-hId--282438690">Executing request to Google:</H3><BR /> This is a trivial direct invocation of the public web page of Google:<BR /> <PRE class="language-abap"><CODE>~ $ curl <A href="https://community.sap.com/www.google.com" target="test_blank" rel="nofollow noopener noreferrer">www.google.com</A> -v<BR /> * Trying 142.250.179.164:80...<BR /> * Connected to <A href="https://community.sap.com/www.google.com" target="test_blank" rel="nofollow noopener noreferrer">www.google.com</A> (142.250.179.164) port 80<BR /> &gt; GET / HTTP/1.1<BR /> &gt; Host: <A href="https://community.sap.com/www.google.com" target="test_blank" rel="nofollow noopener noreferrer">www.google.com</A><BR /> &gt; User-Agent: curl/8.4.0<BR /> &gt; Accept: */*<BR /> &gt; <BR /> &lt; HTTP/1.1 200 OK<BR /> ...<BR /> &lt; <BR /> &lt;!doctype html&gt;&lt;html...&lt;title&gt;Google&lt;/title&gt;&lt;script...</CODE></PRE><BR /> <H3 id="toc-hId--478952195">Executing request to Google via destination:</H3><BR /> This is an example reaching the same public web page of Google, but this time via <EM>destination</EM>, locally exposed and served by Transparent Proxy, and centrally managed via Destination service:<BR /> <PRE class="language-abap"><CODE>~ $ curl google -v<BR /> * Trying 10.111.255.220:80...<BR /> * Connected to google (10.111.255.220) port 80<BR /> &gt; GET / HTTP/1.1<BR /> &gt; Host: google<BR /> &gt; User-Agent: curl/8.4.0<BR /> &gt; Accept: */*<BR /> &gt; <BR /> &lt; HTTP/1.1 200 OK<BR /> ...<BR /> &lt; <BR /> &lt;!doctype html&gt;&lt;html...&lt;title&gt;Google&lt;/title&gt;&lt;script...</CODE></PRE><BR /> <H3 id="toc-hId--675465700">Executing request to Google via destination via Cloud Connector:</H3><BR /> This is an example of reaching the same public web page of Google via&nbsp;<EM>destination</EM>, locally exposed and served by Transparent Proxy, Connectivity Proxy, and centrally managed via Destination service. The destination is configured to point to an on-premises system, exposed to the cloud via Cloud Connector:<BR /> <PRE class="language-abap"><CODE>~ $ curl mypremisegoogle -v<BR /> * Trying 10.111.159.5:80...<BR /> * Connected to mypremisegoogle (10.111.159.5) port 80<BR /> &gt; GET / HTTP/1.1<BR /> &gt; Host: mypremisegoogle<BR /> &gt; User-Agent: curl/8.4.0<BR /> &gt; Accept: */*<BR /> &gt; <BR /> &lt; HTTP/1.1 200 OK<BR /> ...<BR /> &lt; <BR /> &lt;!doctype html&gt;&lt;html...&lt;title&gt;Google&lt;/title&gt;&lt;script...</CODE></PRE><BR /> <H3 id="toc-hId--947210574">Executing request to XSUAA API via destination:</H3><BR /> This is an example for <A href="https://api.sap.com/api/AuthorizationAPI/resource/Applications" target="_blank" rel="noopener noreferrer">getting the registered service instances of the current subaccount</A> via <EM>destination</EM>, locally exposed and served by Transparent Proxy, and centrally managed via Destination service.<BR /> <PRE class="language-abap"><CODE>~ $ curl xsuaa-api/sap/rest/authorization/v2/apps -v<BR /> * Trying 10.106.192.162:80...<BR /> * Connected to xsuaa-api (10.106.192.162) port 80<BR /> &gt; GET /sap/rest/authorization/v2/apps HTTP/1.1<BR /> &gt; Host: xsuaa-api<BR /> &gt; User-Agent: curl/8.4.0<BR /> &gt; Accept: */*<BR /> &gt; <BR /> &lt; HTTP/1.1 200 OK<BR /> &lt; cache-control: no-cache, no-store, max-age=0, must-revalidate<BR /> &lt; content-length: 10621<BR /> ...<BR /> &lt; <BR /> [{"appid":"app123!b13","serviceinstanceid":"15442f82-7d82-11ee-b26d-ab53f17d39a5","planId":"HWEgt9/213f90b0+/7d82-11ee=","planName":"broker"...</CODE></PRE><BR /> <H3 id="toc-hId--1143724079">Executing request to an on-premises HTTP server via destination via Cloud Connector:</H3><BR /> This is an example of connecting to a simple on-premises HTTP server via <EM>destination</EM>, locally exposed and served by Transparent Proxy, Connectivity Proxy, and centrally managed via Destination service. The destination is configured to point to an on-premises system, exposed to the cloud via Cloud Connector:<BR /> <PRE class="language-abap"><CODE>~ $ curl mypremserver/test-path -v<BR /> * Trying 10.110.23.19:80...<BR /> * Connected to mypremserver (10.110.23.19) port 80<BR /> &gt; GET /test-path HTTP/1.1<BR /> &gt; Host: mypremserver<BR /> &gt; User-Agent: curl/8.4.0<BR /> &gt; Accept: */*<BR /> &gt; <BR /> &lt; HTTP/1.1 200 OK<BR /> ...<BR /> &lt; <BR /> Response generated by HTTP server: <BR /> GET /test-path HTTP/1.1<BR /> </CODE></PRE><BR /> <H3 id="toc-hId--1340237584">Executing request to an on-premises HTTPS server via destination via Cloud Connector with Single Sign-On enabled:</H3><BR /> This is an example of connecting to an on-premises HTTPS server via <EM>destination</EM>, locally exposed and served by Transparent Proxy, Connectivity Proxy, and centrally managed via Destination service. The HTTPS server requires the cloud user identity to be propagated. The destination is configured with PrincipalPropagation as authentication type, and to point to an on-premises system, exposed to the cloud via Cloud Connector:<BR /> <PRE class="language-abap"><CODE>~ $ curl myppserver -H 'Authorization: Bearer eyJhbGciOiJSUzI1Ni...bwKMpAGKbhECqvkyibC7Q' -v<BR /> * Trying 10.105.101.106:80...<BR /> * Connected to myppserver (10.105.101.106) port 80<BR /> &gt; GET / HTTP/1.1<BR /> &gt; Host: myppserver<BR /> &gt; User-Agent: curl/8.4.0<BR /> &gt; Accept: */*<BR /> &gt; Authorization: Bearer yJhbGciOiJSUzI1Ni...bwKMpAGKbhECqvkyibC7Q<BR /> &gt; <BR /> &lt; HTTP/1.1 200 OK<BR /> &lt; server: envoy<BR /> &lt; date: Tue, 07 Nov 2023 15:17:47 GMT<BR /> &lt; content-type: text/plain; charset=utf-8<BR /> &lt; content-length: 1956<BR /> &lt; x-envoy-upstream-service-time: 657<BR /> &lt; <BR /> &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;<BR /> Response generated by HTTPS server: <BR /> GET / HTTP/1.1<BR /> =========<BR /> Received X.509 client certificate with Subject: &lt;Name(CN=manol.valchev@sap.com)&gt;</CODE></PRE><BR /> <H2 id="toc-hId--1243348082">Summary</H2><BR /> As you can see,&nbsp;<STRONG>it’s that simple!</STRONG>&nbsp;No matter of the type and hosting location of the target system, from the application development perspective the user experience is the same –&nbsp;<STRONG><EM>simple, unified, virtually transparent</EM></STRONG>, and the technical complexity is handled by the usage of software components and services part of&nbsp;<A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/e54cc8fbbb571014beb5caaf6aa31280.html" target="_blank" rel="noopener noreferrer"><STRONG>SAP BTP Connectivity</STRONG></A>&nbsp;product portfolio:<BR /> <UL><BR /> <LI><A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/7e306250e08340f89d6c103e28840f30.html" target="_blank" rel="noopener noreferrer"><STRONG>Destination service</STRONG></A> for <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/84e45e071c7646c88027fffc6a7bb787.html" target="_blank" rel="noopener noreferrer">managing the technical connection configurations (a.k.a. destinations)</A></LI><BR /> <LI><A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/1700cfe070704d2e80aa76de1033a6c4.html" target="_blank" rel="noopener noreferrer"><STRONG>Transparent Proxy</STRONG></A> for unified, virtually transparent technical connectivity to any destination or data source, an <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/1b548e9ad4744b978b8b595288b0cb5c.html" target="_blank" rel="noopener noreferrer">integrated module in Kyma environment</A>, also <A href="https://hub.docker.com/u/sapse" target="_blank" rel="nofollow noopener noreferrer">available in Docker Hub</A>.</LI><BR /> <LI><A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/0c035010a9d64cc8a02d872829c7fa75.html" target="_blank" rel="noopener noreferrer"><STRONG>Connectivity Proxy</STRONG></A> for cloud to premise technical connectivity, an <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/0c035010a9d64cc8a02d872829c7fa75.html" target="_blank" rel="noopener noreferrer">integrated component in Kyma environment</A>, also <A href="https://hub.docker.com/u/sapse" target="_blank" rel="nofollow noopener noreferrer">available in Docker Hub</A>.</LI><BR /> <LI><A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/e6c7616abb5710148cfcf3e75d96d596.html" target="_blank" rel="noopener noreferrer"><STRONG>Cloud Connector</STRONG></A> for <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/f42fe4471d6a4a5fb09b7f3bb83c66a4.html" target="_blank" rel="noopener noreferrer">controlled and secure exposure concrete systems or resources</A>, hosted in a <A href="https://en.wikipedia.org/wiki/Virtual_private_cloud" target="_blank" rel="nofollow noopener noreferrer">VPC</A> on <A href="https://en.wikipedia.org/wiki/Hyperscale_computing" target="_blank" rel="nofollow noopener noreferrer">Hyperscalers</A> or <A href="https://en.wikipedia.org/wiki/On-premises_software" target="_blank" rel="nofollow noopener noreferrer">on-premises</A>.</LI><BR /> <LI><STRONG><A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/e54cc8fbbb571014beb5caaf6aa31280.html" target="_blank" rel="noopener noreferrer">Connectivity service</A></STRONG> as the backbone for the multitude of <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/0c035010a9d64cc8a02d872829c7fa75.html" target="_blank" rel="noopener noreferrer">Connectivity Proxy</A> and <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/e6c7616abb5710148cfcf3e75d96d596.html" target="_blank" rel="noopener noreferrer">Cloud Connector</A> instances serving thousands of <A href="https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/6a2c1ab5a31b4ed9a2ce17a5329e1dd8.html" target="_blank" rel="noopener noreferrer">SAP BTP</A> customers</LI><BR /> </UL><BR /> Тhis simple yet powerful approach enables <STRONG>application developers</STRONG> to <STRONG>focus more on their business goals</STRONG> and <STRONG>delegate the technical complexity</STRONG> to <STRONG><A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/e54cc8fbbb571014beb5caaf6aa31280.html" target="_blank" rel="noopener noreferrer">SAP BTP Connectivity</A></STRONG>, and at the same time the application administrators can manage the outbound technical connections (via destinations) without affecting the lifecycle and availability of the application itself.<BR /> <BR /> Stay tuned and subscribe to <A href="https://help.sap.com/whats-new/cf0cb2cb149647329b5d02aa96303f56?Component=Connectivity" target="_blank" rel="noopener noreferrer">What's New for SAP BTP Connectivity</A> page. 2023-11-14T21:29:59+01:00 https://community.sap.com/t5/technology-blogs-by-members/hey-abap-cloud-please-let-me-save-my-data-export-to-azure-storage-please/ba-p/13572978 Hey ABAP Cloud please let me save my data export to Azure Storage please🥺🙏- part 4 2023-11-21T13:21:26+01:00 Martin-Pankraz https://community.sap.com/t5/user/viewprofilepage/user-id/143781 <TABLE style="border-collapse: collapse;width: 100%" border="1"><BR /> <TBODY><BR /> <TR style="height: 14px"><BR /> <TD style="width: 100%;background-color: #ffd57a;height: 14px"><BR /> <BR /> <STRONG><span class="lia-unicode-emoji" title=":backhand_index_pointing_right:">👉🏿</span></STRONG><STRONG>back to&nbsp;</STRONG><A href="https://blogs.sap.com/2023/06/06/kick-start-your-sap-abap-platform-integration-journey-with-microsoft/" target="_blank" rel="noopener noreferrer"><STRONG>blog series</STRONG></A> or jump to <A href="https://github.com/MartinPankraz/steampunk-helper" target="_blank" rel="nofollow noopener noreferrer">GitHub repos</A>🧑🏽‍<span class="lia-unicode-emoji" title=":laptop_computer:">💻</span><BR /> <BR /> &lt;&lt;<A href="https://blogs.sap.com/2023/07/20/sap-btp-abap-environment-integration-journey-with-microsoft-part-3/" target="_blank" rel="noopener noreferrer">part 3</A></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> Hello and welcome back to your ABAP Cloud with Microsoft integration journey. Part 3 of this series got you covered with modern GraphQL API definition on top of your ABAP Cloud RAP APIs to expose a single API endpoint that may consume many different OData, OpenAPI, or REST endpoints at the same time.<BR /> <BR /> <STRONG>Today will be different</STRONG>. Sparked by a <A href="https://twitter.com/PanzerDominik/status/1683252126884003840" target="_blank" rel="nofollow noopener noreferrer">SAP community conversation</A> with <SPAN class="mention-scrubbed">dpanzer</SPAN> and <SPAN class="mention-scrubbed">lars.hvam</SPAN> including a <A href="https://answers.sap.com/questions/14009359/createsend-a-file-to-ftp-server-via-abap-cloud-or.html" target="_blank" rel="noopener noreferrer">community question</A> by <SPAN class="mention-scrubbed">rammel</SPAN> on working with files with ABAP Cloud, I got inspired to propose a solution for the question below:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/steampunk-blob-twitter.png" height="146" width="493" /></P><BR /> Before we dive into my proposal see here a list of alternative options that I came across as food for thought for your own research.<BR /> <TABLE><BR /> <TBODY><BR /> <TR><BR /> <TD width="301"><A href="https://docs.cloudfoundry.org/devguide/services/using-vol-services.html" target="_blank" rel="nofollow noopener noreferrer">Mount a file system</A> to a Cloud Foundry app</TD><BR /> <TD width="301">Create custom API hosted by your CF app and call via http client from ABAP Cloud</TD><BR /> </TR><BR /> <TR><BR /> <TD width="301"><A href="https://blogs.sap.com/2021/05/12/how-to-connect-from-sap-cloud-integration-to-on-premise-sftp-server/" target="_blank" rel="noopener noreferrer">Connect to SFTP server</A> via SAP Cloud Integration</TD><BR /> <TD width="301">Design iFlow and call via http client from ABAP Cloud</TD><BR /> </TR><BR /> <TR><BR /> <TD width="301">Integrate with <A href="https://help.sap.com/docs/document-management-service/sap-document-management-service/what-is-document-management-service" target="_blank" rel="noopener noreferrer">SAP Document Management Service</A></TD><BR /> <TD width="301">Call <A href="https://api.sap.com/package/SAPDocumentManagementServiceIntegrationOptionCMISAPI/rest" target="_blank" rel="noopener noreferrer">SAP BTP REST APIs</A> from ABAP Cloud directly</TD><BR /> </TR><BR /> <TR><BR /> <TD width="301">Integrate with <A href="https://help.sap.com/docs/object-store/object-store-service-on-sap-btp/what-is-object-store" target="_blank" rel="noopener noreferrer">SAP BTP Object Store</A> exposing hyperscaler storage services using SDKs</TD><BR /> <TD width="301">Create custom API hosted by your CF or Kyma app and call via http client from ABAP Cloud</TD><BR /> </TR><BR /> <TR><BR /> <TD width="301">Serve directly from ABAP Code via XCO</TD><BR /> <TD width="301">Base64-encode your file content, wrap into ABAP code, and serve as XCO class. Lars likes it at least <span class="lia-unicode-emoji" title=":winking_face_with_tongue:">😜</span>. There were sarcastic smiles involved and some more “oh please”, so take it not too seriously.</TD><BR /> </TR><BR /> <TR><BR /> <TD width="301">Raise an <A href="https://influence.sap.com/sap/ino/#/campaigns" target="_blank" rel="noopener noreferrer">influencing request at SAP</A> to release something like the former NetWeaver MIME repos</TD><BR /> <TD width="301">Live the dream</TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> A <STRONG>common theme</STRONG> among all the options is the <STRONG>need to interact</STRONG> with them from <STRONG>ABAP Cloud via the built-in http client</STRONG>. On the downside some options require an additional app on CF or Kyma to orchestrate the storage interactions.<BR /> <BR /> <STRONG>Ideally ABAP Cloud integrates directly with the storage account</STRONG> to reduce complexity and maintenance.<BR /> <H1 id="toc-hId-834818605">You guessed rightly my own proposal focusses on direct integration with Azure Blob</H1><BR /> To get started with this sample I ran through the SAP developer tutorial “<A href="https://developers.sap.com/tutorials/abap-environment-console-application.html" target="_blank" rel="noopener noreferrer">Create Your First ABAP Cloud Console Application</A>” and steps 1-6 of “<A href="https://developers.sap.com/tutorials/abap-environment-external-api.html" target="_blank" rel="noopener noreferrer">Call an External API and Parse the Response in SAP BTP ABAP Environment</A>. This way you can easily reproduce from an official reference.<BR /> <BR /> Got your hello world on Eclipse? Great, onwards, and upwards in the stack we go then 🪜. Or down to the engine room – that depends on your perspective.<BR /> <BR /> All the blob storage providers offer various options to authenticate with the service. See the current coverage for Azure <A href="https://learn.microsoft.com/en-us/azure/storage/common/authorize-data-access#understand-authorization-for-data-operations" target="_blank" rel="nofollow noopener noreferrer">here</A>.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/steampunk-blob-auth-methods.png" /></P><BR /> <P style="text-align: center">Fig.1 Screenshot of supported authentication methods for Azure Storage</P><BR /> The Microsoft Entra ID option offers superior security capabilities compared to access keys – which can be leaked or lost for example – and is therefore recommended by Microsoft.<BR /> <BR /> For developer ease, I left the code using the simpler to configure “<A href="https://learn.microsoft.com/azure/ai-services/translator/document-translation/how-to-guides/create-sas-tokens?tabs=Containers" target="_blank" rel="nofollow noopener noreferrer">Shared-Access-Signature (SAS) tokens</A>” commented on the <A href="https://github.com/MartinPankraz/steampunk-helper/blob/main/steampunk-part4/z_cl_steampunk_to_azure_blob.abap" target="_blank" rel="nofollow noopener noreferrer">shared GitHub repos</A>. SAS tokens can be created from the Azure portal with two clicks.<BR /> <BR /> The <A href="https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key" target="_blank" rel="nofollow noopener noreferrer">shared key approach</A> requires a bit of hashing and marshaling on ABAP. Use the <A href="https://github.com/microsoft/ABAP-SDK-for-Azure" target="_blank" rel="nofollow noopener noreferrer">ABAP SDK for Azure</A> to accelerate that part of your implementation. Check the “<A href="https://github.com/microsoft/ABAP-SDK-for-Azure/blob/master/src/zadf/zadf_service_blob/zcl_adf_service_blob.clas.abap#L656" target="_blank" rel="nofollow noopener noreferrer">get_sas_token</A>” &nbsp;method for reference.<BR /> <BR /> <A href="https://learn.microsoft.com/azure/storage/blobs/anonymous-read-access-configure?tabs=portal" target="_blank" rel="nofollow noopener noreferrer">Anonymous read access</A> would only be ok for less sensitive content like static image files or the likes because anyone can access them once they have the URL.<BR /> <H1 id="toc-hId-638305100">For an enterprise-grade solution however, you will need to use a more secure protocol like OAuth2 with Microsoft Entra ID</H1><BR /> Technically you could do the OAuth2 token fetching with plain http-client requests from ABAP Cloud. See <A href="https://jacekw.dev/blog/2022/oauth-client-credentials-from-abap-cloud/" target="_blank" rel="nofollow noopener noreferrer">this blog</A> by <SPAN class="mention-scrubbed">jacek.wozniczak</SPAN> for instance. However, it is recommended to use the steampunk “Communication Management” to abstract away the configuration from your code. Think “external configuration store”. Also, it reduces the complexity of your ABAP code, because Communication Management handles the OAuth2 flow for you.<BR /> <TABLE style="border-collapse: collapse;width: 100%" border="1"><BR /> <TBODY><BR /> <TR><BR /> <TD style="width: 100%;background-color: #ffc68a"><span class="lia-unicode-emoji" title=":loudspeaker:">📢</span>Note: SAP will release the needed capability to maintain OAuth2 scopes in communication arrangements as part of your ABAP Cloud requests with the upcoming <A href="https://help.sap.com/docs/abap-cross-product/roadmap-info/integration-services?locale=en-US#security-for-integration-services" target="_blank" rel="noopener noreferrer">SAP BTP, ABAP environment 2402</A>.</TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> So, till then you will need to use the BTP Destination service. Target <STRONG>destinations</STRONG> <STRONG>living on subaccount level</STRONG> by calling them like so (omitting the i_service_instance_name, thank you <SPAN class="mention-scrubbed">thwiegan</SPAN> for calling that out <A href="https://answers.sap.com/questions/13305436/abap-environment-cannot-access-remote-odata-servic.html" target="_blank" rel="noopener noreferrer">here</A><span class="lia-unicode-emoji" title=":disappointed_face:">😞</span><BR /> <PRE class="language-abap"><CODE>destination = cl_http_destination_provider=&gt;create_by_cloud_destination(<BR /> i_name = |azure-blob|<BR /> i_authn_mode = if_a4c_cp_service=&gt;service_specific<BR /> ).</CODE></PRE><BR /> Or call <STRONG>destinations living on Cloud Foundry</STRONG> spaces like so:<BR /> <PRE class="language-abap"><CODE>destination = cl_http_destination_provider=&gt;create_by_cloud_destination(<BR /> i_name = |azure-blob|<BR /> i_service_instance_name = |SAP_BTP_DESTINATION|<BR /> i_authn_mode = if_a4c_cp_service=&gt;service_specific<BR /> ).</CODE></PRE><BR /> For above Cloud Foundry variation you need to deploy the “standard” communication scenario &nbsp;<A href="https://help.sap.com/docs/btp/sap-business-technology-platform/integration-and-connectivity-communication-management#destination" target="_blank" rel="noopener noreferrer">SAP_COM_0276</A>. My generated arrangement id in this case was “SAP_BTP_DESTINATION”.<BR /> <BR /> Be aware, SAP marked the approach with BTP destinations as <A href="https://help.sap.com/docs/btp/sap-business-technology-platform/http-communication-via-destination-service-deprecated" target="_blank" rel="noopener noreferrer">deprecated</A> for BTP ABAP. And we can now see why. It will be much nicer doing it from the single initial communication arrangement only, rather than having the overhead with additional services and arrangements. Looking forward to that in February <span class="lia-unicode-emoji" title=":smiling_face_with_sunglasses:">😎</span><BR /> <BR /> Not everything is “bad” about using BTP destinations with ABAP Cloud though. They have management APIs, which the communication arrangements don’t have yet. Also, re-use of APIs across your BTP estate beyond the boundary of your ABAP Environment tenant would be useful.<BR /> <H3 id="toc-hId-699957033">A fully automated solution deployment with the BTP and Azure terraform providers is only possible with the destination service approach as of today.</H3><BR /> See <A href="https://github.com/SAP-samples/teched2023-XP160" target="_blank" rel="nofollow noopener noreferrer">this TechEd 2023 session</A> and watch this new <A href="https://github.com/SAP-samples/btp-terraform-samples/tree/use-cases-ms/in-development/uc_abap_env_ms_obj_store" target="_blank" rel="nofollow noopener noreferrer">sample repos</A> (still in development) for reference.<BR /> <H1 id="toc-hId-245278090">The application flow is quite simple once the authentication part is figured out</H1><BR /> Access your communication management config from your ABAP web Ui:<BR /> <P style="padding-left: 40px"><A href="https://your-steampunk-domain.abap-web.eu20.hana.ondemand.com/ui#Shell-home" target="test_blank" rel="nofollow noopener noreferrer">https://your-steampunk-domain.abap-web.eu20.hana.ondemand.com/ui#Shell-home</A></P><BR /> Steampunk supports the <A href="https://help.sap.com/docs/sap-btp-abap-environment/abap-environment/supported-protocols-and-authentication-methods" target="_blank" rel="noopener noreferrer">typical set of authentication flows</A> for outbound communication users using http that you are used to from BTP. I chose the OAuth2 Client Credentials grant because that is most widely referenced in the BTP world and reasonably secure.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/steampunk-blob-overview.png" /></P><BR /> <P style="text-align: center">Fig.2 ABAP Cloud API flow including OAuth2 token request from Microsoft Entra ID</P><BR /> Since I am integrating with an Azure Storage account, I will need to authenticate via Microsoft Entra ID (formerly known as Azure Active Directory).<BR /> <BR /> Yes, Microsoft likes renaming stuff from time to time, too <span class="lia-unicode-emoji" title=":winking_face:">😉</span>.<BR /> <BR /> Using the <A href="https://learn.microsoft.com/rest/api/storageservices/operations-on-blobs" target="_blank" rel="nofollow noopener noreferrer">Azure Storage REST API</A> I can create, update, delete, and list files as I please.<BR /> <H1 id="toc-hId-48764585">The Entra ID setup takes a couple of clicks</H1><BR /> Create a new App registration from Microsoft Entra ID service on your Azure portal and generate a new secret. Beware of the expiry date!<BR /> <BR /> Below preferred option will start working once SAP adds the scope parameter for OAuth2 Client Credentials grant as described before.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/steampunk-blob-auth-setup1.png" /></P><BR /> <P style="text-align: center">Fig.3 Screenshot of attribute and secret mapping for ABAP Cloud Outbound user</P><BR /> For now, let’s have a look at a destination on subaccount level instead. Be aware the scope parameter needs to be “<A href="https://storage.azure.com/.default" target="_blank" rel="nofollow noopener noreferrer">https://storage.azure.com/.default</A>” (see fig.4 below, additional properties section called “scope” on the bottom right). That is also the setting that we are missing for the preferred approach mentioned above.<BR /> <BR /> The standard login URLs for OAuth token endpoints on Microsoft Entra ID are the following:<BR /> <P style="padding-left: 40px"><A href="https://login.microsoftonline.com/your-tenantId/oauth2/v2.0/token" target="test_blank" rel="nofollow noopener noreferrer">https://login.microsoftonline.com/your-tenantId/oauth2/v2.0/token</A></P><BR /> <P style="padding-left: 40px"><A href="https://login.microsoftonline.com/your-tenantId/oauth2/v2.0/authorize" target="test_blank" rel="nofollow noopener noreferrer">https://login.microsoftonline.com/your-tenantId/oauth2/v2.0/authorize</A></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/steampunk-blob-auth-setup2.png" /></P><BR /> <P style="text-align: center">Fig.4 Screenshot of attribute mapping from Entra ID to SAP BTP Destination</P><BR /> So far so good. Let’s roll the integration test from our ABAP console application on Eclipse (ADT).<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/steampunk-blob-result.png" /></P><BR /> <P style="text-align: center">Fig.5 Screenshot of file interaction from ABAP Cloud and data container view on Azure</P><BR /> Excellent, there is our booking request: Safe and sound stored as Azure Blob, posted from ABAP, and read again seamlessly.<BR /> <BR /> See the <A href="https://raw.githubusercontent.com/MartinPankraz/steampunk-helper/main/Steampunk-Helper-Lib.postman_collection.json" target="_blank" rel="nofollow noopener noreferrer">shared Postman collection</A> to help with your integration testing.<BR /> <H1 id="toc-hId--147748920">Thoughts on production readiness</H1><BR /> The biggest caveat is the regularly required OAuth2 client credential secret rotation. Unfortunately, credential-free options with Azure Managed Identities are not possible, because BTP is hyperscaler-agnostic and does not expose the underlying Azure components to you.<BR /> <BR /> Some of you might say next: let’s use client certificates with “veeery long validity time frames like 2038” to push out the problem beyond so far out someone else will have to deal with it. Well, certificate lifetimes get reduced more and more (TLS certs for instance have a maximum of 13 months at <A href="https://www.digicert.com/faq/public-trust-and-certificates/how-long-are-tls-ssl-certificate-validity-periods" target="_blank" rel="nofollow noopener noreferrer">DigiCert since 2020</A>) and you have to rotate them eventually, too <span class="lia-unicode-emoji" title=":winking_face:">😉</span>. With shorter certificate lifetimes more secure hashing algorithms come into effect much quicker for instance.<BR /> <BR /> I will dedicate a separate post on client certificates (mTLS) with steampunk to consume Azure services.<BR /> <BR /> What about <A href="https://learn.microsoft.com/graph/api/resources/federatedidentitycredentials-overview" target="_blank" rel="nofollow noopener noreferrer">federated identities</A>? You could configure trust between your SAP Cloud Identity Service (or Steampunk auth service) and Microsoft Entra ID to allow requests from ABAP Cloud to authorize Azure services. However, that would be a more complex configuration with implications for your overall setup causing larger integration test needs. And we embarked on this journey to discover a simple solution not too far away from AL11 and the likes, right? <span class="lia-unicode-emoji" title=":grinning_face_with_sweat:">😅</span><BR /> <BR /> <EM>See a working implementation of federated identities with SAP Cloud Identity service consuming Microsoft Graph published by my colleagure <SPAN class="mention-scrubbed">mraepple</SPAN> in his blog series <A href="https://blogs.sap.com/2022/11/02/principal-propagation-in-a-multi-cloud-solution-between-microsoft-azure-and-sap-business-technology-platform-btp-part-vi-calling-the-microsoft-graph-on-behalf-of-the-sap-authenticated-user/" target="_blank" rel="noopener noreferrer">here</A>.</EM><BR /> <BR /> Ok, then let’s compromise and see how we can automatically rotate secrets. Azure Key Vault exposes events for secrets, keys, and certificates to inform downstream services about due expiry. With that a small low code app can be provided to perform the secret update. See <A href="https://github.com/Azure/AzureAD-AppSecretManager" target="_blank" rel="nofollow noopener noreferrer">below sample</A> that went the extra mile asking the admins via Microsoft Teams if they wanted to perform the change or not:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/steampunk-blob-sec-rotate.png" /></P><BR /> <P style="text-align: center">Fig.6 Architecture of secret rotation with Azure Key Vault and secret refresh approval</P><BR /> A new secret for the app registration on Entra can be generated with the <A href="https://learn.microsoft.com/en-us/graph/api/application-addpassword?view=graph-rest-1.0&amp;tabs=http" target="_blank" rel="nofollow noopener noreferrer">Microsoft Graph API like so</A>. See <A href="https://techcommunity.microsoft.com/t5/azure-integration-services-blog/automate-secret-rotation-in-key-vault/ba-p/3275149" target="_blank" rel="nofollow noopener noreferrer">this post</A> for details on the Azure Key Vault aspects of the mix.<BR /> <BR /> To apply that flow and propagate the new secret to steampunk, we need to call BTP APIs to save the new secret. See the BTP REST API for Destinations <A href="https://api.sap.com/api/SAP_CP_CF_Connectivity_Destination/path/put_subaccountDestinations" target="_blank" rel="noopener noreferrer">here</A> to learn about the secret update method.<BR /> <BR /> Have a look at my earlier <A href="https://blogs.sap.com/2022/12/02/automatic-sap-btp-trust-store-certificate-renewal-with-azure-key-vault-or-how-to-stop-thinking-about-expiry-dates-once-and-for-all/" target="_blank" rel="noopener noreferrer">blog post</A> for specifics on how to do the same with certificates.<BR /> <BR /> <A href="https://github.com/Azure/AzureAD-AppSecretManager#costs" target="_blank" rel="nofollow noopener noreferrer">Estimated cost</A> for such a secret rotation solution for 1000 rotations per month is around 2$ per month. With simpler configurations and less rotations, it can be covered by free tiers even.<BR /> <BR /> Once you have applied the means of automation as discussed above you may incorporate this into your DevOps process and live happily ever after with no manual secret handling <span class="lia-unicode-emoji" title=":smiling_face_with_smiling_eyes:">😊</span>.<BR /> <H1 id="toc-hId--344262425">Final Words</H1><BR /> That’s a wrap <span class="lia-unicode-emoji" title=":burrito:">🌯</span>you saw today how – in the absence of an application server file system and NetWeaver MIME repository (good old days) – you can <STRONG>use Azure Storage Account as your external data store from BTP ABAP Environment</STRONG> (steampunk) using ABAP Cloud. In addition to that, you<STRONG> gained insights into the proper setup for authentication</STRONG> and what flavors are supported by steampunk now. You got a glimpse into <STRONG>automated deployment of the solution with the BTP and Azure terraform provider</STRONG>.<BR /> <BR /> To top it up you learnt what else is needed to <STRONG>operationalize the approach</STRONG> at scale <STRONG>with regular secret/certificate rotation</STRONG>.<BR /> <BR /> Check <A href="https://help.sap.com/docs/btp/sap-business-technology-platform/developing-external-service-consumption-outbound-communication" target="_blank" rel="noopener noreferrer">SAP’s docs for external APIs</A> with steampunk for further official materials.<BR /> <BR /> What do you think <SPAN class="mention-scrubbed">dpanzer</SPAN>&nbsp;and <SPAN class="mention-scrubbed">lars.hvam</SPAN>? Not too bad, is it? <span class="lia-unicode-emoji" title=":winking_face:">😉</span><BR /> <BR /> Find all the resources to replicate this setup on <A href="https://github.com/MartinPankraz/steampunk-helper" target="_blank" rel="nofollow noopener noreferrer">this GitHub repos</A>. Stay tuned for the remaining parts of the steampunk series with Microsoft Integration Scenarios from my <A href="https://blogs.sap.com/2023/06/06/kick-start-your-sap-abap-platform-integration-journey-with-microsoft/" target="_blank" rel="noopener noreferrer">overview post</A>.<BR /> <BR /> Cheers<BR /> <BR /> Martin 2023-11-21T13:21:26+01:00 https://community.sap.com/t5/technology-blogs-by-sap/child-s-play-install-sap-btp-transparent-proxy-using-helm/ba-p/13574118 Child's play: Install SAP BTP transparent proxy using Helm 2024-01-15T16:14:28+01:00 iliyanvidenov9 https://community.sap.com/t5/user/viewprofilepage/user-id/343616 It is inevitable that cloud solutions have to communicate with other remote solutions. The latter can be situated on public or private clouds, or set up on client sites. Of course, it would be easier to have levers to facilitate this in the simplest possible way. This is where the <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/connectivity" target="_blank" rel="noopener noreferrer">SAP BTP Connectivity</A> services and components come to the rescue! In this blog post, you will understand how to install one of these components using <A href="https://helm.sh/" target="_blank" rel="nofollow noopener noreferrer">Helm</A>: the <STRONG><A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/acc64ada71e34f98867f16fbcc471b5e.html" target="_blank" rel="noopener noreferrer">SAP BTP transparent proxy</A></STRONG>.<BR /> <BR /> <SPAN class="ui-provider a b c d e f g h i j k l m n o p q r s t u v w x y z ab ac ae af ag ah ai aj ak" dir="ltr">SAP BTP transparent proxy simplifies the connection between <A href="https://kubernetes.io/" target="_blank" rel="nofollow noopener noreferrer">Kubernetes</A> workloads and target systems defined as destinations in the <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/managing-destinations?version=Cloud" target="_blank" rel="noopener noreferrer">SAP Destination service</A>. To understand more about some of the features of the Transparent Proxy, you could check this <A href="https://blogs.sap.com/2022/11/29/transparent-consumption-of-connectivity/" target="_blank" rel="noopener noreferrer">blog</A>.</SPAN><BR /> <H2 id="toc-hId-963953032">Prerequisites</H2><BR /> Before you start, you should have the following:<BR /> <UL><BR /> <LI>A <A href="https://kubernetes.io/" target="_blank" rel="nofollow noopener noreferrer">Kubernetes</A> cluster</LI><BR /> <LI><A href="https://kubernetes.io/docs/reference/kubectl/" target="_blank" rel="nofollow noopener noreferrer">Kubectl</A> installed and configured on your local machine</LI><BR /> <LI><A href="https://helm.sh/" target="_blank" rel="nofollow noopener noreferrer">Helm</A> installed on your local machine</LI><BR /> <LI><A href="https://help.sap.com/docs/btp/sap-business-technology-platform/btp-getting-started" target="_blank" rel="noopener noreferrer">SAP BTP subaccount</A> with a Destination service instance and a Connectivity Proxy instance (optional for on-premise connectivity)</LI><BR /> <LI><A href="https://istio.io/latest/" target="_blank" rel="nofollow noopener noreferrer">Istio</A> or <A href="https://cert-manager.io/" target="_blank" rel="nofollow noopener noreferrer">cert-manager</A> running in your Kubernetes cluster as a foundation for traffic encryption between the micro-components of the <A href="https://help.sap.com/docs/CP_CONNECTIVITY/cca91383641e40ffbe03bdc78f00f681/acc64ada71e34f98867f16fbcc471b5e.html" target="_blank" rel="noopener noreferrer">Transparent Proxy</A></LI><BR /> <LI><A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/connectivity-proxy-for-kubernetes?version=Cloud" target="_blank" rel="noopener noreferrer">Connectivity proxy</A> installed in your cluster (optional for on-premise connectivity)</LI><BR /> </UL><BR /> <H2 id="toc-hId-767439527">Installation steps</H2><BR /> To install the Transparent Proxy using Helm, follow these steps:<BR /> <OL><BR /> <LI>Create a namespace for the Transparent Proxy in your Kubernetes cluster. For example:<BR /> <PRE class="language-markup"><CODE>kubectl create namespace transparent-proxy​</CODE></PRE><BR /> </LI><BR /> <LI>Create a Kubernetes secret with the credentials of your Destination service instance<BR /> <UL><BR /> <LI>You can obtain the credentials from the SAP BTP cockpit. Navigate to Services -&gt; Instances and Subscriptions -&gt; Click on the service instance row -&gt; Service Keys -&gt; View -&gt; Copy JSON</LI><BR /> <LI>Use the service key data to create the Kubernetes secret. For example:<BR /> <PRE class="language-markup"><CODE>kubectl create secret generic dest-svc-key -n transparent-proxy --from-literal=secret='&lt;credentials&gt;'​</CODE></PRE><BR /> </LI><BR /> </UL><BR /> </LI><BR /> <LI>Create values.yaml according to your needs. You can find all available parameters <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/transparent-proxy-configuration-guide?version=Cloud" target="_blank" rel="noopener noreferrer">here</A>. For example:<BR /> <PRE class="language-markup"><CODE>deployment:<BR /> autoscaling:<BR /> http:<BR /> horizontal:<BR /> # Enables or disables the Horizontal Pod Autoscaler mechanism.<BR /> enabled: true<BR /> # Upper limit for the number of HTTP Transparent Proxy replicas to which the autoscaler can scale up.<BR /> maxReplicaCount: 3<BR /> metrics:<BR /> # Target value of the average CPU metric across all Transparent HTTP Proxy pods, represented as a percentage of the requested value of the CPU for the pods.<BR /> cpuAverageUtilization: 80<BR /> # Target value of the average memory metric across all Transparent HTTP Proxy pods, represented as a percentage of the requested value of the memory for the pods.<BR /> memoryAverageUtilization: 80<BR /> tcp:<BR /> horizontal:<BR /> # Enables or disables the Horizontal Pod Autoscaler mechanism.<BR /> enabled: true<BR /> # Upper limit for the number of TCP Transparent Proxy replicas to which the autoscaler can scale up.<BR /> maxReplicaCount: 3<BR /> metrics:<BR /> # Target value of the average CPU metric across all Transparent TCP Proxy pods represented as a percentage of the requested value of the CPU for the pods.<BR /> cpuAverageUtilization: 80<BR /> # Target value of the average memory metric across all Transparent TCP Proxy pods represented as a percentage of the requested value of the memory for the pods.<BR /> memoryAverageUtilization: 80<BR /> config:<BR /> # Defines the tenant mode in which Transparent Proxy is working in. The option "dedicated" shows that the proxy works in single-tenant mode.<BR /> tenantMode: "dedicated"<BR /> security:<BR /> accessControl:<BR /> destinations:<BR /> ## Defines the scope of Destination CRs.<BR /> defaultScope: "clusterWide"<BR /> communication:<BR /> internal:<BR /> # Enables/Disables mTLS communication between the Transparent Proxy micro-components.<BR /> # It may be disabled only in test environments or if you want to integrate with a Service mesh like Istio.<BR /> encryptionEnabled: true<BR /> certManager:<BR /> issuerRef:<BR /> name: &lt;cert-manager issuer name&gt;<BR /> kind: ClusterIssuer<BR /> # Certificate properties used by cert-manager's Certificate controller.<BR /> certificate:<BR /> privateKey:<BR /> algorithm: ECDSA<BR /> encoding: PKCS8<BR /> size: 256<BR /> duration: 720h<BR /> renewBefore: 120h<BR /> manager:<BR /> # The interval on which the Transparent Proxy will check for updates in the Destination service instance. <BR /> executionIntervalMinutes: 3<BR /> integration:<BR /> destinationService:<BR /> instances:<BR /> # The local cluster name of the Destination service instance, which can later be used as a reference in the Destination CR<BR /> - name: dest-service-instance<BR /> serviceCredentials:<BR /> # The key in the Destination service secret resource, which holds the value of the destination service key.<BR /> secretKey: secret<BR /> # The name of the existing secret, which holds the credentials for the Destination service.<BR /> secretName: dest-svc-key<BR /> # The namespace of the secret to be used, which holds the credentials for the Destination service.<BR /> secretNamespace: transparent-proxy<BR /> connectivityProxy:<BR /> # The Kubernetes service name + namespace that are associated with the Connectivity Proxy workload.<BR /> serviceName: &lt;connectivity proxy service name&gt;.&lt;connectivity proxy namespace&gt;<BR /> # The port on which the HTTP interface of the Connectivity Proxy is started.<BR /> httpPort: 20003<BR /> # The port on which the TCP interface of the Connectivity Proxy is started.<BR /> tcpPort: 20004</CODE></PRE><BR /> </LI><BR /> <LI>Install the Transparent Proxy using the Helm values from step 3:<BR /> <PRE class="language-markup"><CODE>helm install transparent-proxy oci://registry-1.docker.io/sapse/transparent-proxy --version &lt;version of helm chart&gt; --namespace transparent-proxy -f &lt;path-to-values.yaml&gt;​</CODE></PRE><BR /> <P style="overflow: hidden;margin-bottom: 0px">You should receive a similar to this response:</P><BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2024/01/Screenshot-2024-01-11-at-12.45.04.png" /><BR /> <P class="image_caption" style="text-align: center;font-style: italic;font-family: 'SAPRegular', 'Helvetica Neue', Arial, sans-serif">Successful installation of Transparent Proxy with Helm</P><BR /> </LI><BR /> <LI>Verify that the Transparent Proxy is running by checking the status of the pods and the health check:<BR /> <PRE class="language-markup"><CODE>kubectl get pods -n transparent-proxy</CODE></PRE><BR /> <P style="overflow: hidden;margin-bottom: 0px">There should be two pods running:</P><BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2024/01/Screenshot-2024-01-11-at-12.05.51.png" /><BR /> <P class="image_caption" style="text-align: center;font-style: italic;font-family: 'SAPRegular', 'Helvetica Neue', Arial, sans-serif">Transparent Proxy components after installation</P><BR /> As you can see, the Transparent Proxy has a health check pod which constantly checks the status of all Transparent Proxy components. You can look at what capabilities the health check has in the <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/transparent-proxy-verification-and-testing" target="_blank" rel="noopener noreferrer">Verification and Testing</A> page in the Help portal. Here's how you can execute a component check:<BR /> <PRE class="language-markup"><CODE>kubectl run perform-hc --image=curlimages/curl -it --rm --restart=Never -- curl -w "\n" 'sap-transp-proxy-int-healthcheck.transparent-proxy/status'​</CODE></PRE><BR /> And the result should be the following:<BR /> <BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2024/01/Screenshot-2024-01-11-at-12.32.07.png" /><BR /> This means that the sap-transp-proxy-manager, the heart of the Transparent Proxy, is running smoothly and you are ready to consume your first target system through the Transparent Proxy!</LI><BR /> </OL><BR /> <H2 id="toc-hId-570926022">Try it out</H2><BR /> To use the Transparent Proxy, you should create a Destination Custom Resource (CR). Let's create a dynamic one. "<EM>Dynamic</EM>" means a Destination CR will serve all destinations for a Destination service instance or its tenants. Follow these steps:<BR /> <OL><BR /> <LI>Create a Destination CR file with name <EM>dynamic-destination.yaml​</EM>:<BR /> <PRE class="language-markup"><CODE>apiVersion: destination.connectivity.api.sap/v1<BR /> kind: Destination<BR /> metadata:<BR /> name: dynamic-destination<BR /> namespace: transparent-proxy<BR /> spec:<BR /> destinationRef:<BR /> name: "*"<BR /> destinationServiceInstanceName: dest-service-instance​</CODE></PRE><BR /> </LI><BR /> <LI>Create the resource from step 1 in your cluster:<BR /> <PRE class="language-markup"><CODE>kubectl create -f dynamic-destination.yaml​</CODE></PRE><BR /> </LI><BR /> <LI>Wait for a successful status of the Destination CR. To check it execute:<BR /> <PRE class="language-markup"><CODE>kubectl get dst dynamic-destination -n transparent-proxy -o yaml</CODE></PRE><BR /> You should observe a status similar to this one:<BR /> <PRE class="language-markup"><CODE>status:<BR /> conditions:<BR /> - lastUpdateTime: "2024-01-11T11:56:33.605473101Z"<BR /> message: Technical connectivity is configured. Kubernetes service with name<BR /> dynamic-destination is created.<BR /> reason: ConfigurationSuccessful<BR /> status: "True"<BR /> type: Available</CODE></PRE><BR /> </LI><BR /> <LI>Create a curl pod, from where you can test the consumption of the target system through the Transparent Proxy:<BR /> <PRE class="language-markup"><CODE>kubectl run curlpod -n transparent-proxy --image=curlimages/curl -n transparent-proxy -i --tty -- sh</CODE></PRE><BR /> </LI><BR /> <LI>Consume a target system defined as a destination in your Destination service instance:<BR /> <PRE class="language-markup"><CODE>curl dynamic-destination -H "X-Destination-Name: &lt;destination-name&gt;"​</CODE></PRE><BR /> &nbsp;</LI><BR /> </OL><BR /> <H3 id="toc-hId-503495236">Examples</H3><BR /> In the context of my <A href="https://help.sap.com/docs/btp/sap-business-technology-platform/btp-getting-started" target="_blank" rel="noopener noreferrer">SAP BTP subaccount</A>, I have created two destinations: one pointing to the SAP XSUAA API, and another pointing to a server on my local machine, exposed to the cloud via the <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/cloud-connector" target="_blank" rel="noopener noreferrer">SAP Cloud Connector</A>.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2024/01/Screenshot-2024-01-11-at-17.21.39.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Configured destinations in the SAP BTP Cockpit</P><BR /> <BR /> <UL><BR /> <LI>Executing a request to the SAP XSUAA API. This is an example for <A style="font-size: 1rem" href="https://api.sap.com/api/AuthorizationAPI/resource/Applications" target="_blank" rel="noopener noreferrer">getting the registered service instances of the current subaccount</A><SPAN style="font-size: 1rem">&nbsp;via&nbsp;</SPAN><EM style="font-size: 1rem">destination</EM><SPAN style="font-size: 1rem"><SPAN style="font-size: 1rem">, locally exposed and served by Transparent Proxy, and centrally managed via the SAP Destination service:<BR /> </SPAN></SPAN><BR /> <PRE class="language-markup"><CODE>~ $ curl dynamic-destination/sap/rest/authorization/v2/apps -H "X-Destination-Name: xsuaa-api" -v<BR /> * Host dynamic-destination:80 was resolved.<BR /> ...<BR /> &gt; GET /sap/rest/authorization/v2/apps HTTP/1.1<BR /> &gt; Host: dynamic-destination<BR /> &gt; User-Agent: curl/8.5.0<BR /> &gt; Accept: */*<BR /> &gt; X-Destination-Name: xsuaa-api<BR /> &gt; <BR /> &lt; HTTP/1.1 200 OK<BR /> ...<BR /> [{"appid":"auditlog!b3718","serviceinstanceid":"0889a7e7-61d8-41...</CODE></PRE><BR /> </LI><BR /> </UL><BR /> <UL><BR /> <LI>Executing a request to an on-premise system using principal propagation. That system is a simple server that maps the user certificate to a concrete user. The current response greets the requestor.<BR /> <PRE class="language-markup"><CODE>~ $ curl dynamic-destination/principal-propagation -H "X-Destination-Name: my-on-premise-system" -H "Authorization: Bearer $TOKEN" -v<BR /> * Host dynamic-destination:80 was resolved.<BR /> ...<BR /> * Connected to dynamic-destination (10.104.69.106) port 80<BR /> &gt; GET /principal-propagation HTTP/1.1<BR /> &gt; Host: dynamic-destination<BR /> &gt; User-Agent: curl/8.5.0<BR /> &gt; Accept: */*<BR /> &gt; X-Destination-Name: my-on-premise-system<BR /> &gt; Authorization: Bearer eyJhbGciOiJSUzI1NiIsImprdS...<BR /> ...<BR /> &lt; HTTP/1.1 200 OK<BR /> ...<BR /> Hello Iliyan Videnov!​</CODE></PRE><BR /> </LI><BR /> </UL><BR /> &nbsp;<BR /> <BR /> <SPAN class="ui-provider a b c d e f g h i j k l m n o p q r s t u v w x y z ab ac ae af ag ah ai aj ak" dir="ltr">In this blog post, you have learned how to install SAP BTP transparent proxy using Helm, and how to easily set up it for system consumption. I hope you find it useful and enjoy it. Ideas, suggestions, and comments are welcome. Thank you for reading!</SPAN> 2024-01-15T16:14:28+01:00 https://community.sap.com/t5/technology-blogs-by-sap/new-release-available-sap-cloud-connector-2-17-0/ba-p/13697681 New Release Available: SAP Cloud Connector 2.17.0 2024-05-10T14:33:54.505000+02:00 MarcoErtel https://community.sap.com/t5/user/viewprofilepage/user-id/6305 <P>We are happy to announce that the fresh version of the SAP Cloud Connector is now available for <SPAN><A href="https://tools.hana.ondemand.com/#cloud" target="_blank" rel="noopener nofollow noreferrer">download</A></SPAN>. It is (as usual) packed with a host of new features and improvements. From bug fixes to enhancements, we've worked diligently to deliver an updated connector that addresses critical issues while also enhancing usability and functionality, which you can find more detailed in the <SPAN><A href="https://help.sap.com/whats-new/cf0cb2cb149647329b5d02aa96303f56?Component=Connectivity&amp;locale=en-US&amp;version=Cloud&amp;Software_Lifecycle=General%20Availability&amp;Valid_as_Of=2024-05-01%3A2024-05-03" target="_blank" rel="noopener noreferrer">release notes</A></SPAN>.<SPAN><BR /></SPAN>Moving onto enhancements, we've made changes to the underlying architecture and features of the Cloud Connector. One of the major changes is the switch from JavaWeb 3.x runtime on Tomcat 8.5 to JavaWeb 4.x, which operates on Tomcat 9. This new runtime container facilitates better performance and stability.<SPAN><BR /></SPAN>In addition, Cloud Connector 2.17 now supports the use of SapMachine 21 as Java runtime. This change can provide increased efficiency and flexibility for your operations.<SPAN><BR /></SPAN>One of the significant enhancements in this release is the addition of support for up to 3 LDAP servers for authentication.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MarcoErtel_0-1715343899539.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/108662i99117DCC49CE8FA5/image-size/medium?v=v2&amp;px=400" role="button" title="MarcoErtel_0-1715343899539.png" alt="MarcoErtel_0-1715343899539.png" /></span></P><P>This feature is essential for setups where the user base is spread across multiple LDAP user stores or multiple user bases in a single LDAP user store (find more in the <SPAN><A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/use-ldap-for-authentication?version=Cloud" target="_blank" rel="noopener noreferrer">documentation</A></SPAN>).<BR />We've also introduced the option to configure a separate port for the HA-related communication between the master and shadow instances.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MarcoErtel_1-1715343899540.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/108661i432E39BA1A67206C/image-size/medium?v=v2&amp;px=400" role="button" title="MarcoErtel_1-1715343899540.png" alt="MarcoErtel_1-1715343899540.png" /></span></P><P>This new feature enables you to use HA in conjunction with certificate-based authentication to overcome the limitation from 2.16 (find more <SPAN><A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/install-failover-instance-for-high-availability?version=Cloud" target="_blank" rel="noopener noreferrer">here</A></SPAN>)<SPAN><BR /></SPAN>Additional hardware monitoring REST APIs have been provided for disk and CPU status, allowing for more comprehensive system insights. Plus, you can now use the hardware monitor on the shadow instance as well.<SPAN><BR /></SPAN>To improve your operations, we’ve introduced for the access control settings a creation timestamp, providing more detailed and useful information for your operations:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MarcoErtel_2-1715343899541.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/108660i2C75337A93E41BD6/image-size/medium?v=v2&amp;px=400" role="button" title="MarcoErtel_2-1715343899541.png" alt="MarcoErtel_2-1715343899541.png" /></span></P><P>Finally, we've improved the Cloud Connector UI by adding a session expiration progress bar. This new addition helps you keep track of your active session and alerts you when you need to log in again.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MarcoErtel_3-1715343899542.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/108663i3AADF3B061835890/image-size/medium?v=v2&amp;px=400" role="button" title="MarcoErtel_3-1715343899542.png" alt="MarcoErtel_3-1715343899542.png" /></span></P><P>In summary, with this release, we've not only ensured the highest security levels but also worked on improving the overall user experience and functionality. Don't hesitate to upgrade your Cloud Connector to version 2.17.0 today (by downloading it from <SPAN><A href="https://tools.hana.ondemand.com/#cloud" target="_blank" rel="noopener nofollow noreferrer">here</A></SPAN>) and explore these new features and improvements. For more detailed information, make sure to check out the <SPAN><A href="https://help.sap.com/whats-new/cf0cb2cb149647329b5d02aa96303f56?Component=Connectivity&amp;locale=en-US&amp;version=Cloud&amp;Software_Lifecycle=General%20Availability&amp;Valid_as_Of=2024-05-01%3A2024-05-03" target="_blank" rel="noopener noreferrer">official release notes</A></SPAN>. Enjoy the enhanced performance and functionality of the new SAP Cloud Connector!Happy Connecting!</P> 2024-05-10T14:33:54.505000+02:00 https://community.sap.com/t5/technology-blogs-by-sap/configuration-as-code-cac-with-destinations/ba-p/13699003 Configuration as code (CaC) with destinations. 2024-05-13T12:54:57.123000+02:00 quovadis https://community.sap.com/t5/user/viewprofilepage/user-id/743 <H1 id="toc-hId-865494464">Configuration as code (CaC) with destinations.</H1><P>Destinations are very handy and powerful mechanism to facilitate access to target systems and devices.</P><P>When it comes to SAP BTP destinations, the idea is to manage both <STRONG>subaccount</STRONG> and <STRONG>instance</STRONG> level destinations (and/or their certificates) as<SPAN>&nbsp;</SPAN><STRONG>shared</STRONG><SPAN>&nbsp;</SPAN>configuration resources on a provider subaccount level.</P><P>That way, the destinations configurations can be stored as versioned assets in a source repository and need to be maintained only once per provider, thus, without incurring application runtime tie-in.</P><P>Last but not least, BTP destination service is used as a self-configuration tool.</P><H2 id="toc-hId-798063678"><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#configuration-as-code-cac-quovadis-master" target="_blank" rel="noopener nofollow noreferrer">Configuration as code with SAP BTP destination service</A></H2><P>&nbsp;</P><TABLE border="1"><TBODY><TR><TD>Table of Contents<OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#cac-dest" target="_blank" rel="noopener nofollow noreferrer">Configuration as code with SAP BTP destination service.</A></LI><OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#create-dest-service" target="_blank" rel="noopener nofollow noreferrer">create shared destination service instance and binding</A>.</LI></OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#create-bootstrap" target="_blank" rel="noopener nofollow noreferrer">Provision bootstrap destinations.</A></LI><OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#get-dest-credentials" target="_blank" rel="noopener nofollow noreferrer">retrieve destination service credentials from binding</A>.</LI><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#create-bootstrap-payload" target="_blank" rel="noopener nofollow noreferrer">describe bootstrap destination definitions.</A></LI><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#apply-payload" target="_blank" rel="noopener nofollow noreferrer">create bootstrap destinations on subaccount</A>.</LI></OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#configure-dest" target="_blank" rel="noopener nofollow noreferrer">Configure destination resources.</A></LI><OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#dynamic_dest" target="_blank" rel="noopener nofollow noreferrer">dynamic_dest route with managed approuter</A>.</LI><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#cloud-sdk" target="_blank" rel="noopener nofollow noreferrer">SAP Cloud SDK built-in destinations</A>.</LI></OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#documentation" target="_blank" rel="noopener nofollow noreferrer">Documentation.</A></LI></OL></TD></TR></TBODY></TABLE><P>PS.</P><P><STRONG>Bootstrap destinations definitions. </STRONG></P><P>Even, if there is no intrinsic BTP CLI command to assist in creation of destinations from service bindings, this can be achieved quite easily with a bit of jq gimmick by applying service binding credentials to a json payload template, for instance:</P><P>&nbsp;</P><pre class="lia-code-sample language-json"><code>{ "init_data": { "subaccount": { "destinations": [ { "Description": "dest-httpbin", "Type": "HTTP", "clientId": "sb-clone12847c4c89544b4f9234b26ede429f62!b282590|destination-xsappname!b62", "HTML5.DynamicDestination": "true", "HTML5.Timeout": "60000", "Authentication": "OAuth2ClientCredentials", "Name": "dest-httpbin", "tokenServiceURL": "https://&lt;subdomain&gt;.authentication.us10.hana.ondemand.com/oauth/token", "ProxyType": "Internet", "URL": "https://httpbin.org", "tokenServiceURLType": "Dedicated", "clientSecret": "&lt;clientSecret&gt;" }, { "Description": "SAP Destination Service APIs", "Type": "HTTP", "clientId": "sb-clone12847c4c89544b4f9234b26ede429f62!b282590|destination-xsappname!b62", "HTML5.DynamicDestination": "true", "HTML5.Timeout": "60000", "Authentication": "OAuth2ClientCredentials", "Name": "destination-service", "tokenServiceURL": "https://&lt;subdomain&gt;.authentication.us10.hana.ondemand.com/oauth/token", "ProxyType": "Internet", "URL": "https://destination-configuration.cfapps.us10.hana.ondemand.com/destination-configuration/v1", "tokenServiceURLType": "Dedicated", "clientSecret": "&lt;clientSecret&gt;" } ], "certificates": [ ], "existing_certificates_policy": "update", "existing_destinations_policy": "update" } } }</code></pre><P>&nbsp;</P><P>Alternatively, one could resort to using SAP Cloud SDK built-in <A href="https://sap.github.io/cloud-sdk/docs/js/features/connectivity/destinations#service-binding-environment-variables" target="_self" rel="nofollow noopener noreferrer">service binding destinations</A>.</P><P>The below nodejs code snippet demonstrates how to leverage&nbsp;SAP Cloud SDK with its service binding destinations with the likes of service manager and destinations services.</P><pre class="lia-code-sample language-yaml"><code>apiVersion: serverless.kyma-project.io/v1alpha2 kind: Function metadata: name: {{ .Values.services.srv.name }} labels: {{- include "app.labels" . | nindent 4 }} app: {{ .Values.services.srv.name }} spec: runtime: {{ .Values.services.srv.runtime }} # runtimeImageOverride: {{ .Values.services.srv.runtimeImageOverride }} source: inline: dependencies: | { "name": "{{ .Values.services.srv.name }}", "version": "0.0.1", "dependencies": { "axios":"latest" ,"debug": "latest" ,"@sap/xsenv": "latest" ,"@sap-cloud-sdk/http-client": "latest" ,"@sap-cloud-sdk/connectivity": "latest" ,"@sap-cloud-sdk/resilience": "latest" ,"async-retry": "latest" } } source: | const debug = require('debug')('{{ .Values.services.srv.name }}:function'); const NOT_FOUND = 'Not Found'; const xsenv = require('@sap/xsenv'); const services = xsenv.getServices({ sm: { label: 'service-manager', name: 'saas-sm' } , dest: { label: 'destination' } }); console.log('saas-sm: ', services.sm); const readServices = xsenv.readServices(); console.log('readServices: ', readServices); const httpClient = require('@sap-cloud-sdk/http-client'); const cloudSdkConnectivity = require('@sap-cloud-sdk/connectivity'); const { retrieveJwt, decodeJwt, Destination } = require('@sap-cloud-sdk/connectivity'); const { setGlobalLogLevel, createLogger } = require('@sap-cloud-sdk/util'); const { retry } = require ('@sap-cloud-sdk/resilience'); const { resilience } = require ('@sap-cloud-sdk/resilience'); const ResilienceOptions = { retry: 10, circuitBreaker: false, timeout: 300*1000 // 5 minutes in milliseconds }; const retryme = require('async-retry'); setGlobalLogLevel('debug'); const logger = createLogger('http-logs'); module.exports = { main: async function (event, context) { const req = event.extensions.request; const message = `Hello World` + ` from the Kyma Function ${context['function-name']}` + ` running on ${context.runtime}!` + ` with the request headers ${JSON.stringify(req.headers,0,2)}`; console.log(message); if (typeof req.path !== undefined) { console.log('path: ', JSON.stringify(req.path,0,2)) } if (typeof req.params !== undefined) { console.log('params: ', JSON.stringify(req.params,0,2)) } if (typeof req.url !== undefined) { console.log('url: ', JSON.stringify(req.url,0,2)) } if (typeof req.authInfo !== undefined) { console.log('authInfo: ', JSON.stringify(req.authInfo,0,2)) } const { pathname } = new URL(req.url || '', `https://${req.headers.host}`) console.log('pathname: ', pathname) const url = require("url"); var url_parts = url.parse(req.url); console.log(url_parts); console.log(url_parts.pathname); // returns an array with paths let path_array = req.url.match('^[^?]*')[0].split('/').slice(1); console.log(path_array) console.log(req.url.match('^[^?]*')[0]) if (!path_array?.length) return 'Please use an API verb'; const actions = [ { name: 'offerings', verb: 'service_offerings', dest: 'saas-sm', url: '/v1/' }, { name: 'plans', verb: 'service_plans', dest: 'saas-sm', url: '/v1/' }, { name: 'instances', verb: 'service_instances', dest: 'saas-sm', url: '/v1/' }, { name: 'bindings', verb: 'service_bindings', dest: 'saas-sm', url: '/v1/' }, { name: 'instanceDestinations', verb: 'instanceDestinations', dest: 'faas-dest-x509', url: '/destination-configuration/v1/' }, { name: 'subaccountDestinations', verb: 'subaccountDestinations', dest: 'faas-dest-x509' , url: '/destination-configuration/v1/' } ]; const action = actions.find( ({ name }) =&gt; name === path_array[1] ) console.log('action found: ', action) if (path_array[0] == 'srv' &amp;&amp; action !== undefined) { path_array = req.url.match('^[^?]*')[0].split('/').slice(2); console.log('path_array: ', path_array) const queryString = req.query; console.log('queryString: ', queryString) const urlParams = new URLSearchParams(queryString); const params = req.params; console.log('params: ', params) try { // https://sap.github.io/cloud-sdk/docs/js/features/connectivity/destinations#service-binding-environment-variables const endpoint = path_array[1] !== undefined ? '/' + path_array[1] : ''; console.log(endpoint) let res = await httpClient.executeHttpRequest({ destinationName: action.dest }, { method: 'GET', url: action.url + action.verb + endpoint }); return res.data; } catch (err) { console.log(err.stack); return err.message; } } } } scaleConfig: maxReplicas: 5 minReplicas: 3 resourceConfiguration: function: profile: S env: ## https://kyma-project.io/docs/kyma/latest/05-technical-reference/00-configuration-parameters/svls-02-environment-variables/#node-js-runtime-specific-environment-variables - name: FUNC_TIMEOUT ## Specifies the number of seconds in which a runtime must execute the code. value: '1800' - name: REQ_MB_LIMIT ## payload body size limit in megabytes. value: "10" - name: DEBUG value: '{{ .Values.services.srv.name }}:*' - name: SERVICE_BINDING_ROOT value: /bindings secretMounts: - secretName: {{ .Values.services.sm.bindingSecretName }} mountPath: "/bindings/saas-sm" - secretName: {{ .Values.services.dest.bindingSecretNamex509 }} mountPath: "/bindings/faas-dest-x509"</code></pre><P>&nbsp;</P> 2024-05-13T12:54:57.123000+02:00