Skip to content

Releases: glennbyron1/CAC-program

v1.2 — Azure VPN end-to-end; same YubiKey unlocks AD AND cloud

24 Jun 12:43

Choose a tag to compare

Headline — Same physical YubiKey now unlocks AD AND Azure VPN

One slot 9a cert, two authentication contexts. Kerberos PKINIT (Event 4768 Pre-Auth Type 16) authenticates AD logon on-prem; EAP-TLS authenticates Azure Point-to-Site VPN in the cloud. The credential never leaves the hardware token. Both authentications validate the same chain to the same internal Lab-CA. One possession factor (the card), one knowledge factor (the PIN), two clouds — without ever provisioning a parallel "VPN credential."

This is the "hybrid trust" claim federal Zero-Trust roles look for. Not "I built two things"; one credential that works in two clouds because both trust the same internal CA.

📄 Build guide: Architecture/Azure-VPN-Guide.md (ARCH-ICAM-013)

Maps to NIST SP 800-53 IA-2, IA-2(11), IA-5(11), AC-17, SC-8, SC-12, SC-17, CM-3, AU-6 · DoD ZTRA Identity + Devices + Networks pillars · NIST SP 800-207 Zero Trust Architecture.


What's new

Phase 9 Azure VPN — built end-to-end

A complete deploy → test → teardown cycle of Azure Point-to-Site VPN with certificate authentication from the lab's internal CA:

  • Cost guardrail ($20/month budget alert wired before any resource was created)
  • VNet 10.20.0.0/16 with the required GatewaySubnet 10.20.255.0/27
  • VpnGw1 VPN Gateway with Standard Static public IP (~40 min deploy)
  • Lab-CA root cert exported from Lab-DC01 via PowerShell Direct, Base64-uploaded to Azure as the P2S trust anchor
  • jdoe's YubiKey-resident smart card cert (slot 9a, the same one used for AD logon since v1.1) authenticated the EAP-TLS exchange
  • P2S client assigned 172.16.0.2 from the VPN address pool; tunnel up
  • Teardown via Remove-AzResourceGroup -Force -AsJob in the same session — total cost ~$0.40 in gateway hours

Slot 5 of Demo-Walkthrough closed — all 8 slots now captured

  • Screenshots/05-vpn-azure-eap-cert-auth-no-password.png — headline: jdoe@lab.local connected to vnet-cac-lab-phase9 over EAP-TLS, duration counter running, no password prompt
  • Screenshots/05b-vpn-ipconfig-172-16-0-2.pngipconfig showing the PPP adapter with the P2S-assigned IP
  • Screenshots/05c-vpn-caption-azure-p2s-eap-tls.png — configuration caption documenting the auth mechanism

PKI architecture discovery — designed two-tier, deployed single-tier

Honest portfolio finding captured in the Azure VPN guide:

  • The lab's design doc describes a two-tier PKI (offline Root CA signs Issuing CA on Lab-DC01)
  • Lab-DC01's Trusted Root store shows CN=LAB-CA as self-signed — Subject == Issuer
  • The separate CN=Lab Root CA cert exists (10-year, valid 2026 → 2036) but has basicConstraints CA:TRUE, pathlen:0 — per RFC 5280, this means the Root can only sign end-entity certs, NOT sub-CAs. So it could not have signed LAB-CA as an intermediate.
  • The deployed PKI is operationally single-tier with LAB-CA as the trust anchor

Captured as a "designed vs deployed" delta in the build guide, not hidden. Future remediation queued.

Install pitfall + working fix path

Three install paths were attempted before one worked. The lesson ships with the build guide so anyone walking the same path doesn't lose an hour:

Path Result
VpnClientSetupAmd64.exe → Run as administrator Blocked by scforceoption=1 GPO elevation prompt for CardIssuer VSC PIN; even with creds entered, installer left system phonebook at 0 bytes
Azure VPN Client app from Microsoft Store + XML import with thumbprint hardcoded Cert picker doesn't enumerate YubiKey-resident certs; Save validation fails with "client certificate must include an issuer" even with <hash> and <issuer> both populated
VpnProfileSetup.ps1 from elevated PowerShell + Tunnel type Automatic ✅ Works — the script bypasses the GUI elevation block; Automatic tunnel type gives Windows IKEv2/SSTP/L2TP fallback

Three Azure VPN docs consolidated to one canonical guide

