deploy(apple-mdm): route scep to noc1 ca
Adds the GX10 /scep route to the noc1 Apple MDM SCEP CA without exposing NanoHUB APIs.
This commit is contained in:
@@ -13,6 +13,9 @@ traffic at `https://mdm.iamworkin.lan`.
|
||||
- Required secret: `Secret/fc-apple-mdm-runtime`, key `NANOHUB_API_KEY`
|
||||
- Optional later bridge secret: `NANOHUB_WEBHOOK_URL`
|
||||
- Required CA mount: `ConfigMap/fc-apple-mdm-root-ca`, key `root_ca.crt`
|
||||
- SCEP backend: noc1 systemd service `step-ca-apple-mdm-scep`, forwarded through
|
||||
selectorless `Service/fc-apple-mdm-scep` and `EndpointSlice/fc-apple-mdm-scep-noc1`
|
||||
to `10.0.56.10:9080`
|
||||
|
||||
NanoHUB API authentication is HTTP Basic with username `nanohub` and password
|
||||
from `NANOHUB_API_KEY`.
|
||||
@@ -24,16 +27,21 @@ The Traefik route intentionally exposes only:
|
||||
- `/version`
|
||||
- `/mdm`
|
||||
- `/checkin`
|
||||
- `/scep`
|
||||
|
||||
NanoHUB APIs under `/api/v1/*` stay cluster-internal for MDM-N1. The
|
||||
DeviceManagement bridge can use the ClusterIP service directly once its NanoHUB
|
||||
client lane lands.
|
||||
|
||||
SCEP is intentionally not exposed here yet. NanoHUB/NanoMDM expects an external
|
||||
SCEP service; the next runtime lane should either add a dedicated SCEP route
|
||||
such as `https://mdm.iamworkin.lan/scep/...` backed by an Apple-MDM-specific CA,
|
||||
or set `APPLE_MDM_SCEP_URL` in the DeviceManagement runtime secret to another
|
||||
live SCEP endpoint. Do not point the profile at a placeholder URL.
|
||||
SCEP is backed by the dedicated Apple-MDM-specific RSA step-ca hierarchy on
|
||||
noc1, not by the IAmWorkin ACME CA. The live profile URL is:
|
||||
|
||||
```text
|
||||
https://mdm.iamworkin.lan/scep/apple-mdm-scep
|
||||
```
|
||||
|
||||
Do not point `APPLE_MDM_SCEP_URL` at a placeholder URL or at the ECDSA
|
||||
IAmWorkin ACME CA; Smallstep SCEP requires an RSA intermediate/decrypter path.
|
||||
|
||||
## Deployment Notes
|
||||
|
||||
@@ -45,7 +53,9 @@ live SCEP endpoint. Do not point the profile at a placeholder URL.
|
||||
3. Ensure `mdm.iamworkin.lan` resolves to the GX10 Traefik VIP `10.0.57.202`
|
||||
before cert-manager requests `Certificate/fc-apple-mdm-tls`.
|
||||
4. Prove `https://mdm.iamworkin.lan/version` after ArgoCD converges.
|
||||
5. Prove SCEP CA publication with
|
||||
`curl -sk -o /dev/null -w '%{http_code} %{size_download}\n' 'https://mdm.iamworkin.lan/scep/apple-mdm-scep?operation=GetCACert'`.
|
||||
|
||||
This lane does not create an APNs MDM push certificate, enrollment profile,
|
||||
SCEP/device identity service, managed Wi-Fi payload, managed app install, or
|
||||
supervised iPad enrollment. Those remain MDM-N2 through MDM-N8.
|
||||
managed Wi-Fi payload, managed app install, or supervised iPad enrollment. Those
|
||||
remain MDM-N2 through MDM-N8.
|
||||
|
||||
@@ -192,6 +192,43 @@ spec:
|
||||
targetPort: 9004
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: fc-apple-mdm-scep
|
||||
namespace: fc-apple-mdm
|
||||
labels:
|
||||
app: fc-apple-mdm-scep
|
||||
app.kubernetes.io/name: fc-apple-mdm-scep
|
||||
app.kubernetes.io/part-of: flowercore
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 9080
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
kind: EndpointSlice
|
||||
metadata:
|
||||
name: fc-apple-mdm-scep-noc1
|
||||
namespace: fc-apple-mdm
|
||||
labels:
|
||||
kubernetes.io/service-name: fc-apple-mdm-scep
|
||||
app.kubernetes.io/name: fc-apple-mdm-scep
|
||||
app.kubernetes.io/part-of: flowercore
|
||||
addressType: IPv4
|
||||
endpoints:
|
||||
- addresses:
|
||||
- 10.0.56.10
|
||||
conditions:
|
||||
ready: true
|
||||
ports:
|
||||
- name: http
|
||||
port: 9080
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
@@ -218,6 +255,11 @@ spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`mdm.iamworkin.lan`) && PathPrefix(`/scep`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: fc-apple-mdm-scep
|
||||
port: 80
|
||||
- match: Host(`mdm.iamworkin.lan`) && (PathPrefix(`/mdm`) || PathPrefix(`/checkin`) || PathPrefix(`/version`))
|
||||
kind: Rule
|
||||
services:
|
||||
|
||||
@@ -17,6 +17,8 @@ public sealed class Gx10AppleMdmNanohubTests
|
||||
Documents.Should().Contain(document => Is(document, "Namespace", "fc-apple-mdm"));
|
||||
Documents.Should().Contain(document => Is(document, "ConfigMap", "fc-apple-mdm-root-ca"));
|
||||
Documents.Should().Contain(document => Is(document, "Service", "fc-apple-mdm"));
|
||||
Documents.Should().Contain(document => Is(document, "Service", "fc-apple-mdm-scep"));
|
||||
Documents.Should().Contain(document => Is(document, "EndpointSlice", "fc-apple-mdm-scep-noc1"));
|
||||
Documents.Should().Contain(document => Is(document, "NetworkPolicy", "fc-apple-mdm-netpol"));
|
||||
Documents.Should().NotContain(document => (document.Scalar("kind") ?? string.Empty) == "Secret");
|
||||
Documents.Should().NotContain(document => (document.Scalar("kind") ?? string.Empty) == "OnePasswordItem");
|
||||
@@ -66,16 +68,35 @@ public sealed class Gx10AppleMdmNanohubTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Manifest_ExposesOnlyMdmCheckinAndVersionPaths()
|
||||
public void Manifest_ExposesOnlyMdmCheckinVersionAndScepPaths()
|
||||
{
|
||||
var certificate = Single("Certificate", "fc-apple-mdm-tls");
|
||||
certificate.Scalar("spec", "issuerRef", "name").Should().Be("step-ca-acme");
|
||||
certificate.Scalar("spec", "issuerRef", "kind").Should().Be("ClusterIssuer");
|
||||
certificate.ScalarSequence("spec", "dnsNames").Should().ContainSingle("mdm.iamworkin.lan");
|
||||
|
||||
var scepService = Single("Service", "fc-apple-mdm-scep");
|
||||
scepService.Scalar("spec", "type").Should().Be("ClusterIP");
|
||||
var scepServicePort = scepService.MappingSequence("spec", "ports").Should().ContainSingle().Subject;
|
||||
scepServicePort.Scalar("name").Should().Be("http");
|
||||
scepServicePort.Scalar("port").Should().Be("80");
|
||||
scepServicePort.Scalar("targetPort").Should().Be("9080");
|
||||
|
||||
var scepEndpointSlice = Single("EndpointSlice", "fc-apple-mdm-scep-noc1");
|
||||
scepEndpointSlice.Scalar("addressType").Should().Be("IPv4");
|
||||
scepEndpointSlice.Scalar("metadata", "labels", "kubernetes.io/service-name").Should().Be("fc-apple-mdm-scep");
|
||||
var scepEndpoint = scepEndpointSlice.MappingSequence("endpoints").Should().ContainSingle().Subject;
|
||||
scepEndpoint.ScalarSequence("addresses").Should().ContainSingle("10.0.56.10");
|
||||
var scepEndpointPort = scepEndpointSlice.MappingSequence("ports").Should().ContainSingle().Subject;
|
||||
scepEndpointPort.Scalar("name").Should().Be("http");
|
||||
scepEndpointPort.Scalar("port").Should().Be("9080");
|
||||
|
||||
var ingress = Single("IngressRoute", "fc-apple-mdm");
|
||||
var route = ingress.MappingSequence("spec", "routes").Should().ContainSingle().Subject;
|
||||
var match = route.Scalar("match");
|
||||
var routes = ingress.MappingSequence("spec", "routes");
|
||||
routes.Should().HaveCount(2);
|
||||
var scepRoute = routes.Single(route => route.Scalar("match")?.Contains("PathPrefix(`/scep`)") == true);
|
||||
var nanohubRoute = routes.Single(route => route.Scalar("match")?.Contains("PathPrefix(`/mdm`)") == true);
|
||||
var match = nanohubRoute.Scalar("match");
|
||||
|
||||
match.Should().Contain("Host(`mdm.iamworkin.lan`)");
|
||||
match.Should().Contain("PathPrefix(`/mdm`)");
|
||||
@@ -83,6 +104,12 @@ public sealed class Gx10AppleMdmNanohubTests
|
||||
match.Should().Contain("PathPrefix(`/version`)");
|
||||
match.Should().NotContain("/api/v1");
|
||||
match.Should().NotContain("PathPrefix(`/api`)");
|
||||
|
||||
scepRoute.Scalar("match").Should().Contain("Host(`mdm.iamworkin.lan`)");
|
||||
scepRoute.Scalar("match").Should().Contain("PathPrefix(`/scep`)");
|
||||
var scepRouteService = scepRoute.MappingSequence("services").Should().ContainSingle().Subject;
|
||||
scepRouteService.Scalar("name").Should().Be("fc-apple-mdm-scep");
|
||||
scepRouteService.Scalar("port").Should().Be("80");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -94,6 +121,8 @@ public sealed class Gx10AppleMdmNanohubTests
|
||||
readme.Should().Contain("Secret/fc-apple-mdm-runtime");
|
||||
readme.Should().Contain("imagePullPolicy: Never");
|
||||
readme.Should().Contain("10.0.57.202");
|
||||
readme.Should().Contain("https://mdm.iamworkin.lan/scep/apple-mdm-scep");
|
||||
readme.Should().Contain("Smallstep SCEP requires an RSA intermediate");
|
||||
readme.Should().Contain("does not create an APNs MDM push certificate");
|
||||
readme.Should().Contain("managed Wi-Fi payload");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user