# Microsoft IIS Connector — Operator Deep-Dive > Per Phase 14 of the deploy-hardening II master bundle. ## Overview The IIS connector (`internal/connector/target/iis/`) deploys TLS certs to Windows IIS servers via PowerShell (`Import-PfxCertificate` + `New-WebBinding` + SNI binding). Pre-deploy snapshot of the existing thumbprint allows rollback if the new binding fails. ## Vendor versions tested - **Windows Server 2019** with IIS 10 - **Windows Server 2022** with IIS 10 ## CI runner constraint Per frozen decision 0.4: Windows containers run only on Windows hosts. Linux CI runners CAN'T run the IIS sidecar. IIS e2e tests run on a separate `windows-vendor-e2e` GitHub Actions matrix job on `windows-latest` runners. Operators on Linux-only CI use `//go:build integration && !no_iis` to skip. ## Per-quirk operator guidance ### App-pool recycle (opt-in) `TestVendorEdge_IIS_AppPoolRecycle_OptInForCertChange_E2E` By default, IIS picks up new SSL bindings without app-pool recycle (the binding-edit path is hot). Some sites need recycle to fully reload (e.g., apps that cache cert handles). **Operator action:** set `AppPoolRecycle: true` per-target. The connector then runs `Restart-WebAppPool ` after binding update. ### SNI multi-binding per site `TestVendorEdge_IIS_SNIMultiBindingPerSite_DeployUpdatesCorrectBinding_E2E` When a site has multiple SNI bindings (different hostnames on the same site), connector targets the binding matching the operator-supplied hostname. Other bindings unchanged. ### CCS (Centralized Certificate Store) `TestVendorEdge_IIS_CCSCentralizedCertStoreVariant_DeployToSharedStore_E2E` CCS is the file-based variant where multiple IIS servers share a UNC path of cert files. Connector writes to the shared path; all IIS servers pick it up automatically. ### WinRM remote vs local PowerShell `TestVendorEdge_IIS_WinRMRemotePath_vs_LocalPowerShellPath_BothWork_E2E` Two code paths produce equivalent cert installs: - `WinRMHost: ""` → local PowerShell (agent runs on the IIS server) - `WinRMHost: "iis.example"` → remote PowerShell via WinRM Both rotate the same way. WinRM path requires network reachability to port 5985/5986. ### Server 2019 vs 2022 PowerShell compat `TestVendorEdge_IIS_WindowsServer2019_vs_2022_PowerShellCompat_E2E` `Import-PfxCertificate` + `New-WebBinding` semantics are stable across server versions. PowerShell 5.1 (2019) + PowerShell 7.x (2022) both work. ### Friendly name `TestVendorEdge_IIS_FriendlyNameUpdatedOnRotation_E2E` Connector preserves operator-supplied `FriendlyName` on the cert across rotation. Useful for IIS GUI identification. ### HTTP/2 + ALPN `TestVendorEdge_IIS_HTTP2ALPNPreserved_E2E` IIS h2 negotiation preserved across cert rotation. The `netsh http show sslcert` ALPN attribute survives the binding swap. ### Binding-type validation `TestVendorEdge_IIS_BindingTypeHttpsValidated_E2E` Connector refuses to deploy to non-`https` bindings (e.g., `http`, `net.tcp`). Surfaces actionable error. ### ARR reverse-proxy `TestVendorEdge_IIS_ARRReverseProxyCertRotation_E2E` Sites using Application Request Routing as reverse proxy: cert rotation does not invalidate ARR routes. The cert-binding edit is independent of the ARR config. ### Atomic SNI binding swap `TestVendorEdge_IIS_RemovePreviousBindingOnRotate_E2E` Connector removes the previous SNI binding BEFORE inserting the new one (atomicity at the IIS API level). Prevents brief window where two bindings serve different certs for the same hostname. ## Troubleshooting matrix | Symptom | Test name | Operator action | |---|---|---| | Cert installed but app pool serving old cert | `AppPoolRecycle_OptInForCertChange_E2E` | set `AppPoolRecycle: true` | | Wrong SNI binding updated | `SNIMultiBindingPerSite_E2E` | verify hostname selector | | Permission denied on cert install | n/a | agent must run as administrator | | WinRM connection failed | `WinRMRemotePath_vs_LocalPowerShellPath_E2E` | check WinRM port 5985/5986 reachability | | h2 negotiation broken post-rotate | `HTTP2ALPNPreserved_E2E` | re-run `netsh http add sslcert` with `appid + clientcertnegotiation=enable` | ## V3-Pro deferrals - IIS Application Initialization module integration (warm cert cache after rotation). - Azure Key Vault + IIS integration (operator opt-in). ## Related docs - [Atomic deploy + post-verify + rollback](deployment-atomicity.md) - [Vendor compatibility matrix](deployment-vendor-matrix.md) ## Operator validation playbook (Windows host) CI no longer runs the IIS + WinCertStore vendor-e2e tests on every push. Per ci-pipeline-cleanup bundle frozen decision 0.5 (which revises Bundle II decision 0.4), the Windows matrix was deleted because (a) it couldn't physically work on `windows-latest` GitHub runners (Docker not started in Windows-containers mode by default; `bridge` network driver doesn't exist on Windows Docker — uses `nat`), and (b) all IIS + WinCertStore vendor-edge tests are `t.Log` placeholder stubs that exercise no IIS-specific behavior. The real IIS connector validation lives in: 1. `internal/connector/target/iis/` unit tests (run on Linux in the regular Go Build & Test job — already green on every push). 2. This playbook — operator manual smoke against a real Windows host pre-release. ### Prerequisites - Windows Server 2019 or 2022 host (or Windows 10/11 Pro with Hyper-V) - Docker Desktop in Windows containers mode (Settings → "Switch to Windows containers") - Go 1.25.9 + git ### Procedure ```powershell # Clone + checkout git clone https://github.com/certctl-io/certctl.git cd certctl git fetch --tags git checkout v2.X.0 # whichever release is being validated # Bring up the Windows IIS sidecar docker compose --profile deploy-e2e-windows ` -f deploy/docker-compose.test.yml ` up -d windows-iis-test Start-Sleep -Seconds 30 # Run IIS + WinCertStore vendor-edge tests $env:INTEGRATION = "1" go test -tags integration -race -count=1 ` -run 'VendorEdge_(IIS|WinCertStore)' ` ./deploy/test/... | Tee-Object -FilePath iis-validation.log # Tear down docker compose --profile deploy-e2e-windows ` -f deploy/docker-compose.test.yml ` down -v ``` ### Acceptance Per Bundle II frozen decision 0.14, the IIS / WinCertStore cells in `docs/deployment-vendor-matrix.md` flip from "CI" / "pending" → "✓" only when ALL of the following are true: - ≥1 happy-path e2e passes against the real Windows IIS sidecar - ≥1 specific-quirk test for that Windows Server version passes - This playbook's full procedure ran clean once on a real Windows host Operator records the validation date + Windows Server version in `cowork//iis-validation-receipts.md` for audit trail.