From e4f03427b744c3d530c2a4b7843cebb146897b31 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 6 Feb 2026 14:47:15 +0000 Subject: [PATCH] feat: Add professional hierarchical documentation - Created comprehensive README.md with Mermaid diagrams, badges, and TOC - Added docs/ directory with 7 sections and 14 markdown files - Included architecture diagrams, flowcharts, and sequence diagrams - All documentation is fully interlinked with cross-references - Added ISO storage location on Proxmox development server - Included troubleshooting guide and evaluation management docs - All config files (Packer, Terraform, Ansible, Forgejo) documented - Added icons and visual elements throughout documentation --- .forgejo/workflows/release.yml | 54 ++++ .gitignore | 40 +++ README.md | 356 ++++++++++++++++++++- ansible/pipeline.yml | 26 ++ doc.tex | 461 ++++++++++++++++++++++++++++ docs/01-overview/architecture.md | 234 ++++++++++++++ docs/02-prerequisites/isos.md | 182 +++++++++++ docs/02-prerequisites/secrets.md | 224 ++++++++++++++ docs/03-packer/autounattend.md | 238 ++++++++++++++ docs/03-packer/configuration.md | 218 +++++++++++++ docs/04-terraform/main.tf.md | 223 ++++++++++++++ docs/04-terraform/variables.md | 158 ++++++++++ docs/05-ansible/pipeline.md | 195 ++++++++++++ docs/06-ci-cd/forgejo-workflows.md | 288 +++++++++++++++++ docs/07-advanced/evaluation.md | 200 ++++++++++++ docs/07-advanced/troubleshooting.md | 273 ++++++++++++++++ docs/index.md | 258 ++++++++++++++++ installer.nsi | 22 ++ packer/Autounattend.xml | 71 +++++ packer/windows.pkr.hcl | 70 +++++ src/main.c | 7 + terraform/main.tf | 34 ++ terraform/outputs.tf | 4 + terraform/variables.tf | 10 + 24 files changed, 3844 insertions(+), 2 deletions(-) create mode 100644 .forgejo/workflows/release.yml create mode 100644 .gitignore create mode 100644 ansible/pipeline.yml create mode 100644 doc.tex create mode 100644 docs/01-overview/architecture.md create mode 100644 docs/02-prerequisites/isos.md create mode 100644 docs/02-prerequisites/secrets.md create mode 100644 docs/03-packer/autounattend.md create mode 100644 docs/03-packer/configuration.md create mode 100644 docs/04-terraform/main.tf.md create mode 100644 docs/04-terraform/variables.md create mode 100644 docs/05-ansible/pipeline.md create mode 100644 docs/06-ci-cd/forgejo-workflows.md create mode 100644 docs/07-advanced/evaluation.md create mode 100644 docs/07-advanced/troubleshooting.md create mode 100644 docs/index.md create mode 100644 installer.nsi create mode 100644 packer/Autounattend.xml create mode 100644 packer/windows.pkr.hcl create mode 100644 src/main.c create mode 100644 terraform/main.tf create mode 100644 terraform/outputs.tf create mode 100644 terraform/variables.tf diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml new file mode 100644 index 0000000..e4c5d73 --- /dev/null +++ b/.forgejo/workflows/release.yml @@ -0,0 +1,54 @@ +name: Build and Release +on: [push] + +jobs: + build-sign-package: + runs-on: ubuntu-latest + container: archlinux:latest + steps: + - name: Install Tools + run: pacman -Syu --noconfirm mingw-w64-gcc nsis osslsigncode opentofu ansible python-pywinrm packer + + - name: Checkout + uses: actions/checkout@v3 + + - name: Cross-Compile (MinGW) + run: x86_64-w64-mingw32-gcc src/main.c -o dist/app.exe + + - name: Package (NSIS) + run: makensis -DVERSION=${{ gitea.ref_name }} installer.nsi + + - name: Code Sign (Linux Native) + env: + PFX_PASS: ${{ secrets.PFX_PASS }} + run: | + osslsigncode sign -pkcs12 cert.pfx -pass "$PFX_PASS" \ + -t http://timestamp.digicert.com \ + -in dist/installer.exe -out dist/installer_signed.exe + + - name: Provision Windows VM (OpenTofu) + env: + PM_API_TOKEN_ID: ${{ secrets.PM_TOKEN_ID }} + PM_API_TOKEN_SECRET: ${{ secrets.PM_TOKEN_SECRET }} + TF_VAR_build_id: ${{ gitea.run_number }} + run: | + cd terraform + tofu init + tofu apply -auto-approve + echo "VM_IP=$(tofu output -raw vm_ip)" >> $GITHUB_ENV + + - name: Verify on Windows (Ansible) + env: + ANSIBLE_USER: Administrator + ANSIBLE_PASSWORD: ${{ secrets.WIN_ADMIN_PASS }} + run: | + echo "[windows_vm]" > inventory.ini + echo "$VM_IP ansible_user=$ANSIBLE_USER ansible_password=$ANSIBLE_PASSWORD ansible_connection=winrm ansible_winrm_server_cert_validation=ignore" >> inventory.ini + + ansible-playbook -i inventory.ini ansible/pipeline.yml + + - name: Cleanup + if: always() + run: | + cd terraform + tofu destroy -auto-approve diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ff17f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# Packer +*.pkr.hcl.pkr.hcl + +# Terraform +*.tfstate +*.tfstate.* +.terraform/ +.terraform.lock.hcl +crash.log +override.tf +override.tf.json +*.tfplan + +# Ansible +*.retry +inventory.ini + +# Forgejo +*.pfx + +# Build artifacts +dist/ +*.exe +*.msi +*.dll +*.o + +# OS +.DS_Store +Thumbs.db + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Logs +*.log diff --git a/README.md b/README.md index ef36bc9..6acf542 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,355 @@ -# windows-iac-vm-tooling +# ๐Ÿ–ฅ๏ธ Windows Automation on Proxmox -This repo contains scripts and docs on how to create a golden image and then also how to use IaC tooling (OpenTofu, Ansibla and Jinja) to deploy windows build and test machines. \ No newline at end of file + +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) +[![Pipeline Status](https://img.shields.io/badge/Pipeline-Packer%20%E2%86%92%20OpenTofu%20%E2%86%92%20Forgejo-blue)](.forgejo/workflows/release.yml) +[![Windows Version](https://img.shields.io/badge/Windows-11%20LTSC%202024-0078D6?style=flat&logo=windows)](https://www.microsoft.com/en-us/windows/windows-11-enterprise) + +## ๐Ÿ“‹ Table of Contents + +1. [Overview](#-overview) +2. [Architecture](#-architecture) +3. [Quick Start](#-quick-start) +4. [Project Structure](#-project-structure) +5. [Documentation Index](#-documentation-index) +6. [Prerequisites](#-prerequisites) +7. [Pipeline Phases](#-pipeline-phases) +8. [Advanced Topics](#-advanced-topics) +9. [Contributing](#-contributing) + +--- + +## ๐Ÿš€ Overview + +This repository contains a complete **automated build, package, and test pipeline** for Windows applications using infrastructure as code. The system enables a **"One-Click"** Forgejo pipeline that produces signed, verified Windows installer artifacts without manual intervention. + +### Key Features + +- **๐Ÿ”ง Automated Golden Image Creation** - Packer builds reproducible Windows templates +- **โ˜๏ธ Ephemeral Infrastructure** - OpenTofu provisions temporary Windows VMs for testing +- **๐Ÿ” Code Signing** - Linux-native code signing with timestamp verification +- **โœ… Automated Testing** - Ansible verifies installations on live Windows VMs +- **๐Ÿ”„ Cross-Platform Compilation** - MinGW cross-compilation for Windows on Linux + +--- + +## ๐Ÿ—๏ธ Architecture + +```mermaid +flowchart TB + subgraph CI["Forgejo CI/CD"] + direction LR + C[Checkout] --> X[Cross-Compile
MinGW] --> P[Package
NSIS] --> S[Sign
osslsigncode] + end + + subgraph Build["Build Phase"] + P --> B[Packer Build
Windows Template] + B --> T[OpenTofu Provision
Windows VM] + end + + subgraph Verify["Verification Phase"] + S --> A[Ansible Test
Smoke Test] + T --> A + end + + subgraph Artifacts["Output"] + A --> EXE[ installer_signed.exe] + EXE --> Release[Release Artifacts] + end + + CI --> Build --> Verify --> Artifacts + + style CI fill:#e1f5fe + style Build fill:#e8f5e9 + style Verify fill:#fff3e0 + style Artifacts fill:#fce4ec +``` + +### Pipeline Flow + +| Phase | Technology | Purpose | +|-------|------------|---------| +| **1. Build** | Packer | Create Windows golden image template | +| **2. Provision** | OpenTofu | Spin up ephemeral Windows test VMs | +| **3. Compile** | MinGW | Cross-compile Windows applications on Linux | +| **4. Package** | NSIS | Create Windows installer packages | +| **5. Sign** | osslsigncode | Code-sign binaries with timestamp | +| **6. Verify** | Ansible | Test installation on live Windows VM | + +--- + +## โšก Quick Start + +### Prerequisites + +Before beginning, ensure ISOs are available on Proxmox: + +```bash +# ISO Storage Location +/mnt/pve-07-iso-nvme/template/iso/ +``` + +**Required Files:** +- `CLIENT_LTSC_EVAL_x64FRE_en-us.iso` - Windows 11 LTSC 2024 +- `virtio-win.iso` - VirtIO drivers for I/O performance + +**Download Sources:** +- [Windows 11 Enterprise](https://info.microsoft.com/ww-landing-windows-11-enterprise.html) +- [VirtIO Drivers](https://github.com/virtio-win/virtio-win-pkg-scripts/releases) + +### Step 1: Build Golden Image + +```bash +cd packer +packer init . +packer build windows.pkr.hcl +``` + +### Step 2: Provision Test Environment + +```bash +cd terraform +tofu init +export PM_API_TOKEN_ID="your-token-id" +export PM_API_TOKEN_SECRET="your-token-secret" +tofu apply -auto-approve +``` + +### Step 3: Run Verification + +```bash +ansible-playbook -i inventory.ini ../ansible/pipeline.yml +``` + +--- + +## ๐Ÿ“ Project Structure + +``` +windows-iac-vm-tooling/ +โ”œโ”€โ”€ ๐Ÿ“„ README.md # โ† Entry point (this file) +โ”œโ”€โ”€ ๐Ÿ“„ doc.tex # Full LaTeX documentation +โ”œโ”€โ”€ ๐Ÿ“„ LICENSE # MIT License +โ”œโ”€โ”€ ๐Ÿ“„ installer.nsi # NSIS installer script +โ”œโ”€โ”€ ๐Ÿ“ .forgejo/ +โ”‚ โ””โ”€โ”€ ๐Ÿ“ workflows/ +โ”‚ โ””โ”€โ”€ ๐Ÿ“„ release.yml # Forgejo CI/CD pipeline +โ”œโ”€โ”€ ๐Ÿ“ ansible/ +โ”‚ โ””โ”€โ”€ ๐Ÿ“„ pipeline.yml # Ansible verification playbook +โ”œโ”€โ”€ ๐Ÿ“ docs/ # Hierarchical documentation +โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ index.md # Documentation index +โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 01-overview/ +โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ architecture.md # Detailed architecture +โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 02-prerequisites/ +โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ isos.md # ISO requirements +โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ secrets.md # Secret management +โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 03-packer/ +โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ configuration.md # Packer HCL config +โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ autounattend.md # Windows answer file +โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 04-terraform/ +โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ main.tf.md # OpenTofu resources +โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ variables.md # Terraform variables +โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 05-ansible/ +โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ pipeline.md # Ansible playbook guide +โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 06-ci-cd/ +โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ forgejo-workflows.md # CI/CD pipeline details +โ”‚ โ””โ”€โ”€ ๐Ÿ“ 07-advanced/ +โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ evaluation.md # 90-day evaluation management +โ”‚ โ””โ”€โ”€ ๐Ÿ“„ troubleshooting.md # Common issues & solutions +โ”œโ”€โ”€ ๐Ÿ“ packer/ +โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ windows.pkr.hcl # Packer template configuration +โ”‚ โ””โ”€โ”€ ๐Ÿ“„ Autounattend.xml # Windows unattended installation +โ”œโ”€โ”€ ๐Ÿ“ src/ +โ”‚ โ””โ”€โ”€ ๐Ÿ“„ main.c # Example Windows application +โ””โ”€โ”€ ๐Ÿ“ terraform/ + โ”œโ”€โ”€ ๐Ÿ“„ main.tf # OpenTofu main configuration + โ”œโ”€โ”€ ๐Ÿ“„ variables.tf # Input variables + โ””โ”€โ”€ ๐Ÿ“„ outputs.tf # Output values +``` + +--- + +## ๐Ÿ“š Documentation Index + +### Getting Started +- **[Documentation Index](docs/index.md)** - Complete navigation guide +- **[Architecture Overview](docs/01-overview/architecture.md)** - System design and components + +### Prerequisites +- **[ISO Requirements](docs/02-prerequisites/isos.md)** - Download and placement instructions +- **[Secret Management](docs/02-prerequisites/secrets.md)** - Configure required credentials + +### Implementation Guides +- **[Packer Configuration](docs/03-packer/configuration.md)** - Build Windows templates +- **[Autounattend.xml Guide](docs/03-packer/autounattend.md)** - Windows installation automation +- **[OpenTofu Resources](docs/04-terraform/main.tf.md)** - Infrastructure as code +- **[Ansible Pipeline](docs/05-ansible/pipeline.md)** - Automated testing +- **[Forgejo Workflows](docs/06-ci-cd/forgejo-workflows.md)** - CI/CD pipeline reference + +### Advanced Topics +- **[Evaluation Management](docs/07-advanced/evaluation.md)** - Handle 90-day expiration +- **[Troubleshooting](docs/07-advanced/troubleshooting.md)** - Debug common issues + +--- + +## ๐Ÿ“‹ Prerequisites + +### Required ISO Images on Proxmox Storage + +**Storage Location:** `/mnt/pve-07-iso-nvme/template/iso/` + +| File | Description | Required | +|------|-------------|----------| +| `CLIENT_LTSC_EVAL_x64FRE_en-us.iso` | Windows 11 LTSC 2024 | โœ… Yes | +| `virtio-win.iso` | VirtIO drivers | โœ… Yes | +| `SERVER_EVAL_x64FRE_en-us.iso` | Windows Server 2022 | Optional | +| `26100.1742.240906-0331...iso` | Alternate Windows 11 | Optional | + +### Required Secrets + +Configure these in your Forgejo repository settings: + +| Secret | Description | Usage | +|--------|-------------|-------| +| `PFX_PASS` | Code signing certificate password | `osslsigncode sign` | +| `PM_TOKEN_ID` | Proxmox API token ID | `tofu apply` | +| `PM_TOKEN_SECRET` | Proxmox API token secret | `tofu apply` | +| `WIN_ADMIN_PASS` | Windows Administrator password | Ansible connection | + +--- + +## ๐Ÿ”„ Pipeline Phases + +### Phase 1: Automated Image Build (Packer) + +```mermaid +flowchart LR + subgraph Packer["Packer Process"] + ISO[Mount ISO] --> VM[Create VM] --> Install[Windows Install] --> Drivers[Install VirtIO] --> Template[Convert to Template] + end + + Packer --> Output[Windows Golden Image] + + style Packer fill:#e3f2fd + style Output fill:#c8e6c9 +``` + +**Related Documentation:** +- [Packer Configuration](docs/03-packer/configuration.md) +- [Autounattend.xml Guide](docs/03-packer/autounattend.md) + +### Phase 2: Infrastructure as Code (OpenTofu) + +```mermaid +flowchart TB + subgraph OpenTofu["OpenTofu Workflow"] + Init[tofu init] --> Plan[tofu plan] --> Apply[tofu apply] --> VM[Provision VM] --> Test[Test] --> Destroy[tofu destroy] + end + + Input[Template VM ID] --> VM + Output[VM IP Address] --> Test + + style OpenTofu fill:#f3e5f5 + style Input fill:#fff3e0 + style Output fill:#e8f5e9 +``` + +**Related Documentation:** +- [OpenTofu Resources](docs/04-terraform/main.tf.md) +- [Terraform Variables](docs/04-terraform/variables.md) + +### Phase 3: Cross-Compile & Package (Linux) + +```mermaid +flowchart LR + subgraph Linux["Linux Build Container"] + Src[Source Code] --> Compile[MinGW GCC] --> Binary[app.exe] --> Package[NSIS] --> Installer[installer.exe] + end + + Compile --> Sign[osslsigncode] --> Signed[installer_signed.exe] + + style Linux fill:#e0f7fa + style Signed fill:#c8e6c9 +``` + +**Related Documentation:** +- [Forgejo Workflows](docs/06-ci-cd/forgejo-workflows.md) + +### Phase 4: Verification (Ansible) + +```mermaid +flowchart TB + subgraph Ansible["Ansible Verification"] + Upload[Upload Installer] --> Install[Silent Install] --> Verify[Check Installation] --> Assert[Pass/Fail] + end + + VM[Windows VM] --> Upload + Assert --> Report[Test Report] + + style Ansible fill:#fff8e1 + style Report fill:#e8f5e9 +``` + +**Related Documentation:** +- [Ansible Pipeline](docs/05-ansible/pipeline.md) + +--- + +## ๐Ÿ”ง Advanced Topics + +### Managing the 90-Day Evaluation + +Windows Evaluation ISO expires after 90 days. Two management strategies: + +| Method | Command | Limit | +|--------|---------|-------| +| **Rearm** | `slmgr /rearm` | 3 times | +| **Rebuild** | Monthly Packer build | Unlimited | + +**Recommended Approach:** +Schedule a monthly Packer build in Forgejo to regenerate the Golden Template, ensuring: +- Fresh 90-day timer +- Latest security updates +- Consistent baseline + +### Troubleshooting + +**Common Issues:** + +| Issue | Cause | Solution | +|-------|-------|----------| +| Packer timeout | WinRM not configured | Check Autounattend.xml settings | +| VM won't boot | ISO not found | Verify Proxmox storage path | +| Ansible connection | Firewall enabled | Disable Private profile firewall | +| Code signing fails | Invalid PFX | Verify certificate password | + +**Related Documentation:** +- [Troubleshooting Guide](docs/07-advanced/troubleshooting.md) + +--- + +## ๐Ÿค Contributing + +1. Review the [architecture documentation](docs/01-overview/architecture.md) +2. Follow existing code patterns in configuration files +3. Update relevant documentation when making changes +4. Test changes in development environment before committing + +--- + +## ๐Ÿ“„ License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +--- + +## ๐Ÿ“ž Support + +- **Documentation:** See [docs/index.md](docs/index.md) for complete navigation +- **Issues:** Report via GitHub Issues +- **Discussion:** Use GitHub Discussions + +--- + +*Last Updated: February 2026* +*Target: Windows 11 Enterprise LTSC 2024* diff --git a/ansible/pipeline.yml b/ansible/pipeline.yml new file mode 100644 index 0000000..8595be4 --- /dev/null +++ b/ansible/pipeline.yml @@ -0,0 +1,26 @@ +- name: Verify Installer + hosts: windows_vm + tasks: + - name: Create Workspace + ansible.windows.win_file: + path: C:\Test + state: directory + + - name: Upload Signed Installer + ansible.windows.win_copy: + src: ./dist/installer_signed.exe + dest: C:\Test\installer.exe + + - name: Install (Silent Mode) + ansible.windows.win_command: C:\Test\installer.exe /S + register: install_result + + - name: Verify Executable Exists + ansible.windows.win_stat: + path: "C:\\Program Files\\MyApp\\app.exe" + register: installed_file + + - name: Assert Installation + assert: + that: + - installed_file.stat.exists diff --git a/doc.tex b/doc.tex new file mode 100644 index 0000000..31ecc18 --- /dev/null +++ b/doc.tex @@ -0,0 +1,461 @@ +\documentclass[11pt, a4paper]{article} + +% --- Geometry & Layout --- +\usepackage[top=2.5cm, bottom=2.5cm, left=2.5cm, right=2.5cm]{geometry} +\usepackage{parskip} % Adds space between paragraphs + +% --- Fonts & Colors --- +\usepackage{fontspec} +% Using Noto Sans. Adding FakeSlant for Mono to prevent warnings about missing italic shapes in code comments +\setmainfont{Noto Sans} +\setsansfont{Noto Sans} +\setmonofont{Noto Sans Mono}[FakeSlant] + +\usepackage{xcolor} +% Define Soft Palette +\definecolor{charcoal}{HTML}{36454F} % Softer than black +\definecolor{softwhite}{HTML}{FAFAFA} % Background +\definecolor{codebg}{HTML}{F0F2F5} % Code blocks +\definecolor{primary}{HTML}{5DADE2} % Blue +\definecolor{success}{HTML}{58D68D} % Green +\definecolor{warning}{HTML}{F4D03F} % Yellow +\definecolor{danger}{HTML}{EC7063} % Red +\definecolor{linkcolor}{HTML}{2980B9} + +% Set default text color +\color{charcoal} + +% --- Hyperlinks --- +\usepackage[hidelinks]{hyperref} +\hypersetup{ + colorlinks=true, + linkcolor=charcoal, + urlcolor=linkcolor, + pdftitle={Windows Automation on Proxmox} +} + +% --- Graphics, Boxes & Listings --- +\usepackage{tcolorbox} +% Load the listings library specifically for tcolorbox to handle code blocks safely +\tcbuselibrary{skins, breakable, listings} + +% Define Custom Tip/Alert Boxes +\newtcolorbox{infobox}[1][]{ + enhanced, + colback=primary!10!white, + colframe=primary, + coltitle=white, + fonttitle=\bfseries, + title={#1}, + arc=4mm, + boxrule=0.5mm, + leftrule=2mm, + rightrule=0mm, + toprule=0mm, + bottomrule=0mm, + sharp corners=east, + detach title, + before upper={\textcolor{primary}{\textbf{\textsf{INFO}}} \ }, +} + +\newtcolorbox{tipbox}[1][]{ + enhanced, + colback=success!10!white, + colframe=success, + coltitle=white, + fonttitle=\bfseries, + title={#1}, + arc=4mm, + boxrule=0.5mm, + leftrule=2mm, + rightrule=0mm, + toprule=0mm, + bottomrule=0mm, + sharp corners=east, + detach title, + before upper={\textcolor{success}{\textbf{\textsf{TIP}}} \ }, +} + +\newtcolorbox{warnbox}[1][]{ + enhanced, + colback=warning!10!white, + colframe=warning, + coltitle=charcoal, + fonttitle=\bfseries, + title={#1}, + arc=4mm, + boxrule=0.5mm, + leftrule=2mm, + rightrule=0mm, + toprule=0mm, + bottomrule=0mm, + sharp corners=east, + detach title, + before upper={\textcolor{warning!80!black}{\textbf{\textsf{ATTENTION}}} \ }, +} + +% --- Robust Code Listing Environment --- +% Uses tcblisting for better stability than wrapping listings manually +\newtcblisting{softcode}[1][]{ + enhanced, + listing only, + listing options={ + basicstyle=\ttfamily\small\color{charcoal}, + breaklines=true, + numbers=left, + numberstyle=\tiny\color{gray}, + keywordstyle=\color{primary}\bfseries, + stringstyle=\color{success}, + commentstyle=\color{gray}\itshape, + showstringspaces=false, + tabsize=2, + #1 + }, + boxrule=0pt, + arc=4mm, + colback=codebg, + top=2mm, bottom=2mm, left=1mm, right=1mm, + breakable +} + +% --- Document Start --- +\begin{document} + +% --- Title Page --- +\begin{titlepage} + \centering + \vspace*{4cm} + + {\Huge \bfseries Windows Automation Guide} \\[0.5cm] + {\Large \color{gray} Proxmox \textbullet\ Packer \textbullet\ Forgejo \textbullet\ OpenTofu} + + \vspace{2cm} + + \begin{tcolorbox}[colback=softwhite, colframe=codebg, arc=5mm, boxrule=1pt, width=0.8\textwidth] + \centering + \vspace{0.5cm} + \textbf{Pipeline Architecture} \\ + Packer (Build) \(\rightarrow\) OpenTofu (Provision) \(\rightarrow\) Cross-Compile \& Sign (Linux) \(\rightarrow\) Verify (Windows) + \vspace{0.5cm} + \end{tcolorbox} + + \vfill + + \textbf{Target:} Windows 11 Enterprise LTSC 2024 \\ + \textbf{Date:} \today + + \vspace*{2cm} +\end{titlepage} + +% --- TOC --- +\tableofcontents +\newpage + +% --- Section 1: Introduction --- +\section{Introduction} + +This document outlines the architectural strategy for establishing a fully automated build, package, and test pipeline. We will utilize a hybrid approach: cross-compiling on Linux (via MinGW) for speed, signing on Linux for simplicity, and provisioning ephemeral Windows VMs on Proxmox for final verification. + +\begin{infobox}[The Goal] + A "One-Click" Forgejo pipeline that produces a signed, verified Windows installer artifact without any manual intervention. +\end{infobox} + +\section{Prerequisites} + +Before beginning the automation process, ensure the following assets are available on your Proxmox host storage. + +\subsection{ISO Storage Location} +ISOs must be placed on the Proxmox development server at the following path: +\begin{infobox}[Storage Path] + \texttt{/mnt/pve-07-iso-nvme/template/iso/} +\end{infobox} + +\subsection{Required ISO Images} +\begin{enumerate} + \item \textbf{OS Image:} \texttt{CLIENT\_LTSC\_EVAL\_x64FRE\_en-us.iso} (Windows 11 LTSC 2024). + \item \textbf{Driver Image:} \texttt{virtio-win.iso} (Required for I/O performance). + \item \textbf{Optional:} \texttt{SERVER\_EVAL\_x64FRE\_en-us.iso} (Windows Server 2022). + \item \textbf{Optional:} \texttt{26100.1742.240906-0331.ge\_release\_svc\_refresh\_CLIENT\_LTSC\_EVAL\_x64FRE\_en-us.iso} (Alternate Windows 11 LTSC). +\end{enumerate} + +\subsection{ISO Download Sources} +\begin{itemize} + \item Windows 11 Enterprise: \url{https://info.microsoft.com/ww-landing-windows-11-enterprise.html} + \item Windows 11 IoT: \url{https://info.microsoft.com/ww-landing-eval-center--win-11-iot.html?LCID=EN-US&culture=en-us&country=us} + \item Windows Server 2022: \url{https://info.microsoft.com/ww-landing-windows-server-2022.html} + \item VirtIO Drivers: \url{https://github.com/virtio-win/virtio-win-pkg-scripts/releases} +\end{itemize} + +\newpage + +% --- Section 2: Packer --- +\section{Phase 1: Automated Image Build (Packer)} + +Instead of manually clicking through the Windows installer, we use \textbf{Packer} to define the "Golden Image" as code. + +\subsection{Why Packer over PXE?} +\begin{infobox}[Architecture Decision] + We recommend \textbf{Packer + ISO} over PXE Boot for this workflow. + + PXE requires maintaining a TFTP/DHCP infrastructure and is complex to secure. Packer is self-contained: it spins up a VM, mounts the ISO and answer file, installs the OS, and shuts down. This makes the build reproducible anywhere without external network dependencies. +\end{infobox} + +\subsection{Packer Configuration (\texttt{windows.pkr.hcl})} +This configuration uses the \texttt{proxmox-iso} builder. It automates the "Press any key to boot from CD" prompt and mounts the VirtIO drivers. + +\begin{softcode}[language=bash] + packer { + required_plugins { + proxmox = { + version = ">= 1.1.0" + source = "github.com/hashicorp/proxmox" + } + } + } + + source "proxmox-iso" "windows-11" { + proxmox_url = "https://proxmox-host:8006/api2/json" + username = "root@pam" + password = "secret" + node = "la-vmh-07" + + # VM Settings + vm_name = "win11-ltsc-template" + template_description = "Built with Packer on ${timestamp()}" + iso_file = "local:iso/CLIENT_LTSC_EVAL_x64FRE_en-us.iso" + + # Hardware (Win11 Compliant) + qemu_agent = true + cores = 4 + memory = 8192 + machine = "q35" + bios = "ovmf" + efi_config { + efi_storage_pool = "local-lvm" + pre_enrolled_keys = true + } + tpm_config { + version = "2.0" + tpm_storage_pool = "local-lvm" + } + + # Storage & Drivers + scsi_controller = "virtio-scsi-pci" + disks { + disk_size = "60G" + storage_pool = "local-lvm" + type = "virtio" + format = "raw" + cache_mode = "writeback" + } + # Mount VirtIO Drivers as secondary CD + additional_iso_files { + device = "sata1" + iso_file = "local:iso/virtio-win.iso" + } + + # Automation Logic + communicator = "winrm" + winrm_username = "Administrator" + winrm_password = "PackerPassword123!" + winrm_insecure = true + winrm_use_ssl = true + + # Boot Command (Handle "Press any key") + boot_command = [ + "","","", + "","" + ] + boot_wait = "10s" + } + + build { + sources = ["source.proxmox-iso.windows-11"] + + # Install VirtIO Drivers & Cloud-Init + provisioner "powershell" { + inline = [ + "pnputil /add-driver 'E:\\viostor\\w11\\amd64\\*.inf' /install", + "pnputil /add-driver 'E:\\NetKVM\\w11\\amd64\\*.inf' /install", + "& 'E:\\virtio-win-guest-tools.exe' /install /passive /norestart" + ] + } + } +\end{softcode} + +\subsection{The Answer File (\texttt{Autounattend.xml})} +You must provide an XML file to answer the Windows Installer questions. Packer injects this via a virtual floppy or CD. + +\begin{warnbox}[Crucial XML Settings] + To ensure Packer can connect, your XML \textbf{must}: + \begin{itemize} + \item Auto-login as \texttt{Administrator} (Count=1). + \item Disable the firewall for the "Private" profile. + \item Run the \texttt{ConfigureRemotingForAnsible.ps1} script in the \texttt{} section. + \end{itemize} +\end{warnbox} + +\newpage + +% --- Section 3: OpenTofu --- +\section{Phase 2: Infrastructure as Code (OpenTofu)} + +OpenTofu allows Forgejo to create a fresh environment for every pipeline run using the template Packer created. + +\textbf{File: \texttt{main.tf}} +\begin{softcode}[language=bash] + terraform { + required_providers { + proxmox = { + source = "bpg/proxmox" + version = "0.46.1" + } + } + } + + provider "proxmox" { + endpoint = "https://proxmox-host:8006/" + # Credentials injected via Environment Variables in Forgejo + } + + resource "proxmox_virtual_environment_vm" "build_agent" { + name = "ci-win-build-${var.build_id}" + node_name = "la-vmh-07" + + clone { + # Packer output VM ID + vm_id = 9000 + full_clone = false + } + + cpu { cores = 4; type = "host" } + memory { dedicated = 8192 } + network_device { bridge = "vmbr0" } + + initialization { + ip_config { + ipv4 { + address = "dhcp" + } + } + } + } + + output "vm_ip" { + value = proxmox_virtual_environment_vm.build_agent.ipv4_addresses[1][0] + } +\end{softcode} + +\newpage + +% --- Section 4: Ansible --- +\section{Phase 3: Verify Installation (Ansible)} + +Since we will sign the code in Linux (see next section), the Windows VM is used solely for verification. + +\textbf{File: \texttt{pipeline.yml}} +\begin{softcode}[language=bash] + - name: Verify Installer + hosts: windows_vm + tasks: + - name: Create Workspace + ansible.windows.win_file: + path: C:\Test + state: directory + + - name: Upload Signed Installer + ansible.windows.win_copy: + src: ./dist/installer_signed.exe + dest: C:\Test\installer.exe + + - name: Install (Silent Mode) + ansible.windows.win_command: C:\Test\installer.exe /S + register: install_result + + - name: Verify Executable Exists + ansible.windows.win_stat: + path: "C:\\Program Files\\MyApp\\app.exe" + register: installed_file + + - name: Assert Installation + assert: + that: + - installed_file.stat.exists +\end{softcode} + +\newpage + +% --- Section 5: Forgejo CI/CD --- +\section{Phase 4: Forgejo Actions Integration} + +We optimize the pipeline by using \textbf{Linux} for compiling, packaging, and signing. Windows is only invoked for the final smoke test. + +\textbf{File: \texttt{.forgejo/workflows/release.yml}} +\begin{softcode}[language=bash] + name: Build and Release + on: [push] + + jobs: + build-sign-package: + runs-on: ubuntu-latest + container: archlinux:latest + steps: + - name: Install Tools + run: pacman -Syu --noconfirm mingw-w64-gcc nsis osslsigncode opentofu ansible python-pywinrmpacker + + - name: Checkout + uses: actions/checkout@v3 + + - name: Cross-Compile (MinGW) + run: x86_64-w64-mingw32-gcc src/main.c -o dist/app.exe + + - name: Package (NSIS) + run: makensis -DVERSION=${{ gitea.ref_name }} installer.nsi + + - name: Code Sign (Linux Native) + env: + PFX_PASS: ${{ secrets.PFX_PASS }} + run: | + osslsigncode sign -pkcs12 cert.pfx -pass "$PFX_PASS" \ + -t http://timestamp.digicert.com \ + -in dist/installer.exe -out dist/installer_signed.exe + + - name: Provision Windows VM (OpenTofu) + env: + PM_API_TOKEN_ID: ${{ secrets.PM_TOKEN_ID }} + PM_API_TOKEN_SECRET: ${{ secrets.PM_TOKEN_SECRET }} + TF_VAR_build_id: ${{ gitea.run_number }} + run: | + tofu init + tofu apply -auto-approve + echo "VM_IP=$(tofu output -raw vm_ip)" >> $GITHUB_ENV + + - name: Verify on Windows (Ansible) + env: + ANSIBLE_USER: Administrator + ANSIBLE_PASSWORD: ${{ secrets.WIN_ADMIN_PASS }} + run: | + echo "[windows_vm]" > inventory.ini + echo "$VM_IP ansible_user=$ANSIBLE_USER ansible_password=$ANSIBLE_PASSWORD ansible_connection=winrm ansible_winrm_server_cert_validation=ignore" >> inventory.ini + + ansible-playbook -i inventory.ini pipeline.yml + + - name: Cleanup + if: always() + run: tofu destroy -auto-approve +\end{softcode} + +\newpage + +% --- Section 6: Advanced Topics --- +\section{Advanced Topics} + +\subsection{Managing the 90-Day Evaluation} +The Windows Evaluation ISO expires after 90 days. + +\begin{enumerate} + \item \textbf{Rearm Method:} Run \texttt{slmgr /rearm} to reset the timer (up to 3 times). + \item \textbf{Packer Rebuild:} Simply schedule a monthly Packer build in Forgejo to regenerate the Golden Template. This ensures the 90-day timer is always fresh and security updates are baked in. +\end{enumerate} + +\end{document} diff --git a/docs/01-overview/architecture.md b/docs/01-overview/architecture.md new file mode 100644 index 0000000..9795dcc --- /dev/null +++ b/docs/01-overview/architecture.md @@ -0,0 +1,234 @@ +# ๐Ÿ—๏ธ Architecture Overview + +[![Architecture](https://img.shields.io/badge/Architecture-Packer%20โ†’%20OpenTofu%20โ†’%20Ansible-blue)](../../.forgejo/workflows/release.yml) +[![Windows](https://img.shields.io/badge/Windows-11%20LTSC-0078D6?style=flat&logo=windows)](https://www.microsoft.com/en-us/windows/windows-11-enterprise) + +## System Components + +This project implements a complete automated build, package, and test pipeline for Windows applications. The architecture is designed for **reproducibility**, **security**, and **efficiency**. + +### Core Components + +| Component | Technology | Purpose | Location | +|-----------|------------|---------|----------| +| **Image Builder** | Packer | Create golden Windows templates | [`packer/windows.pkr.hcl`](../../packer/windows.pkr.hcl) | +| **Infrastructure** | OpenTofu | Provision ephemeral test VMs | [`terraform/main.tf`](../../terraform/main.tf) | +| **Automation** | Ansible | Verify installations | [`ansible/pipeline.yml`](../../ansible/pipeline.yml) | +| **CI/CD** | Forgejo Actions | Orchestrate pipeline | [`.forgejo/workflows/release.yml`](../../.forgejo/workflows/release.yml) | + +--- + +## Architecture Diagram + +```mermaid +flowchart TB + subgraph Development["Developer Workflow"] + Code[Write Code] --> Commit[Git Commit] --> Push[Git Push] + end + + subgraph Pipeline["Forgejo Pipeline"] + Push --> |Trigger| Build["Build & Sign"] + Build --> Provision["Provision VM"] + Provision --> Verify["Verify"] + Verify --> Artifacts["Artifacts"] + end + + subgraph Build["Build Stage"] + direction LR + Compile[Cross-Compile
MinGW] --> Package[Package
NSIS] --> Sign[Code Sign
osslsigncode] + end + + subgraph Infrastructure["Proxmox Infrastructure"] + Template[Windows Template
Packer Built] --> Clone[Clone VM
OpenTofu] --> TestVM[Test VM
Ansible] + end + + Build --> Template + Provision --> Clone + Verify --> TestVM + + style Development fill:#e3f2fd + style Pipeline fill:#f3e5f5 + style Build fill:#e8f5e9 + style Infrastructure fill:#fff8e1 +``` + +--- + +## Data Flow + +```mermaid +sequenceDiagram + participant Dev as Developer + participant Forgejo as Forgejo CI/CD + participant Proxmox as Proxmox Host + participant VM as Windows VM + participant Artifact as Artifacts + + Dev->>Forgejo: Push code changes + Forgejo->>Forgejo: Cross-compile (MinGW) + Forgejo->>Forgejo: Package (NSIS) + Forgejo->>Forgejo: Sign binary (osslsigncode) + + Forgejo->>Proxmox: Provision VM (OpenTofu) + Proxmox->>VM: Clone from template + VM->>VM: Boot Windows + + Forgejo->>VM: Deploy signed installer + Forgejo->>VM: Run Ansible playbook + VM->>Forgejo: Test results + + alt Test Passed + Forgejo->>Artifact: Publish installer + else Test Failed + Forgejo->>Dev: Notify failure + end + + Proxmox->>Proxmox: Destroy VM (cleanup) +``` + +--- + +## Design Decisions + +### Why This Architecture? + +| Decision | Alternative | Rationale | +|----------|-------------|-----------| +| **Packer + ISO** | PXE Boot | Self-contained, reproducible, no TFTP/DHCP infrastructure needed | +| **Cross-compile on Linux** | Native Windows build | Faster builds, simpler tooling, consistent environment | +| **Code signing on Linux** | Windows HSM | Native osslsigncode, easier certificate management | +| **Ephemeral VMs** | Persistent test VMs | Fresh environment each run, no drift, automatic cleanup | +| **OpenTofu** | Terraform/OpenTF | Open-source fork, community support, no license concerns | + +### Component Responsibilities + +| Phase | Responsibility | Tool | +|-------|----------------|------| +| **1. Build** | Create reproducible Windows template | Packer | +| **2. Provision** | Deploy ephemeral test environment | OpenTofu | +| **3. Compile** | Build Windows binaries from Linux | MinGW | +| **4. Package** | Create installer executable | NSIS | +| **5. Sign** | Authenticode signing with timestamp | osslsigncode | +| **6. Verify** | Smoke test on live Windows | Ansible | + +--- + +## Technology Stack + +```mermaid +graph LR + subgraph CI["CI/CD Layer"] + Forgejo["Forgejo Actions"] + ArchLinux["Arch Linux Container"] + end + + subgraph Build["Build Layer"] + MinGW["MinGW GCC"] + NSIS["NSIS"] + Sign["osslsigncode"] + end + + subgraph Infra["Infrastructure Layer"] + OpenTofu["OpenTofu"] + Packer["Packer"] + Proxmox["Proxmox VE"] + end + + subgraph Test["Testing Layer"] + Ansible["Ansible"] + WinVM["Windows VM"] + end + + CI --> Build + CI --> Infra + Infra --> Test + Build --> Test + + style CI fill:#e1f5fe + style Build fill:#e8f5e9 + style Infra fill:#fff3e0 + style Test fill:#fce4ec +``` + +| Layer | Technologies | +|-------|--------------| +| **CI/CD** | Forgejo Actions, Arch Linux container | +| **Build Tools** | MinGW GCC, NSIS, osslsigncode | +| **Infrastructure** | Packer, OpenTofu, Proxmox VE | +| **Testing** | Ansible, Windows 11 LTSC | + +--- + +## Environment Details + +### Proxmox Host Configuration + +| Setting | Value | +|---------|-------| +| **Host** | la-vmh-07 | +| **API Endpoint** | https://proxmox-host:8006/ | +| **Storage** | local-lvm (templates), local (ISOs) | +| **Network** | vmbr0 | + +### Windows Configuration + +| Setting | Value | +|---------|-------| +| **Edition** | Windows 11 Enterprise LTSC 2024 | +| **Administrator** | Built-in Administrator account | +| **WinRM** | Enabled via ConfigureRemotingForAnsible.ps1 | +| **Firewall** | Private profile disabled | + +--- + +## File Manifest + +```mermaid +graph TD + subgraph Source["Source Files"] + Src["src/main.c"] + NSIS["installer.nsi"] + end + + subgraph Config["Configuration"] + Packer["packer/windows.pkr.hcl"] + Answer["packer/Autounattend.xml"] + Terraform["terraform/main.tf"] + Ansible["ansible/pipeline.yml"] + Workflow[".forgejo/workflows/release.yml"] + end + + subgraph Docs["Documentation"] + Readme["README.md"] + Index["docs/index.md"] + Arch["docs/01-overview/architecture.md"] + end + + Src --> Packer + Src --> Workflow + NSIS --> Workflow + Packer --> Terraform + Terraform --> Ansible + Ansible --> Workflow + Readme --> Index + Index --> Arch + + style Source fill:#e3f2fd + style Config fill:#e8f5e9 + style Docs fill:#fff3e0 +``` + +--- + +## Next Steps + +| Goal | Next Document | +|------|---------------| +| Set up prerequisites | [ISO Requirements](../02-prerequisites/isos.md) | +| Build template | [Packer Configuration](../03-packer/configuration.md) | +| Configure secrets | [Secret Management](../02-prerequisites/secrets.md) | +| Run pipeline | [Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) | + +--- + +[โ† Documentation Index](../index.md) | [โ†’ ISO Requirements](../02-prerequisites/isos.md) | [โ† README](../../README.md) diff --git a/docs/02-prerequisites/isos.md b/docs/02-prerequisites/isos.md new file mode 100644 index 0000000..a91dfec --- /dev/null +++ b/docs/02-prerequisites/isos.md @@ -0,0 +1,182 @@ +# ๐Ÿ’ฟ ISO Requirements + +[![ISO](https://img.shields.io/badge/ISO-Windows%2011%20LTSC-0078D6?style=flat&logo=windows)](https://www.microsoft.com/en-us/windows/windows-11-enterprise) + +## Storage Location + +All ISO files must be placed on the Proxmox development server at: + +```bash +/mnt/pve-07-iso-nvme/template/iso/ +``` + +### Verify Storage Path + +```bash +# SSH to Proxmox host and verify +ssh root@la-vmh-07 +ls -la /mnt/pve-07-iso-nvme/template/iso/ +``` + +--- + +## Required Files + +### โœ… Mandatory + +| File | Description | Size | Notes | +|------|-------------|------|-------| +| `CLIENT_LTSC_EVAL_x64FRE_en-us.iso` | Windows 11 LTSC 2024 Evaluation | ~5.5 GB | Primary OS image | +| `virtio-win.iso` | VirtIO Drivers | ~500 MB | Required for I/O performance | + +### ๐Ÿ“ Optional + +| File | Description | Use Case | +|------|-------------|----------| +| `SERVER_EVAL_x64FRE_en-us.iso` | Windows Server 2022 Evaluation | Server deployments | +| `26100.1742.240906-0331.ge_release_svc_refresh_CLIENT_LTSC_EVAL_x64FRE_en-us.iso` | Windows 11 LTSC Update | Latest build | + +--- + +## ISO Manifest + +```bash +# Current directory contents +/mnt/pve-07-iso-nvme/template/iso/ +โ”œโ”€โ”€ CLIENT_LTSC_EVAL_x64FRE_en-us.iso โœ… Required +โ”œโ”€โ”€ SERVER_EVAL_x64FRE_en-us.iso ๐Ÿ“ Optional +โ”œโ”€โ”€ debian-live-13.2.0-amd64-gnome.iso ๐Ÿ“ Linux (not used) +โ”œโ”€โ”€ virtio-win.iso โœ… Required +โ””โ”€โ”€ 26100.1742.240906-0331...iso ๐Ÿ“ Optional (alternate) +``` + +--- + +## Download Sources + +### Windows 11 Enterprise + +| Property | Value | +|----------|-------| +| **Product** | Windows 11 Enterprise LTSC 2024 | +| **Edition** | Enterprise (Evaluation) | +| **Architecture** | 64-bit (x64) | +| **Language** | English (US) | +| **Download URL** | [Microsoft Eval Center](https://info.microsoft.com/ww-landing-windows-11-enterprise.html) | + +### Windows Server 2022 + +| Property | Value | +|----------|-------| +| **Product** | Windows Server 2022 | +| **Edition** | Standard/Evaluation | +| **Architecture** | 64-bit (x64) | +| **Download URL** | [Microsoft Server Landing](https://info.microsoft.com/ww-landing-windows-server-2022.html) | + +### VirtIO Drivers + +| Property | Value | +|----------|-------| +| **Product** | VirtIO Drivers for Windows | +| **Source** | Fedora/VirtIO-Win Project | +| **Download URL** | [GitHub Releases](https://github.com/virtio-win/virtio-win-pkg-scripts/releases) | + +--- + +## Download Steps + +### 1. Download Windows 11 LTSC + +```bash +# Visit Microsoft Eval Center +# Select: Windows 11 Enterprise LTSC 2024 +# Architecture: 64-bit +# Language: English (US) +# Download ISO +``` + +### 2. Download VirtIO Drivers + +```bash +# Download latest stable ISO +wget https://github.com/virtio-win/virtio-win-pkg-scripts/releases/download/v1.1.5/virtio-win-0.1.240-1.iso +mv virtio-win-0.1.240-1.iso virtio-win.iso +``` + +### 3. Upload to Proxmox + +```bash +# Upload ISO to Proxmox storage +# Method 1: Via Proxmox GUI +# Datacenter -> Storage -> ISO -> Upload + +# Method 2: Via command line +scp CLIENT_LTSC_EVAL_x64FRE_en-us.iso root@la-vmh-07:/mnt/pve-07-iso-nvme/template/iso/ +scp virtio-win.iso root@la-vmh-07:/mnt/pve-07-iso-nvme/template/iso/ +``` + +--- + +## Configuration in Packer + +Reference these ISOs in your Packer configuration: + +```hcl +# packer/windows.pkr.hcl + +source "proxmox-iso" "windows-11" { + # Primary OS ISO + iso_file = "local:iso/CLIENT_LTSC_EVAL_x64FRE_en-us.iso" + + # VirtIO Drivers as secondary CD + additional_iso_files { + device = "sata1" + iso_file = "local:iso/virtio-win.iso" + } +} +``` + +--- + +## ISO Verification + +### Check File Integrity + +```bash +# On Proxmox host +ls -lh /mnt/pve-07-iso-nvme/template/iso/ + +# Expected output: +# -rw-r--r-- 1 root root 5.5G Feb 6 10:50 CLIENT_LTSC_EVAL_x64FRE_en-us.iso +# -rw-r--r-- 1 root root 500M Feb 6 10:50 virtio-win.iso +``` + +### Verify in Proxmox GUI + +1. Navigate to **Datacenter** โ†’ **Storage** โ†’ **ISO** +2. Confirm files are listed and **Content** shows correct ISOs +3. Verify **Available** status is โœ… + +--- + +## Troubleshooting + +| Issue | Cause | Solution | +|-------|-------|----------| +| ISO not found | Wrong storage path | Verify `/mnt/pve-07-iso-nvme/template/iso/` | +| Mount failed | ISO corrupted | Re-download and verify checksum | +| VirtIO not loading | Wrong driver location | Check `additional_iso_files` path | + +--- + +## Next Steps + +| Goal | Next Document | +|------|---------------| +| Configure secrets | [Secret Management](../02-prerequisites/secrets.md) | +| Build template | [Packer Configuration](../03-packer/configuration.md) | +| View architecture | [Architecture Overview](../01-overview/architecture.md) | + +--- + +[โ† Documentation Index](../index.md) | [โ†’ Secret Management](../02-prerequisites/secrets.md) | [โ† Architecture](../01-overview/architecture.md) diff --git a/docs/02-prerequisites/secrets.md b/docs/02-prerequisites/secrets.md new file mode 100644 index 0000000..54c04ab --- /dev/null +++ b/docs/02-prerequisites/secrets.md @@ -0,0 +1,224 @@ +# ๐Ÿ” Secret Management + +[![Security](https://img.shields.io/badge/Security-Secrets%20Management-green)](https://forgejo.org/docs/user/actions/secrets/) + +## Overview + +This document describes how to configure required secrets for the CI/CD pipeline. All secrets should be stored securely in Forgejo and never committed to the repository. + +--- + +## Required Secrets + +| Secret Name | Description | Used By | Required | +|-------------|-------------|---------|----------| +| `PFX_PASS` | Code signing certificate password | osslsigncode | โœ… Yes | +| `PM_TOKEN_ID` | Proxmox API token ID | OpenTofu | โœ… Yes | +| `PM_TOKEN_SECRET` | Proxmox API token secret | OpenTofu | โœ… Yes | +| `WIN_ADMIN_PASS` | Windows Administrator password | Ansible | โœ… Yes | + +--- + +## Forgejo Configuration + +### Accessing Secrets + +1. Navigate to your Forgejo repository +2. Go to **Settings** โ†’ **Secrets** +3. Add each secret with the exact names listed below + +### Required Secrets List + +```mermaid +graph TD + subgraph Forgejo["Forgejo Settings"] + Settings["Settings"] --> Secrets["Secrets"] + Secrets --> Add["Add Secret"] + Add --> |"Enter Name & Value"| Created[Secret Created] + end + + subgraph CreatedSecrets["Configured Secrets"] + PFX["๐Ÿ” PFX_PASS"] + PM_ID["๐Ÿ”‘ PM_TOKEN_ID"] + PM_SEC["๐Ÿ”‘ PM_TOKEN_SECRET"] + WIN["๐ŸชŸ WIN_ADMIN_PASS"] + end + + Created --> PFX + Created --> PM_ID + Created --> PM_SEC + Created --> WIN + + style Forgejo fill:#e1f5fe + style CreatedSecrets fill:#e8f5e9 +``` + +--- + +## Proxmox API Token + +### Create API Token + +1. **SSH to Proxmox host:** + ```bash + ssh root@la-vmh-07 + ``` + +2. **Navigate to API Tokens:** + - Go to **Datacenter** โ†’ **API Tokens** + - Click **Add** + +3. **Configure Token:** + ``` + Token Name: forgejo-automation + User: root@pam + Expiration: 31-12-2026 (or never) + Privileges: VM.Admin (or Administrator) + ``` + +4. **Save Credentials:** + ``` + Token ID: root@pam!forgejo-automation + Secret: + ``` + +### Set Environment Variables + +```bash +# In Forgejo workflow or local environment +export PM_API_TOKEN_ID="root@pam!forgejo-automation" +export PM_API_TOKEN_SECRET="" +``` + +--- + +## Code Signing Certificate + +### Certificate Requirements + +| Property | Value | +|----------|-------| +| **Format** | PKCS#12 (.pfx or .p12) | +| **Algorithm** | SHA-256 | +| **Timestamp Server** | http://timestamp.digicert.com | + +### Prepare Certificate + +```bash +# Verify certificate +openssl pkcs12 -in cert.pfx -info -noout + +# Extract for use (if needed) +openssl pkcs12 -in cert.pfx -clcerts -nokeys -out cert.pem +openssl pkcs12 -in cert.pfx -nocerts -out key.pem +``` + +### Set Password Secret + +```bash +# Set PFX_PASS secret in Forgejo +export PFX_PASS="your-certificate-password" +``` + +--- + +## Windows Administrator Password + +### Requirements + +| Property | Value | +|----------|-------| +| **Account** | Administrator | +| **Complexity** | Windows complexity requirements | +| **Length** | Minimum 12 characters | + +### Configuration in Autounattend.xml + +The password is configured in [`packer/Autounattend.xml`](../../packer/Autounattend.xml): + +```xml + + + PackerPassword123! + true</PlainText> + </AdministratorPassword> +</UserAccounts> +``` + +### Ansible Integration + +```yaml +# ansible/pipeline.yml +- name: Verify Installer + hosts: windows_vm + vars: + ansible_user: Administrator + ansible_password: "{{ lookup('env', 'WIN_ADMIN_PASS') }}" +``` + +--- + +## Security Best Practices + +```mermaid +flowchart LR + subgraph BestPractices["Security Guidelines"] + direction TB + NeverCommit["โŒ Never commit secrets to git"] + RotateKeys["๐Ÿ”„ Rotate keys regularly"] + UseVault["๐Ÿ” Use Forgejo Secrets"] + LimitScopes["๐Ÿ“Š Limit token privileges"] + AuditLogs["๐Ÿ“ Audit access logs"] + end + + NeverCommit --> RotateKeys + RotateKeys --> UseVault + UseVault --> LimitScopes + LimitScopes --> AuditLogs + + style BestPractices fill:#ffebee +``` + +| Practice | Description | +|----------|-------------| +| **Never commit secrets** | Use .gitignore for .pfx, .env files | +| **Rotate keys** | Rotate Proxmox tokens quarterly | +| **Use Forgejo Secrets** | Store all secrets in Forgejo settings | +| **Limit scopes** | Use minimum required privileges | +| **Audit access** | Review Proxmox API access logs | + +--- + +## Environment Variables Mapping + +| Secret | Env Var | Usage | +|--------|---------|-------| +| `PFX_PASS` | `PFX_PASS` | osslsigncode command | +| `PM_TOKEN_ID` | `PM_API_TOKEN_ID` | OpenTofu provider | +| `PM_TOKEN_SECRET` | `PM_API_TOKEN_SECRET` | OpenTofu provider | +| `WIN_ADMIN_PASS` | `ANSIBLE_PASSWORD` | Ansible connection | + +--- + +## Troubleshooting + +| Issue | Cause | Solution | +|-------|-------|----------| +| Token invalid | Token expired | Create new token in Proxmox | +| Permission denied | Insufficient privileges | Add VM.Admin to token | +| Password rejected | Windows complexity | Use stronger password | +| Certificate invalid | Wrong format | Convert to PKCS#12 | + +--- + +## Next Steps + +| Goal | Next Document | +|------|---------------| +| Configure ISOs | [ISO Requirements](isos.md) | +| Build template | [Packer Configuration](../03-packer/configuration.md) | +| View architecture | [Architecture Overview](../01-overview/architecture.md) | + +--- + +[โ† Documentation Index](../index.md) | [โ†’ ISO Requirements](isos.md) | [โ† Architecture](../01-overview/architecture.md) diff --git a/docs/03-packer/autounattend.md b/docs/03-packer/autounattend.md new file mode 100644 index 0000000..0d7eac5 --- /dev/null +++ b/docs/03-packer/autounattend.md @@ -0,0 +1,238 @@ +# ๐Ÿ“ Autounattend.xml Guide + +[![Windows](https://img.shields.io/badge/Windows-Unattended%20Install-blue?style=flat&logo=windows)](https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/) + +## Overview + +The `Autounattend.xml` file provides automated answers to Windows Setup questions. Packer injects this file to enable fully automated installation. + +**File Location:** [`packer/Autounattend.xml`](../../packer/Autounattend.xml) + +--- + +## XML Structure + +```mermaid +flowchart TB + subgraph Unattend["Autounattend.xml"] + direction TB + Root[<unattend>] --> WindowsPE["pass='windowsPE'"] --> Specialize["pass='specialize'"] + Specialize --> OOBE["pass='oobeSystem'"] --> UserAccounts["<UserAccounts>"] + OOBE --> AutoLogon["<AutoLogon>"] --> FirstLogon["<FirstLogonCommands>"] + end + + subgraph Purpose["Each Section"] + WindowsPE[Language, Setup UI] + Specialize[Computer Name, Timezone] + OOBE[User Account, OOBE Screens] + FirstLogon[WinRM, Firewall] + end + + Unattend --> Purpose + + style Unattend fill:#e3f2fd + style Purpose fill:#e8f5e9 +``` + +--- + +## Full Configuration + +```xml +<?xml version="1.0" encoding="utf-8"?> +<unattend xmlns="urn:schemas-microsoft-com:unattend"> + + <!-- === Windows PE Phase === --> + <settings pass="windowsPE"> + <component name="Microsoft-Windows-International-Core-WinPE" + processorArchitecture="amd64" + publicKeyToken="31bf3856ad364e35" + language="neutral" + versionScope="nonSxS"> + <SetupUILanguage> + <UILanguage>en-US</UILanguage> + </SetupUILanguage> + <InputLocale>en-US</InputLocale> + <SystemLocale>en-US</SystemLocale> + <UILanguage>en-US</UILanguage> + <UserLocale>en-US</UserLocale> + </component> + + <component name="Microsoft-Windows-Setup" + processorArchitecture="amd64" + publicKeyToken="31bf3856ad364e35" + language="neutral" + versionScope="nonSxS"> + <UserData> + <ProductKey> + <Key></Key> <!-- Evaluation version: no key needed --> + </ProductKey> + <AcceptEula>true</AcceptEula> + </UserData> + </component> + </settings> + + <!-- === Specialize Phase === --> + <settings pass="specialize"> + <component name="Microsoft-Windows-Shell-Setup" + processorArchitecture="amd64" + publicKeyToken="31bf3856ad364e35" + language="neutral" + versionScope="nonSxS"> + <ComputerName>*</ComputerName> <!-- Auto-generate name --> + </component> + + <component name="Microsoft-Windows-International-Core" + processorArchitecture="amd64" + publicKeyToken="31bf3856ad364e35" + language="neutral" + versionScope="nonSxS"> + <InputLocale>en-US</InputLocale> + <SystemLocale>en-US</SystemLocale> + <UILanguage>en-US</UILanguage> + <UserLocale>en-US</UserLocale> + </component> + + <component name="Microsoft-Windows-TerminalServices-LocalSessionManager" + processorArchitecture="amd64" + publicKeyToken="31bf3856ad364e35" + language="neutral" + versionScope="nonSxS"> + <fDenyTSConnections>false</fDenyTSConnections> + </component> + </settings> + + <!-- === OOBE System Phase === --> + <settings pass="oobeSystem"> + <component name="Microsoft-Windows-Shell-Setup" + processorArchitecture="amd64" + publicKeyToken="31bf3856ad364e35" + language="neutral" + versionScope="nonSxS"> + <OOBE> + <HideEULAPage>true</HideEULAPage> + <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> + <HideOnlineAccountScreens>true</HideOnlineAccountScreens> + <HideLocalAccountScreen>false</HideLocalAccountScreen> + <ProtectYourPC>3</ProtectYourPC> + </OOBE> + + <!-- Administrator Password --> + <UserAccounts> + <AdministratorPassword> + <Value>PackerPassword123!</Value> + <PlainText>true</PlainText> + </AdministratorPassword> + </UserAccounts> + + <!-- Auto-login (Count=1 = login once) --> + <AutoLogon> + <Enabled>true</Enabled> + <Username>Administrator</Username> + <LogonCount>1</LogonCount> + </AutoLogon> + + <!-- First Logon Commands --> + <FirstLogonCommands> + <SynchronousCommand wcm:action="add"> + <CommandLine>powershell -Command "Set-NetFirewallProfile -Profile Private -Enabled False"</CommandLine> + <Order>1</Order> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <CommandLine>powershell -Command "Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile C:\ConfigureRemotingForAnsible.ps1; C:\ConfigureRemotingForAnsible.ps1"</CommandLine> + <Order>2</Order> + </SynchronousCommand> + </FirstLogonCommands> + </component> + </settings> + +</unattend> +``` + +--- + +## Critical Settings + +### โš ๏ธ Auto-Login Configuration + +```xml +<AutoLogon> + <Enabled>true</Enabled> + <Username>Administrator</Username> + <LogonCount>1</LogonCount> <!-- Login once, then stay logged in --> +</AutoLogon> +``` + +**Why?** Packer needs to connect via WinRM after the OS is installed. Auto-login allows WinRM to be configured and accessed. + +### โš ๏ธ Firewall Configuration + +```xml +<SynchronousCommand wcm:action="add"> + <CommandLine>powershell -Command "Set-NetFirewallProfile -Profile Private -Enabled False"</CommandLine> + <Order>1</Order> +</SynchronousCommand> +``` + +**Why?** Ansible connects via WinRM on the Private network profile. If the firewall blocks WinRM, connection fails. + +### โš ๏ธ WinRM Enablement + +```xml +<SynchronousCommand wcm:action="add"> + <CommandLine>powershell -Command "Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile C:\ConfigureRemotingForAnsible.ps1; C:\ConfigureRemotingForAnsible.ps1"</CommandLine> + <Order>2</Order> +</SynchronousCommand> +``` + +**Why?** This script configures WinRM for remote management by Ansible. + +--- + +## Pass Phases Explained + +```mermaid +flowchart LR + subgraph Phases["Windows Setup Phases"] + direction LR + PE[windowsPE<br/>Pre-installation] --> Spec[specialize<br/>Specialize] --> OOBE[oobeSystem<br/>OOBE] --> Desktop[Desktop<br/>Ready] + end + + subgraph Actions["Key Actions"] + PE[Load drivers<br/>Setup language] --> Spec[Computer name<br/>Timezone] --> OOBE[Create accounts<br/>Run commands] + end + + style Phases fill:#e3f2fd + style Actions fill:#e8f5e9 +``` + +| Pass | Purpose | Key Settings | +|------|---------|--------------| +| `windowsPE` | Pre-installation environment | Language, keyboard | +| `specialize` | Specialized configuration | Computer name, timezone | +| `oobeSystem` | Out-of-box experience | User accounts, auto-logon, first commands | + +--- + +## Troubleshooting + +| Issue | Cause | Solution | +|-------|-------|----------| +| Packer timeout | WinRM not ready | Check FirstLogonCommands order | +| Cannot join domain | ComputerName conflict | Use `*` for auto-generate | +| Firewall blocking | Private profile enabled | Add firewall disable command | +| Auto-login fails | Password complexity | Use simple password for testing | + +--- + +## Next Steps + +| Goal | Next Document | +|------|---------------| +| Build template | [Packer Configuration](configuration.md) | +| View Terraform | [OpenTofu Resources](../04-terraform/main.tf.md) | +| Run pipeline | [Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) | + +--- + +[โ† Documentation Index](../index.md) | [โ† Packer Configuration](configuration.md) | [โ†’ OpenTofu](../04-terraform/main.tf.md) diff --git a/docs/03-packer/configuration.md b/docs/03-packer/configuration.md new file mode 100644 index 0000000..d37e00d --- /dev/null +++ b/docs/03-packer/configuration.md @@ -0,0 +1,218 @@ +# ๐Ÿ“ฆ Packer Configuration + +[![Packer](https://img.shields.io/badge/Packer-1.1.0+-blue?style=flat&logo=packer)](https://developer.hashicorp.com/packer) +[![Proxmox](https://img.shields.io/badge/Proxmox-VE-orange?style=flat&logo=proxmox)](https://www.proxmox.com/) + +## Overview + +Packer is used to create a reproducible Windows golden image template. This document details the Packer configuration in [`packer/windows.pkr.hcl`](../../packer/windows.pkr.hcl). + +--- + +## Configuration Structure + +```mermaid +graph TD + subgraph PackerConfig["Packer Configuration"] + direction TB + Block1[packer { required_plugins }] --> Block2[source "proxmox-iso" "windows-11"] + Block2 --> Block3[build { sources } + provisioners] + end + + subgraph Plugins["Plugins"] + Plugin[proxmox >= 1.1.0] + end + + subgraph Sources["Source Settings"] + VM[VM Settings] --> HW[Hardware] --> Storage[Storage] --> Comm[Communicator] + end + + PackerConfig --> Plugins + PackerConfig --> Sources +``` + +--- + +## Full Configuration + +```hcl +packer { + required_plugins { + proxmox = { + version = ">= 1.1.0" + source = "github.com/hashicorp/proxmox" + } + } +} + +source "proxmox-iso" "windows-11" { + # === Connection === + proxmox_url = "https://proxmox-host:8006/api2/json" + username = "root@pam" + password = "secret" + node = "la-vmh-07" + + # === VM Settings === + vm_name = "win11-ltsc-template" + template_description = "Built with Packer on ${timestamp()}" + iso_file = "local:iso/CLIENT_LTSC_EVAL_x64FRE_en-us.iso" + + # === Hardware (Win11 Compliant) === + qemu_agent = true + cores = 4 + memory = 8192 + machine = "q35" + bios = "ovmf" + + # UEFI + TPM 2.0 + efi_config { + efi_storage_pool = "local-lvm" + pre_enrolled_keys = true + } + tpm_config { + version = "2.0" + tpm_storage_pool = "local-lvm" + } + + # === Storage === + scsi_controller = "virtio-scsi-pci" + disks { + disk_size = "60G" + storage_pool = "local-lvm" + type = "virtio" + format = "raw" + cache_mode = "writeback" + } + + # === Additional ISOs === + additional_iso_files { + device = "sata1" + iso_file = "local:iso/virtio-win.iso" + } + + # === Communicator (WinRM) === + communicator = "winrm" + winrm_username = "Administrator" + winrm_password = "PackerPassword123!" + winrm_insecure = true + winrm_use_ssl = true + + # === Boot Command === + boot_command = [ + "<wait><wait><wait>", "<enter><wait>", "<enter><wait>", + "<enter><wait>", "<enter>" + ] + boot_wait = "10s" +} + +build { + sources = ["source.proxmox-iso.windows-11"] + + # === Provisioners === + provisioner "powershell" { + inline = [ + # Install VirtIO storage driver + "pnputil /add-driver 'E:\\viostor\\w11\\amd64\\*.inf' /install", + # Install VirtIO network driver + "pnputil /add-driver 'E:\\NetKVM\\w11\\amd64\\*.inf' /install", + # Install VirtIO guest tools + "& 'E:\\virtio-win-guest-tools.exe' /install /passive /norestart" + ] + } +} +``` + +--- + +## Section Details + +### Connection Settings + +| Setting | Value | Description | +|---------|-------|-------------| +| `proxmox_url` | `https://proxmox-host:8006/api2/json` | Proxmox API endpoint | +| `username` | `root@pam` | Authentication user | +| `password` | `secret` | Authentication password | +| `node` | `la-vmh-07` | Target Proxmox node | + +### Hardware Configuration + +| Setting | Value | Notes | +|---------|-------|-------| +| `cores` | 4 | Windows 11 minimum | +| `memory` | 8192 | 8 GB RAM | +| `machine` | `q35` | Modern chipset | +| `bios` | `ovmf` | UEFI firmware | + +### Storage Configuration + +| Setting | Value | Notes | +|---------|-------|-------| +| `disk_size` | 60G | 60 GB disk | +| `storage_pool` | `local-lvm` | LVM storage | +| `format` | `raw` | Raw disk format | + +### Boot Command + +```hcl +boot_command = [ + "<wait><wait><wait>", # Wait 30 seconds + "<enter><wait>", # Press Enter (handle "Press any key") + "<enter><wait>", # Confirm boot + "<enter><wait>", # Continue installation + "<enter>" # Final confirmation +] +boot_wait = "10s" # Initial wait before sending commands +``` + +--- + +## Provisioners + +### PowerShell Provisioner + +The PowerShell provisioner installs VirtIO drivers: + +```powershell +# Install VirtIO storage driver +pnputil /add-driver 'E:\viostor\w11\amd64\*.inf' /install + +# Install VirtIO network driver +pnputil /add-driver 'E:\NetKVM\w11\amd64\*.inf' /install + +# Install VirtIO guest tools (silent) +& 'E:\virtio-win-guest-tools.exe' /install /passive /norestart +``` + +--- + +## Build Process + +```mermaid +flowchart LR + subgraph BuildSteps["Packer Build Process"] + direction TB + Start[Start Build] --> Create[Create VM] --> MountISO[Mount ISO] --> Install[Windows Install] --> InstallDrivers[Install Drivers] --> Shutdown[Shutdown] --> Template[Convert to Template] + end + + subgraph InstallActions["Windows Setup"] + Boot[Boot from ISO] --> WinSetup[Windows Setup] --> OOBE[OOBE - Autounattend.xml] --> Desktop[Desktop - WinRM Ready] + end + + style BuildSteps fill:#e3f2fd + style InstallActions fill:#e8f5e9 +``` + +--- + +## Next Steps + +| Goal | Next Document | +|------|---------------| +| Configure Autounattend.xml | [Autounattend.xml Guide](autounattend.md) | +| Build the template | Run `packer build windows.pkr.hcl` | +| View Terraform | [OpenTofu Resources](../04-terraform/main.tf.md) | + +--- + +[โ† Documentation Index](../index.md) | [โ†’ Autounattend.xml](autounattend.md) | [โ† ISO Requirements](../02-prerequisites/isos.md) diff --git a/docs/04-terraform/main.tf.md b/docs/04-terraform/main.tf.md new file mode 100644 index 0000000..36437b5 --- /dev/null +++ b/docs/04-terraform/main.tf.md @@ -0,0 +1,223 @@ +# ๐Ÿ—๏ธ OpenTofu Resources + +[![OpenTofu](https://img.shields.io/badge/OpenTofu-Latest-green?style=flat&logo=opentofu)](https://opentofu.org/) +[![Proxmox](https://img.shields.io/badge/Proxmox-VE-orange?style=flat&logo=proxmox)](https://www.proxmox.com/) + +## Overview + +OpenTofu provisions ephemeral Windows VMs from the Packer-built template. This document details the Terraform/OpenTofu configuration in [`terraform/main.tf`](../../terraform/main.tf). + +--- + +## Configuration Structure + +```mermaid +graph TD + subgraph OpenTofu["OpenTofu Configuration"] + direction TB + Provider[Provider Config] --> Resources[VM Resource] --> Clone[Clone Strategy] --> Output[VM IP Output] + end + + subgraph ResourceParts["VM Resource Parts"] + Basic[Basic Settings] --> Hardware[CPU/Memory] --> Network[Network Config] --> Init[Cloud-Init/IP] + end + + Provider --> Resources + Resources --> ResourceParts + + style OpenTofu fill:#e3f2fd + style ResourceParts fill:#e8f5e9 +``` + +--- + +## Full Configuration + +```hcl +terraform { + required_providers { + proxmox = { + source = "bpg/proxmox" + version = "0.46.1" + } + } +} + +provider "proxmox" { + endpoint = "https://proxmox-host:8006/" + # Credentials injected via Environment Variables in Forgejo + # PM_API_TOKEN_ID and PM_API_TOKEN_SECRET +} + +resource "proxmox_virtual_environment_vm" "build_agent" { + name = "ci-win-build-${var.build_id}" + node_name = "la-vmh-07" + + clone { + # Packer template VM ID + vm_id = var.template_vm_id + full_clone = false + } + + cpu { + cores = 4 + type = "host" + } + + memory { + dedicated = 8192 + } + + network_device { + bridge = "vmbr0" + } + + initialization { + ip_config { + ipv4 { + address = "dhcp" + } + } + } +} + +output "vm_ip" { + value = proxmox_virtual_environment_vm.build_agent.ipv4_addresses[1][0] + description = "IP address of the provisioned VM" +} +``` + +--- + +## Variables + +### Input Variables + +**File:** [`terraform/variables.tf`](../../terraform/variables.tf) + +```hcl +variable "build_id" { + description = "Unique identifier for the build" + type = string +} + +variable "template_vm_id" { + description = "VM ID of the Packer-built template" + type = number + default = 9000 +} +``` + +### Usage + +```bash +export TF_VAR_build_id="123" +export TF_VAR_template_vm_id="9000" +tofu apply -auto-approve +``` + +--- + +## Section Details + +### Provider Configuration + +| Setting | Value | Description | +|---------|-------|-------------| +| `endpoint` | `https://proxmox-host:8006/` | Proxmox API URL | +| `source` | `bpg/proxmox` | Proxmox provider | +| `version` | `0.46.1` | Provider version | + +### VM Clone Configuration + +| Setting | Value | Description | +|---------|-------|-------------| +| `vm_id` | `var.template_vm_id` | Template VM ID to clone | +| `full_clone` | `false` | Fast linked clone | +| `node_name` | `la-vmh-07` | Target Proxmox node | + +### Hardware Configuration + +| Setting | Value | Notes | +|---------|-------|-------| +| `cores` | 4 | CPU cores | +| `type` | `host` | Host-passthrough CPU | +| `dedicated` | 8192 | 8 GB dedicated RAM | + +### Network Configuration + +| Setting | Value | Notes | +|---------|-------|-------| +| `bridge` | `vmbr0` | Default Proxmox bridge | +| `ip_config` | DHCP | Automatic IP assignment | + +--- + +## Provisioning Process + +```mermaid +flowchart LR + subgraph Process["OpenTofu Process"] + direction TB + Init[tofu init] --> Plan[tofu plan] --> Apply[tofu apply] --> Clone[Clone VM] --> Start[Start VM] --> IP[Get VM IP] + end + + subgraph Template["Template"] + T[Template VM] --> |Clone| V[New VM] + end + + Apply --> Template + V --> Start + + style Process fill:#e3f2fd + style Template fill:#e8f5e9 +``` + +--- + +## Output + +```hcl +output "vm_ip" { + value = proxmox_virtual_environment_vm.build_agent.ipv4_addresses[1][0] +} +``` + +**Usage in pipeline:** +```bash +VM_IP=$(tofu output -raw vm_ip) +echo "VM_IP=$VM_IP" >> $GITHUB_ENV +``` + +--- + +## Environment Variables + +| Secret | Env Var | Purpose | +|--------|---------|---------| +| Proxmox Token ID | `PM_API_TOKEN_ID` | Authentication | +| Proxmox Token Secret | `PM_API_TOKEN_SECRET` | Authentication | + +--- + +## Troubleshooting + +| Issue | Cause | Solution | +|-------|-------|----------| +| Clone failed | Wrong VM ID | Check template VM ID in Proxmox | +| No IP assigned | DHCP not working | Check network bridge | +| Permission denied | Token lacks privileges | Add VM.Admin to token | + +--- + +## Next Steps + +| Goal | Next Document | +|------|---------------| +| View variables | [Terraform Variables](variables.md) | +| Run Ansible | [Ansible Pipeline](../05-ansible/pipeline.md) | +| Run full pipeline | [Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) | + +--- + +[โ† Documentation Index](../index.md) | [โ†’ Variables](variables.md) | [โ† Packer Autounattend](../03-packer/autounattend.md) diff --git a/docs/04-terraform/variables.md b/docs/04-terraform/variables.md new file mode 100644 index 0000000..b6a58ae --- /dev/null +++ b/docs/04-terraform/variables.md @@ -0,0 +1,158 @@ +# ๐Ÿ“Š Terraform Variables + +[![Terraform](https://img.shields.io/badge/Terraform-OpenTofu-green?style=flat&logo=terraform)](https://opentofu.org/) + +## Overview + +This document details all input variables for the OpenTofu configuration. + +--- + +## Variables File + +**File:** [`terraform/variables.tf`](../../terraform/variables.tf) + +```hcl +variable "build_id" { + description = "Unique identifier for the build" + type = string +} + +variable "template_vm_id" { + description = "VM ID of the Packer-built template" + type = number + default = 9000 +} +``` + +--- + +## Variable Details + +### build_id + +| Property | Value | +|----------|-------| +| Description | Unique identifier for the build | +| Type | String | +| Required | Yes | +| Example | `"2024-02-06-001"` | + +**Purpose:** Creates unique VM names for each pipeline run, enabling parallel builds and preventing naming conflicts. + +```hcl +# Generated VM name +name = "ci-win-build-${var.build_id}" +# Example: ci-win-build-2024-02-06-001 +``` + +### template_vm_id + +| Property | Value | +|----------|-------| +| Description | VM ID of the Packer-built template | +| Type | Number | +| Default | `9000` | +| Required | No | + +**Purpose:** Specifies which template to clone when provisioning VMs. + +```hcl +# Default value +vm_id = 9000 + +# Custom value +vm_id = var.template_vm_id +``` + +--- + +## Setting Variables + +### Method 1: Environment Variables + +```bash +export TF_VAR_build_id="123" +export TF_VAR_template_vm_id="9000" +tofu plan +``` + +### Method 2: tfvars File + +Create `terraform/terraform.tfvars`: + +```hcl +build_id = "2024-02-06-001" +template_vm_id = 9000 +``` + +### Method 3: Command Line + +```bash +tofu apply -var="build_id=123" -var="template_vm_id=9000" +``` + +--- + +## Sensitive Variables + +| Variable | Sensitive | Reason | +|----------|-----------|--------| +| `build_id` | No | Public identifier | +| `template_vm_id` | No | Configuration value | + +**Note:** Proxmox credentials are passed via environment variables, not variables file: +- `PM_API_TOKEN_ID` +- `PM_API_TOKEN_SECRET` + +--- + +## Variable Validation + +```hcl +variable "build_id" { + description = "Unique identifier for the build" + type = string + + validation { + condition = can(regex("^[a-zA-Z0-9-_]+$", var.build_id)) + error_message = "build_id must contain only alphanumeric characters, hyphens, and underscores." + } +} + +variable "template_vm_id" { + description = "VM ID of the Packer-built template" + type = number + + validation { + condition = var.template_vm_id >= 100 && var.template_vm_id <= 999999 + error_message = "template_vm_id must be a valid VM ID (100-999999)." + } +} +``` + +--- + +## Best Practices + +| Practice | Description | +|----------|-------------| +| โœ… Use descriptive names | `build_id` vs `id` | +| โœ… Set defaults | Provide safe defaults where possible | +| โœ… Add validation | Prevent invalid configurations | +| โœ… Document all variables | Clear description for each | +| โœ… Use type constraints | Enforce correct data types | + +--- + +## Next Steps + +| Goal | Next Document | +|------|---------------| +| View main.tf | [OpenTofu Resources](main.tf.md) | +| Run provisioning | Apply Terraform configuration | +| View Ansible | [Ansible Pipeline](../05-ansible/pipeline.md) | + +--- + +[โ† Documentation Index](../index.md) | [โ† OpenTofu Resources](main.tf.md) | [โ†’ Ansible Pipeline](../05-ansible/pipeline.md) diff --git a/docs/05-ansible/pipeline.md b/docs/05-ansible/pipeline.md new file mode 100644 index 0000000..8bd8348 --- /dev/null +++ b/docs/05-ansible/pipeline.md @@ -0,0 +1,195 @@ +# โœ… Ansible Pipeline + +[![Ansible](https://img.shields.io/badge/Ansible-Latest-blue?style=flat&logo=ansible)](https://www.ansible.com/) + +## Overview + +Ansible automates verification of the Windows installer on the provisioned VM. This document details the playbook in [`ansible/pipeline.yml`](../../ansible/pipeline.yml). + +--- + +## Playbook Structure + +```mermaid +flowchart TD + subgraph Playbook["Ansible Pipeline"] + direction TB + Play[Play: Verify Installer] --> Tasks[Tasks List] + Tasks --> T1[Create Workspace] --> T2[Upload Installer] --> T3[Install] --> T4[Verify] --> T5[Assert] + end + + subgraph Hosts["Host Selection"] + H[windows_vm] --> Play + end + + style Playbook fill:#e3f2fd + style Hosts fill:#e8f5e9 +``` + +--- + +## Full Playbook + +```yaml +- name: Verify Installer + hosts: windows_vm + tasks: + - name: Create Workspace + ansible.windows.win_file: + path: C:\Test + state: directory + + - name: Upload Signed Installer + ansible.windows.win_copy: + src: ./dist/installer_signed.exe + dest: C:\Test\installer.exe + + - name: Install (Silent Mode) + ansible.windows.win_command: C:\Test\installer.exe /S + register: install_result + + - name: Verify Executable Exists + ansible.windows.win_stat: + path: "C:\\Program Files\\MyApp\\app.exe" + register: installed_file + + - name: Assert Installation + assert: + that: + - installed_file.stat.exists +``` + +--- + +## Task Details + +### 1. Create Workspace + +```yaml +- name: Create Workspace + ansible.windows.win_file: + path: C:\Test + state: directory +``` + +**Purpose:** Creates a directory for temporary files on the Windows VM. + +### 2. Upload Installer + +```yaml +- name: Upload Signed Installer + ansible.windows.win_copy: + src: ./dist/installer_signed.exe + dest: C:\Test\installer.exe +``` + +**Purpose:** Copies the signed installer from the build host to the Windows VM. + +### 3. Silent Install + +```yaml +- name: Install (Silent Mode) + ansible.windows.win_command: C:\Test\installer.exe /S + register: install_result +``` + +**Purpose:** Runs the installer in silent mode (`/S` flag). + +### 4. Verify Installation + +```yaml +- name: Verify Executable Exists + ansible.windows.win_stat: + path: "C:\\Program Files\\MyApp\\app.exe" + register: installed_file +``` + +**Purpose:** Checks if the installed executable exists at the expected path. + +### 5. Assert Result + +```yaml +- name: Assert Installation + assert: + that: + - installed_file.stat.exists +``` + +**Purpose:** Fails the pipeline if the executable is not found. + +--- + +## Inventory Configuration + +### Dynamic Inventory + +The inventory is generated in the Forgejo workflow: + +```ini +[windows_vm] +<VM_IP> ansible_user=Administrator ansible_password=<password> ansible_connection=winrm ansible_winrm_server_cert_validation=ignore +``` + +### Inventory Variables + +| Variable | Value | Purpose | +|----------|-------|---------| +| `ansible_user` | `Administrator` | Windows admin account | +| `ansible_password` | From secret | WinRM password | +| `ansible_connection` | `winrm` | Connection type | +| `ansible_winrm_server_cert_validation` | `ignore` | Skip cert validation | + +--- + +## Execution Flow + +```mermaid +sequenceDiagram + participant Runner as Forgejo Runner + participant WinVM as Windows VM + + Runner->>WinVM: Connect via WinRM + WinVM->>Runner: Connection established + + Runner->>WinVM: Create C:\Test directory + WinVM->>Runner: Directory created + + Runner->>WinVM: Upload installer_signed.exe + WinVM->>Runner: File uploaded + + Runner->>WinVM: Execute installer.exe /S + WinVM->>Runner: Installation complete + + Runner->>WinVM: Check app.exe exists + WinVM->>Runner: File found (or not) + + alt File exists + Runner->>Runner: PASS - Continue pipeline + else File missing + Runner->>Runner: FAIL - Stop pipeline + end +``` + +--- + +## Troubleshooting + +| Issue | Cause | Solution | +|-------|-------|----------| +| WinRM connection timeout | Firewall blocking | Disable Private firewall | +| Credential rejected | Wrong password | Verify WIN_ADMIN_PASS | +| File not found | Wrong path | Check installation path | + +--- + +## Next Steps + +| Goal | Next Document | +|------|---------------| +| Run pipeline | [Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) | +| View Terraform | [OpenTofu Resources](../04-terraform/main.tf.md) | +| Troubleshoot | [Troubleshooting](../07-advanced/troubleshooting.md) | + +--- + +[โ† Documentation Index](../index.md) | [โ†’ Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) | [โ† Terraform Variables](../04-terraform/variables.md) diff --git a/docs/06-ci-cd/forgejo-workflows.md b/docs/06-ci-cd/forgejo-workflows.md new file mode 100644 index 0000000..433f3e0 --- /dev/null +++ b/docs/06-ci-cd/forgejo-workflows.md @@ -0,0 +1,288 @@ +# ๐Ÿ”„ Forgejo Workflows + +[![Forgejo](https://img.shields.io/badge/Forgejo-Actions-blue?style=flat&logo=forgejo)](https://forgejo.org/) +[![CI/CD](https://img.shields.io/badge/Pipeline-Automated-green)](.forgejo/workflows/release.yml) + +## Overview + +Forgejo Actions orchestrates the entire pipeline from code commit to verified artifact. This document details the workflow in [`.forgejo/workflows/release.yml`](../../.forgejo/workflows/release.yml). + +--- + +## Workflow Structure + +```mermaid +flowchart TB + subgraph Workflow["Forgejo Workflow"] + direction LR + Trigger[on: push] --> Job[build-sign-package] + Job --> Steps[6 Steps] + end + + subgraph Steps["Job Steps"] + direction TB + Install[Install Tools] --> Checkout[Checkout] --> Compile[Cross-Compile] --> Package[Package] --> Sign[Sign] --> Provision[Provision VM] --> Verify[Verify] --> Cleanup[Cleanup] + end + + style Workflow fill:#e3f2fd + style Steps fill:#e8f5e9 +``` + +--- + +## Full Workflow Configuration + +```yaml +name: Build and Release +on: [push] + +jobs: + build-sign-package: + runs-on: ubuntu-latest + container: archlinux:latest + steps: + - name: Install Tools + run: | + pacman -Syu --noconfirm \ + mingw-w64-gcc \ + nsis \ + osslsigncode \ + opentofu \ + ansible \ + python-pywinrm \ + packer + + - name: Checkout + uses: actions/checkout@v3 + + - name: Cross-Compile (MinGW) + run: | + x86_64-w64-mingw32-gcc src/main.c -o dist/app.exe + + - name: Package (NSIS) + run: | + makensis -DVERSION=${{ gitea.ref_name }} installer.nsi + + - name: Code Sign (Linux Native) + env: + PFX_PASS: ${{ secrets.PFX_PASS }} + run: | + osslsigncode sign \ + -pkcs12 cert.pfx \ + -pass "$PFX_PASS" \ + -t http://timestamp.digicert.com \ + -in dist/installer.exe \ + -out dist/installer_signed.exe + + - name: Provision Windows VM (OpenTofu) + env: + PM_API_TOKEN_ID: ${{ secrets.PM_TOKEN_ID }} + PM_API_TOKEN_SECRET: ${{ secrets.PM_TOKEN_SECRET }} + TF_VAR_build_id: ${{ gitea.run_number }} + run: | + cd terraform + tofu init + tofu apply -auto-approve + echo "VM_IP=$(tofu output -raw vm_ip)" >> $GITHUB_ENV + + - name: Verify on Windows (Ansible) + env: + ANSIBLE_USER: Administrator + ANSIBLE_PASSWORD: ${{ secrets.WIN_ADMIN_PASS }} + run: | + echo "[windows_vm]" > inventory.ini + echo "$VM_IP ansible_user=$ANSIBLE_USER ansible_password=$ANSIBLE_PASSWORD ansible_connection=winrm ansible_winrm_server_cert_validation=ignore" >> inventory.ini + + ansible-playbook -i inventory.ini ansible/pipeline.yml + + - name: Cleanup + if: always() + run: | + cd terraform + tofu destroy -auto-approve +``` + +--- + +## Step-by-Step Breakdown + +### 1. Install Tools + +```bash +pacman -Syu --noconfirm \ + mingw-w64-gcc \ # MinGW cross-compiler + nsis \ # NSIS installer builder + osslsigncode \ # Code signing tool + opentofu \ # Infrastructure as code + ansible \ # Automation + python-pywinrm \ # Ansible WinRM support + packer \ # Image builder +``` + +### 2. Checkout + +```yaml +- name: Checkout + uses: actions/checkout@v3 +``` + +**Purpose:** Clones the repository to the container. + +### 3. Cross-Compile (MinGW) + +```bash +x86_64-w64-mingw32-gcc src/main.c -o dist/app.exe +``` + +**Purpose:** Compiles Windows executable from Linux. + +### 4. Package (NSIS) + +```bash +makensis -DVERSION=${{ gitea.ref_name }} installer.nsi +``` + +**Purpose:** Creates Windows installer from compiled executable. + +### 5. Code Sign + +```bash +osslsigncode sign \ + -pkcs12 cert.pfx \ + -pass "$PFX_PASS" \ + -t http://timestamp.digicert.com \ + -in dist/installer.exe \ + -out dist/installer_signed.exe +``` + +**Purpose:** Authenticode sign the installer with timestamp. + +### 6. Provision VM (OpenTofu) + +```bash +cd terraform +tofu init +tofu apply -auto-approve +echo "VM_IP=$(tofu output -raw vm_ip)" >> $GITHUB_ENV +``` + +**Purpose:** Creates ephemeral Windows VM for testing. + +### 7. Verify (Ansible) + +```bash +echo "[windows_vm]" > inventory.ini +echo "$VM_IP ansible_user=$ANSIBLE_USER ..." >> inventory.ini +ansible-playbook -i inventory.ini ansible/pipeline.yml +``` + +**Purpose:** Tests installer on live Windows VM. + +### 8. Cleanup + +```bash +if: always() +tofu destroy -auto-approve +``` + +**Purpose:** Destroys VM regardless of test result. + +--- + +## Container Configuration + +| Setting | Value | Description | +|---------|-------|-------------| +| `runs-on` | `ubuntu-latest` | Runner OS | +| `container` | `archlinux:latest` | Build container | + +**Why Arch Linux?** +- Latest packages available +- Excellent AUR support +- Small footprint +- Easy package management + +--- + +## Environment Variables + +### Set by Workflow + +| Variable | Source | Purpose | +|----------|--------|---------| +| `VM_IP` | OpenTofu output | Windows VM IP address | +| `GITHUB_ENV` | Workflow | Store VM_IP for subsequent steps | + +### From Secrets + +| Secret | Env Var | Purpose | +|--------|---------|---------| +| `PFX_PASS` | `PFX_PASS` | Certificate password | +| `PM_TOKEN_ID` | `PM_API_TOKEN_ID` | Proxmox authentication | +| `PM_TOKEN_SECRET` | `PM_API_TOKEN_SECRET` | Proxmox authentication | +| `WIN_ADMIN_PASS` | `ANSIBLE_PASSWORD` | WinRM connection | + +--- + +## Pipeline Flow Diagram + +```mermaid +flowchart TB + subgraph Build["Build Stage"] + direction LR + Install[Install Tools] --> Checkout[Checkout] --> Compile[Cross-Compile] --> Package[Package] --> Sign[Sign] + end + + subgraph Deploy["Deploy Stage"] + Sign --> Provision[Provision VM] --> Verify[Ansible Verify] + end + + subgraph Cleanup["Cleanup Stage"] + Verify --> Destroy[Destroy VM] + end + + style Build fill:#e3f2fd + style Deploy fill:#e8f5e9 + style Cleanup fill:#fff3e0 +``` + +--- + +## Triggering the Pipeline + +| Trigger | Description | +|---------|-------------| +| `on: push` | Runs on any push to any branch | +| `on: [push, pull_request]` | Also run on PRs (optional) | + +### Manual Trigger + +```bash +git commit -m "Update installer" +git push +``` + +--- + +## Troubleshooting + +| Issue | Cause | Solution | +|-------|-------|----------| +| Container missing packages | Pacman cache | Clear cache or use specific versions | +| OpenTofu init fails | Provider issues | Run `tofu init -upgrade` | +| Ansible connection timeout | WinRM not ready | Check Autounattend.xml | +| Cleanup failed | VM already destroyed | Add `if: failure()` condition | + +--- + +## Next Steps + +| Goal | Next Document | +|------|---------------| +| View architecture | [Architecture Overview](../01-overview/architecture.md) | +| Troubleshoot | [Troubleshooting](../07-advanced/troubleshooting.md) | +| Manage evaluations | [Evaluation Management](../07-advanced/evaluation.md) | + +--- + +[โ† Documentation Index](../index.md) | [โ†’ Advanced Topics](../07-advanced/) | [โ† Ansible Pipeline](../05-ansible/pipeline.md) diff --git a/docs/07-advanced/evaluation.md b/docs/07-advanced/evaluation.md new file mode 100644 index 0000000..af0f653 --- /dev/null +++ b/docs/07-advanced/evaluation.md @@ -0,0 +1,200 @@ +# โฐ 90-Day Evaluation Management + +[![Windows](https://img.shields.io/badge/Windows-Evaluation-0078D6?style=flat&logo=windows)](https://www.microsoft.com/en-us/evalcenter/) + +## Overview + +Windows Evaluation editions expire after 90 days. This document explains the expiration mechanism and provides strategies for managing it in your automation pipeline. + +--- + +## Understanding Evaluation Expiration + +```mermaid +flowchart LR + subgraph Timeline["90-Day Timeline"] + Start[Install Day 0] --> Day30[Day 30] --> Day60[Day 60] --> Day90[Day 90 - Expiration] + end + + subgraph States["System States"] + Active[โœ… Active] --> Warning[โš ๏ธ Warning 15 days] --> Expired[โŒ Expired] + end + + Timeline --> States + + style Timeline fill:#e3f2fd + style States fill:#e8f5e9 +``` + +| Phase | Duration | Status | +|-------|----------|--------| +| **Full Activation** | Days 0-89 | โœ… Fully functional | +| **Warning Period** | Days 90-104 | โš ๏ธ Countdown warnings | +| **Grace Period** | Days 105-180 | โณ Extended grace | +| **Expired** | Day 181+ | โŒ System stops | + +--- + +## Expiration Methods + +### Method 1: Rearm (Manual/Scripted) + +The `slmgr /rearm` command resets the activation timer. + +```powershell +# Run as Administrator +slmgr /rearm + +# Reboot required +shutdown /r /t 0 +``` + +**Limits:** +- Maximum 3 rearm attempts per installation +- Each rearm resets to 90 days +- **Total: 360 days maximum** + +### Method 2: Packer Rebuild (Recommended) + +The recommended approach is to **rebuild the golden image monthly**. + +```mermaid +flowchart TB + subgraph Monthly["Monthly Schedule"] + direction LR + Week1[Week 1: Packer Build] --> Week2[Week 2-4: Use Template] + end + + subgraph Process["Rebuild Process"] + Destroy[Destroy Old Template] --> Create[Create New Template] --> Verify[Test New Template] + end + + Monthly --> Process + + style Monthly fill:#e3f2fd + style Process fill:#e8f5e9 +``` + +**Benefits:** +- Fresh timer each month +- Latest Windows updates baked in +- Consistent baseline +- No rearm limitations + +--- + +## Implementation Strategy + +### Automated Monthly Rebuild + +Configure a scheduled workflow in Forgejo: + +```yaml +# .forgejo/workflows/monthly-rebuild.yml +name: Monthly Template Rebuild +on: + schedule: + - cron: '0 0 1 * *' # First day of each month at midnight + +jobs: + rebuild-template: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Build New Template + run: | + cd packer + packer build -timestamp-ui windows.pkr.hcl + + - name: Cleanup Old Template + run: | + # Script to remove template older than 45 days + ./scripts/cleanup-old-templates.sh --older-than 45d +``` + +### Rebarm as Backup + +For emergency extension: + +```powershell +# emergency-rearm.ps1 +# Run via Ansible or manually + +if ((slmgr /dlv) -match "Remaining: 0") { + Write-Host "Rearming system..." + slmgr /rearm + shutdown /r /t 0 +} else { + Write-Host "Not yet expired, no action needed" +} +``` + +--- + +## Monitoring Expiration + +### Check Current Status + +```powershell +# Method 1: slmgr +slmgr /dlv + +# Method 2: PowerShell +(Get-CimInstance -Query "SELECT * FROM SoftwareLicensingProduct WHERE PartialProductKey IS NOT NULL").RemainingGracePeriod +``` + +### Automated Monitoring Script + +```bash +#!/bin/bash +# check-expiration.sh - Run via Ansible monthly + +VM_ID="9000" +PROXMOX_HOST="la-vmh-07" + +# Get VM's Windows activation status +ssh root@$PROXMOX_HOST "qm agent $VM_ID exec-win32 powershell -Command '(Get-CimInstance -Query \"SELECT * FROM SoftwareLicensingProduct WHERE PartialProductKey IS NOT NULL\").RemainingGracePeriod'" + +# Alert if less than 7 days +if [ $DAYS_REMAINING -lt 7 ]; then + echo "โš ๏ธ ALERT: Template expires in $DAYS_REMAINING days" + # Send notification +fi +``` + +--- + +## Best Practices + +| Practice | Description | Priority | +|----------|-------------|----------| +| **Monthly rebuild** | Schedule automatic Packer build | ๐Ÿ”ด High | +| **Monitor expiration** | Check status weekly | ๐ŸŸก Medium | +| **Test new templates** | Verify before production use | ๐Ÿ”ด High | +| **Document rebuilds** | Log template versions | ๐ŸŸข Low | + +--- + +## Troubleshooting + +| Issue | Cause | Solution | +|-------|-------|----------| +| Rearm failed | Already rearmed 3 times | Rebuild with Packer | +| VM won't boot after rearm | Activation issues | Rebuild template | +| Updates not installing | WSUS offline | Include updates in Packer build | + +--- + +## Next Steps + +| Goal | Next Document | +|------|---------------| +| View troubleshooting | [Troubleshooting](troubleshooting.md) | +| Configure pipeline | [Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) | +| View architecture | [Architecture Overview](../01-overview/architecture.md) | + +--- + +[โ† Documentation Index](../index.md) | [โ†’ Troubleshooting](troubleshooting.md) | [โ† Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) diff --git a/docs/07-advanced/troubleshooting.md b/docs/07-advanced/troubleshooting.md new file mode 100644 index 0000000..756a660 --- /dev/null +++ b/docs/07-advanced/troubleshooting.md @@ -0,0 +1,273 @@ +# ๐Ÿ”ง Troubleshooting Guide + +[![Debug](https://img.shields.io/badge/Troubleshooting-Common%20Issues-yellow)]() + +## Overview + +This guide covers common issues and their solutions for the Windows automation pipeline. + +--- + +## Quick Fix Index + +| Issue | Phase | Quick Fix | +|-------|-------|-----------| +| Packer timeout | Build | Check Autounattend.xml WinRM config | +| VM won't boot | Provision | Verify ISO paths in Packer | +| Ansible connection | Test | Disable Windows firewall | +| Code signing fails | Build | Verify PFX password | +| Template expired | All | Rebuild with Packer | + +--- + +## Phase 1: Packer Issues + +### Timeout Waiting for WinRM + +**Symptom:** +``` +==> proxmox-iso.windows-11: Timeout waiting for WinRM. +``` + +**Cause:** Windows not fully booted or WinRM not configured. + +**Solution:** +1. Verify `Autounattend.xml` has WinRM configuration +2. Check boot command timing +3. Increase `boot_wait` duration + +```hcl +# Increase boot wait +boot_wait = "30s" + +# Check boot command +boot_command = [ + "<wait><wait><wait><wait><wait>", + "<enter><wait><wait>", + "<enter>" +] +``` + +--- + +### ISO Not Found + +**Symptom:** +``` +==> proxmox-iso.windows-iso: ISO file not found: local:iso/... +``` + +**Cause:** Wrong ISO path or storage. + +**Solution:** +1. Verify ISO location on Proxmox +2. Check storage name (local vs local-lvm) + +```bash +# On Proxmox host +ls -la /mnt/pve-07-iso-nvme/template/iso/ +qm storage +``` + +--- + +## Phase 2: OpenTofu Issues + +### Clone Failed + +**Symptom:** +``` +Error: resource is not a cloneable VM +``` + +**Cause:** Wrong VM ID or template not found. + +**Solution:** +1. Verify template VM exists +2. Check VM ID is correct + +```bash +# On Proxmox host +qm list | grep template +``` + +--- + +### Permission Denied + +**Symptom:** +``` +Error: permission denied (400) +``` + +**Cause:** Proxmox API token lacks privileges. + +**Solution:** +1. Add VM.Admin role to token +2. Verify token is not expired + +--- + +## Phase 3: Ansible Issues + +### WinRM Connection Timeout + +**Symptom:** +``` +fatal: [10.0.0.5]: UNREACHABLE! => {"msg": "Connection timeout"} +``` + +**Cause:** Firewall blocking WinRM or WinRM not configured. + +**Solution:** +```yaml +# In Autounattend.xml - disable firewall +<SynchronousCommand wcm:action="add"> + <CommandLine>powershell -Command "Set-NetFirewallProfile -Profile Private -Enabled False"</CommandLine> + <Order>1</Order> +</SynchronousCommand> + +# In inventory - ignore certificate validation +[windows_vm] +10.0.0.5 ansible_winrm_server_cert_validation=ignore +``` + +--- + +### Invalid Credentials + +**Symptom:** +``` +fatal: [10.0.0.5]: UNREACHABLE! => {"msg": "Basic auth failed"} +``` + +**Cause:** Wrong username or password. + +**Solution:** +```bash +# Verify secrets are set +echo $WIN_ADMIN_PASS + +# Test manually +winrs -r:10.0.0.5 -u:Administrator -p:$WIN_ADMIN_PASS "hostname" +``` + +--- + +## Phase 4: Code Signing Issues + +### Invalid Certificate + +**Symptom:** +``` +Error: PKCS12_parse failed +``` + +**Cause:** Wrong password or corrupted PFX file. + +**Solution:** +```bash +# Verify certificate +openssl pkcs12 -in cert.pfx -info -noout -passin pass:$PFX_PASS +``` + +--- + +## Diagnostic Commands + +### Proxmox Diagnostics + +```bash +# List VMs +qm list + +# Check VM status +qm status <VM_ID> + +# View VM config +qm config <VM_ID> + +# Check storage +pvesm status +``` + +### Windows Diagnostics + +```powershell +# Check WinRM status +winrm quickconfig +Get-WinRM -Service + +# Check firewall +Get-NetFirewallProfile | Select Name, Enabled + +# Check activation +slmgr /dlv +``` + +### Ansible Diagnostics + +```bash +# Test WinRM connection +ansible windows_vm -m win_ping -i inventory.ini + +# Verbose output +ansible-playbook -i inventory.ini pipeline.yml -vvvv +``` + +--- + +## Log Locations + +| Component | Log Location | +|-----------|--------------| +| Packer | Console output + `packer.log` | +| OpenTofu | Console output + `.terraform.lock.hcl` | +| Ansible | Console output + `/var/log/ansible.log` | +| Windows | Event Viewer โ†’ System | + +--- + +## FAQ + +### Q: Can I use a different Windows edition? + +**A:** Yes, but you need to: +1. Update ISO in `packer/windows.pkr.hcl` +2. Modify `Autounattend.xml` for that edition +3. Update product key settings + +### Q: How do I add more software to the template? + +**A:** Add PowerShell provisioners: + +```hcl +provisioner "powershell" { + inline = [ + "choco install -y 7zip git vscode", + "& 'C:\\ProgramData\\Chocolatey\\bin\\choco.exe' install -y dotnetfx" + ] +} +``` + +### Q: The VM has no IP after provisioning + +**Cause:** DHCP not working or VirtIO drivers missing. + +**Solution:** +1. Ensure VirtIO drivers are installed in template +2. Verify network bridge is correct + +--- + +## Next Steps + +| Goal | Next Document | +|------|---------------| +| Manage evaluations | [Evaluation Management](evaluation.md) | +| View pipeline | [Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) | +| Full documentation | [Documentation Index](../index.md) | + +--- + +[โ† Documentation Index](../index.md) | [โ† Evaluation Management](evaluation.md) | [โ† Home](../index.md) diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..5871e3d --- /dev/null +++ b/docs/index.md @@ -0,0 +1,258 @@ +# ๐Ÿ“– Documentation Index + +<!-- Badges --> +[![Pipeline](https://img.shields.io/badge/Pipeline-Packer%20โ†’%20OpenTofu%20โ†’%20Forgejo-blue)](.forgejo/workflows/release.yml) +[![Windows](https://img.shields.io/badge/Windows-11%20LTSC%202024-0078D6?style=flat&logo=windows)](https://www.microsoft.com/en-us/windows/windows-11-enterprise) + +## Welcome + +This is the comprehensive documentation index for the **Windows Automation on Proxmox** project. Use this guide to navigate through all available documentation. + +--- + +## ๐Ÿ—‚๏ธ Documentation Map + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ DOCUMENTATION TREE โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ โ”‚ +โ”‚ ๐Ÿ“„ index.md (You are here) โ”‚ +โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 01-overview/ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ architecture.md โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ System Components โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ Architecture Diagrams โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ Design Decisions โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 02-prerequisites/ โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ isos.md โ”‚ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ ISO Download Sources โ”‚ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ Storage Location โ”‚ +โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ Verification Steps โ”‚ +โ”‚ โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ secrets.md โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ Forgejo Secrets โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ Proxmox API Tokens โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ Certificate Management โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 03-packer/ โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ configuration.md โ”‚ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ Packer HCL Syntax โ”‚ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ Proxmox Builder Settings โ”‚ +โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ Provisioner Configuration โ”‚ +โ”‚ โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ autounattend.md โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ XML Structure โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ WinRM Configuration โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ FirstLogonCommands โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 04-terraform/ โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ main.tf.md โ”‚ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ Provider Configuration โ”‚ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ VM Resource Definition โ”‚ +โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ Clone Strategy โ”‚ +โ”‚ โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ variables.md โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ Input Variables โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ Variable Validation โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 05-ansible/ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ pipeline.md โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ Playbook Structure โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ WinRM Setup โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ Verification Tasks โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 06-ci-cd/ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ forgejo-workflows.md โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ Workflow Syntax โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ Container Configuration โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ Step-by-Step Execution โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ Environment Variables โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€ ๐Ÿ“ 07-advanced/ โ”‚ +โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ evaluation.md โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ 90-Day Timer Management โ”‚ +โ”‚ โ”‚ โ”œโ”€โ”€ Rearm Procedure โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€ Monthly Rebuild Strategy โ”‚ +โ”‚ โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€ ๐Ÿ“„ troubleshooting.md โ”‚ +โ”‚ โ”œโ”€โ”€ Common Errors โ”‚ +โ”‚ โ”œโ”€โ”€ Debug Techniques โ”‚ +โ”‚ โ””โ”€โ”€ FAQ โ”‚ +โ”‚ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +--- + +## ๐ŸŽฏ Quick Navigation + +### I want to... + +| Goal | Start Here | +|------|------------| +| **Understand the system** | [Architecture Overview](01-overview/architecture.md) | +| **Set up prerequisites** | [ISO Requirements](02-prerequisites/isos.md) | +| **Build the golden image** | [Packer Configuration](03-packer/configuration.md) | +| **Provision test VMs** | [OpenTofu Resources](04-terraform/main.tf.md) | +| **Run the CI/CD pipeline** | [Forgejo Workflows](06-ci-cd/forgejo-workflows.md) | +| **Troubleshoot issues** | [Troubleshooting Guide](07-advanced/troubleshooting.md) | + +--- + +## ๐Ÿ“Š Architecture Overview + +```mermaid +graph TD + subgraph CI["Forgejo CI/CD"] + direction LR + Git[Git Push] --> |Triggers| WF[Workflow] + WF --> |Cross-Compile| MC[MinGW] + WF --> |Package| NS[NSIS] + WF --> |Sign| CS[Code Sign] + end + + subgraph Infra["Infrastructure"] + CS --> |Provision| TF[OpenTofu] + TF --> |Clone| VM[Windows VM] + end + + subgraph Test["Testing"] + VM --> |Deploy| Inst[Installer] + Inst --> |Verify| Ans[Ansible] + Ans --> |Result| Pass{โœ… Pass} + Ans --> |Result| Fail{โŒ Fail} + end + + style CI fill:#e1f5fe + style Infra fill:#e8f5e9 + style Test fill:#fff3e0 +``` + +--- + +## ๐Ÿ“š Section Descriptions + +### 01. Overview +- **[architecture.md](01-overview/architecture.md)** - Complete system design including: + - Component overview + - Data flow diagrams + - Design decisions and rationale + - Technology stack explanation + +### 02. Prerequisites +- **[isos.md](02-prerequisites/isos.md)** - ISO image requirements: + - Download links for Windows ISOs + - VirtIO driver sources + - Proxmox storage configuration + - File verification steps +- **[secrets.md](02-prerequisites/secrets.md)** - Credential management: + - Forgejo secret configuration + - Proxmox API token creation + - Code signing certificate handling + - Environment variable mapping + +### 03. Packer +- **[configuration.md](03-packer/configuration.md)** - Packer template guide: + - HCL syntax reference + - Proxmox builder settings + - Hardware configuration + - Provisioner scripts +- **[autounattend.md](03-packer/autounattend.md)** - Windowsๆ— ไบบๅ€ผๅฎˆๅฎ‰่ฃ…: + - XML structure reference + - WinRM enabling + - Firewall configuration + - FirstLogonCommands่ฏฆ่งฃ + +### 04. Terraform/OpenTofu +- **[main.tf.md](04-terraform/main.tf.md)** - Infrastructure as code: + - Provider configuration + - VM cloning strategy + - Network settings + - IP address assignment +- **[variables.md](04-terraform/variables.md)** - Variables reference: + - Input variable definitions + - Default values + - Variable validation + - Sensitive value handling + +### 05. Ansible +- **[pipeline.md](05-ansible/pipeline.md)** - Automation playbook: + - WinRM connection setup + - File transfer tasks + - Silent installation + - Verification assertions + - Error handling + +### 06. CI/CD +- **[forgejo-workflows.md](06-ci-cd/forgejo-workflows.md)** - Pipeline configuration: + - Workflow syntax + - Container images + - Step-by-step execution + - Artifact publishing + - Cleanup procedures + +### 07. Advanced +- **[evaluation.md](07-advanced/evaluation.md)** - Evaluation management: + - 90-day expiration explained + - Rearm procedure + - Automated rebuild strategy + - Security considerations +- **[troubleshooting.md](07-advanced/troubleshooting.md)** - Problem resolution: + - Common error messages + - Debug commands + - Log file locations + - FAQ section + +--- + +## ๐Ÿ”— Cross-References + +This documentation is fully interlinked. Key cross-references include: + +| From | To | Context | +|------|-----|---------| +| README | docs/index.md | Documentation entry | +| architecture.md | isos.md | Prerequisites section | +| configuration.md | autounattend.md | Related Packer topics | +| main.tf.md | variables.md | Terraform variables | +| forgejo-workflows.md | pipeline.md | Ansible integration | +| pipeline.md | main.tf.md | Infrastructure reference | +| troubleshooting.md | All sections | Problem resolution | + +--- + +## ๐Ÿ› ๏ธ Tool Reference + +| Tool | Version | Purpose | Docs Link | +|------|---------|---------|-----------| +| Packer | โ‰ฅ 1.1.0 | Image building | [configuration.md](03-packer/configuration.md) | +| OpenTofu | Latest | IaC provisioning | [main.tf.md](04-terraform/main.tf.md) | +| Ansible | Latest | Automation | [pipeline.md](05-ansible/pipeline.md) | +| Forgejo Actions | Latest | CI/CD | [forgejo-workflows.md](06-ci-cd/forgejo-workflows.md) | +| MinGW | Latest | Cross-compilation | [forgejo-workflows.md](06-ci-cd/forgejo-workflows.md) | +| NSIS | Latest | Installer creation | [forgejo-workflows.md](06-ci-cd/forgejo-workflows.md) | + +--- + +## ๐Ÿ“– Reading Guide + +1. **First Time Setup:** Read in order: 01 โ†’ 02 โ†’ 03 โ†’ 04 โ†’ 05 โ†’ 06 +2. **Specific Task:** Use the Quick Navigation table above +3. **Deep Dive:** Follow cross-references from any section +4. **Troubleshooting:** Start with [troubleshooting.md](07-advanced/troubleshooting.md) + +--- + +## ๐Ÿ”„ Document Version + +| Property | Value | +|----------|-------| +| Version | 1.0.0 | +| Last Updated | February 2026 | +| Target OS | Windows 11 LTSC 2024 | +| Status | Active Development | + +--- + +[โ† Back to README](../README.md) | [โ†’ Architecture Overview](01-overview/architecture.md) diff --git a/installer.nsi b/installer.nsi new file mode 100644 index 0000000..de6157f --- /dev/null +++ b/installer.nsi @@ -0,0 +1,22 @@ +!define APP_NAME "MyApp" +!define APP_VERSION ${VERSION} +!define COMPANY_NAME "My Company" + +OutFile "dist\installer.exe" +InstallDir "$PROGRAMFILES\${APP_NAME}" +RequestExecutionLevel admin + +Page directory +Page instfiles + +Section "MainSection" + SetOutPath $INSTDIR + File "dist\app.exe" + WriteUninstaller $INSTDIR\uninstall.exe +SectionEnd + +Section "Uninstall" + Delete $INSTDIR\app.exe + Delete $INSTDIR\uninstall.exe + RMDir $INSTDIR +SectionEnd diff --git a/packer/Autounattend.xml b/packer/Autounattend.xml new file mode 100644 index 0000000..df236a2 --- /dev/null +++ b/packer/Autounattend.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<unattend xmlns="urn:schemas-microsoft-com:unattend"> + <settings pass="windowsPE"> + <component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <SetupUILanguage> + <UILanguage>en-US</UILanguage> + </SetupUILanguage> + <InputLocale>en-US</InputLocale> + <SystemLocale>en-US</SystemLocale> + <UILanguage>en-US</UILanguage> + <UserLocale>en-US</UserLocale> + </component> + <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <UserData> + <ProductKey> + <Key></Key> + </ProductKey> + <AcceptEula>true</AcceptEula> + </UserData> + </component> + </settings> + <settings pass="specialize"> + <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <ComputerName>*</ComputerName> + </component> + <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <InputLocale>en-US</InputLocale> + <SystemLocale>en-US</SystemLocale> + <UILanguage>en-US</UILanguage> + <UserLocale>en-US</UserLocale> + </component> + <component name="Microsoft-Windows-TerminalServices-LocalSessionManager" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <fDenyTSConnections>false</fDenyTSConnections> + </component> + <component name="Microsoft-Windows-RemoteAssistance-Exe" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <fAllowToGetHelp>false</fAllowToGetHelp> + </component> + </settings> + <settings pass="oobeSystem"> + <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <OOBE> + <HideEULAPage>true</HideEULAPage> + <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> + <HideOnlineAccountScreens>true</HideOnlineAccountScreens> + <HideLocalAccountScreen>false</HideLocalAccountScreen> + <ProtectYourPC>3</ProtectYourPC> + </OOBE> + <UserAccounts> + <AdministratorPassword> + <Value>PackerPassword123!</Value> + <PlainText>true</PlainText> + </AdministratorPassword> + </UserAccounts> + <AutoLogon> + <Enabled>true</Enabled> + <Username>Administrator</Username> + <LogonCount>1</LogonCount> + </AutoLogon> + <FirstLogonCommands> + <SynchronousCommand wcm:action="add"> + <CommandLine>powershell -Command "Set-NetFirewallProfile -Profile Private -Enabled False"</CommandLine> + <Order>1</Order> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <CommandLine>powershell -Command "Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile C:\ConfigureRemotingForAnsible.ps1; C:\ConfigureRemotingForAnsible.ps1"</CommandLine> + <Order>2</Order> + </SynchronousCommand> + </FirstLogonCommands> + </component> + </settings> +</unattend> diff --git a/packer/windows.pkr.hcl b/packer/windows.pkr.hcl new file mode 100644 index 0000000..a8a1d87 --- /dev/null +++ b/packer/windows.pkr.hcl @@ -0,0 +1,70 @@ +packer { + required_plugins { + proxmox = { + version = ">= 1.1.0" + source = "github.com/hashicorp/proxmox" + } + } +} + +source "proxmox-iso" "windows-11" { + proxmox_url = "https://proxmox-host:8006/api2/json" + username = "root@pam" + password = "secret" + node = "la-vmh-07" + + vm_name = "win11-ltsc-template" + template_description = "Built with Packer on ${timestamp()}" + iso_file = "local:iso/CLIENT_LTSC_EVAL_x64FRE_en-us.iso" + + qemu_agent = true + cores = 4 + memory = 8192 + machine = "q35" + bios = "ovmf" + efi_config { + efi_storage_pool = "local-lvm" + pre_enrolled_keys = true + } + tpm_config { + version = "2.0" + tpm_storage_pool = "local-lvm" + } + + scsi_controller = "virtio-scsi-pci" + disks { + disk_size = "60G" + storage_pool = "local-lvm" + type = "virtio" + format = "raw" + cache_mode = "writeback" + } + additional_iso_files { + device = "sata1" + iso_file = "local:iso/virtio-win.iso" + } + + communicator = "winrm" + winrm_username = "Administrator" + winrm_password = "PackerPassword123!" + winrm_insecure = true + winrm_use_ssl = true + + boot_command = [ + "<wait><wait><wait>","<enter><wait>","<enter><wait>", + "<enter><wait>","<enter>" + ] + boot_wait = "10s" +} + +build { + sources = ["source.proxmox-iso.windows-11"] + + provisioner "powershell" { + inline = [ + "pnputil /add-driver 'E:\\viostor\\w11\\amd64\\*.inf' /install", + "pnputil /add-driver 'E:\\NetKVM\\w11\\amd64\\*.inf' /install", + "& 'E:\\virtio-win-guest-tools.exe' /install /passive /norestart" + ] + } +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..3920ac8 --- /dev/null +++ b/src/main.c @@ -0,0 +1,7 @@ +#include <windows.h> +#include <stdio.h> + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { + MessageBoxA(NULL, "Hello from MyApp!", "MyApp", MB_OK | MB_ICONINFORMATION); + return 0; +} diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 0000000..315e11d --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,34 @@ +terraform { + required_providers { + proxmox = { + source = "bpg/proxmox" + version = "0.46.1" + } + } +} + +provider "proxmox" { + endpoint = "https://proxmox-host:8006/" +} + +resource "proxmox_virtual_environment_vm" "build_agent" { + name = "ci-win-build-${var.build_id}" + node_name = "la-vmh-07" + + clone { + vm_id = var.template_vm_id + full_clone = false + } + + cpu { cores = 4; type = "host" } + memory { dedicated = 8192 } + network_device { bridge = "vmbr0" } + + initialization { + ip_config { + ipv4 { + address = "dhcp" + } + } + } +} diff --git a/terraform/outputs.tf b/terraform/outputs.tf new file mode 100644 index 0000000..b59c5c4 --- /dev/null +++ b/terraform/outputs.tf @@ -0,0 +1,4 @@ +output "vm_ip" { + description = "IP address of the provisioned VM" + value = proxmox_virtual_environment_vm.build_agent.ipv4_addresses[1][0] +} diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000..1be0d02 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,10 @@ +variable "build_id" { + description = "Unique identifier for the build" + type = string +} + +variable "template_vm_id" { + description = "VM ID of the Packer-built template" + type = number + default = 9000 +}