The original "starter" Azure-VPN-Lab-Guide.md, the build doc Phase9-Azure-VPN-Build-Guide.md, and the roadmap design CAC_PIV_Phase9_Azure_VPN_ConditionalAccess.md are merged into one Architecture/Azure-VPN-Guide.md. Sits parallel to the existing Architecture/WatchGuard-IKEv2-VPN-Guide.md for on-prem.

The new guide covers: CGNAT framing, cost discipline, architecture diagram with trust chain, full 11-step build sequence, lessons learned, PKI discovery, control mapping (NIST + Zero Trust), future phases 9.1/9.3/9.4/9.5/9.6 (designed not built), and honest framing.


What's NOT in v1.2 — designed but not built

Documented in the build guide so the "what's shipped vs what's designed" line is honest:

  • 9.1 Entra ID baseline — M365 Developer tenant + synthetic test users + MFA enrollment
  • 9.3 Conditional Access — the actual DoD pattern, where "VPN = you're in" becomes "policy decides on every connection"
  • 9.4 Device compliance signal — Intune compliance policy + Entra device registration
  • 9.5 Visibility & decisioning — Entra sign-in logs to Log Analytics + basic detections

These will land in a future v1.3 or as their own incremental tags. The Phase 9 design doc is preserved inside the consolidated build guide so the full vision stays visible.


Infrastructure changes

Documentation consolidation

3 source docs deleted: Architecture/Azure-VPN-Lab-Guide.md, Architecture/Phase9-Azure-VPN-Build-Guide.md, Architecture/Roadmap/CAC_PIV_Phase9_Azure_VPN_ConditionalAccess.md

7 cross-references updated across Demo-Walkthrough.md, CSET-Assessment-Guide.md, SSP-Template.md, and TODO.md. Zero broken refs after consolidation.

Screenshots catalog rewritten

Screenshots/README.md reorganized into 5 tiers (Demo-Walkthrough headline shots, Lessons-Learned discovery evidence, session evidence, FIDO2 credential evidence, portfolio reference). Phase 9 slot 5 captures added to the catalog.


For reviewers — start here

Artifact Why it matters
Architecture/Azure-VPN-Guide.md The headline v1.2 deliverable. Complete Azure VPN P2S build with Lab-CA + YubiKey cert auth. Includes the install pitfall lesson and the PKI discovery.
Demo-Walkthrough.md Step 5 The slot 5 marquee shot — same YubiKey unlocks AD AND Azure VPN, no password anywhere
Lab-Kit/Reference/RUNBOOK-YubiKey-Enrollment.md The runbook that produced jdoe's smart card cert; same cert authenticates v1.2's Azure VPN
Architecture/Lessons-Learned/2026-06-16-Silent-VSC-Fallback-Discovery.md The v1.1 acceptance check pattern this build inherits — certutil -scinfo as reader-level verification

Acknowledgments

The "same physical card, two clouds" pattern is a real federal-IT design pattern, not original to this lab. What this lab demonstrates is the buildable proof of it in a homelab with commodity hardware (one YubiKey, free Azure for Students subscription, internal CA). The deploy → test → teardown cost discipline is itself a learnable artifact for cloud-governance interview answers.

v1.1 — YubiKey end-to-end + Silent VSC Fallback discovery

17 Jun 11:37

Choose a tag to compare

Headline finding — Silent TPM Virtual Smart Card Fallback Discovery

During v1.1 enrollment testing we discovered that smart card enrollment can silently land on a TPM-backed Virtual Smart Card instead of the intended physical token, with no error surfaced anywhere in the GUI. Logon works, audit events fire, the user is happy — but the credential is on the wrong factor. A hardware-factor authentication design silently demotes to a software-factor design.

The discovery doc captures the failure mode in full: environment, what was observed, why it happened, how certutil -scinfo exposes it, a detection-script sketch, and four compensating controls. The most important compensating control is procedural — the operator runbook now mandates a four-point acceptance check on every enrollment.

📄 Architecture/Lessons-Learned/2026-06-16-Silent-VSC-Fallback-Discovery.md

Maps to NIST SP 800-53 IA-2(11), IA-5(11), CM-6, AU-6 and CISA ZTMM Identity pillar.


What's new

YubiKey enrollment validated end-to-end

