{"id":70,"date":"2026-07-16T16:18:46","date_gmt":"2026-07-16T15:18:46","guid":{"rendered":"https:\/\/blog.gindox.com\/?p=70"},"modified":"2026-07-16T16:18:46","modified_gmt":"2026-07-16T15:18:46","slug":"omni-with-entraid-and-on-prem-ad-ca","status":"publish","type":"post","link":"https:\/\/blog.gindox.com\/?p=70","title":{"rendered":"Omni with EntraID and on-prem AD CA"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/docs.siderolabs.com\/omni\/self-hosted\/run-omni-on-prem\">https:\/\/docs.siderolabs.com\/omni\/self-hosted\/run-omni-on-prem<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Skip steps 4.1 and 4.2 entirely since we are using our own AD CA.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Step 4.3 I remove the auth endpoint from the SSL cert since we are going to authenticate with EntraID<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat &lt;&lt;EOF > wildcard-csr.json\n{\n  \"CN\": \"omni.#####.####\",\n  \"hosts\": &#91;\n    \"${OMNI_ENDPOINT}\",\n    \"127.0.0.1\",\n    \"${HOST_PUBLIC_IP}\",\n    \"${HOST_PRIVATE_IP}\"\n  ],\n  \"key\": { \"algo\": \"rsa\", \"size\": 4096 }\n}\nEOF\n\ncfssl genkey wildcard-csr.json | cfssljson -bare server<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That gives you server-key.pem (stays on the Omni host) and server.csr. Submit the CSR to your AD CA<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then convert it  <br><br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openssl x509 -inform der -in server.cer -out server.pem\n\ncat server.pem issuing-ca.pem root-ca.pem > server-chain.pem\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Omni supports generic OIDC natively now (since 1.2.0), and step 7.4 in the current guide is already using it \u2014 it just points at the local Dex container. To use Entra ID directly you swap the provider URL and credentials, and you get to delete Dex from the setup entirely.<br>Entra side \u2014 app registration:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Entra ID \u2192 App registrations \u2192 New registration. Single tenant is fine.<br><br>Platform: Web, redirect URI: https:\/\/\/oidc\/consume \u2014 that&#8217;s Omni&#8217;s OIDC callback path (you can see it in the guide&#8217;s Dex config, where it&#8217;s registered as the allowed redirectURIs for the omni client). Entra accepts non-public hostnames like omni.internal as long as it&#8217;s HTTPS.<br><br>Certificates &amp; secrets \u2192 new client secret (Omni only supports secret auth, not cert-based client auth). Note the expiry \u2014 max 24 months, so calendar the rotation.<br><br>Token configuration \u2192 add the email optional claim to the ID token, and make sure your account actually has the mail attribute populated. This matters because Omni identifies users purely by the email claim, and Entra ID tokens frequently omit it by default \u2014 if it&#8217;s missing, login will succeed at Entra and fail at Omni.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The following is important when using EntraID<br><code>--auth-oidc-allow-unverified-email=true<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export EULA_NAME=\"Grzegorz\"\nexport EULA_EMAIL=\"########@######.###\"\n\ndocker run -d \\\n  --name omni \\\n  --net=host \\\n  --cap-add=NET_ADMIN \\\n  --device \/dev\/net\/tun:\/dev\/net\/tun \\\n  --restart=unless-stopped \\\n  -v \/opt\/omni\/ca.pem:\/etc\/ssl\/certs\/ca-certificates.crt:ro,Z \\\n  -v \/opt\/omni\/server-key.pem:\/server-key.pem:ro,Z \\\n  -v \/opt\/omni\/server-chain.pem:\/server-chain.pem:ro,Z \\\n  -v \/opt\/omni\/omni.asc:\/omni.asc:ro,Z \\\n  -v \/opt\/omni\/sqlite:\/_out\/sqlite:rw,Z \\\n  ghcr.io\/siderolabs\/omni:${OMNI_VERSION} \\\n    --name=omni \\\n    --cert=\/server-chain.pem \\\n    --key=\/server-key.pem \\\n    --machine-api-cert=\/server-chain.pem \\\n    --machine-api-key=\/server-key.pem \\\n    --machine-api-bind-addr=0.0.0.0:8090 \\\n    --private-key-source=file:\/\/\/omni.asc \\\n    --event-sink-port=8091 \\\n    --bind-addr=0.0.0.0:443 \\\n    --k8s-proxy-bind-addr=0.0.0.0:8100 \\\n    --advertised-api-url=https:\/\/${OMNI_ENDPOINT}\/ \\\n    --siderolink-api-advertised-url=https:\/\/${OMNI_ENDPOINT}:8090\/ \\\n    --siderolink-wireguard-advertised-addr=${HOST_PUBLIC_IP}:50180 \\\n    --advertised-kubernetes-proxy-url=https:\/\/${OMNI_ENDPOINT}:8100\/ \\\n\t--auth-auth0-enabled=false \\\n\t--auth-oidc-enabled=true \\\n\t--auth-oidc-provider-url=https:\/\/login.microsoftonline.com\/#########-####-####-#######\/v2.0 \\\n\t--auth-oidc-client-id=#####-####-####-####-########## \\\n\t--auth-oidc-client-secret=######################### \\\n\t--auth-oidc-scopes=openid \\\n\t--auth-oidc-scopes=profile \\\n\t--auth-oidc-scopes=email \\\n\t--sqlite-storage-path=\/_out\/sqlite\/omni.db \\\n\t--initial-users=########@######.### \\\n    --eula-accept-name=\"${EULA_NAME}\" \\\n    --eula-accept-email=\"${EULA_EMAIL}\" \\\n\t--auth-oidc-allow-unverified-email=true\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>https:\/\/docs.siderolabs.com\/omni\/self-hosted\/run-omni-on-prem Skip steps 4.1 and 4.2 entirely since we are using our own AD CA. Step 4.3 I remove the auth endpoint from the SSL [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-70","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.gindox.com\/index.php?rest_route=\/wp\/v2\/posts\/70","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.gindox.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.gindox.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.gindox.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.gindox.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=70"}],"version-history":[{"count":1,"href":"https:\/\/blog.gindox.com\/index.php?rest_route=\/wp\/v2\/posts\/70\/revisions"}],"predecessor-version":[{"id":72,"href":"https:\/\/blog.gindox.com\/index.php?rest_route=\/wp\/v2\/posts\/70\/revisions\/72"}],"wp:attachment":[{"href":"https:\/\/blog.gindox.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=70"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.gindox.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=70"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.gindox.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=70"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}