SAP Cloud Foundry – Python and Cloud Connector – TCP

Estimated read time 18 min read

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.

SAP Cloud Foundry is the Platform-as-a-service offering on BTP to build all kinds of Apps, Integration and nowadays also AI functionalities. 

In this blog post, we will walk you through the process of establishing connectivity to an on-premises TCP-based system using Python within the Cloud Foundry runtime.

Accessing TCP-Based Resources

Scenario: The objective is to establish a connection to a TCP-based system using Python within SAP Cloud Foundry. Many commonly used systems, such as databases like SAP HANA, PostgreSQL, and MySQL, as well as protocols like SSH and SFTP, rely on TCP for communication.

To achieve this, we will configure the Cloud Connector, a crucial tool for enabling secure communication between SAP Cloud Foundry and on-premises systems. For demonstration purposes, we will use a simple “Hello TCP” server running locally on my computer. The goal is to successfully connect to this server from within SAP Cloud Foundry using the Cloud Connector.

Prerequisite:

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 (https://blogs.sap.com/2021/09/05/installation-and-configuration-of-sap-cloud-connector/) to install and configure the cloud connector.

The second requirement is a BTP subaccount with a Data Intelligence cluster. To this Subaccount we will connect the Cloud Connector.

1. Configuration:

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 “Hello TCP!”.

 

 

telnet localhost 4444

Connecting to localhost …

Hello TCP!

 

To create the configuration, navigate to the admin interface for the cloud connector and create a “Cloud to On-Premise” configuration.

Cloud Connector configuration

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.

BTP Cockpit Cloud Connector Resources

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.

2. Create Connectivity Service instance:

To use the Cloud Connector from our runtime environment, we first need a connectivity service instance. Here’s how to do it:

In the BTP Cockpit, go to your desired Subaccount and create a new service instance, as shown below.

 

We use the “Connectivity Service” with the plan “lite”. Give the service instance a name, assign it to a space, and click create.

 

The important credentials are stored in a service key. To get these credentials, we create a service key.

 

{
“clientid”: “sb-sampleclientid!b3008|connectivity!b137”,
“clientsecret”: “****-****-****-****”,
“url”: “https://tenant_name.authentication.sap.hana.ondemand.com”,
“identityzone”: “sample-zone”,
“tenantid”: “xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,
“tenantmode”: “dedicated”,
“verificationkey”: “—–BEGIN PUBLIC KEY—–nXXXXXX…n—–END PUBLIC KEY—–“,
“xsappname”: “sampleappname!b3008|connectivity!b137”,
“uaadomain”: “authentication.sap.hana.ondemand.com”,
“credential-type”: “binding-secret”,
“onpremise_proxy_host”: “connectivityproxy.internal.cf.sap.hana.ondemand.com”,
“onpremise_proxy_http_port”: “20003”,
“onpremise_proxy_ldap_port”: “20001”,
“onpremise_proxy_port”: “20003”,
“onpremise_proxy_rfc_port”: “20001”,
“onpremise_socks5_proxy_port”: “20004”,
“token_service_domain”: “authentication.sap.hana.ondemand.com”,
“token_service_url”: “https://tenant_name.authentication.sap.hana.ondemand.com”
}

 

We now have a set of credentials, as shown above. The key details are:

OAuth Credentials: These include the “clientid”, “clientsecret”, and “url”. They are used to authenticate when accessing the proxy.

Proxy Details: These include the “onpremise_proxy_host” and the various ports, such as “onpremise_proxy_port”, “onpremise_proxy_http_port”, and “onpremise_socks5_proxy_port”. These details are configured as the proxy to route traffic. The proxy securely tunnels requests through the Cloud Connector to the on-premise destination.

3. Developing a Cloud Foundry App:

Now let’s put this together in a simple Python example to perform an actual TCP request:

The Python script will send a request using Python’s standard socket library. We use the connection details provided by the Connectivity Service Service Key. To route the traffic through the Cloud Connector, we specify the proxy configuration, including the host, port, and the proxy-authentication header.

To realize the connection to the Connectivity Proxy, we will be using the sapcloudconnectorpythonsocket library I created for this purpose. This is a seperate dependency and needs to be included into the requirements file. The reason we cannot use standard library’s like PySocks to connect to the connectivity service, is the custom authentication flow used.

The actual script looks straightforward:

 

import requests
from sapcloudconnectorpythonsocket import CloudConnectorSocket

# Connectivity Service Service Key
connectivity_service_key = {
“clientid”: “sb-sampleclientid!b3008|connectivity!b137”,
“clientsecret”: “****-****-****-****”,
“url”: “https://tenant_name.authentication.sap.hana.ondemand.com”,
“identityzone”: “sample-zone”,
“tenantid”: “xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,
“tenantmode”: “dedicated”,
“verificationkey”: “—–BEGIN PUBLIC KEY—–nXXXXXX…n—–END PUBLIC KEY—–“,
“xsappname”: “sampleappname!b3008|connectivity!b137”,
“uaadomain”: “authentication.sap.hana.ondemand.com”,
“credential-type”: “binding-secret”,
“onpremise_proxy_host”: “connectivityproxy.internal.cf.sap.hana.ondemand.com”,
“onpremise_proxy_http_port”: “20003”,
“onpremise_proxy_ldap_port”: “20001”,
“onpremise_proxy_port”: “20003”,
“onpremise_proxy_rfc_port”: “20001”,
“onpremise_socks5_proxy_port”: “20004”,
“token_service_domain”: “authentication.sap.hana.ondemand.com”,
“token_service_url”: “https://tenant_name.authentication.sap.hana.ondemand.com”
}

# Target Application Details (replace with your app information)
application_host = “virtualhost”
application_port = 4444
location_id = “FELIXLAPTOP” # Adjust to match your Cloud Connector location

def get_connectivity_service_token(client_id, client_secret, token_service_url):
“””
Fetches an OAuth token from the SAP Connectivity Service.
“””
response = requests.post(
url=token_service_url,
params={“grant_type”: “client_credentials”},
auth=(client_id, client_secret)
)

if response.status_code != 200:
print(f”Error: {response.status_code} – {response.text}”)
exit(-1)

return response.json().get(“access_token”)

def example_tcp_request(host, port, auth_token, location_id, proxy_host, proxy_port):
“””
Performs an TCP request through SAP Cloud Connector.
“””
cc_socket = CloudConnectorSocket()
cc_socket.connect(
dest_host=host,
dest_port=port,
proxy_host=proxy_host,
proxy_port=proxy_port,
token=auth_token,
location_id=location_id
)

cc_socket.send(b””)

response = cc_socket.recv(4096)
return response

# Fetch OAuth Token
print(“Fetching OAuth token…”)
token = get_connectivity_service_token(
connectivity_service_key[“clientid”],
connectivity_service_key[“clientsecret”],
connectivity_service_key[“token_service_url”] + “/oauth/token”
)
print(“Token acquired successfully.”)

# Perform TCP Request
print(“Sending TCP request through SAP Cloud Connector…”)
response = example_tcp_request(application_host, application_port, token, location_id, connectivity_service_key[“onpremise_proxy_host”], int(connectivity_service_key[“onpremise_socks5_proxy_port”]))
print(“Response received:”)
print(response)

print(“Script execution completed.”)

 

Let’s break down the steps performed in the script:

Authentication
The script begins by authenticating with the OAuth endpoint using the details from the service key in

get_connectivity_service_token. This step retrieves a Bearer Token, which is required to access the Connectivity Proxy.

Establishing the Connection
Next, the example_tcp_request function is called to send a sample request. This function establishes a connection to the target system via the SAP Cloud Connector. Under the hood, this involves multiple TCP request exchanges, during which the authentication token and location ID are passed. This process results in an open connection through the secure tunnel created by the Cloud Connector.

Using the SOCKS5 Proxy Port
A key detail to note is that the script uses the SOCKS5 proxy port instead of the standard HTTP proxy port of the Connectivity Service. Looking at the service key of a Connectivity Service instance provides clarity:

HTTP Proxy Port: 20003SOCKS5/TCP Proxy Port: 20004

The SOCKS5 port (20004) is explicitly specified when opening the socket, as it is required for TCP communication in this context.

Sending and Receiving Data
With the socket successfully opened, the script sends a request to the TCP server. In this example, an empty request body is sent, and the local server should respond with “Hello TCP!” for every request.

To make it deployable on Cloud Foundry, we add a standard manifest.yaml file.

 


applications:
– name: cloud_connector_test_task
memory: 128MB
buildpack: python_buildpack
command: python app.py

 

It sets the buildpack to python_buildpack.

Additionally, we include a requirements.txt file in the directory.

 

 

requests
sapcloudconnectorpythonsocket

 

 

Ending up with the following structure:

 

my-python-cloud-connector-app/

├── manifest.yaml
├── requirements.txt
├── app.py (or your main Python script)

 

Note: The script we created obviously does not run on our local environment. Because a) we cannot connect to the connectivity service from outside of the BTP and b) the destination URL is not reachable from our local environment. In this blog, I show how to use a hybrid testing setup to develop against backend resources that  are behind the cloud connector.