jdoe enrolled on a physical YubiKey 5 NFC via New-YubiKeyToken.ps1 + Enroll-on-Behalf, with the Yubico Smart Card Minidriver, against the lab's internal Issuing CA. Logs into WO02 with card + PIN under full SmartcardLogonRequired=True enforcement. Event 4768 Pre-Auth Type 16 (PKINIT) on the DC confirms the protocol-level handshake.

Slots 1, 1b, 1d, and 4 of the Demo-Walkthrough captured and embedded:

  • Slot 1 — 01-lockscreen-smartcard-only.png — lock screen with smart-card-only logon
  • Slot 1b — 01b-certutil-scinfo-yubikey-chain-validates.png — cert chain validates on physical reader
  • Slot 1d — 01d-certutil-scinfo-yubikey-cert-context-jane-doe.png — Subject + UPN binding evidence
  • Slot 4 — 04-session-lock-on-card-removal.png — ~2-second session lock on card removal

Hirsch uTrust FIDO2 FIPS — declared NO-GO for PIV (n=2 cards)

Factory 3DES management key rejected on both cards (OpenSC admin_mode failed -1201). The vendor minidriver assumes an already-personalized card; it does not personalize one. FIDO2 applet on the same cards works fine — but for PIV / AD smart-card logon, the card is a dead end without the vendor's per-card management key + personalization software.

This is now the lab's procurement-evaluation criterion for any new card form factor: can the card be brought to a known-management-key state using off-the-shelf tooling (ykman, OpenSC, GIDS minidriver), or does it require vendor-specific software + per-card management key?

Enrollment kit — five new operator artifacts

In Lab-Kit/03-DomainController/:

  • New-LabUser.ps1 — AD user creation with OU resolver + numbered menu
  • New-TokenEnrollment.ps1 — RA + Issuer ceremony script (SCRIPT-ICAM-011, NIST SP 800-53 AC-5)
  • New-YubiKeyToken.ps1 — YubiKey PIV provisioning (SCRIPT-ICAM-016)
  • Deploy-ScriptsToDC.ps1 — SMB-based deploy of the three above to Lab-DC01

In Lab-Kit/Reference/:

  • RUNBOOK-YubiKey-Enrollment.md (RUNBOOK-ICAM-001) — operator runbook for the scripted path
  • MANUAL-Enrollment-Walkthrough.md (RUNBOOK-ICAM-002) — GUI-driven walkthrough using the real-world "copy a peer in ADUC" pattern. Companion piece showing what the scripts automate, click-by-click.

The two runbooks are explicitly cross-referenced. Anyone reading both gets a complete picture of the workflow regardless of whether their environment uses scripted automation or GUI-driven user management.

Card-Test-Matrix.md filled in

PIV and FIDO2 rows populated for both tested cards (YubiKey 5 NFC, Hirsch uTrust FIDO2 FIPS). Six observations documenting the YubiKey path that works, the Yubico minidriver requirement, the mgmt-key sequencing rule, the Hirsch NO-GO finding, the silent VSC fallback callout, and the procurement-evaluation criterion for future cards.

Framing rewritten as ongoing testing rather than complete — the matrix grows as new card form factors are evaluated.

Documentation expansions

  • Architecture/Lessons-Learned/2026-06-16-CAC-Enrollment-Session.md — full forensic session log (scrubbed) tracing the v1.1 enrollment journey with 10 documented issues and fixes
  • 24 v1.1 screenshots staged in Screenshots/ with named slot filenames; one redacted to hide YubiKey serial + AES-256 management key
  • Screenshots/README.md catalog rewritten to reflect five-tier structure (headline / lessons-learned / session evidence / FIDO2 / portfolio reference)

Infrastructure improvements

Scrub-Repo.ps1 — two bug fixes, caught before any file was touched

Both bugs were caught by the -WhatIf preview during the v1.1 pre-push cycle, not by a real run. They're shipped publicly as documentation:

  1. _* meta-key filter — when documentation keys like _README, _README_REBUILT are added to .scrub-patterns.local.json to explain the file inline, the scrubber must skip them. Previously, it would treat them as substitution patterns and corrupt every file containing the literal string _README. Now matches Scan-LocalRepo.ps1's existing behavior.

  2. Skip gitignored local-only scanner filesScan-LocalRepo.ps1 and SCAN-README.md are gitignored local tools that contain real values BY DESIGN (they document the scrub patterns). The scrubber must not rewrite them, since that would degrade the local documentation used during pre-push scans.

