From 0d71a789c28d0e7036ef534e667cf2da2b41aa2d Mon Sep 17 00:00:00 2001 From: Robot Date: Fri, 19 Jun 2026 00:51:01 -0500 Subject: [PATCH] deploy(gx10): add DeviceManagement agent mTLS route --- apps-gx10/fc-devicemgmt/README.md | 20 ++++++--- .../certificate-devicemgmt-agent-tls.json | 18 ++++++++ .../deployment-fc-devicemgmt-web.json | 10 ++++- .../ingressroute-devicemgmt-agent-mtls.json | 42 +++++++++++++++++++ ...are-devicemgmt-agent-pass-client-cert.json | 13 ++++++ ...devicemgmt-agent-strip-forwarded-cert.json | 15 +++++++ .../tlsoption-devicemgmt-agent-mtls.json | 13 ++++++ 7 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 apps-gx10/fc-devicemgmt/certificate-devicemgmt-agent-tls.json create mode 100644 apps-gx10/fc-devicemgmt/ingressroute-devicemgmt-agent-mtls.json create mode 100644 apps-gx10/fc-devicemgmt/middleware-devicemgmt-agent-pass-client-cert.json create mode 100644 apps-gx10/fc-devicemgmt/middleware-devicemgmt-agent-strip-forwarded-cert.json create mode 100644 apps-gx10/fc-devicemgmt/tlsoption-devicemgmt-agent-mtls.json diff --git a/apps-gx10/fc-devicemgmt/README.md b/apps-gx10/fc-devicemgmt/README.md index 245fc18..424563d 100644 --- a/apps-gx10/fc-devicemgmt/README.md +++ b/apps-gx10/fc-devicemgmt/README.md @@ -1,7 +1,9 @@ # FlowerCore DeviceManagement on GX10 This adopted GX10 app hosts `FlowerCore.DeviceManagement.Web` at -`https://devices.iamworkin.lan`. +`https://devices.iamworkin.lan`. Agent-only REST/SignalR callbacks can use +`https://devices-agent.iamworkin.lan`, which is a separate Traefik router that +requires a TLS client certificate and forwards the presented PEM to the app. ## Apple MDM Runtime Contract @@ -35,10 +37,18 @@ DeviceManagement auth is enabled on GX10. The deployment maps `FlowerCore__Auth__ApiKey`; the unprefixed key keeps the MCP API key post-config path aligned with REST auth. Agent heartbeat, inventory, command poll, app-catalog, and command-result callbacks use the agent-specific authorization boundary: the -server validates a device client certificate when Kestrel receives one, and also -accepts only the scoped `DEVICE_MANAGEMENT_AGENT_API_KEY` via `Authorization: -Bearer` or `X-Agent-Api-Key` when TLS is terminated before the app. Operator write -endpoints must use `X-Api-Key`. +server validates a direct device client certificate when Kestrel receives one, +validates Traefik-forwarded client certificate PEM only on +`devices-agent.iamworkin.lan`, and also accepts only the scoped +`DEVICE_MANAGEMENT_AGENT_API_KEY` via `Authorization: Bearer` or +`X-Agent-Api-Key` as the fallback path. Operator write endpoints must use +`X-Api-Key`. + +The agent-only Traefik route currently uses `RequireAnyClientCert`; the +application remains the authorization boundary by matching the forwarded client +certificate thumbprint to the enrolled device record. Once DeviceManagement +exports a persistent enrollment CA bundle, switch this TLSOption to +`RequireAndVerifyClientCert` with that CA secret. ## Readiness Check diff --git a/apps-gx10/fc-devicemgmt/certificate-devicemgmt-agent-tls.json b/apps-gx10/fc-devicemgmt/certificate-devicemgmt-agent-tls.json new file mode 100644 index 0000000..ff21088 --- /dev/null +++ b/apps-gx10/fc-devicemgmt/certificate-devicemgmt-agent-tls.json @@ -0,0 +1,18 @@ +{ + "apiVersion": "cert-manager.io/v1", + "kind": "Certificate", + "metadata": { + "name": "fc-devicemgmt-agent-tls", + "namespace": "fc-devicemgmt" + }, + "spec": { + "dnsNames": [ + "devices-agent.iamworkin.lan" + ], + "issuerRef": { + "kind": "ClusterIssuer", + "name": "step-ca-acme" + }, + "secretName": "fc-devicemgmt-agent-tls" + } +} diff --git a/apps-gx10/fc-devicemgmt/deployment-fc-devicemgmt-web.json b/apps-gx10/fc-devicemgmt/deployment-fc-devicemgmt-web.json index fa32d04..41161db 100644 --- a/apps-gx10/fc-devicemgmt/deployment-fc-devicemgmt-web.json +++ b/apps-gx10/fc-devicemgmt/deployment-fc-devicemgmt-web.json @@ -155,6 +155,14 @@ } } }, + { + "name": "FlowerCore__DeviceManagement__AgentMtls__ForwardedCertificateHosts__0", + "value": "devices-agent.iamworkin.lan" + }, + { + "name": "FlowerCore__DeviceManagement__AgentMtls__ForwardedCertificateHeader", + "value": "X-Forwarded-Tls-Client-Cert" + }, { "name": "FlowerCore__EventBus__Redis__Configuration", "value": "redis.fc-redis.svc:6379" @@ -313,7 +321,7 @@ "value": "true" } ], - "image": "localhost/fc-devicemgmt-web:v20260619-agentkey-48b20bc", + "image": "localhost/fc-devicemgmt-web:v20260619-agentmtls-3b298d7", "imagePullPolicy": "Never", "livenessProbe": { "failureThreshold": 3, diff --git a/apps-gx10/fc-devicemgmt/ingressroute-devicemgmt-agent-mtls.json b/apps-gx10/fc-devicemgmt/ingressroute-devicemgmt-agent-mtls.json new file mode 100644 index 0000000..69307c1 --- /dev/null +++ b/apps-gx10/fc-devicemgmt/ingressroute-devicemgmt-agent-mtls.json @@ -0,0 +1,42 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "IngressRoute", + "metadata": { + "name": "devicemgmt-agent-mtls", + "namespace": "fc-devicemgmt" + }, + "spec": { + "entryPoints": [ + "websecure" + ], + "routes": [ + { + "kind": "Rule", + "match": "Host(`devices-agent.iamworkin.lan`)", + "middlewares": [ + { + "name": "devicemgmt-agent-strip-forwarded-cert", + "namespace": "fc-devicemgmt" + }, + { + "name": "devicemgmt-agent-pass-client-cert", + "namespace": "fc-devicemgmt" + } + ], + "services": [ + { + "name": "fc-devicemgmt-web", + "port": 80 + } + ] + } + ], + "tls": { + "options": { + "name": "devicemgmt-agent-mtls", + "namespace": "fc-devicemgmt" + }, + "secretName": "fc-devicemgmt-agent-tls" + } + } +} diff --git a/apps-gx10/fc-devicemgmt/middleware-devicemgmt-agent-pass-client-cert.json b/apps-gx10/fc-devicemgmt/middleware-devicemgmt-agent-pass-client-cert.json new file mode 100644 index 0000000..0fc4452 --- /dev/null +++ b/apps-gx10/fc-devicemgmt/middleware-devicemgmt-agent-pass-client-cert.json @@ -0,0 +1,13 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "Middleware", + "metadata": { + "name": "devicemgmt-agent-pass-client-cert", + "namespace": "fc-devicemgmt" + }, + "spec": { + "passTLSClientCert": { + "pem": true + } + } +} diff --git a/apps-gx10/fc-devicemgmt/middleware-devicemgmt-agent-strip-forwarded-cert.json b/apps-gx10/fc-devicemgmt/middleware-devicemgmt-agent-strip-forwarded-cert.json new file mode 100644 index 0000000..38bf1ec --- /dev/null +++ b/apps-gx10/fc-devicemgmt/middleware-devicemgmt-agent-strip-forwarded-cert.json @@ -0,0 +1,15 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "Middleware", + "metadata": { + "name": "devicemgmt-agent-strip-forwarded-cert", + "namespace": "fc-devicemgmt" + }, + "spec": { + "headers": { + "customRequestHeaders": { + "X-Forwarded-Tls-Client-Cert": "" + } + } + } +} diff --git a/apps-gx10/fc-devicemgmt/tlsoption-devicemgmt-agent-mtls.json b/apps-gx10/fc-devicemgmt/tlsoption-devicemgmt-agent-mtls.json new file mode 100644 index 0000000..a110b3a --- /dev/null +++ b/apps-gx10/fc-devicemgmt/tlsoption-devicemgmt-agent-mtls.json @@ -0,0 +1,13 @@ +{ + "apiVersion": "traefik.io/v1alpha1", + "kind": "TLSOption", + "metadata": { + "name": "devicemgmt-agent-mtls", + "namespace": "fc-devicemgmt" + }, + "spec": { + "clientAuth": { + "clientAuthType": "RequireAnyClientCert" + } + } +}