4. Testing the Application:

Now lets deploy using the following command:

 

cf push cloud_connector_test_task –task

 

You push your script as a task (one-time executable) to the Cloud Foundry space. Then, you start the task using the following command:

 

cf run-task cloud_connector_test_task –command “python app.py” –name example_task
cf logs cloud_connector_test_task –recent

 

This will show the logs from the latest task execution. It may take a few seconds for the task to start and complete.

In the logs, if everything worked correctly, you should see the “Hello TCP!” message from your on-premises machine, confirming that the connection through the Cloud Connector was successful.

 

2024-12-18T23:30:15.23+0100 [APP/TASK/example_task/0] OUT Fetching OAuth token…
2024-12-18T23:30:15.38+0100 [APP/TASK/example_task/0] OUT Token acquired successfully.
2024-12-18T23:30:15.38+0100 [APP/TASK/example_task/0] OUT Sending TCP request through SAP Cloud Connector…
2024-12-18T23:30:15.53+0100 [APP/TASK/example_task/0] OUT Response received:
2024-12-18T23:30:15.53+0100 [APP/TASK/example_task/0] OUT b’Hello TCP!’
2024-12-18T23:30:15.53+0100 [APP/TASK/example_task/0] OUT Script execution completed.

 

That means we were successful and the script was able to request the local TCP server on my windows machine. Checkout my similar blogpost targeting a example based on HTTP.