Scrub pattern coverage extended

  • New literal patterns: YubiKey AES-256 management key, Hyper-V host name, YubiKey serial
  • New preemptive tripwire patterns for off-repo business context that should never appear in the public repo (commercial-build entity names, vendor-relationship contacts)
  • Four _README_* documentation keys explain the file's organization, rebuild history, and tripwire policy

Deferred to a future tag

  • Slot 5 — VPN EAP-TLS capture — depends on Phase 9 (Azure VPN Gateway) or Phase 9B (OPNsense on-prem appliance). Honest framing: the credential story closes when the VPN build lands, not before.
  • Real AAGUID values via ykman fido info and equivalent for Hirsch — webauthn.io anonymizes them; device-side CLI captures pending
  • Optional Ansible STIG hardening pass — would push SCAP scores up but the delta from hardening is the portfolio value, not the absolute number
  • Additional card form factors — GIDS smart cards and other vendors queued

For reviewers — start here

Artifact Why it matters
Architecture/Lessons-Learned/2026-06-16-Silent-VSC-Fallback-Discovery.md The headline DevSecOps finding. Demonstrates ability to catch a high-severity silent failure mode that vendor and Microsoft documentation does not adequately cover, and to codify the fix as a procedural control.
Lab-Kit/Reference/RUNBOOK-YubiKey-Enrollment.md + MANUAL-Enrollment-Walkthrough.md Two runbooks — scripted and GUI-driven — for the same workflow. Shows operator-engineering discipline: automation for compliance environments, manual procedure for small-shop reality.
Lab-Kit/Reference/Card-Test-Matrix.md Hardware-evaluation methodology applied across multiple form factors with both ✅ and ❌ outcomes. Procurement-question criterion stated explicitly.
Demo-Walkthrough.md Step-by-step live demo with slots 1, 1b, 1d, 3, 4, 6, 7, 8 captured. NIST control mapping table at the bottom.

Diff from v1.0: 46 changed files, 19 new files, 27 modified files.

Acknowledgments: The Silent VSC Fallback failure mode was discovered during normal lab operations, not from any vendor or industry source. The methodology to detect it (certutil -scinfo as a reader-level acceptance check) is now baked into the operator runbook and the four-point verification at the end of every enrollment.

First stable milestone of the CAC/PIV ICAM portfolio.

04 Jun 10:54

Choose a tag to compare

What's in v1.0

  • Two-tier PKI — Offline Root CA + Enterprise Issuing CA on Lab-DC01
  • Smart card MFA end-to-end — VM + physical endpoint (WO02). User LAB\labtech enrolled with TPM Virtual Smart Card; smart card logon confirmed working via RDP
  • NIST IA-2(11) protocol evidence — Event 4768 captured with Pre-Auth Type 16 (PKINIT). See Demo-Walkthrough.md Step 3
  • SCAP compliance baseline — three hosts scanned with SCC 5.10.2: DC01 44.95% → 42.66%, WS01 42.20% → 42.20%, WO02 37.00% (Win 11 STIG, MAC-1 Classified). Full HTML / XCCDF / OVAL / CKL artifacts staged in Compliance-Reports/
  • Phase 8 Zero Trust extension — 21 PowerShell scripts in Lab-Kit/07-ZeroTrust/ (8 working implementations + 13 product-dependent scaffolds) covering tiered admin model, Authentication Policy Silos, device certs, Kerberos lifetimes, microsegmentation, ZT validation; companion Demo-Walkthrough-ZT.md
  • RMF artifact package — SAR, POAM, SSP, Annual-STIG-Rescan-SOP populated with real numbers
  • DevSecOps scaffolding — GitHub Actions (CodeQL, gitleaks, secret scan, PSScriptAnalyzer), pre-commit hook, local sensitive-pattern scanner, Scrub-Repo.ps1 workflow

Deferred to v1.1 (card-blocked)

  • Demo screenshots — lock screen smart-card-only, session lock on card removal, VPN connected (waiting on YubiKey 5 NFC + Hirsch uTrust FIDO2 cards)
  • VPN EAP-TLS test from WO02
  • Card-Test-Matrix.md with PIV / FIDO2 / reset workflow comparisons

Frameworks

NIST SP 800-53 Rev 5 (AC-2/3/5/6/11/12/17, IA-2/2(11)/3/5, SC-7/8, AU-2/6/12, CA-7, SI-4), NIST SP 800-207, CISA Zero Trust Maturity Model v2.0, FIPS 201-3, DISA STIG.