Blog Post

Azure Integration Services Blog
6 MIN READ

Hybrid Logic Apps Deployment on Red Hat OpenShift

anandgmenon's avatar
anandgmenon
Icon for Microsoft rankMicrosoft
Jul 08, 2026

Azure Logic Apps Hybrid runs the Logic Apps runtime on your own Kubernetes cluster (on-premises or at the edge) while you keep authoring, deploying, and monitoring it from Azure. This walkthrough covers self-managed Red Hat OpenShift, where most Hybrid deployments run. It works on Azure Red Hat OpenShift (ARO) too with a few caveats.

 

What makes OpenShift different?

If you've done this on K3s or AKS, most of the flow is identical as mentioned in Set up your own infrastructure for Standard logic app workflows - Azure Logic Apps | Microsoft Learn. Two OpenShift specifics are worth flagging up front. First, SCCs: the default restricted-v2 policy blocks the elevated permissions the runtime and CSI driver need, so you grant the right SCCs before installing (Step 2). Second, DNS: OpenShift runs DNS through the openshift-dns operator rather than the kube-system/coredns you'd find on AKS, so the DNS setup targets that instead (Step 7).

Prerequisites

RequirementNotes
Azure subscriptionWith rights to create Arc resources, custom locations, and connected environments.
Azure CLILatest, with the connectedk8s, k8s-extension, customlocation, and containerapp extensions.
OpenShift clusterSelf-managed OpenShift (bare metal, datacenter, or Single-Node OpenShift), or ARO. oc logged in as a cluster-admin. Newer OCP is better (some storage options are GA only on 4.18+). 

 Don't have one yet? See the install links under References section below

A SMB file sharea SMB file share discoverable from the cluster to store workflow artifacts
Ingress / load balancerOn self-managed OpenShift you provide the ingress IP yourself: an in-cluster LB (MetalLB or similar) or an external L4 LB in front of a NodePort. See Choose your ingress path below. (ARO provides it automatically.)

 

Install/confirm the CLI extensions:

az extension add --name connectedk8s az extension add --name k8s-extension az extension add --name customlocation az extension add --name containerapp

Choose your ingress path (self-managed)

Every app is reached through one shared Envoy ingress, and that ingress needs an IP clients can hit. A self-managed cluster has no cloud load balancer to hand one out, so this is the piece you provide. Two options work well; pick whichever fits your environment:

OptionHow it worksYou set upBest when
In-cluster load balancerA bare-metal LoadBalancer controller gives the envoy LoadBalancer service an IP from a pool on your node subnet. MetalLB is the common pick; kube-vip, Cilium, and OpenELB work the same wayInstall the controller + an address pool; envoy.serviceType=LoadBalancerYou have a spare IP range on the node network and want a self-contained cluster
External LB + NodePortAny external L4 load balancer forwards to a NodePort on every node. That can be an appliance (F5, NetScaler, HAProxy, a hardware VIP…) or an Azure Standard Load Balancer when your nodes are Azure VMs in the same regionenvoy.serviceType=NodePort; wire your LB → NodePortYou already run a datacenter load balancer, or your cluster runs on Azure VMs

Your choice affects exactly two later steps: the envoy.serviceType value in Step 4, and which IP you pass to --static-ip in Step 6. Nothing else changes.

On ARO you can skip this section. Leave envoy.serviceType=LoadBalancer and the cloud controller assigns the EXTERNAL-IP for you; the rest of the guide is unchanged.

Step 1: Connect your OpenShift cluster to Azure Arc

Log in to OpenShift and confirm you're cluster-admin:

oc login <api-url> -u kubeadmin oc whoami # should be able to run cluster-admin actions

Connect the cluster to Arc:

az connectedk8s connect --name <cluster> --resource-group <rg>

Step 2: Install the SMB CSI driver

helm repo add csi-driver-smb https://raw.githubusercontent.com/kubernetes-csi/csi-driver-smb/master/charts helm repo update helm install csi-driver-smb csi-driver-smb/csi-driver-smb \ --namespace kube-system --version v1.16.0 \ --set image.smb.repository=mcr.microsoft.com/oss/kubernetes-csi/csi-driver-smb

Step 3: Grant the required SCCs (OpenShift-specific)

The extension installs with Helm --atomic, so if any pod is denied byrestricted-v2 the entire install rolls back. Grant the SCCs to the install
namespace's service accounts before installing:

oc create namespace logicapps-aca-ns 
oc adm policy add-scc-to-group anyuid system:serviceaccounts:logicapps-aca-ns 
oc adm policy add-scc-to-group privileged system:serviceaccounts:logicapps-aca-ns 
oc adm policy add-scc-to-group hostnetwork system:serviceaccounts:logicapps-aca-ns

Step 4: Install the Container Apps extension

Now install the extension that turns the cluster into a Logic Apps host. The command is the same for every cluster; the only line that depends on your ingress choice is the last one, envoy.serviceType:

az k8s-extension create \ 
--resource-group <rg> --cluster-name <cluster> \
--cluster-type connectedClusters --name logicapps-aca-extension \ 
--extension-type Microsoft.App.Environment \ 
--release-train stable --auto-upgrade-minor-version true --scope cluster \ 
--release-namespace logicapps-aca-ns \ 
--configuration-settings "Microsoft.CustomLocation.ServiceAccount=default" \ 
--configuration-settings "appsNamespace=logicapps-aca-ns" \ 
--configuration-settings "clusterName=<env-name>" \ 
--configuration-settings "keda.enabled=true" \ 
--configuration-settings "keda.logicAppsScaler.enabled=true" \ 
--configuration-settings "keda.logicAppsScaler.replicaCount=1" \
--configuration-settings "containerAppController.api.functionsServerEnabled=true" \ 
--configuration-settings "functionsProxyApiConfig.enabled=true" \ 
--configuration-settings "Azure.Cluster.Distribution=openshift" \ 
--configuration-settings "coreDNSVersion=1.8.6" \ 
--configuration-settings "envoy.serviceType=LoadBalancer"

The two OpenShift-specific settings:

SettingWhy
Azure.Cluster.Distribution=openshiftRenders the chart's OpenShift branch with the privileged security contexts OpenShift requires.
coreDNSVersion=1.8.6Makes the DNS config the setup generates compatible with OpenShift's resolver so app hostnames resolve. Keep this value.

Ingress setting, per your path:

  • In-cluster LB (e.g. MetalLB) → envoy.serviceType=LoadBalancer (as above); the LB controller assigns the EXTERNAL-IP from your pool.
  • External LB (on-prem) → envoy.serviceType=NodePort plus envoy.nodeHttpsPort=30443 and envoy.nodeHttpPort=30080, then point your
    external L4 LB at those NodePorts.
  • ARO → leave envoy.serviceType=LoadBalancer; Azure assigns the EXTERNAL-IP automatically.

Wait for the extension and read the ingress IP:

az k8s-extension show -g <rg> --cluster-name <cluster> \ --cluster-type connectedClusters --name logicapps-aca-extension \ --query provisioningState -o tsv # -> Succeeded oc get svc microsoft-app-environment-k8se-envoy -n logicapps-aca-ns # LoadBalancer: EXTERNAL-IP | NodePort: 80:30080, 443:30443 (EXTERNAL-IP stays <none>)
sample of envoy service using external LB

 

 

Step 5: Create a custom location

EXT_ID=$(az k8s-extension show -g <rg> --cluster-name <cluster> \
  --cluster-type connectedClusters --name logicapps-aca-extension --query id -o tsv)
CC_ID=$(az connectedk8s show -g <rg> -n <cluster> --query id -o tsv)

az customlocation create \
  --resource-group <rg> --name <custom-location> \
  --location <arc-region> --host-resource-id $CC_ID \
  --namespace logicapps-aca-ns --cluster-extension-ids $EXT_ID

Step 6: Create the connected environment

The connected environment is the Logic Apps environment your apps live in. Whether you set --static-ip depends on your ingress:

  • External LB + NodePort: pass --static-ip <your LB VIP>. The envoy service is a NodePort with no EXTERNAL-IP, so the platform can't discover the ingress IP on its own; you give it the LB VIP explicitly.
  • In-cluster LB (MetalLB) or ARO: you can omit --static-ip. The platform uses the EXTERNAL-IP already assigned to the envoy LoadBalancer service. 
CL_ID=$(az customlocation show -g <rg> -n <custom-location> --query id -o tsv)

az containerapp connected-env create \
  --resource-group <rg> --name <env-name> \
  --location <arc-region> --custom-location $CL_ID \
  --static-ip <your-lb-vip>          # external LB + NodePort; omit for in-cluster LB / ARO

When you do set --static-ip, it's create-only. You can't patch it later; to change it you delete and recreate the environment.

Step 7: Configure cluster DNS

So that app hostnames resolve to the Envoy ingress inside the cluster, run the DNS setup with the OpenShift flag:

az containerapp arc setup-core-dns --distro=openshift --verbose

This creates a small coredns-custom service and adds a zone-scoped forward in OpenShift's DNS Operator that covers only the environment's domain. Every other name (internet, *.svc.cluster.local, your own domains) is left alone.

Step 8: Create and deploy a Logic App

You can now target the connected environment from the portal or CLI, exactly like any Logic App Standard. In the portal, choose Logic App (Standard) → Hybrid, pick your connected environment, point storage at your SMB share, and create.

Once the logic app is ready, you are now ready to author and test workflows hosted in your openshift cluster.

Troubleshooting common issues

SymptomCause & fix
Extension install fails and rolls back with SCC/PodSecurity denialsSCCs not granted before install. Grant anyuid + privileged + hostnetwork to the install namespace (Step 2), then retry.
UnauthorizedNamespaceError / 401 during onboardingCustom-locations RBAC incomplete. Re-run enable-features … --custom-locations-oid <oid>; ensure the caller has Contributor/Azure Arc Kubernetes Cluster Admin.
App pods stuck ContainerCreating, PVC PendingSMB driver missing/misregistered. Confirm a smb.csi.k8s.io CSIDriver exists and its pods are Running. Install one driver only.
Envoy has no EXTERNAL-IP on bare metalNo LoadBalancer provider. Install an in-cluster LB (MetalLB or similar) or front NodePort with an external LB (ARO does this automatically).

 

References

Setting up an OpenShift cluster

Logic Apps Hybrid

Updated Jul 20, 2026
Version 2.0
No CommentsBe the first to comment