Hope you find the content of this blog helpful. Feel free to comment for further clarifications.

 

​ 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.SAP Cloud Foundry is the Platform-as-a-service offering on BTP to build all kinds of Apps, Integration and nowadays also AI functionalities. In this blog post, we will walk you through the process of establishing connectivity to an on-premises TCP-based system using Python within the Cloud Foundry runtime.Accessing TCP-Based ResourcesScenario: The objective is to establish a connection to a TCP-based system using Python within SAP Cloud Foundry. Many commonly used systems, such as databases like SAP HANA, PostgreSQL, and MySQL, as well as protocols like SSH and SFTP, rely on TCP for communication.To achieve this, we will configure the Cloud Connector, a crucial tool for enabling secure communication between SAP Cloud Foundry and on-premises systems. For demonstration purposes, we will use a simple “Hello TCP” server running locally on my computer. The goal is to successfully connect to this server from within SAP Cloud Foundry using the Cloud Connector.Prerequisite: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 (https://blogs.sap.com/2021/09/05/installation-and-configuration-of-sap-cloud-connector/) to install and configure the cloud connector.The second requirement is a BTP subaccount with a Data Intelligence cluster. To this Subaccount we will connect the Cloud Connector.1. Configuration: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 “Hello TCP!”.  telnet localhost 4444

Connecting to localhost …

Hello TCP! To create the configuration, navigate to the admin interface for the cloud connector and create a “Cloud to On-Premise” configuration.Cloud Connector configurationIn 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.BTP Cockpit Cloud Connector ResourcesOn 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.2. Create Connectivity Service instance:To use the Cloud Connector from our runtime environment, we first need a connectivity service instance. Here’s how to do it:In the BTP Cockpit, go to your desired Subaccount and create a new service instance, as shown below. We use the “Connectivity Service” with the plan “lite”. Give the service instance a name, assign it to a space, and click create. The important credentials are stored in a service key. To get these credentials, we create a service key. {
“clientid”: “sb-sampleclientid!b3008|connectivity!b137”,
“clientsecret”: “****-****-****-****”,
“url”: “https://tenant_name.authentication.sap.hana.ondemand.com”,
“identityzone”: “sample-zone”,
“tenantid”: “xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,
“tenantmode”: “dedicated”,
“verificationkey”: “—–BEGIN PUBLIC KEY—–nXXXXXX…n—–END PUBLIC KEY—–“,
“xsappname”: “sampleappname!b3008|connectivity!b137”,
“uaadomain”: “authentication.sap.hana.ondemand.com”,
“credential-type”: “binding-secret”,
“onpremise_proxy_host”: “connectivityproxy.internal.cf.sap.hana.ondemand.com”,
“onpremise_proxy_http_port”: “20003”,
“onpremise_proxy_ldap_port”: “20001”,
“onpremise_proxy_port”: “20003”,
“onpremise_proxy_rfc_port”: “20001”,
“onpremise_socks5_proxy_port”: “20004”,
“token_service_domain”: “authentication.sap.hana.ondemand.com”,
“token_service_url”: “https://tenant_name.authentication.sap.hana.ondemand.com”
} We now have a set of credentials, as shown above. The key details are:OAuth Credentials: These include the “clientid”, “clientsecret”, and “url”. They are used to authenticate when accessing the proxy.Proxy Details: These include the “onpremise_proxy_host” and the various ports, such as “onpremise_proxy_port”, “onpremise_proxy_http_port”, and “onpremise_socks5_proxy_port”. These details are configured as the proxy to route traffic. The proxy securely tunnels requests through the Cloud Connector to the on-premise destination.3. Developing a Cloud Foundry App:Now let’s put this together in a simple Python example to perform an actual TCP request:The Python script will send a request using Python’s standard socket library. We use the connection details provided by the Connectivity Service Service Key. To route the traffic through the Cloud Connector, we specify the proxy configuration, including the host, port, and the proxy-authentication header.To realize the connection to the Connectivity Proxy, we will be using the sapcloudconnectorpythonsocket library I created for this purpose. This is a seperate dependency and needs to be included into the requirements file. The reason we cannot use standard library’s like PySocks to connect to the connectivity service, is the custom authentication flow used.The actual script looks straightforward: import requests
from sapcloudconnectorpythonsocket import CloudConnectorSocket

# Connectivity Service Service Key
connectivity_service_key = {
“clientid”: “sb-sampleclientid!b3008|connectivity!b137”,
“clientsecret”: “****-****-****-****”,
“url”: “https://tenant_name.authentication.sap.hana.ondemand.com”,
“identityzone”: “sample-zone”,
“tenantid”: “xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,
“tenantmode”: “dedicated”,
“verificationkey”: “—–BEGIN PUBLIC KEY—–nXXXXXX…n—–END PUBLIC KEY—–“,
“xsappname”: “sampleappname!b3008|connectivity!b137”,
“uaadomain”: “authentication.sap.hana.ondemand.com”,
“credential-type”: “binding-secret”,
“onpremise_proxy_host”: “connectivityproxy.internal.cf.sap.hana.ondemand.com”,
“onpremise_proxy_http_port”: “20003”,
“onpremise_proxy_ldap_port”: “20001”,
“onpremise_proxy_port”: “20003”,
“onpremise_proxy_rfc_port”: “20001”,
“onpremise_socks5_proxy_port”: “20004”,
“token_service_domain”: “authentication.sap.hana.ondemand.com”,
“token_service_url”: “https://tenant_name.authentication.sap.hana.ondemand.com”
}

# Target Application Details (replace with your app information)
application_host = “virtualhost”
application_port = 4444
location_id = “FELIXLAPTOP” # Adjust to match your Cloud Connector location

def get_connectivity_service_token(client_id, client_secret, token_service_url):
“””
Fetches an OAuth token from the SAP Connectivity Service.
“””
response = requests.post(
url=token_service_url,
params={“grant_type”: “client_credentials”},
auth=(client_id, client_secret)
)

if response.status_code != 200:
print(f”Error: {response.status_code} – {response.text}”)
exit(-1)

return response.json().get(“access_token”)

def example_tcp_request(host, port, auth_token, location_id, proxy_host, proxy_port):
“””
Performs an TCP request through SAP Cloud Connector.
“””
cc_socket = CloudConnectorSocket()
cc_socket.connect(
dest_host=host,
dest_port=port,
proxy_host=proxy_host,
proxy_port=proxy_port,
token=auth_token,
location_id=location_id
)

cc_socket.send(b””)

response = cc_socket.recv(4096)
return response

# Fetch OAuth Token
print(“Fetching OAuth token…”)
token = get_connectivity_service_token(
connectivity_service_key[“clientid”],
connectivity_service_key[“clientsecret”],
connectivity_service_key[“token_service_url”] + “/oauth/token”
)
print(“Token acquired successfully.”)

# Perform TCP Request
print(“Sending TCP request through SAP Cloud Connector…”)
response = example_tcp_request(application_host, application_port, token, location_id, connectivity_service_key[“onpremise_proxy_host”], int(connectivity_service_key[“onpremise_socks5_proxy_port”]))
print(“Response received:”)
print(response)

print(“Script execution completed.”) Let’s break down the steps performed in the script:AuthenticationThe script begins by authenticating with the OAuth endpoint using the details from the service key inget_connectivity_service_token. This step retrieves a Bearer Token, which is required to access the Connectivity Proxy.Establishing the ConnectionNext, the example_tcp_request function is called to send a sample request. This function establishes a connection to the target system via the SAP Cloud Connector. Under the hood, this involves multiple TCP request exchanges, during which the authentication token and location ID are passed. This process results in an open connection through the secure tunnel created by the Cloud Connector.Using the SOCKS5 Proxy PortA key detail to note is that the script uses the SOCKS5 proxy port instead of the standard HTTP proxy port of the Connectivity Service. Looking at the service key of a Connectivity Service instance provides clarity:HTTP Proxy Port: 20003SOCKS5/TCP Proxy Port: 20004The SOCKS5 port (20004) is explicitly specified when opening the socket, as it is required for TCP communication in this context.Sending and Receiving DataWith the socket successfully opened, the script sends a request to the TCP server. In this example, an empty request body is sent, and the local server should respond with “Hello TCP!” for every request.To make it deployable on Cloud Foundry, we add a standard manifest.yaml file. —
applications:
– name: cloud_connector_test_task
memory: 128MB
buildpack: python_buildpack
command: python app.py It sets the buildpack to python_buildpack.Additionally, we include a requirements.txt file in the directory.  requests
sapcloudconnectorpythonsocket  Ending up with the following structure: my-python-cloud-connector-app/

├── manifest.yaml
├── requirements.txt
├── app.py (or your main Python script) Note: The script we created obviously does not run on our local environment. Because a) we cannot connect to the connectivity service from outside of the BTP and b) the destination URL is not reachable from our local environment. In this blog, I show how to use a hybrid testing setup to develop against backend resources that  are behind the cloud connector.4. Testing the Application:Now lets deploy using the following command: cf push cloud_connector_test_task –task You push your script as a task (one-time executable) to the Cloud Foundry space. Then, you start the task using the following command: cf run-task cloud_connector_test_task –command “python app.py” –name example_task
cf logs cloud_connector_test_task –recent This will show the logs from the latest task execution. It may take a few seconds for the task to start and complete.In the logs, if everything worked correctly, you should see the “Hello TCP!” message from your on-premises machine, confirming that the connection through the Cloud Connector was successful. 2024-12-18T23:30:15.23+0100 [APP/TASK/example_task/0] OUT Fetching OAuth token…
2024-12-18T23:30:15.38+0100 [APP/TASK/example_task/0] OUT Token acquired successfully.
2024-12-18T23:30:15.38+0100 [APP/TASK/example_task/0] OUT Sending TCP request through SAP Cloud Connector…
2024-12-18T23:30:15.53+0100 [APP/TASK/example_task/0] OUT Response received:
2024-12-18T23:30:15.53+0100 [APP/TASK/example_task/0] OUT b’Hello TCP!’
2024-12-18T23:30:15.53+0100 [APP/TASK/example_task/0] OUT Script execution completed. That means we were successful and the script was able to request the local TCP server on my windows machine. Checkout my similar blogpost targeting a example based on HTTP.Hope you find the content of this blog helpful. Feel free to comment for further clarifications.   Read More Technology Blogs by SAP articles 

#SAP

#SAPTechnologyblog

You May Also Like

More From Author