
Conditional Access Policy – Building Real MFA Enforcement in Microsoft Entra ID
July 8, 2026
350 – Microsoft Tech Updates
July 9, 2026
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
| Requirement | Notes |
|---|---|
| Azure subscription | With rights to create Arc resources, custom locations, and connected environments. |
| Azure CLI | Latest, with the connectedk8s, k8s-extension, customlocation, and containerapp extensions. |
| OpenShift cluster | Self-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 share | a SMB file share discoverable from the cluster to store workflow artifacts |
| Ingress / load balancer | On 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:
| Option | How it works | You set up | Best when |
|---|---|---|---|
| In-cluster load balancer | A 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 way | Install the controller + an address pool; envoy.serviceType=LoadBalancer | You have a spare IP range on the node network and want a self-contained cluster |
| External LB + NodePort | Any 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 region | envoy.serviceType=NodePort; wire your LB → NodePort | You 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 -u kubeadmin oc whoami # should be able to run cluster-admin actions
Connect the cluster to Arc:
az connectedk8s connect –name –resource-group
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 –cluster-name –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=” –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:
| Setting | Why |
|---|---|
| Azure.Cluster.Distribution=openshift | Renders the chart’s OpenShift branch with the privileged security contexts OpenShift requires. |
| coreDNSVersion=1.8.6 | Makes 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 –cluster-name –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 )
Step 5: Create a custom location
EXT_ID=$(az k8s-extension show -g –cluster-name
–cluster-type connectedClusters –name logicapps-aca-extension –query id -o tsv)
CC_ID=$(az connectedk8s show -g -n –query id -o tsv)
az customlocation create
–resource-group –name
–location –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 . 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 -n –query id -o tsv)
az containerapp connected-env create
–resource-group –name
–location –custom-location $CL_ID
–static-ip # 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
| Symptom | Cause & fix |
|---|---|
| Extension install fails and rolls back with SCC/PodSecurity denials | SCCs not granted before install. Grant anyuid + privileged + hostnetwork to the install namespace (Step 2), then retry. |
| UnauthorizedNamespaceError / 401 during onboarding | Custom-locations RBAC incomplete. Re-run enable-features … –custom-locations-oid ; ensure the caller has Contributor/Azure Arc Kubernetes Cluster Admin. |
| App pods stuck ContainerCreating, PVC Pending | SMB 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 metal | No 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
- Install OpenShift on bare metal
- Install Single-Node OpenShift (SNO)
- Create an Azure Red Hat OpenShift (ARO) cluster
- OpenShift Local (run a cluster on your laptop)
Logic Apps Hybrid