Compare commits

...

No commits in common. "main" and "test-docs" have entirely different histories.

103 changed files with 3087 additions and 2 deletions

3
.browserslistrc Normal file
View File

@ -0,0 +1,3 @@
hi
bye
I am browser

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,11 @@
{
"assets/images/social/about.png": "5ed39e9c24e521029fa93987b97dee1b77ab09e6",
"assets/images/social/code-examples.png": "0da5d582d2750fb297ed7e57d2a9fb9a16886a30",
"assets/images/social/grid%20copy.png": "ecc4ae11a67bb969e396aae33f971df688661a4a",
"assets/images/social/grid.png": "e669f66479a4c377e90eeb0df0ac23917b670502",
"assets/images/social/grid/grid%20copy.png": "bfa73a37760081fbe1cedc5801025477fb3ea1c5",
"assets/images/social/grid/grid.png": "bfa73a37760081fbe1cedc5801025477fb3ea1c5",
"assets/images/social/index.png": "aea930440ead3805bf257fc6878c3a23acbdfeb7",
"assets/images/social/list.png": "91bd4e207c2aac59e22d6b16e6ebbc41b307f92e",
"assets/images/social/tables.png": "720388a3598f6037a3e862c16828d2c806d9b67f"
}

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
site/

View File

@ -1,2 +0,0 @@
# packer-ssl-docs

72
docs/about.md Normal file
View File

@ -0,0 +1,72 @@
# Document Information
* **Author:** Bhaskar Kumar Aligi
* **Maintainer:** Bhaskar Kumar Aligi
* **Created By:** Bhaskar Kumar Aligi
* **Guided By:** Satish Kumar
* **Date Created:** 19-05-2026
* **Date Modified:** 19-05-2026
---
# **Short Desc**
A fully automated, zero-trust infrastructure pipeline that executes SSL/TLS certificate generation like a serverless function by provisioning disposable, short-lived virtual machines on VMware ESXi to process ACME validation and distribute cryptographic assets securely.
---
# **Long Desc**
The **Automated Certbot Ephemeral Pipeline** is an Infrastructure-as-Code (IaC) platform engineered to replace traditional, permanently running certificate management virtual machines with a secure, disposable, and deterministic execution model. Instead of maintaining persistent VM infrastructure that accumulates configuration drift and increases the system's attack surface, this architecture treats **SSL certificate generation as a serverless function**.
When a certificate lifecycle event is triggered, the pipeline temporarily materializes on-demand virtual environments directly onto a standalone **VMware ESXi** hypervisor. It features two specialized provisioning strategies tailored for operational speed and immutability: an **ISO-Based Method** that completely automates a fresh OS deployment via Ubuntu's cloud-init (`autoinstall`) framework, and a high-speed **Clone-Based Method** that bypasses installation by duplicating a thin-provisioned base template.
To preserve dynamic networking identities across automated runs without persistent overhead, the pipeline manipulates the raw virtual machine configuration (`.vmx`) text files programmatically. By injecting dedicated static MAC addresses, it guarantees that core gateway routers (such as **pfSense**) cleanly allocate expected IP addresses out of isolated infrastructure scopes every execution.
Once booted, the ephemeral worker launches an isolated, containerized **Docker Compose Certbot stack** to handle incoming Let's Encrypt validation queries routed dynamically through **HAProxy** ACL rules. After the ACME challenge is completed and certificates are successfully issued, a secure synchronization layer pulls or pushes the cryptographic materials into the local cache and production targets (such as a live **Nginx** reverse proxy). Once synchronization completes, the pipeline automatically issues destructive lifecycle routines to erase the ephemeral machine entirely from the ESXi host datastore.
### Core Capabilities
* **Serverless Automation Pattern:** Converts infrastructure-level VM configurations into lightweight task runtimes that exist strictly for the certificate validation lifetime.
* **Dual Provisioning Engines:** Offers a choice between completely fresh, drift-free ISO autoinstalls or high-speed template cloning for rapid certificate deployment.
* **Dynamic Identity Overrides:** Implements explicit programmatic `.vmx` parameter patching to enforce persistent MAC-to-IP relationships on standalone hypervisors.
* **Containerized Challenge Execution:** Isolates the Let's Encrypt validation surface using transient, internal Docker-bound Certbot environments.
* **Secure Egress Delivery:** Automates end-to-end asset distribution to live production web configurations, instantly invoking safe reloads without downtime.
### Architecture Highlights
* Implements a disposable infrastructure model ensuring that the execution workspace is completely cleared upon certificate handoff.
* **Decoupled Lifecycle Framework:**
* Automated Wrapper Engine → `run-certbot.sh` / `benchmark_certgen.sh`
* Compute & Hypervisor Provider → Standalone VMware ESXi Host
* Infrastructure as Code Configuration → HashiCorp Packer (`certbot.pkr.hcl`)
* Traffic Gateway & Reverse Proxy Ingress → pfSense Firewall & HAProxy
* Local Validation Runtime Engine → Docker & Docker Compose
* Restricts external firewall exposure exclusively to the validation window using explicit path matching constraints (`/.well-known/acme-challenge/*`).
### Technology Stack
* **HashiCorp Packer** – Core orchestration tool executing build workflows, bootstrapping runtimes, and driving guest configurations.
* **VMware ESXi** – The underlying bare-metal hypervisor holding the temporary infrastructure states and template datastores.
* **Docker / Docker Compose** – Containerization engine hosting the application challenge layers.
* **Certbot (ACME Engine)** – Automates token requests, validation routines, and interactions with production Let's Encrypt directory endpoints.
* **pfSense & HAProxy** – Perimeter firewall and load-balancer frontend enforcing strict ACL path routing to the ephemeral node (`192.168.2.9`).
* **Nginx** – Target production system receiving final, decrypted edge certificates.
* **Mermaid.js** – Operational pipeline, benchmark tracks, and system dependency visualizations.
### Key Features in Practice
* Execution lifecycle guarantees deterministic recreation, completely neutralizing security risks like credential sprawl and static server decay.
* Empowers engineers with diagnostic benchmarking scripts to continuously capture performance trade-offs between ISO compilation paths and template block-cloning speeds.
* Secure, isolated file synchronization to protected local storage caches (`./backup_certs/`) alongside live updates to active server destinations (e.g., `articles.clinilaunchresearch.in`).
* Built-in crash-dump routing hooks (`PACKER_LOG=1`) and granular, pre-destruction Let's Encrypt trace handling for efficient log auditing.
### Getting Started
To begin working with the Automated Certbot Ephemeral Pipeline:
* Refer to the **[Pipeline Configuration Guide](configuration.md)** to register infrastructure variables, secrets, and pfSense/HAProxy routing parameters.
* Explore the step-by-step build tracks using either the **[ISO-Based Setup Guide](iso-process.md)** or the high-speed **[Clone-Based Setup Guide](clone-process.md)**.
* Follow the **[Architecture Verification Guide](verification.md)** to run safe pre-flight sanity checks and evaluate issued artifact validity.

BIN
docs/assets/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

BIN
docs/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 KiB

324
docs/assets/report.log Normal file
View File

@ -0,0 +1,324 @@
```
lms2@sd2 MINGW64 ~/Documents/packer/packer-esxi/packer-certbot-clone-esxi
$ ./benchmark_certgen.sh
--- STARTING BENCHMARK: CLONE VS ISO ---
Target: articles.clinilaunchresearch.in (staging)
----------------------------------------
Running Method: CLONE...
Step 1: Cleaning old runs...
Step 2: Cloning template...
Destination disk format: VMFS thin-provisioned
Cloning disk '/vmfs/volumes/app-platform/ubuntu-2404-base-template/ubuntu-2404-base-template.vmdk'...
Clone: 100% done.
Step 3: Hard-coding Static MACs and cleaning IDs...
Step 4: Starting VM...
Powering on VM:
Step 5: Waiting for Network (192.168.60.164)...
Step 6: Handing over to Packer (Mode: staging)...
null.certbot_vm: output will be in this color.
==> null.certbot_vm: Using SSH communicator to connect: 192.168.60.164
==> null.certbot_vm: Waiting for SSH to become available...
==> null.certbot_vm: Connected to SSH!
==> null.certbot_vm: Running local shell script: C:\Users\lms2\AppData\Local\Temp\packer-shell1648547175.cmd
null.certbot_vm:
null.certbot_vm: C:\Users\lms2\Documents\packer\packer-esxi\packer-certbot-clone-esxi>if not exist backup_certs mkdir backup_certs
==> null.certbot_vm: Provisioning with shell script: C:\Users\lms2\AppData\Local\Temp\packer-shell1643664071
==> null.certbot_vm: Uploading ./certbot-server => /home/packer/
==> null.certbot_vm: Uploading ./keys/certbot_master_key => /home/packer/.ssh/id_rsa
==> null.certbot_vm: Provisioning with shell script: C:\Users\lms2\AppData\Local\Temp\packer-shell1455892980
null.certbot_vm: --- STAGING MODE ACTIVE ---
null.certbot_vm: --- STARTING CERTIFICATE PROCESS FOR articles.clinilaunchresearch.in ---
null.certbot_vm: Target Path on Remote: /etc/nginx/certs-test/articles.clinilaunchresearch.in
==> null.certbot_vm: Creating network "certbot-server_default" with the default driver
==> null.certbot_vm: Pulling nginx (nginx:latest)...
null.certbot_vm: latest: Pulling from library/nginx
null.certbot_vm: Digest: sha256:06aa3d7be10bc6307990c81bdca075793132e9163391abc370c015e344e23128
null.certbot_vm: Status: Downloaded newer image for nginx:latest
==> null.certbot_vm: Creating certbot-server_nginx_1 ...
==> null.certbot_vm: Creating certbot-server_nginx_1 ... done
==> null.certbot_vm: Pulling certbot (certbot/certbot:)...
null.certbot_vm: latest: Pulling from certbot/certbot
null.certbot_vm: Digest: sha256:0107d084c225631fc64a8313e19adb07275f7296fde338f7dfa93986c80b2e3e
null.certbot_vm: Status: Downloaded newer image for certbot/certbot:latest
==> null.certbot_vm: Creating certbot-server_certbot_run ...
==> null.certbot_vm: Creating certbot-server_certbot_run ... done
==> null.certbot_vm: Saving debug log to /var/log/letsencrypt/letsencrypt.log
null.certbot_vm: Account registered.
null.certbot_vm: Requesting a certificate for articles.clinilaunchresearch.in
null.certbot_vm:
null.certbot_vm: Successfully received certificate.
null.certbot_vm: Certificate is saved at: /etc/letsencrypt/live/articles.clinilaunchresearch.in/fullchain.pem
null.certbot_vm: Key is saved at: /etc/letsencrypt/live/articles.clinilaunchresearch.in/privkey.pem
null.certbot_vm: This certificate expires on 2026-08-12.
null.certbot_vm: These files will be updated when the certificate renews.
null.certbot_vm: NEXT STEPS:
null.certbot_vm: - The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.
null.certbot_vm: --- SYNCING TO NGINX VM ---
==> null.certbot_vm: Warning: Permanently added '192.168.2.13' (ED25519) to the list of known hosts.
==> null.certbot_vm: Warning: Permanently added '192.168.2.13' (ED25519) to the list of known hosts.
null.certbot_vm: sending incremental file list
null.certbot_vm: fullchain.pem
null.certbot_vm:
null.certbot_vm: sent 3,312 bytes received 83 bytes 6,790.00 bytes/sec
null.certbot_vm: total size is 5,129 speedup is 1.51
==> null.certbot_vm: Warning: Permanently added '192.168.2.13' (ED25519) to the list of known hosts.
null.certbot_vm: sending incremental file list
null.certbot_vm: privkey.pem
null.certbot_vm:
null.certbot_vm: sent 315 bytes received 41 bytes 237.33 bytes/sec
null.certbot_vm: total size is 241 speedup is 0.68
null.certbot_vm: --- RELOADING REMOTE NGINX ---
==> null.certbot_vm: Warning: Permanently added '192.168.2.13' (ED25519) to the list of known hosts.
null.certbot_vm: --- ALL DONE: articles.clinilaunchresearch.in deployed to /etc/nginx/certs-test ---
==> null.certbot_vm: Downloading /home/packer/certbot-server/certbot/conf/archive/ => ./backup_certs/
Build 'null.certbot_vm' finished after 51 seconds 879 milliseconds.
==> Wait completed after 51 seconds 879 milliseconds
==> Builds finished. The artifacts of successful builds are:
--> null.certbot_vm: Did not export anything. This is the null builder
Step 7: Final Cleanup...
Powering off VM:
Process Complete.
Waiting for ESXi to settle...
Running Method: ISO...
--- Starting ISO-Based Build Process ---
--- Domain: articles.clinilaunchresearch.in | Mode: staging ---
vsphere-iso.certbot_vm: output will be in this color.
==> vsphere-iso.certbot_vm: Creating virtual machine...
==> vsphere-iso.certbot_vm: Applying custom hardware configuration...
==> vsphere-iso.certbot_vm: Mounting ISO images...
==> vsphere-iso.certbot_vm: Adding configuration parameters...
==> vsphere-iso.certbot_vm: Starting HTTP server on port 8017
==> vsphere-iso.certbot_vm: Setting temporary boot order...
==> vsphere-iso.certbot_vm: Powering on virtual machine...
==> vsphere-iso.certbot_vm: Waiting 10s for boot...
==> vsphere-iso.certbot_vm: Serving HTTP requests at http://192.168.60.221:8017/.
==> vsphere-iso.certbot_vm: Typing boot command...
==> vsphere-iso.certbot_vm: Waiting for IP...
==> vsphere-iso.certbot_vm: IP address: 192.168.60.164
==> vsphere-iso.certbot_vm: Using SSH communicator to connect: 192.168.60.164
==> vsphere-iso.certbot_vm: Waiting for SSH to become available...
==> vsphere-iso.certbot_vm: Connected to SSH!
==> vsphere-iso.certbot_vm: Provisioning with shell script: C:\Users\lms2\AppData\Local\Temp\packer-shell1301726987
vsphere-iso.certbot_vm: Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
vsphere-iso.certbot_vm: Hit:2 http://archive.ubuntu.com/ubuntu noble-updates InRelease
vsphere-iso.certbot_vm: Hit:3 http://archive.ubuntu.com/ubuntu noble-backports InRelease
vsphere-iso.certbot_vm: Hit:4 http://security.ubuntu.com/ubuntu noble-security InRelease
vsphere-iso.certbot_vm: Reading package lists...
vsphere-iso.certbot_vm: Reading package lists...
vsphere-iso.certbot_vm: Building dependency tree...
vsphere-iso.certbot_vm: Reading state information...
vsphere-iso.certbot_vm: rsync is already the newest version (3.2.7-1ubuntu1.2).
vsphere-iso.certbot_vm: rsync set to manually installed.
vsphere-iso.certbot_vm: The following additional packages will be installed:
vsphere-iso.certbot_vm: bridge-utils containerd dns-root-data dnsmasq-base pigz python3-compose
vsphere-iso.certbot_vm: python3-docker python3-dockerpty python3-docopt python3-dotenv
vsphere-iso.certbot_vm: python3-texttable python3-websocket runc ubuntu-fan
vsphere-iso.certbot_vm: Suggested packages:
vsphere-iso.certbot_vm: ifupdown aufs-tools cgroupfs-mount | cgroup-lite debootstrap docker-buildx
vsphere-iso.certbot_vm: docker-compose-v2 docker-doc rinse zfs-fuse | zfsutils
vsphere-iso.certbot_vm: The following NEW packages will be installed:
vsphere-iso.certbot_vm: bridge-utils containerd dns-root-data dnsmasq-base docker-compose docker.io
vsphere-iso.certbot_vm: pigz python3-compose python3-docker python3-dockerpty python3-docopt
vsphere-iso.certbot_vm: python3-dotenv python3-texttable python3-websocket runc ubuntu-fan
vsphere-iso.certbot_vm: 0 upgraded, 16 newly installed, 0 to remove and 37 not upgraded.
vsphere-iso.certbot_vm: Need to get 74.1 MB of archives.
vsphere-iso.certbot_vm: After this operation, 280 MB of additional disk space will be used.
vsphere-iso.certbot_vm: Get:1 http://archive.ubuntu.com/ubuntu noble/universe amd64 pigz amd64 2.8-1 [65.6 kB]
vsphere-iso.certbot_vm: Get:2 http://archive.ubuntu.com/ubuntu noble/main amd64 bridge-utils amd64 1.7.1-1ubuntu2 [33.9 kB]
vsphere-iso.certbot_vm: Get:3 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 runc amd64 1.3.4-0ubuntu1~24.04.1 [9574 kB]
vsphere-iso.certbot_vm: Get:4 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 containerd amd64 2.2.1-0ubuntu1~24.04.2 [28.1 MB]
vsphere-iso.certbot_vm: Get:5 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 dns-root-data all 2024071801~ubuntu0.24.04.1 [5918 B]
vsphere-iso.certbot_vm: Get:6 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 dnsmasq-base amd64 2.90-2ubuntu0.3 [376 kB]
vsphere-iso.certbot_vm: Get:7 http://archive.ubuntu.com/ubuntu noble/universe amd64 python3-websocket all 1.7.0-1 [38.1 kB]
vsphere-iso.certbot_vm: Get:8 http://archive.ubuntu.com/ubuntu noble-updates/universe amd64 python3-docker all 5.0.3-1ubuntu1.1 [89.1 kB]
vsphere-iso.certbot_vm: Get:9 http://archive.ubuntu.com/ubuntu noble/universe amd64 python3-dockerpty all 0.4.1-5 [11.4 kB]
vsphere-iso.certbot_vm: Get:10 http://archive.ubuntu.com/ubuntu noble/universe amd64 python3-docopt all 0.6.2-6 [26.1 kB]
vsphere-iso.certbot_vm: Get:11 http://archive.ubuntu.com/ubuntu noble/universe amd64 python3-dotenv all 1.0.1-1 [22.3 kB]
vsphere-iso.certbot_vm: Get:12 http://archive.ubuntu.com/ubuntu noble/universe amd64 python3-texttable all 1.6.7-1 [11.0 kB]
vsphere-iso.certbot_vm: Get:13 http://archive.ubuntu.com/ubuntu noble/universe amd64 python3-compose all 1.29.2-6ubuntu1 [84.6 kB]
vsphere-iso.certbot_vm: Get:14 http://archive.ubuntu.com/ubuntu noble/universe amd64 docker-compose all 1.29.2-6ubuntu1 [14.0 kB]
vsphere-iso.certbot_vm: Get:15 http://archive.ubuntu.com/ubuntu noble-updates/universe amd64 docker.io amd64 29.1.3-0ubuntu3~24.04.2 [35.6 MB]
vsphere-iso.certbot_vm: Get:16 http://archive.ubuntu.com/ubuntu noble-updates/universe amd64 ubuntu-fan all 0.12.16+24.04.1 [34.2 kB]
==> vsphere-iso.certbot_vm: debconf: unable to initialize frontend: Dialog
==> vsphere-iso.certbot_vm: debconf: (Dialog frontend will not work on a dumb terminal, an emacs shell buffer, or without a controlling terminal.)
==> vsphere-iso.certbot_vm: debconf: falling back to frontend: Readline
==> vsphere-iso.certbot_vm: debconf: unable to initialize frontend: Readline
==> vsphere-iso.certbot_vm: debconf: (This frontend requires a controlling tty.)
==> vsphere-iso.certbot_vm: debconf: falling back to frontend: Teletype
==> vsphere-iso.certbot_vm: dpkg-preconfigure: unable to re-open stdin:
vsphere-iso.certbot_vm: Fetched 74.1 MB in 5s (14.2 MB/s)
vsphere-iso.certbot_vm: Selecting previously unselected package pigz.
vsphere-iso.certbot_vm: (Reading database ... 88202 files and directories currently installed.)
vsphere-iso.certbot_vm: Preparing to unpack .../00-pigz_2.8-1_amd64.deb ...
vsphere-iso.certbot_vm: Unpacking pigz (2.8-1) ...
vsphere-iso.certbot_vm: Selecting previously unselected package bridge-utils.
vsphere-iso.certbot_vm: Preparing to unpack .../01-bridge-utils_1.7.1-1ubuntu2_amd64.deb ...
vsphere-iso.certbot_vm: Unpacking bridge-utils (1.7.1-1ubuntu2) ...
vsphere-iso.certbot_vm: Selecting previously unselected package runc.
vsphere-iso.certbot_vm: Preparing to unpack .../02-runc_1.3.4-0ubuntu1~24.04.1_amd64.deb ...
vsphere-iso.certbot_vm: Unpacking runc (1.3.4-0ubuntu1~24.04.1) ...
vsphere-iso.certbot_vm: Selecting previously unselected package containerd.
vsphere-iso.certbot_vm: Preparing to unpack .../03-containerd_2.2.1-0ubuntu1~24.04.2_amd64.deb ...
vsphere-iso.certbot_vm: Unpacking containerd (2.2.1-0ubuntu1~24.04.2) ...
vsphere-iso.certbot_vm: Selecting previously unselected package dns-root-data.
vsphere-iso.certbot_vm: Preparing to unpack .../04-dns-root-data_2024071801~ubuntu0.24.04.1_all.deb ...
vsphere-iso.certbot_vm: Unpacking dns-root-data (2024071801~ubuntu0.24.04.1) ...
vsphere-iso.certbot_vm: Selecting previously unselected package dnsmasq-base.
vsphere-iso.certbot_vm: Preparing to unpack .../05-dnsmasq-base_2.90-2ubuntu0.3_amd64.deb ...
vsphere-iso.certbot_vm: Unpacking dnsmasq-base (2.90-2ubuntu0.3) ...
vsphere-iso.certbot_vm: Selecting previously unselected package python3-websocket.
vsphere-iso.certbot_vm: Preparing to unpack .../06-python3-websocket_1.7.0-1_all.deb ...
vsphere-iso.certbot_vm: Unpacking python3-websocket (1.7.0-1) ...
vsphere-iso.certbot_vm: Selecting previously unselected package python3-docker.
vsphere-iso.certbot_vm: Preparing to unpack .../07-python3-docker_5.0.3-1ubuntu1.1_all.deb ...
vsphere-iso.certbot_vm: Unpacking python3-docker (5.0.3-1ubuntu1.1) ...
vsphere-iso.certbot_vm: Selecting previously unselected package python3-dockerpty.
vsphere-iso.certbot_vm: Preparing to unpack .../08-python3-dockerpty_0.4.1-5_all.deb ...
vsphere-iso.certbot_vm: Unpacking python3-dockerpty (0.4.1-5) ...
vsphere-iso.certbot_vm: Selecting previously unselected package python3-docopt.
vsphere-iso.certbot_vm: Preparing to unpack .../09-python3-docopt_0.6.2-6_all.deb ...
vsphere-iso.certbot_vm: Unpacking python3-docopt (0.6.2-6) ...
vsphere-iso.certbot_vm: Selecting previously unselected package python3-dotenv.
vsphere-iso.certbot_vm: Preparing to unpack .../10-python3-dotenv_1.0.1-1_all.deb ...
vsphere-iso.certbot_vm: Unpacking python3-dotenv (1.0.1-1) ...
vsphere-iso.certbot_vm: Selecting previously unselected package python3-texttable.
vsphere-iso.certbot_vm: Preparing to unpack .../11-python3-texttable_1.6.7-1_all.deb ...
vsphere-iso.certbot_vm: Unpacking python3-texttable (1.6.7-1) ...
vsphere-iso.certbot_vm: Selecting previously unselected package python3-compose.
vsphere-iso.certbot_vm: Preparing to unpack .../12-python3-compose_1.29.2-6ubuntu1_all.deb ...
vsphere-iso.certbot_vm: Unpacking python3-compose (1.29.2-6ubuntu1) ...
vsphere-iso.certbot_vm: Selecting previously unselected package docker-compose.
vsphere-iso.certbot_vm: Preparing to unpack .../13-docker-compose_1.29.2-6ubuntu1_all.deb ...
vsphere-iso.certbot_vm: Unpacking docker-compose (1.29.2-6ubuntu1) ...
vsphere-iso.certbot_vm: Selecting previously unselected package docker.io.
vsphere-iso.certbot_vm: Preparing to unpack .../14-docker.io_29.1.3-0ubuntu3~24.04.2_amd64.deb ...
vsphere-iso.certbot_vm: Unpacking docker.io (29.1.3-0ubuntu3~24.04.2) ...
vsphere-iso.certbot_vm: Selecting previously unselected package ubuntu-fan.
vsphere-iso.certbot_vm: Preparing to unpack .../15-ubuntu-fan_0.12.16+24.04.1_all.deb ...
vsphere-iso.certbot_vm: Unpacking ubuntu-fan (0.12.16+24.04.1) ...
vsphere-iso.certbot_vm: Setting up python3-dotenv (1.0.1-1) ...
vsphere-iso.certbot_vm: Setting up python3-texttable (1.6.7-1) ...
vsphere-iso.certbot_vm: Setting up python3-docopt (0.6.2-6) ...
vsphere-iso.certbot_vm: Setting up dnsmasq-base (2.90-2ubuntu0.3) ...
vsphere-iso.certbot_vm: Setting up runc (1.3.4-0ubuntu1~24.04.1) ...
vsphere-iso.certbot_vm: Setting up dns-root-data (2024071801~ubuntu0.24.04.1) ...
vsphere-iso.certbot_vm: Setting up bridge-utils (1.7.1-1ubuntu2) ...
vsphere-iso.certbot_vm: debconf: unable to initialize frontend: Dialog
vsphere-iso.certbot_vm: debconf: (Dialog frontend will not work on a dumb terminal, an emacs shell buffer, or without a controlling terminal.)
vsphere-iso.certbot_vm: debconf: falling back to frontend: Readline
vsphere-iso.certbot_vm: debconf: unable to initialize frontend: Readline
vsphere-iso.certbot_vm: debconf: (This frontend requires a controlling tty.)
vsphere-iso.certbot_vm: debconf: falling back to frontend: Teletype
vsphere-iso.certbot_vm: Setting up pigz (2.8-1) ...
vsphere-iso.certbot_vm: Setting up containerd (2.2.1-0ubuntu1~24.04.2) ...
vsphere-iso.certbot_vm: Created symlink /etc/systemd/system/multi-user.target.wants/containerd.service → /usr/lib/systemd/system/containerd.service.
vsphere-iso.certbot_vm: Setting up python3-websocket (1.7.0-1) ...
vsphere-iso.certbot_vm: Setting up python3-dockerpty (0.4.1-5) ...
vsphere-iso.certbot_vm: Setting up ubuntu-fan (0.12.16+24.04.1) ...
vsphere-iso.certbot_vm: Created symlink /etc/systemd/system/multi-user.target.wants/ubuntu-fan.service → /usr/lib/systemd/system/ubuntu-fan.service.
vsphere-iso.certbot_vm: Setting up python3-docker (5.0.3-1ubuntu1.1) ...
vsphere-iso.certbot_vm: Setting up docker.io (29.1.3-0ubuntu3~24.04.2) ...
vsphere-iso.certbot_vm: debconf: unable to initialize frontend: Dialog
vsphere-iso.certbot_vm: debconf: (Dialog frontend will not work on a dumb terminal, an emacs shell buffer, or without a controlling terminal.)
vsphere-iso.certbot_vm: debconf: falling back to frontend: Readline
vsphere-iso.certbot_vm: debconf: unable to initialize frontend: Readline
vsphere-iso.certbot_vm: debconf: (This frontend requires a controlling tty.)
vsphere-iso.certbot_vm: debconf: falling back to frontend: Teletype
vsphere-iso.certbot_vm: info: Selecting GID from range 100 to 999 ...
vsphere-iso.certbot_vm: info: Adding group `docker' (GID 110) ...
vsphere-iso.certbot_vm: Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
vsphere-iso.certbot_vm: Created symlink /etc/systemd/system/sockets.target.wants/docker.socket → /usr/lib/systemd/system/docker.socket.
vsphere-iso.certbot_vm: Setting up python3-compose (1.29.2-6ubuntu1) ...
vsphere-iso.certbot_vm: Setting up docker-compose (1.29.2-6ubuntu1) ...
vsphere-iso.certbot_vm: Processing triggers for dbus (1.14.10-4ubuntu4.1) ...
vsphere-iso.certbot_vm: Processing triggers for man-db (2.12.0-4build2) ...
==> vsphere-iso.certbot_vm: debconf: unable to initialize frontend: Dialog
==> vsphere-iso.certbot_vm: debconf: (Dialog frontend will not work on a dumb terminal, an emacs shell buffer, or without a controlling terminal.)
==> vsphere-iso.certbot_vm: debconf: falling back to frontend: Readline
==> vsphere-iso.certbot_vm: debconf: unable to initialize frontend: Readline
==> vsphere-iso.certbot_vm: debconf: (This frontend requires a controlling tty.)
==> vsphere-iso.certbot_vm: debconf: falling back to frontend: Teletype
==> vsphere-iso.certbot_vm:
==> vsphere-iso.certbot_vm: Running kernel seems to be up-to-date.
==> vsphere-iso.certbot_vm:
==> vsphere-iso.certbot_vm: No services need to be restarted.
==> vsphere-iso.certbot_vm:
==> vsphere-iso.certbot_vm: No containers need to be restarted.
==> vsphere-iso.certbot_vm:
==> vsphere-iso.certbot_vm: No user sessions are running outdated binaries.
==> vsphere-iso.certbot_vm:
==> vsphere-iso.certbot_vm: No VM guests are running outdated hypervisor (qemu) binaries on this host.
==> vsphere-iso.certbot_vm: Uploading ./certbot-server => /home/packer/
==> vsphere-iso.certbot_vm: Uploading ./keys/certbot_master_key => /home/packer/.ssh/id_rsa
==> vsphere-iso.certbot_vm: Provisioning with shell script: C:\Users\lms2\AppData\Local\Temp\packer-shell2508594125
vsphere-iso.certbot_vm: --- STAGING MODE ACTIVE ---
vsphere-iso.certbot_vm: --- STARTING CERTIFICATE PROCESS FOR articles.clinilaunchresearch.in ---
==> vsphere-iso.certbot_vm: Creating network "certbot-server_default" with the default driver
==> vsphere-iso.certbot_vm: Pulling nginx (nginx:latest)...
vsphere-iso.certbot_vm: latest: Pulling from library/nginx
vsphere-iso.certbot_vm: Digest: sha256:06aa3d7be10bc6307990c81bdca075793132e9163391abc370c015e344e23128
vsphere-iso.certbot_vm: Status: Downloaded newer image for nginx:latest
==> vsphere-iso.certbot_vm: Creating certbot-server_nginx_1 ...
==> vsphere-iso.certbot_vm: Creating certbot-server_nginx_1 ... done
vsphere-iso.certbot_vm: --- REQUESTING STAGING CERTIFICATE ---
==> vsphere-iso.certbot_vm: Pulling certbot (certbot/certbot:)...
vsphere-iso.certbot_vm: latest: Pulling from certbot/certbot
vsphere-iso.certbot_vm: Digest: sha256:0107d084c225631fc64a8313e19adb07275f7296fde338f7dfa93986c80b2e3e
vsphere-iso.certbot_vm: Status: Downloaded newer image for certbot/certbot:latest
==> vsphere-iso.certbot_vm: Creating certbot-server_certbot_run ...
==> vsphere-iso.certbot_vm: Creating certbot-server_certbot_run ... done
==> vsphere-iso.certbot_vm: Saving debug log to /var/log/letsencrypt/letsencrypt.log
vsphere-iso.certbot_vm: Account registered.
vsphere-iso.certbot_vm: Requesting a certificate for articles.clinilaunchresearch.in
vsphere-iso.certbot_vm:
vsphere-iso.certbot_vm: Successfully received certificate.
vsphere-iso.certbot_vm: Certificate is saved at: /etc/letsencrypt/live/articles.clinilaunchresearch.in/fullchain.pem
vsphere-iso.certbot_vm: Key is saved at: /etc/letsencrypt/live/articles.clinilaunchresearch.in/privkey.pem
vsphere-iso.certbot_vm: This certificate expires on 2026-08-12.
vsphere-iso.certbot_vm: These files will be updated when the certificate renews.
vsphere-iso.certbot_vm: NEXT STEPS:
vsphere-iso.certbot_vm: - The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.
vsphere-iso.certbot_vm: --- CERTIFICATE GENERATED SUCCESSFULLY ---
vsphere-iso.certbot_vm: --- PREPARING LOCAL BACKUP PERMISSIONS ---
vsphere-iso.certbot_vm: --- SYNCING TO NGINX VM (192.168.2.13) ---
==> vsphere-iso.certbot_vm: Warning: Permanently added '192.168.2.13' (ED25519) to the list of known hosts.
==> vsphere-iso.certbot_vm: Warning: Permanently added '192.168.2.13' (ED25519) to the list of known hosts.
vsphere-iso.certbot_vm: sending incremental file list
vsphere-iso.certbot_vm: fullchain.pem
vsphere-iso.certbot_vm:
vsphere-iso.certbot_vm: sent 1,107 bytes received 83 bytes 793.33 bytes/sec
vsphere-iso.certbot_vm: total size is 5,133 speedup is 4.31
==> vsphere-iso.certbot_vm: Warning: Permanently added '192.168.2.13' (ED25519) to the list of known hosts.
vsphere-iso.certbot_vm: sending incremental file list
vsphere-iso.certbot_vm: privkey.pem
vsphere-iso.certbot_vm:
vsphere-iso.certbot_vm: sent 318 bytes received 41 bytes 718.00 bytes/sec
vsphere-iso.certbot_vm: total size is 241 speedup is 0.67
vsphere-iso.certbot_vm: --- RELOADING REMOTE NGINX ---
==> vsphere-iso.certbot_vm: Warning: Permanently added '192.168.2.13' (ED25519) to the list of known hosts.
vsphere-iso.certbot_vm: --- ALL DONE: articles.clinilaunchresearch.in ---
==> vsphere-iso.certbot_vm: Downloading /home/packer/certbot-server/certbot/conf/archive/articles.clinilaunchresearch.in/ => ./backup_certs/articles.clinilaunchresearch.in/
==> vsphere-iso.certbot_vm: Running shutdown command...
==> vsphere-iso.certbot_vm: Deleting floppy drives...
==> vsphere-iso.certbot_vm: Ejecting CD-ROM media...
==> vsphere-iso.certbot_vm: Clearing boot order...
==> vsphere-iso.certbot_vm: Destroying VM...
==> vsphere-iso.certbot_vm: Closing sessions...
Build 'vsphere-iso.certbot_vm' finished after 14 minutes 35 seconds.
==> Wait completed after 14 minutes 35 seconds
==> Builds finished. The artifacts of successful builds are:
--> vsphere-iso.certbot_vm: ephemeral-cert-build
--- ISO Build Complete ---
----------------------------------------
BENCHMARK COMPLETE
Clone Method Time: 174.107 seconds
ISO Method Time: 876.910 seconds
----------------------------------------
```

29
docs/benchmark-report.md Normal file
View File

@ -0,0 +1,29 @@
## Pipeline Performance Benchmarks
An execution pass can be validated against empirical telemetry captured during baseline system testing. Use the following metrics to evaluate whether a build cycle is performing within normal operational constraints:
### Baseline Execution Summary
| Deployment Method | Baseline Duration | Primary Time Consumer | Ideal Deployment Frequency |
| --- | --- | --- | --- |
| **Clone-Based Pipeline** | **~2.9 Minutes** (174s) | VM provisioning & disk thin-provisioning expansion | Recommended for rapid scheduled `cron` updates |
| **ISO-Based Pipeline** | **~14.6 Minutes** (876s) | Network package updates (`apt-get`) and OS compilation | Recommended for quarterly security baseline updates |
### Verification of Lifecycle Stages (Clone vs ISO)
#### A. Clone-Based Execution Sequence
When auditing a clone run, watch for the thin-provisioned disk generation cycle. A healthy sequence should mirror this timestamp envelope:
1. **Disk Provisioning:** `Cloning disk '/vmfs/volumes/app-platform/...vmdk'... Clone: 100% done.`
2. **Network Alignment:** Connects to `192.168.60.164` over SSH.
3. **Execution Block:** Spins up the localized Docker-compose network structures and requests the certificate.
4. **Total Run Threshold:** Must complete entirely under **3 minutes**.
#### B. ISO-Based Execution Sequence
When running via raw ISO, the pipeline spends a significant portion of its time fetching dependencies.
1. **OS Boot Phase:** Packer stands up a temporary HTTP server (e.g., port `8017`) to feed autoinstall cloud-config maps.
2. **Package Fetch Latency:** The system downloads roughly **74.1 MB** of core archive dependencies (`docker.io`, `docker-compose`, etc.). If this step takes longer than 5–7 minutes, check your gateway DNS and network bandwidth paths.
3. **Total Run Threshold:** Must complete entirely under **15 minutes**.

516
docs/clone-process.md Normal file
View File

@ -0,0 +1,516 @@
This documentation provides an in-depth, production-grade guide to the **VM Clone-Based Certificate Automation Pipeline** within the **Automated Certbot Ephemeral Pipeline** framework. By reading this guide, you will completely understand how the system orchestrates standalone VMware ESXi hosts via SSH, clones clean infrastructure templates, enforces strict networking identities via raw `.vmx` manipulations, generates SSL certificates using Dockerized Certbot, deploys them to target web nodes, and handles destructive resource teardown.
---
## 1. Architectural System Overview
The **Clone Method** optimizes for execution speed by duplicating an existing, slimmed-down base virtual disk on your ESXi host rather than completing an operating system installation from scratch.
The primary challenge with cloning on standalone ESXi hosts is the loss of network synchronization—cloned VMs traditionally receive random MAC addresses, which breaks static DHCP reservations. This pipeline solves that problem by using programmatic `sed` and `echo` manipulations on the raw `.vmx` configuration text file to hard-code a static MAC identity before boot. This guarantees that downstream firewalls (like pfSense) cleanly allocate the expected IP address every single time.
### The Master Automation Lifecycle
=== "Diagram"
```mermaid
graph TD
A[1. Execution Entry: run-certbot.sh] -->|Invokes with method=clone| B(2. Wrapper Logic: generate_cert_with_clone.sh)
B -->|Cleans legacy locks| C[3. ESXi Hypervisor via SSH]
B -->|vmkfstools -i thin copy| C
B -->|sed / vmx raw text injection| C
B -->|vim-cmd power.on| C
B -->|Blocks until Ping passes| D[4. Active Guest VM: 192.168.60.164]
B -->|Hands over control plane| E[5. Packer Build Core Engine]
E -->|Null Builder SSH Session| D
E -->|Pushes Workspace Directories| D
D -->|Executes: create-cert.sh| F[6. Local Guest Runtime]
F -->|Docker Compose Sidecar| G[7. Let's Encrypt CA]
F -->|Secure Rsync Sync / Reload| H[8. Production Nginx: 192.168.2.13]
E -->|Downloads backup artifacts| I[9. Host Storage Space]
B -->|Teardown: unregister & rm -rf| C
```
=== "Raw"
```text
graph TD
A[1. Execution Entry: run-certbot.sh] -->|Invokes with method=clone| B(2. Wrapper Logic: generate_cert_with_clone.sh)
B -->|Cleans legacy locks| C[3. ESXi Hypervisor via SSH]
B -->|vmkfstools -i thin copy| C
B -->|sed / vmx raw text injection| C
B -->|vim-cmd power.on| C
B -->|Blocks until Ping passes| D[4. Active Guest VM: 192.168.60.164]
B -->|Hands over control plane| E[5. Packer Build Core Engine]
E -->|Null Builder SSH Session| D
E -->|Pushes Workspace Directories| D
D -->|Executes: create-cert.sh| F[6. Local Guest Runtime]
F -->|Docker Compose Sidecar| G[7. Let's Encrypt CA]
F -->|Secure Rsync Sync / Reload| H[8. Production Nginx: 192.168.2.13]
E -->|Downloads backup artifacts| I[9. Host Storage Space]
B -->|Teardown: unregister & rm -rf| C
```
---
## 2. Technical Component & Pipeline Deep-Dive
### Phase 1: Arguments Parsing and Validation
The operator executes the wrapper script: `./run-certbot.sh test articles.clinilaunchresearch.in clone`. The script validates arguments, verifies that the tracking method equals `clone`, and forwards variables to the isolated infrastructure configuration module (`generate_cert_with_clone.sh`) while injecting environmental flags (`staging` vs `prod`).
### Phase 2: ESXi Hardware Engineering via SSH Commands
Because standalone ESXi (without vCenter) lacks a centralized provisioning API, the script establishes passwordless SSH connections directly to the hypervisor bare-metal shell to execute low-level management binaries:
* `vmkfstools`: Performs an advanced block-level copy of the parent `.vmdk` file into the ephemeral run folder using the `-d thin` parameter. Thin provisioning ensures the clone only consumes actual data blocks rather than reserving the full allocated disk space upfront, maximizing datastore capacity.
* Raw `.vmx` Injections: The script runs destructive line edits (`sed '/ethernet0/d'`) to purge old hardware fingerprints from the configuration metadata. It then appends text blocks forcing the hypervisor to recognize the virtual interface cards explicitly as `vmxnet3` adapters assigned to fixed hardware MAC targets (`00:0c:29:9c:31:db`).
### Phase 3: Network Interlocking and Synchronization
The guest VM requires dual-homed networking connectivity to bridge separate subnets:
1. **Interface `ethernet0` (VM Network):** Dedicated control plane interface. Maps directly against structural network parameters to inherit the orchestration IP `192.168.60.164` via static MAC reservation tables.
2. **Interface `ethernet1` (network2):** Public tracking routing network. Maps directly out towards the validation layer to route HTTP-01 ACME authorization challenge traffic outward via upstream gateways.
The control script pauses execution with a blocking network validation loop (`until ping -n 1 -w 1000 $VM_IP`). This ensures Packer does not attempt to initiate an orchestration connection until the guest operating system's kernel has completed initialization, requested its lease, and started its internal OpenSSH daemon.
---
## 3. Core Blueprint Files & Scripts
Below are the exact implementation blueprints matching your Clone-based architecture workspace.
### `run-certbot.sh`
```bash
#!/usr/bin/env bash
# 1. Source the function files
source /c/Users/lms2/Documents/packer/packer-esxi/packer-certbot-clone-esxi/bash_fn/generate_cert_with_clone.sh
source /c/Users/lms2/Documents/packer/packer-esxi/packer-certbot-clone-esxi/bash_fn/generate_cert_without_clone.sh
# Capture Arguments
ACTION=$1 # test | prod
TARGET_DOMAIN=$2 # your domain
METHOD=$3 # clone | iso (New argument)
# Check for required arguments
if [ -z "$TARGET_DOMAIN" ] || [ -z "$METHOD" ]; then
echo "Error: Missing arguments."
echo "Usage: $0 {test|prod} <domain> {clone|iso}"
echo "Example: $0 test articles.clinilaunchresearch.in iso"
exit 1
fi
# Define the execution logic in a reusable way
run_build() {
local mode=$1
if [ "$METHOD" == "clone" ]; then
echo "--- RUNNING CLONE-BASED BUILD ($mode) ---"
generate_cert_with_clone "$TARGET_DOMAIN" "$mode"
elif [ "$METHOD" == "iso" ]; then
echo "--- RUNNING ISO-BASED BUILD ($mode) ---"
generate_cert_without_clone "$TARGET_DOMAIN" "$mode"
else
echo "Error: Invalid method '$METHOD'. Use 'clone' or 'iso'."
exit 1
fi
}
case "$ACTION" in
"test")
echo "--- STARTING STAGING PROCESS FOR: $TARGET_DOMAIN ---"
run_build "staging"
;;
"prod")
echo "--- STARTING PRODUCTION DEPLOYMENT FOR: $TARGET_DOMAIN ---"
echo "!!! This will request a REAL certificate from Let's Encrypt !!!"
read -p "Are you sure? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
run_build "prod"
else
echo "Deployment cancelled."
fi
;;
*)
echo "Usage: $0 {test|prod} <domain> {clone|iso}"
exit 1
;;
esac
```
### `bash_fn/generate_cert_with_clone.sh`
```bash
#!/bin/bash
generate_cert_with_clone() {
# Accept arguments passed from run-certbot.sh
DOMAIN_TO_GENERATE=${1:-"articles.clinilaunchresearch.in"}
TARGET_MODE=${2:-"staging"}
# --- CONFIG ---
ESXI_HOST="192.168.60.179"
ESXI_USER="root"
DS_PATH="/vmfs/volumes/app-platform"
TPL_NAME="ubuntu-2404-base-template"
VM_NAME="ephemeral-cert-build"
VM_IP="192.168.60.164"
SSH_KEY="C:/Users/lms2/.ssh/privkey.pem"
SSH_OPTS="-i $SSH_KEY -o BatchMode=yes -o ConnectTimeout=10"
run_ssh() { ssh $SSH_OPTS "$ESXI_USER@$ESXI_HOST" "$1"; }
echo "Step 1: Cleaning old runs..."
VM_ID=$(run_ssh "vim-cmd vmsvc/getallvms | grep '$VM_NAME' | awk '{print \$1}'")
if [ ! -z "$VM_ID" ]; then
run_ssh "vim-cmd vmsvc/power.off $VM_ID && vim-cmd vmsvc/unregister $VM_ID"
fi
run_ssh "rm -rf $DS_PATH/$VM_NAME"
echo "Step 2: Cloning template..."
run_ssh "mkdir -p $DS_PATH/$VM_NAME && \
vmkfstools -i '$DS_PATH/$TPL_NAME/$TPL_NAME.vmdk' '$DS_PATH/$VM_NAME/$VM_NAME.vmdk' -d thin && \
cp '$DS_PATH/$TPL_NAME/$TPL_NAME.vmx' '$DS_PATH/$VM_NAME/$VM_NAME.vmx'"
echo "Step 3: Hard-coding Static MACs and cleaning IDs..."
run_ssh "sed -i '/uuid./d' $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
sed -i '/ethernet0/d' $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
sed -i '/ethernet1/d' $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
sed -i 's/displayName = .*/displayName = \"$VM_NAME\"/g' $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'ethernet0.virtualDev = \"vmxnet3\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'ethernet0.networkName = \"VM Network\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'ethernet0.addressType = \"static\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'ethernet0.address = \"00:0c:29:9c:31:db\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'ethernet0.checkMACAddress = \"false\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'ethernet0.present = \"TRUE\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'ethernet1.virtualDev = \"vmxnet3\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'ethernet1.networkName = \"network2\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'ethernet1.addressType = \"static\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'ethernet1.address = \"00:0c:29:a9:8c:05\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'ethernet1.checkMACAddress = \"false\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'ethernet1.present = \"TRUE\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
sed -i \"s/$TPL_NAME.vmdk/$VM_NAME.vmdk/g\" $DS_PATH/$VM_NAME/$VM_NAME.vmx && \
echo 'uuid.action = \"create\"' >> $DS_PATH/$VM_NAME/$VM_NAME.vmx"
echo "Step 4: Starting VM..."
NEW_ID=$(run_ssh "vim-cmd solo/registervm $DS_PATH/$VM_NAME/$VM_NAME.vmx")
run_ssh "vim-cmd vmsvc/power.on $NEW_ID"
echo "Step 5: Waiting for Network ($VM_IP)..."
until ping -n 1 -w 1000 $VM_IP > /dev/null; do sleep 5; done
sleep 10
echo "Step 6: Handing over to Packer (Mode: $TARGET_MODE)..."
packer build \
-var "domain_name=$DOMAIN_TO_GENERATE" \
-var "cert_mode=$TARGET_MODE" \
certbot.pkr.hcl
echo "Step 7: Final Cleanup..."
run_ssh "vim-cmd vmsvc/power.off $NEW_ID && vim-cmd vmsvc/unregister $NEW_ID && rm -rf $DS_PATH/$VM_NAME"
echo "Process Complete."
}
```
### `certbot.pkr.hcl`
```hcl
variable "domain_name" {
type = string
default = "articles.clinilaunchresearch.in"
}
variable "cert_mode" {
type = string
default = "staging" # Options: staging, prod
}
source "null" "certbot_vm" {
ssh_host = "192.168.60.164"
ssh_username = "packer"
ssh_password = "packer"
}
build {
sources = ["source.null.certbot_vm"]
# 1. Local workspace pre-requisites mapping
provisioner "shell-local" {
inline = ["if not exist backup_certs mkdir backup_certs"]
}
# 2. Remote configuration framework verification
provisioner "shell" {
inline = [
"mkdir -p /home/packer/.ssh",
"chmod 700 /home/packer/.ssh"
]
}
# 3. Transfer engine orchestration dependencies
provisioner "file" {
source = "./certbot-server"
destination = "/home/packer/"
}
# 4. Inject structural private key for distribution
provisioner "file" {
source = "./keys/certbot_master_key"
destination = "/home/packer/.ssh/id_rsa"
}
# 5. Run ACME transaction sequence
provisioner "shell" {
inline = [
"chmod 600 /home/packer/.ssh/id_rsa",
"cd /home/packer/certbot-server",
"chmod +x create-cert.sh",
"chown packer:packer create-cert.sh",
"./create-cert.sh ${var.domain_name} ${var.cert_mode}"
]
}
# 6. Archive generated artifacts back onto the execution engine
provisioner "file" {
direction = "download"
source = "/home/packer/certbot-server/certbot/conf/archive/"
destination = "./backup_certs/"
}
}
```
### `certbot-server/create-cert.sh`
```bash
#!/bin/bash
set -e
# --- CONFIGURATION ---
DOMAIN=$1
MODE=${2:-"staging"}
EMAIL="bhaskar.kumar@clinilaunchresearch.in"
# Destination Nginx VM details
NGINX_USER="dev1"
NGINX_HOST="192.168.2.13"
# --- DYNAMIC PATHING LOGIC ---
if [ "$MODE" == "prod" ]; then
echo "!!! PRODUCTION MODE ACTIVE !!!"
CERTBOT_FLAGS=""
NGINX_CERT_PATH="/etc/nginx/certs"
else
echo "--- STAGING MODE ACTIVE ---"
CERTBOT_FLAGS="--staging"
NGINX_CERT_PATH="/etc/nginx/certs-test"
fi
# Validation
if [ -z "$DOMAIN" ]; then
echo "Usage: ./create-cert.sh <domain> [staging|prod]"
exit 1
fi
echo "--- STARTING CERTIFICATE PROCESS FOR $DOMAIN ---"
echo "Target Path on Remote: $NGINX_CERT_PATH/$DOMAIN"
# 1. Start Nginx sidecar to handle ACME challenge path routing
sudo docker-compose up -d nginx
# 2. Run Certbot container matching parameters
sudo docker-compose run --rm certbot certonly \
--webroot \
--webroot-path=/var/www/certbot \
-d "$DOMAIN" \
--email "$EMAIL" \
--agree-tos \
--no-eff-email \
--non-interactive \
--keep-until-expiring \
$CERTBOT_FLAGS
# 3. Map cryptographic lineage targets
BASE_DIR=$(pwd)
LINEAGE="$BASE_DIR/certbot/conf/live/$DOMAIN"
FULLCHAIN="$LINEAGE/fullchain.pem"
PRIVKEY="$LINEAGE/privkey.pem"
# 4. System Transport Logistics Setup
SSH_KEY="/home/packer/.ssh/id_rsa"
SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i $SSH_KEY"
# Adjust filesystem permissions to resolve root vs user authorization limits
sudo chown -R packer:packer "$BASE_DIR/certbot/conf/"
sudo chmod -R 755 "$BASE_DIR/certbot/conf/archive/"
echo "--- SYNCING TO NGINX VM ---"
# Provision storage architecture on target production cluster
ssh $SSH_OPTS "$NGINX_USER@$NGINX_HOST" "sudo mkdir -p $NGINX_CERT_PATH/$DOMAIN && sudo chown $NGINX_USER:$NGINX_USER $NGINX_CERT_PATH/$DOMAIN"
# Execute secure synchronized payload distribution following Symlink references (-L)
rsync -avzL -e "ssh $SSH_OPTS" --chmod=F644 "$FULLCHAIN" "$NGINX_USER@$NGINX_HOST:$NGINX_CERT_PATH/$DOMAIN/"
rsync -avzL -e "ssh $SSH_OPTS" --chmod=F600 "$PRIVKEY" "$NGINX_USER@$NGINX_HOST:$NGINX_CERT_PATH/$DOMAIN/"
# 5. Live Service Synchronization Execution
echo "--- RELOADING REMOTE NGINX ---"
ssh $SSH_OPTS "$NGINX_USER@$NGINX_HOST" "sudo systemctl reload nginx"
echo "--- ALL DONE: $DOMAIN deployed to $NGINX_CERT_PATH ---"
```
### `certbot-server/docker-compose.yml`
```yaml
services:
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./certbot/www:/var/www/certbot:ro
- ./certbot/conf:/etc/letsencrypt
restart: always
certbot:
image: certbot/certbot
volumes:
- ./certbot/www:/var/www/certbot
- ./certbot/conf:/etc/letsencrypt
```
---
## 4. Operational Sequence Diagram
This sequential roadmap establishes how authorization flows, network links, and target actions line up chronologically over the lifetime of a clone-based validation execution loop.
=== "Diagram"
```mermaid
sequenceDiagram
autonumber
participant Host as Host Operator Machine (Windows OS Context)
participant ESXi as ESXi Bare Metal (192.168.60.179)
participant VM as Ephemeral Clone Node (192.168.60.164)
participant LE as Let's Encrypt CA Core
participant Prod as Production Web Node (192.168.2.13)
Host->>Host: Execute run-certbot.sh test <domain> clone
Host->>ESXi: SSH: Power-off & Unregister any lingering legacy 'ephemeral-cert-build' VMs
Host->>ESXi: SSH: Execute vmkfstools thin copy on base-template storage blocks
Host->>ESXi: SSH: Run sed edits to force static MACs and vmxnet3 adapters in .vmx text
Host->>ESXi: SSH: Register newly modified VM configurations & trigger boot sequence
Host->>VM: Pings VM address repeatedly until network stack answers
Host->>Host: Instantiates 'packer build' matching Null builder configuration maps
Host->>VM: Handover: Opens Master SSH execution socket (192.168.60.164)
Host->>VM: File Push: Copies certbot-server/ directories and target distribution SSH keys
Host->>VM: SSH Engine: Executes ./create-cert.sh <domain> staging
VM->>VM: Docker Engine launches Nginx Sidecar container bound to local port 80
VM->>LE: Certbot issues a validation application check request matching domain target
LE->>VM: ACME Challenge crawl hits external proxy layers, reaching VM port 80 path
LE->>VM: Challenge verified: Signed certificate transaction output dropped to live directory
VM->>VM: Programmatic chown shifts container file limits over to user permissions
VM->>Prod: SSH Control Socket: Issues target storage folder initialization
VM->>Prod: Rsync Pipe: Dispatches Fullchain (644) and Privkey (600) assets over to path
VM->>Prod: SSH Target Engine: Executes 'sudo systemctl reload nginx' line directive
Host->>VM: File Pull: Backs up current active archive generation certificates to Host local storage
Host->>ESXi: SSH Cleanup: Shuts down VM, clears registration records, wipes datastore folder
```
=== "Raw"
```text
sequenceDiagram
autonumber
participant Host as Host Operator Machine (Windows OS Context)
participant ESXi as ESXi Bare Metal (192.168.60.179)
participant VM as Ephemeral Clone Node (192.168.60.164)
participant LE as Let's Encrypt CA Core
participant Prod as Production Web Node (192.168.2.13)
Host->>Host: Execute run-certbot.sh test <domain> clone
Host->>ESXi: SSH: Power-off & Unregister any lingering legacy 'ephemeral-cert-build' VMs
Host->>ESXi: SSH: Execute vmkfstools thin copy on base-template storage blocks
Host->>ESXi: SSH: Run sed edits to force static MACs and vmxnet3 adapters in .vmx text
Host->>ESXi: SSH: Register newly modified VM configurations & trigger boot sequence
Host->>VM: Pings VM address repeatedly until network stack answers
Host->>Host: Instantiates 'packer build' matching Null builder configuration maps
Host->>VM: Handover: Opens Master SSH execution socket (192.168.60.164)
Host->>VM: File Push: Copies certbot-server/ directories and target distribution SSH keys
Host->>VM: SSH Engine: Executes ./create-cert.sh <domain> staging
VM->>VM: Docker Engine launches Nginx Sidecar container bound to local port 80
VM->>LE: Certbot issues a validation application check request matching domain target
LE->>VM: ACME Challenge crawl hits external proxy layers, reaching VM port 80 path
LE->>VM: Challenge verified: Signed certificate transaction output dropped to live directory
VM->>VM: Programmatic chown shifts container file limits over to user permissions
VM->>Prod: SSH Control Socket: Issues target storage folder initialization
VM->>Prod: Rsync Pipe: Dispatches Fullchain (644) and Privkey (600) assets over to path
VM->>Prod: SSH Target Engine: Executes 'sudo systemctl reload nginx' line directive
Host->>VM: File Pull: Backs up current active archive generation certificates to Host local storage
Host->>ESXi: SSH Cleanup: Shuts down VM, clears registration records, wipes datastore folder
```
---
![clone process workflow](./img/clone-based-cert-flow.png)
---
## 5. In-Depth Step-by-Step Deployment Instructions
Follow these exact steps to test and put this system into production in your workspace:
### Step 1: Pre-flight Integrity Mapping
Verify that your directory architecture matches this structure before executing the orchestration engine:
```text
packer-certbot-clone-esxi/
├── run-certbot.sh
├── certbot.pkr.hcl
├── bash_fn/
│ └── generate_cert_with_clone.sh
├── keys/
│ └── certbot_master_key
└── certbot-server/
├── create-cert.sh
└── docker-compose.yml
```
### Step 2: Establish Cryptographic Authentication Clearances
1. Your local operator machine must have access permissions saved to allow script commands to control your ESXi host shell cleanly. Confirm this setup by validating that your private keys line up properly with your configured path: `C:/Users/lms2/.ssh/privkey.pem`.
2. Verify that the matching public key for the master script distribution token (`/keys/certbot_master_key`) is present on your target production web server within `/home/dev1/.ssh/authorized_keys`.
### Step 3: Run the Verification Workflow
#### Running an Isolated Staging Verification Run
Initiate the workflow engine using the `test` argument path:
```bash
./run-certbot.sh test articles.clinilaunchresearch.in clone
```
* The control console will track the execution flow, showing block cloning progress, MAC address injection patterns, network tracking delay logs, and final container verification sequences.
* Once completed, confirm your system output reads: `"--- ALL DONE ---"`. Open your local files to verify that backup certificate structures have successfully tracking dropped into your local `./backup_certs/` folder.
#### Running a Live Production Release
Once you have verified that the configuration layers load without errors, run a live issuance cycle:
```bash
./run-certbot.sh prod articles.clinilaunchresearch.in clone
```
* The application wrapper catches the request, flags the risk configuration tier, and prompts you with a safety message.
* Press `y` to confirm. The guest agent will strip staging flags, connect to production Let's Encrypt servers, obtain a valid certificate, distribute it to your live web node, and execute a live reload to apply the updates immediately.

418
docs/configuration.md Normal file
View File

@ -0,0 +1,418 @@
# Pipeline Configuration Guide
This section outlines the operational variables, network routing profiles, and explicit file configurations required to ensure a reliable and predictable automated certificate execution path.
---
## Identity & Secret Configurations
The infrastructure uses localized environment initialization inputs passed down to the Packer execution engines securely to avoid credential leaks within source repositories.
### Required Environment Variables
| Parameter Name | Purpose Context | Example Data Definition |
| :--- | :--- | :--- |
| `PKR_VAR_esxi_password` | Management credential access for target ESXi / vSphere nodes | `SuperSecureESXiPass123!`|
| `PKR_VAR_ssh_automation_password` | Local runtime system automation entry pass key | `AutomatedWorkerPass456$`|
---
## Network Routing Architecture
To handle incoming Let's Encrypt validation queries seamlessly without running a persistent public web engine, the infrastructure maps traffic flows dynamically during the validation window:
=== "Diagram"
```mermaid
flowchart TD
A[Public Web Client / Let's Encrypt Engine]
-->|Port 80 / 443 Requests| B[pfSense Firewall Gateway]
B -->|Inbound Pass-Through| C[HAProxy SSL/HTTP Routing Frontend]
C -->|Match ACL Path<br/>/.well-known/acme-challenge/*| D[Dynamic Backend Forwarding]
D --> E[Ephemeral Worker Node<br/>192.168.2.9]
```
=== "Raw"
```text
flowchart TD
A[Public Web Client / Let's Encrypt Engine]
-->|Port 80 / 443 Requests| B[pfSense Firewall Gateway]
B -->|Inbound Pass-Through| C[HAProxy SSL/HTTP Routing Frontend]
C -->|Match ACL Path<br/>/.well-known/acme-challenge/*| D[Dynamic Backend Forwarding]
D --> E[Ephemeral Worker Node<br/>192.168.2.9]
```
### Automation Routing & Mechanics
* **MAC Address Impersonation:** To ensure the worker VM gets assigned the exact network identity needed to catch incoming validation streams, specific hardware MAC addresses must be enforced during provisioning.
* **Static DHCP Lease Reservation:** The network gateway firewall configuration maps these precise MAC addresses to the exact static internal IP expected by upstream HAProxy routing blocks.
* **HAProxy Path Matching:** HAProxy intercepts incoming requests matching the `/.well-known/acme-challenge/*` path and automatically forwards them directly to the ephemeral worker VM's static IP reservation.
---
## Target Build Files to Update
Below are the explicit configurations and parameters that must be declared depending on your deployment execution approach.
=== "ISO-Based Configuration"
### ISO-Based Configuration (`certbot-iso-esxi/certbot.pkr.hcl`)
This deployment mode provisions a completely fresh Ubuntu VM directly from installation media using unattended cloud-init autoinstall workflows.
```hcl
variable "domain_name" {
type = string
default = "articles.clinilaunchresearch.in"
}
variable "cert_mode" {
type = string
default = "staging" # Options: staging, prod
}
packer {
required_plugins {
vsphere = {
version = ">= 1.2.1"
source = "github.com/hashicorp/vsphere"
}
}
}
source "vsphere-iso" "certbot_vm" {
# --- HYPERVISOR COORDINATES ---
vcenter_server = "192.168.60.179"
host = "192.168.60.179"
username = "root"
password = "Admin@123"
insecure_connection = true
vm_name = "ephemeral-cert-build"
CPUs = 1
RAM = 2048
guest_os_type = "ubuntu64Guest"
datastore = "app-platform"
storage {
disk_size = 20480
disk_thin_provisioned = true
}
# --- NETWORK ADAPTERS & MAC IMPERSONATION ---
# NIC 1: Management (VM Network / vmnic0)
network_adapters {
network = "VM Network"
network_card = "vmxnet3"
mac_address = "00:0C:29:9C:31:DB"
}
# NIC 2: Public Routing / pfSense
network_adapters {
network = "network2"
network_card = "vmxnet3"
mac_address = "00:0c:29:a9:8c:05"
}
configuration_parameters = {
"ethernet0.checkMACAddress" = "false"
"ethernet1.checkMACAddress" = "false"
}
ip_wait_address = "192.168.60.164/32"
# --- OS INSTALLATION SOURCES ---
iso_paths = ["[datastore1] ISOs/ubuntu-24.04.4-live-server-amd64.iso"]
http_bind_address = "192.168.60.221"
http_directory = "http"
boot_wait = "10s"
boot_command = [
"<esc><wait><esc><wait><esc><wait>",
"c<wait>",
"set gfxpayload=keep<enter>",
"linux /casper/vmlinuz quiet autoinstall cloud-config-url=/dev/null ds=nocloud-net\\;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ ip=dhcp dhcp-identifier=mac nameserver=1.1.1.1 --- <enter>",
"initrd /casper/initrd<enter>",
"boot<enter>"
]
# --- SSH PARAMETERS ---
ssh_username = "packer"
ssh_password = "packer"
ssh_private_key_file = "C:/Users/lms2/.ssh/privkey.pem"
ssh_host = "192.168.60.164"
ssh_timeout = "25m"
ip_wait_timeout = "20m"
ssh_handshake_attempts = "100"
destroy = true
convert_to_template = false
shutdown_command = "echo 'packer' | sudo -S shutdown -P now"
shutdown_timeout = "5m"
}
build {
sources = ["source.vsphere-iso.certbot_vm"]
# Base package installation
provisioner "shell" {
inline = [
"sleep 30",
"sudo apt-get update",
"sudo apt-get install -y docker.io docker-compose rsync",
"sudo usermod -aG docker packer",
"mkdir -p /home/packer/.ssh",
"chmod 700 /home/packer/.ssh"
]
}
# Upload certbot runtime stack
provisioner "file" {
source = "./certbot-server"
destination = "/home/packer/"
}
# Upload deployment SSH key
provisioner "file" {
source = "./keys/certbot_master_key"
destination = "/home/packer/.ssh/id_rsa"
}
# Execute certificate generation workflow
provisioner "shell" {
inline = [
"chmod 600 /home/packer/.ssh/id_rsa",
"cd /home/packer/certbot-server",
"chmod +x create-cert.sh",
"sed -i 's/home\\/dev1/home\\/packer/g' create-cert.sh",
"./create-cert.sh ${var.domain_name} ${var.cert_mode}"
]
}
# Download certificates locally
provisioner "file" {
direction = "download"
source = "/home/packer/certbot-server/certbot/conf/archive/${var.domain_name}/"
destination = "./backup_certs/${var.domain_name}/"
}
}
```
=== "Clone-Based Configuration"
### Clone-Based Configuration (`certbot-clone-esxi/pkr.hcl`)
This deployment mode skips full operating system installation and instead connects directly to a pre-existing cloned VM instance for rapid execution workflows.
```hcl
variable "domain_name" {
type = string
default = "articles.clinilaunchresearch.in"
}
variable "cert_mode" {
type = string
default = "staging" # Options: staging, prod
}
source "null" "certbot_vm" {
# Direct SSH target
ssh_host = "192.168.60.164"
ssh_username = "packer"
ssh_password = "packer"
}
build {
sources = ["source.null.certbot_vm"]
# Local workspace preparation
provisioner "shell-local" {
inline = [
"if not exist backup_certs mkdir backup_certs"
]
}
# Remote SSH workspace preparation
provisioner "shell" {
inline = [
"mkdir -p /home/packer/.ssh",
"chmod 700 /home/packer/.ssh"
]
}
# Upload certbot runtime stack
provisioner "file" {
source = "./certbot-server"
destination = "/home/packer/"
}
# Upload deployment SSH key
provisioner "file" {
source = "./keys/certbot_master_key"
destination = "/home/packer/.ssh/id_rsa"
}
# Execute certificate workflow
provisioner "shell" {
inline = [
"chmod 600 /home/packer/.ssh/id_rsa",
"cd /home/packer/certbot-server",
"chmod +x create-cert.sh",
"chown packer:packer create-cert.sh",
"./create-cert.sh ${var.domain_name} ${var.cert_mode}"
]
}
# Download generated certificates
provisioner "file" {
direction = "download"
source = "/home/packer/certbot-server/certbot/conf/archive/"
destination = "./backup_certs/"
}
}
```
## Gateway & Firewall Infrastructure Configurations
To replicate or maintain this environment, the following static network configurations must be present on your routing appliances:
### 1. R1 Router (MikroTik 192.168.60.X Series) ESXi Native Network
Packer orchestration connects to the worker VM over the ESXi native network interface to inject configuration files and scripts.
* **Objective:** Ensure the VMNative network interface consistently pulls `192.168.60.164`.
* **Configuration:** Navigate to **IP > DHCP Server > Leases** and add a static lease binding your hardcoded Packer management MAC address directly to the management IP.
| Interface Target | Hardcoded MAC Address | Assigned Static IP | Lease Type |
| --- | --- | --- | --- |
| **NIC 1 (Management)** | `00:0C:29:9C:31:DB` | `192.168.60.164` | Static (Infinite) |
![R1 router staic lease](./img/R1-router-static-lease.png)
---
### 2. pfSense LAN — ACME Challenge Interface
The second network adapter hooks into the pfSense isolated LAN network pool (`network2`) where internet access and inbound validation challenges are processed.
* **Objective:** Bind the second NIC so pfSense handles it deterministically.
* **Configuration:** Navigate to **Services > DHCP Server > LAN** (or your mapped `network2` interface tab), scroll down to **DHCP Static Mappings for this Interface**, and register the second MAC address.
| Interface Target | Hardcoded MAC Address | Assigned Static IP | Description | Hostname |
| --- | --- | --- | --- | --- |
| **NIC 2 (pfSense LAN)** | `00:0c:29:a9:8c:05` | *Assigned LAN Range IP* | Ephemeral Certbot Challenge Link | ephemeral-cert-build |
![Pfsense LAN static lease](./img/pfsense-5.png)
*(Note: In your Packer config, `ip_wait_address` is strictly waiting on the `192.168.60.164/32` management IP via the R1 router to establish its stable SSH control tunnel before proceeding).*
---
### 3. pfSense HAProxy — ACME Challenge Routing Rules
To allow Let's Encrypt to verify domain ownership via an HTTP-01 challenge while your production applications are live, HAProxy must intercept validation requests specifically and steer them away from production web servers to your ephemeral worker.
Log into your pfSense web GUI, navigate to **Services > HAProxy**, and modify your primary port 80/443 shared frontend settings using the rules below:
![pfsense-HAProxy](./img/pfsense-1.png)
#### Step A: Configure the Backend Server Pool (`certbot_backend`)
Navigate to the **Backend** tab, click **Add**, and establish the target pool parameters pointing to your ephemeral runner host node:
* **Name:** `certbot_backend`
* **Server list Table:**
* **Mode:** `active`
* **Name:** `certbot`
* **Forwardto:** `Address+Port`
* **Address:** `192.168.2.9`
* **Port:** `80`
* **Health checking:**
* **Health check method:** `HTTP`
---
![HAProxy-backend](./img/pfsense-2.png)
#### Step B: Edit the Shared HTTP Frontend (`http_frontend`)
Navigate to the **Frontend** tab and select your primary public interface handler (e.g., `http_frontend`), which binds onto `WAN address (IPv4)` over **Port 80** with `SSL Offloading` unchecked. Scroll down to the **Access Control lists and Actions** segment to enforce the following rules:
![HAProxy-frontend](./img/pfsense-3.png)
##### I. Access Control Lists (ACLs)
| # | Name | Expression | CS | Not | Value |
| --- | --- | --- | --- | --- | --- |
| **1** | `acme` | `Path starts with:` | no | no | `/.well-known/acme-challenge` |
| **2** | `not_acme` | `Path starts with:` | no | yes | `/.well-known/acme-challenge` |
##### II. Actions
| # | Action | Parameters | Condition acl names |
| --- | --- | --- | --- |
| **3** | `Use Backend` | backend: `certbot_backend` | `acme` |
| **4** | `http-request redirect` | rule: `scheme https` | `not_acme` |
![HAProxy-frontend-acl](./img/pfsense-4.png)
!!! info "Routing Control Logic Execution Profile"
- ACME validation requests are dynamically routed to the ephemeral Certbot VM.
- Standard web traffic bypasses the ACME backend entirely.
- Non-validation requests are automatically redirected to HTTPS.
- Routing logic is enforced through HAProxy ACL evaluation rules.
??? warning "Static DHCP Lease Planning Requirement"
Ensure that all statically assigned DHCP lease addresses used by the ephemeral Certbot infrastructure are configured **outside** the active DHCP dynamic allocation pool range.
Failure to isolate these addresses may result in:
- IP address collisions
- Unpredictable lease reassignment
- Packer SSH connection failures
- ACME validation routing instability
- Intermittent HAProxy backend resolution issues
Recommended practice:
- Reserve a dedicated static infrastructure subnet range for automation workloads.
- Exclude all statically mapped VM addresses from the DHCP auto-assignment scope within pfSense.
Example:
```text
DHCP Pool Range: 192.168.2.10 - 192.168.2.245
Static Lease Target: 192.168.2.9 âś… SAFE
DHCP Pool Range: 192.168.2.10 - 192.168.2.245
Static Lease Target: 192.168.2.19 ❌ CONFLICT RISK
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
docs/img/pfsense-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

BIN
docs/img/pfsense-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
docs/img/pfsense-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
docs/img/pfsense-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

BIN
docs/img/pfsense-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

415
docs/index.md Normal file
View File

@ -0,0 +1,415 @@
# Automated Certbot Ephemeral Pipeline
Welcome to the official technical documentation for the **Automated Certbot Ephemeral Pipeline** — an Infrastructure-as-Code (IaC) driven SSL/TLS automation platform engineered for secure, disposable, and deterministic certificate lifecycle management.
This project replaces traditional long-running certificate management Virtual Machines (VMs) with a fully automated **ephemeral execution model**. Instead of maintaining permanently deployed Certbot servers, the system dynamically provisions short-lived infrastructure only when certificate issuance or renewal is required.
Once execution completes, the environment is securely destroyed, leaving behind only the deployed certificates and operational logs.
---
## Why This Architecture Exists
Traditional SSL automation environments often suffer from:
- Long-lived infrastructure drift
- Persistent attack surfaces
- Manual dependency management
- Configuration inconsistency
- Credential sprawl
- VM lifecycle overhead
The **Ephemeral Certbot Pipeline** solves these problems by treating certificate issuance as a temporary workload rather than a permanently running service.
Each execution cycle performs the following:
1. Provision a clean ephemeral VM on VMware ESXi
2. Bootstrap networking and routing automatically
3. Launch Dockerized Certbot + Nginx challenge handlers
4. Complete ACME validation through HAProxy/pfSense
5. Deploy generated certificates to production systems
6. Securely destroy the VM and datastore artifacts
This ensures every run starts from a known-good immutable state.
---
## High-Level System Architecture
=== "Diagram"
```mermaid
flowchart TD
A[Operator Executes Pipeline] --> B[Packer Automation Engine]
B --> C[Provision Ephemeral Ubuntu VM]
C --> D[Apply Cloud-Init AutoInstall]
D --> E[Configure Static Networking]
E --> F[Launch Dockerized Certbot Stack]
F --> G[Nginx Handles ACME HTTP-01 Challenge]
G --> H[Let's Encrypt Validation]
H --> I[Generate SSL Certificates]
I --> J[Secure Rsync Deployment]
J --> K[Production Nginx Reverse Proxy]
K --> L[Reload Production Services]
L --> M[Archive Local Certificate Backup]
M --> N[Destroy Ephemeral VM]
```
=== "Raw"
```text
flowchart TD
A[Operator Executes Pipeline] --> B[Packer Automation Engine]
B --> C[Provision Ephemeral Ubuntu VM]
C --> D[Apply Cloud-Init AutoInstall]
D --> E[Configure Static Networking]
E --> F[Launch Dockerized Certbot Stack]
F --> G[Nginx Handles ACME HTTP-01 Challenge]
G --> H[Let's Encrypt Validation]
H --> I[Generate SSL Certificates]
I --> J[Secure Rsync Deployment]
J --> K[Production Nginx Reverse Proxy]
K --> L[Reload Production Services]
L --> M[Archive Local Certificate Backup]
M --> N[Destroy Ephemeral VM]
```
---
## Operational Workflow Overview
The pipeline execution lifecycle consists of several tightly orchestrated phases.
### Phase 1 — Pipeline Invocation
The operator launches the automation process using:
```bash
./run-certbot.sh test example.domain.com iso
```
The wrapper script determines:
- deployment mode (`test` or `prod`)
- provisioning strategy (`iso` or `clone`)
- target domain
- Packer execution context
---
### Phase 2 — Ephemeral Infrastructure Provisioning
HashiCorp Packer communicates directly with the VMware ESXi API to:
- create a temporary VM
- attach Ubuntu installation media
- inject unattended autoinstall parameters
- boot the machine automatically
- configure static networking
Cloud-init handles the entire operating system installation without human interaction.
---
### Phase 3 — Runtime Service Deployment
After SSH availability is confirmed, the pipeline:
- installs Docker and dependencies
- uploads the Certbot stack
- injects deployment SSH keys
- starts temporary Nginx challenge responders
- launches Certbot ACME validation requests
---
### Phase 4 — ACME Challenge Validation
Traffic routing occurs dynamically through:
- pfSense firewall policies
- HAProxy frontend ACLs
- HTTP-01 challenge forwarding
Let's Encrypt validates ownership by querying the ephemeral VM directly over port `80`.
---
### Phase 5 — Secure Certificate Deployment
Once certificates are issued:
- `fullchain.pem`
- `privkey.pem`
are securely synchronized via `rsync + SSH` to the production Nginx reverse proxy infrastructure.
Permissions are hardened automatically:
| File | Permission |
|---|---|
| fullchain.pem | 644 |
| privkey.pem | 600 |
The target Nginx service is then gracefully reloaded.
---
### Phase 6 — Infrastructure Teardown
After deployment completion:
- local backups are archived
- the VM powers off
- datastore files are deleted
- ESXi unregisters the VM entirely
No persistent workload remains.
---
## Infrastructure Topology
```text
+------------------------------------------------------------------+
| AUTOMATION CONTROL PLANE |
|------------------------------------------------------------------|
| Local Operator Machine |
| HashiCorp Packer |
| VMware ESXi API |
+------------------------------------------------------------------+
|
v
+------------------------------------------------------------------+
| EPHEMERAL CERTBOT EXECUTION VM |
|------------------------------------------------------------------|
| Ubuntu AutoInstall / Cloud-Init |
| Docker Runtime |
| Nginx ACME Challenge Handler |
| Certbot ACME Client |
| Rsync + SSH Deployment Engine |
+------------------------------------------------------------------+
|
v
+------------------------------------------------------------------+
| NETWORK ROUTING & VALIDATION LAYER |
|------------------------------------------------------------------|
| pfSense Firewall |
| HAProxy Reverse Proxy |
| ACME HTTP-01 Challenge Routing |
+------------------------------------------------------------------+
|
v
+------------------------------------------------------------------+
| PRODUCTION DELIVERY TARGETS |
|------------------------------------------------------------------|
| Nginx Reverse Proxies |
| Internal TLS Services |
| Production Certificate Stores |
+------------------------------------------------------------------+
```
---
## Core Architectural Principles
### Immutable Execution
Every execution starts from a completely fresh operating system installation.
No previous runtime state survives between builds.
---
### Minimal Attack Surface
The Certbot environment exists only during certificate issuance windows.
This dramatically reduces:
- exposed services
- stale package vulnerabilities
- credential persistence
- unauthorized access windows
---
### Deterministic Automation
Infrastructure provisioning, networking, routing, deployment, and cleanup are fully reproducible through declarative configuration.
No manual steps are required after initial setup.
---
### Infrastructure-as-Code First
The entire platform is version-controlled through:
- Packer templates
- Cloud-init configurations
- Docker Compose
- Shell automation
- Network routing rules
---
## Key Features
| Feature | Description |
|---|---|
| Ephemeral VM Lifecycle | Disposable infrastructure created per execution |
| Automated Ubuntu Installation | Fully unattended cloud-init deployment |
| Dockerized Certbot Runtime | Isolated ACME challenge environment |
| HAProxy ACME Routing | Dynamic HTTP-01 challenge forwarding |
| Secure SSH/Rsync Deployment | Automated certificate synchronization |
| Automatic Cleanup | VM destruction after deployment |
| Production/Staging Modes | Safe Let's Encrypt testing workflows |
| Multi-Interface Networking | Dedicated management and public challenge interfaces |
---
## Supported Deployment Modes
### ISO-Based Pipeline
Builds a completely fresh Ubuntu environment from official installation media every execution.
Best suited for:
- security-sensitive environments
- immutable infrastructure policies
- clean-room provisioning
- deterministic builds
➡ Proceed to: [iso process](iso-process.md)
---
### Clone-Based Pipeline
Deploys certificates using prebuilt VMware golden image templates for significantly faster execution.
Best suited for:
- rapid deployment cycles
- large-scale automation
- environments prioritizing speed
➡ Proceed to: [clone process](clone-process.md)
---
## Operations & Troubleshooting
### Configuration Guide
Detailed explanations covering:
- Packer variables
- cloud-init networking
- SSH authentication
- HAProxy ACLs
- pfSense NAT rules
- Let's Encrypt staging vs production
➡ Proceed to: [configuration](configuration.md)
---
### Architecture Verification
Pre-flight validation procedures for:
- ESXi datastore accessibility
- DNS resolution
- routing correctness
- ACME reachability
- network mappings
➡ Proceed to: [Verification](verification.md)
---
### Logging & Observability
Comprehensive operational diagnostics covering:
- Packer build logs
- Certbot execution traces
- Docker container logs
- rsync deployment output
- common failure scenarios
➡ Proceed to: [Logs](logs.md)
---
## Recommended Deployment Flow
=== "Diagram"
```mermaid
graph LR
A[Validate Infrastructure] --> B[Run Staging Pipeline]
B --> C[Verify Certificate Deployment]
C --> D[Run Production Pipeline]
D --> E[Monitor Renewal Lifecycle]
```
=== "Raw"
```text
graph LR
A[Validate Infrastructure] --> B[Run Staging Pipeline]
B --> C[Verify Certificate Deployment]
C --> D[Run Production Pipeline]
D --> E[Monitor Renewal Lifecycle]
```
---
## Security Model
This platform intentionally avoids maintaining persistent certificate infrastructure.
Security is achieved through:
- disposable execution environments
- temporary runtime exposure
- isolated deployment credentials
- immutable provisioning
- deterministic infrastructure recreation
- minimal service lifetime
The result is a hardened, low-maintenance certificate automation ecosystem optimized for modern private infrastructure environments.
---
## Next Steps
To begin implementation:
1. Review the infrastructure prerequisites
2. Configure networking and HAProxy routing
3. Validate ESXi API access
4. Test the staging workflow
5. Deploy production certificates
➡ Start with: [Iso Process](iso-process.md)

617
docs/iso-process.md Normal file
View File

@ -0,0 +1,617 @@
# VM ISO-Based SSL Certificate Automation system
This documentation provides an in-depth, step-by-step guide to the **ISO-Based Certificate Automation** pipeline. By reading this guide, an engineer will completely understand how the system boots an automated Ubuntu environment from scratch, generates Let's Encrypt SSL certificates using Docker, deploys them to a production environment, and tears itself down.
---
## 1. Architectural System Overview
The **ISO Method** builds an entirely clean, ephemeral Virtual Machine (VM) directly from an Ubuntu live installer ISO on VMware ESXi. Unlike the clone method—which copies an existing virtual disk—the ISO method completely automates a fresh OS installation using Ubuntu's `autoinstall` (cloud-init) framework.
This guarantees an immutable, predictable environment every single run, eliminating configuration drift.
### The Master Automation Lifecycle
=== "Diagram"
```mermaid
graph TD
A[1. Execution Entry: run-certbot.sh] -->|Invokes with method=iso| B(2. Wrapper Logic: generate_cert_without_clone.sh)
B -->|Changes Context to project directory| C[3. Core Runner: packer build certbot.pkr.hcl]
C -->|Serves Autoinstall Config| D[4. HTTP Sidecar: http/user-data]
C -->|Mounts OS ISO & Boots VM| E[5. ESXi Host Server: 192.168.60.179]
E -->|Automated OS Install via Cloud-Init| F[6. Running Ephemeral VM: 192.168.60.164]
C -->|Connects via SSH & Executes| G[7. Guest Engine: create-cert.sh]
G -->|Launches Containers| H[8. Docker Environment]
H -->|Nginx handles ACME Challenge| I[9. Let's Encrypt CA]
G -->|Rsyncs Keys & Reloads| J[10. Production Nginx: 192.168.2.13]
C -->|Teardown: destroy=true| E
```
=== "Raw"
```text
graph TD
A[1. Execution Entry: run-certbot.sh] -->|Invokes with method=iso| B(2. Wrapper Logic: generate_cert_without_clone.sh)
B -->|Changes Context to project directory| C[3. Core Runner: packer build certbot.pkr.hcl]
C -->|Serves Autoinstall Config| D[4. HTTP Sidecar: http/user-data]
C -->|Mounts OS ISO & Boots VM| E[5. ESXi Host Server: 192.168.60.179]
E -->|Automated OS Install via Cloud-Init| F[6. Running Ephemeral VM: 192.168.60.164]
C -->|Connects via SSH & Executes| G[7. Guest Engine: create-cert.sh]
G -->|Launches Containers| H[8. Docker Environment]
H -->|Nginx handles ACME Challenge| I[9. Let's Encrypt CA]
G -->|Rsyncs Keys & Reloads| J[10. Production Nginx: 192.168.2.13]
C -->|Teardown: destroy=true| E
```
---
## 2. Comprehensive Workflow Deep-Dive
### Phase 1: Context Isolation and Variables
The workflow starts when the operator runs `./run-certbot.sh test articles.clinilaunchresearch.in iso`. The execution is captured by a subshell wrapper that changes directories to the isolated ISO project directory (`/packer-certbot-iso-esxi`). This prevents local environment variables or state history from polluting separate automation pipelines.
### Phase 2: PXE/Automated Boot Sequence
Packer launches a micro HTTP server natively on the machine running the build (`192.168.60.221`). It sends a structured boot command sequence through the vSphere API to manipulate the VM’s virtual keyboard:
1. It hits Escape (`<esc>`) multiple times to clear GRUB boot menus.
2. It inputs automated kernel parameters that instruct the installer to fetch configuration flags from Packer's internal HTTP engine using:
`ds=nocloud-net;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/`
3. It sets `dhcp-identifier=mac` and explicit public nameservers (`1.1.1.1`) to guarantee DNS resolution succeeds immediately during installation.
### Phase 3: Hardware Tracking and Static Routing
The configuration hardcodes specific hardware MAC addresses (`00:0C:29:9C:31:DB`) across both the Packer builder and the cloud-init network engine (`user-data`).
* **Interface `ens192**` hooks into your standard management network to map directly against pfSense static DHCP maps, routing the explicit address `192.168.60.164` to the VM.
* **Interface `ens224**` configures a secondary static routing path (`192.168.2.9/24`) pointed directly to the upstream internal gateway (`192.168.2.1`), giving the dynamic ACME challenge traffic an isolated layer-2 pipeline to navigate out through local proxy layers cleanly.
---
## 3. Core Blueprint Files & Scripts
Below are the exact production files powering this automated pipeline.
### `run-certbot.sh`
```bash
#!/usr/bin/env bash
# 1. Source the function files
source /c/Users/lms2/Documents/packer/packer-esxi/packer-certbot-clone-esxi/bash_fn/generate_cert_with_clone.sh
source /c/Users/lms2/Documents/packer/packer-esxi/packer-certbot-clone-esxi/bash_fn/generate_cert_without_clone.sh
# Capture Arguments
ACTION=$1 # test | prod
TARGET_DOMAIN=$2 # your domain
METHOD=$3 # clone | iso (New argument)
# Check for required arguments
if [ -z "$TARGET_DOMAIN" ] || [ -z "$METHOD" ]; then
echo "Error: Missing arguments."
echo "Usage: $0 {test|prod} <domain> {clone|iso}"
echo "Example: $0 test articles.clinilaunchresearch.in iso"
exit 1
fi
# Define the execution logic in a reusable way
run_build() {
local mode=$1
if [ "$METHOD" == "clone" ]; then
echo "--- RUNNING CLONE-BASED BUILD ($mode) ---"
generate_cert_with_clone "$TARGET_DOMAIN" "$mode"
elif [ "$METHOD" == "iso" ]; then
echo "--- RUNNING ISO-BASED BUILD ($mode) ---"
generate_cert_without_clone "$TARGET_DOMAIN" "$mode"
else
echo "Error: Invalid method '$METHOD'. Use 'clone' or 'iso'."
exit 1
fi
}
case "$ACTION" in
"test")
echo "--- STARTING STAGING PROCESS FOR: $TARGET_DOMAIN ---"
run_build "staging"
;;
"prod")
echo "--- STARTING PRODUCTION DEPLOYMENT FOR: $TARGET_DOMAIN ---"
echo "!!! This will request a REAL certificate from Let's Encrypt !!!"
read -p "Are you sure? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
run_build "prod"
else
echo "Deployment cancelled."
fi
;;
*)
echo "Usage: $0 {test|prod} <domain> {clone|iso}"
exit 1
;;
esac
```
### `bash_fn/generate_cert_without_clone.sh`
```bash
#!/bin/bash
generate_cert_without_clone() {
# Accept arguments passed from run-certbot.sh
DOMAIN_TO_GENERATE=${1:-"articles.clinilaunchresearch.in"}
TARGET_MODE=${2:-"staging"}
# 1. Define where the ISO project lives
PROJECT_DIR="/c/Users/lms2/Documents/packer/packer-esxi/packer-certbot-iso-esxi"
echo "--- Starting ISO-Based Build Process ---"
echo "--- Domain: $DOMAIN_TO_GENERATE | Mode: $TARGET_MODE ---"
# 2. Use a subshell to avoid changing your terminal's directory permanently
(
cd "$PROJECT_DIR" || { echo "Folder not found!"; exit 1; }
# 3. Run Packer
packer build \
-var "domain_name=$DOMAIN_TO_GENERATE" \
-var "cert_mode=$TARGET_MODE" \
certbot.pkr.hcl
)
echo "--- ISO Build Complete ---"
}
```
### `certbot.pkr.hcl`
```hcl
variable "domain_name" {
type = string
default = "articles.clinilaunchresearch.in"
}
variable "cert_mode" {
type = string
default = "staging" # Options: staging, prod
}
packer {
required_plugins {
vsphere = {
version = ">= 1.2.1"
source = "github.com/hashicorp/vsphere"
}
}
}
source "vsphere-iso" "certbot_vm" {
vcenter_server = "192.168.60.179"
host = "192.168.60.179"
username = "root"
password = "Admin@123"
insecure_connection = true
vm_name = "ephemeral-cert-build"
CPUs = 1
RAM = 2048
guest_os_type = "ubuntu64Guest"
datastore = "app-platform"
storage {
disk_size = 20480
disk_thin_provisioned = true
}
# NIC 1: Management Link (Packer orchestration control plane)
network_adapters {
network = "VM Network"
network_card = "vmxnet3"
mac_address = "00:0C:29:9C:31:DB"
}
# NIC 2: Public Traffic (ACME HTTP-01 Challenges / Let's Encrypt)
network_adapters {
network = "network2"
network_card = "vmxnet3"
mac_address = "00:0c:29:a9:8c:05"
}
configuration_parameters = {
"ethernet0.checkMACAddress" = "false"
}
ip_wait_address = "192.168.60.164/32"
iso_paths = ["[datastore1] ISOs/ubuntu-24.04.4-live-server-amd64.iso"]
http_bind_address = "192.168.60.221"
http_directory = "http"
boot_wait = "10s"
boot_command = [
"<esc><wait><esc><wait><esc><wait>",
"c<wait>",
"set gfxpayload=keep<enter>",
"linux /casper/vmlinuz quiet autoinstall cloud-config-url=/dev/null ds=nocloud-net\\;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ ip=dhcp dhcp-identifier=mac nameserver=1.1.1.1 --- <enter>",
"initrd /casper/initrd<enter>",
"boot<enter>"
]
ssh_username = "packer"
ssh_password = "packer"
ssh_private_key_file = "C:/Users/lms2/.ssh/privkey.pem"
ssh_host = "192.168.60.164"
ssh_timeout = "25m"
ip_wait_timeout = "20m"
ssh_handshake_attempts = "100"
destroy = true
convert_to_template = false
shutdown_command = "echo 'packer' | sudo -S shutdown -P now"
shutdown_timeout = "5m"
}
build {
sources = ["source.vsphere-iso.certbot_vm"]
# Step 1: Core System Provisioning & Engine Installation
provisioner "shell" {
inline = [
"sleep 30",
"sudo apt-get update",
"sudo apt-get install -y docker.io docker-compose rsync",
"sudo usermod -aG docker packer",
"mkdir -p /home/packer/.ssh",
"chmod 700 /home/packer/.ssh"
]
}
# Step 2: Upload dockerized Certbot configurations
provisioner "file" {
source = "./certbot-server"
destination = "/home/packer/"
}
# Step 3: Inject deployment target master SSH authentication keys
provisioner "file" {
source = "./keys/certbot_master_key"
destination = "/home/packer/.ssh/id_rsa"
}
# Step 4: Execute ACME validation routine
provisioner "shell" {
inline = [
"chmod 600 /home/packer/.ssh/id_rsa",
"cd /home/packer/certbot-server",
"chmod +x create-cert.sh",
"sed -i 's/home\\/dev1/home\\/packer/g' create-cert.sh",
"./create-cert.sh ${var.domain_name} ${var.cert_mode}"
]
}
# Step 5: Archive copy locally onto the host executing Packer
provisioner "file" {
direction = "download"
source = "/home/packer/certbot-server/certbot/conf/archive/${var.domain_name}/"
destination = "./backup_certs/${var.domain_name}/"
}
}
```
### `http/user-data`
```yaml
#cloud-config
autoinstall:
version: 1
refresh-installer-netcfg: true
identity:
hostname: ephemeral-cert-build
username: packer
password: "$6$exXG6pOfC.H79O81$848.74W9.6v.hU2.S869A.e53A1"
locale: en_US
keyboard:
layout: us
network:
version: 2
ethernets:
ens192:
match:
macaddress: "00:0c:29:9c:31:db"
set-name: ens192
dhcp4: true
dhcp4-overrides:
use-routes: false
route-metric: 200
ens224:
match:
macaddress: "00:0c:29:a9:8c:05"
set-name: ens224
addresses:
- 192.168.2.9/24
nameservers:
addresses: [1.1.1.1, 8.8.8.8]
routes:
- to: default
via: 192.168.2.1
metric: 10
ssh:
install-server: true
allow-pw: true
user-data:
users:
- name: packer
passwd: "$6$exXG6pOfC.H79O81$848.74W9.6v.hU2.S869A.e53A1"
shell: /bin/bash
lock_passwd: false
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_authorized_keys:
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC9RrFJUpI2WdMrYphpPoEXgT1tcDl0qpKEagpMkSRhyb/r9eTEBTtO+RCHjSVHQtJdCw7ibRAQY1Yyf8pCoc5xBIaQxky1b6K4Yvi3ifhANhTCX7el4EkPO3FTiOZuHk0CoXc0RGWd9a/PF1BlfxtJ+mYSc2NGZ6F2MRK4uU2Pkm884J/G88HQHUIZLIxQejraP+E800on3GJTc+72REnXplphrYJhEN3KTD0iW8RCtWdgvd+3TTUgIZrZq0BFWYSiBnrrd4ZBnLGLr3Aeod5rJyCuqP0Sb2saqr4wDGRUaMd8aX2G4XY03LnR8TMggkWpyzUhxi8CqWcAB0Ft8uc65jC+R+unxXAAD+v1N9bI8Zui3iTuTAOF40/yBnMUCu9kEvRUFCNYagHZBbf0gwEzhRTpWP+8Gd4o4hPyuXysrIJ5KvzbD8J17u2Y7emBu09t29hc7V+48ZB5j2ZHfYhzAL2Qd8n+EZIpi+Y16ErC6o8zvO5qdyeJPRRwDb+xuscbiew7WX+SPsSc/uhjN7nnmqZMX5veP7PGR8XwuDTqNy14jZIWVOCsG5Yv05I9RAaFgONTfnt7TH5sn2gdT8uuqsaNGOf01QKYt3oT0xQlmZlLaWtGP/sZ/p4loA27XL8y8cz7UUXXOQTxKZTAVg+kAhQ5Fedi0cpRLCIwGHYDUQ=="
storage:
layout:
name: direct
termination: reboot
```
### `certbot-server/create-cert.sh`
```bash
#!/bin/bash
set -e
# Take domain from argument
DOMAIN=$1
MODE=$2
EMAIL="bhaskar.kumar@clinilaunchresearch.in"
# Destination Nginx VM details
NGINX_USER="dev1"
NGINX_HOST="192.168.2.13"
# --- DYNAMIC PATHING LOGIC ---
if [ "$MODE" == "prod" ]; then
echo "!!! PRODUCTION MODE ACTIVE !!!"
CERTBOT_FLAGS=""
NGINX_CERT_PATH="/etc/nginx/certs"
else
echo "--- STAGING MODE ACTIVE ---"
CERTBOT_FLAGS="--staging"
NGINX_CERT_PATH="/etc/nginx/certs-test"
fi
# Validation
if [ -z "$DOMAIN" ]; then
echo "Usage: ./create-cert.sh <domain> [staging|prod]"
exit 1
fi
echo "--- STARTING CERTIFICATE PROCESS FOR $DOMAIN ---"
# 1. Start Nginx sidecar (needed for the --webroot challenge)
sudo docker-compose up -d nginx
# 2. Run Certbot
echo "--- REQUESTING STAGING CERTIFICATE ---"
sudo docker-compose run --rm certbot certonly \
--webroot \
--webroot-path=/var/www/certbot \
-d "$DOMAIN" \
--email "$EMAIL" \
--agree-tos \
--no-eff-email \
--non-interactive \
--keep-until-expiring \
$CERTBOT_FLAGS
echo "--- CERTIFICATE GENERATED SUCCESSFULLY ---"
# 3. Define Paths
LINEAGE="$(pwd)/certbot/conf/live/$DOMAIN"
FULLCHAIN="$LINEAGE/fullchain.pem"
PRIVKEY="$LINEAGE/privkey.pem"
# 4. SSH/Rsync Setup
SSH_KEY="$HOME/.ssh/id_rsa"
SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i $SSH_KEY"
# --- BEFORE SYNCING ---
echo "--- PREPARING LOCAL BACKUP PERMISSIONS ---"
sudo chown -R packer:packer /home/packer/certbot-server/certbot/conf/live/
sudo chown -R packer:packer /home/packer/certbot-server/certbot/conf/archive/
sudo chmod -R 755 /home/packer/certbot-server/certbot/conf/archive/
echo "--- SYNCING TO NGINX VM ($NGINX_HOST) ---"
# Create remote directory on the Nginx Host
ssh $SSH_OPTS "$NGINX_USER@$NGINX_HOST" "sudo mkdir -p $NGINX_CERT_PATH/$DOMAIN && sudo chown $NGINX_USER:$NGINX_USER $NGINX_CERT_PATH/$DOMAIN"
# Sync Fullchain (Using -L to follow symlinks created by Certbot)
rsync -avzL -e "ssh $SSH_OPTS" --chmod=F644 "$FULLCHAIN" "$NGINX_USER@$NGINX_HOST:$NGINX_CERT_PATH/$DOMAIN/"
# Sync Private Key
rsync -avzL -e "ssh $SSH_OPTS" --chmod=F600 "$PRIVKEY" "$NGINX_USER@$NGINX_HOST:$NGINX_CERT_PATH/$DOMAIN/"
# 5. Remote Reload
echo "--- RELOADING REMOTE NGINX ---"
ssh $SSH_OPTS "$NGINX_USER@$NGINX_HOST" "sudo systemctl reload nginx" || echo "Warning: Could not reload Nginx. Manual reload may be needed."
echo "--- ALL DONE: $DOMAIN ---"
```
### `certbot-server/docker-compose.yml`
```yaml
services:
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./certbot/www:/var/www/certbot:ro
- ./certbot/conf:/etc/letsencrypt
restart: always
certbot:
image: certbot/certbot
volumes:
- ./certbot/www:/var/www/certbot
- ./certbot/conf:/etc/letsencrypt
```
---
## 4. Operational In-Depth Flow Diagram
This diagram visualizes exactly how data, dependencies, and state move across your network topology during the ISO deployment lifecycle.
=== "Diagram"
```mermaid
sequenceDiagram
autonumber
participant Host as Local Operator Machine (192.168.60.221)
participant ESXi as ESXi Hypervisor (192.168.60.179)
participant VM as Ephemeral VM (192.168.60.164)
participant LE as Let's Encrypt CA Engine
participant Prod as Production Nginx VM (192.168.2.13)
Host->>Host: Run run-certbot.sh test <domain> iso
Host->>Host: Spin up background HTTP Sidecar server
Host->>ESXi: Instruct to create 'ephemeral-cert-build' & mount Ubuntu ISO
ESXi->>VM: Power on VM and simulate Boot Command keystrokes
VM->>Host: Read AutoInstall config from HTTP Sidecar
VM->>VM: Partition disk, assign MACs, write networking configuration, reboot
VM->>Host: Raise SSH availability indicator
Host->>VM: Establishes SSH connection (192.168.60.164)
Host->>VM: Shell Provisioner: Install docker, docker-compose, rsync
Host->>VM: File Provisioner: Push certbot-server/ and deployment key
Host->>VM: Execute: ./create-cert.sh <domain> staging
VM->>VM: Docker-compose up -d nginx (Port 80 active)
VM->>LE: Certbot container initializes ACME Webroot challenge request
LE->>VM: Validates domain challenge token back through HAProxy/pfSense
LE->>VM: Approves transaction & writes .pem cert blocks to /archive/
VM->>VM: Execute chown/chmod fixing root ownership to packer user
VM->>Prod: SSH Target Initialization: sudo mkdir -p /etc/nginx/certs-test/
VM->>Prod: Rsync payloads (Fullchain: 644, Privkey: 600) following Symlinks
VM->>Prod: SSH Command Execution: sudo systemctl reload nginx
Host->>VM: File Provisioner (Download): Backup cert copies locally to Host
Host->>ESXi: Build Complete -> destroy=true API request issued
ESXi->>ESXi: Hard Power-off & completely unregister/purge VM files from Datastore
```
=== "Raw"
```text
sequenceDiagram
autonumber
participant Host as Local Operator Machine (192.168.60.221)
participant ESXi as ESXi Hypervisor (192.168.60.179)
participant VM as Ephemeral VM (192.168.60.164)
participant LE as Let's Encrypt CA Engine
participant Prod as Production Nginx VM (192.168.2.13)
Host->>Host: Run run-certbot.sh test <domain> iso
Host->>Host: Spin up background HTTP Sidecar server
Host->>ESXi: Instruct to create 'ephemeral-cert-build' & mount Ubuntu ISO
ESXi->>VM: Power on VM and simulate Boot Command keystrokes
VM->>Host: Read AutoInstall config from HTTP Sidecar
VM->>VM: Partition disk, assign MACs, write networking configuration, reboot
VM->>Host: Raise SSH availability indicator
Host->>VM: Establishes SSH connection (192.168.60.164)
Host->>VM: Shell Provisioner: Install docker, docker-compose, rsync
Host->>VM: File Provisioner: Push certbot-server/ and deployment key
Host->>VM: Execute: ./create-cert.sh <domain> staging
VM->>VM: Docker-compose up -d nginx (Port 80 active)
VM->>LE: Certbot container initializes ACME Webroot challenge request
LE->>VM: Validates domain challenge token back through HAProxy/pfSense
LE->>VM: Approves transaction & writes .pem cert blocks to /archive/
VM->>VM: Execute chown/chmod fixing root ownership to packer user
VM->>Prod: SSH Target Initialization: sudo mkdir -p /etc/nginx/certs-test/
VM->>Prod: Rsync payloads (Fullchain: 644, Privkey: 600) following Symlinks
VM->>Prod: SSH Command Execution: sudo systemctl reload nginx
Host->>VM: File Provisioner (Download): Backup cert copies locally to Host
Host->>ESXi: Build Complete -> destroy=true API request issued
ESXi->>ESXi: Hard Power-off & completely unregister/purge VM files from Datastore
```
---
![iso based process](./img/iso-based-cert-flow.png)
---
## 5. Step-by-Step Implementation & Execution Guide
Follow these exact implementation instructions to configure and execute this solution in your environment.
### Step 1: Directory Layout & File Verification
Verify that your directory structure perfectly matches this layout before launching the process:
```text
packer-certbot-iso-esxi/
├── run-certbot.sh
├── certbot.pkr.hcl
├── bash_fn/
│ └── generate_cert_without_clone.sh
├── http/
│ └── user-data
├── keys/
│ └── certbot_master_key
└── certbot-server/
├── create-cert.sh
└── docker-compose.yml
```
### Step 2: Establish SSH Connection
1. Ensure your local operator system has SSH access to your ESXi root host. Test this connectivity by running:
```bash
ssh username@<esxi-ipaddress>
ssh root@192.168.60.179
```
2. Your private deployment master key file (`/keys/certbot_master_key`) **must** be pre-authorized inside your target production Nginx server. Verify this entry exists on `192.168.2.13` inside `/home/dev1/.ssh/authorized_keys`. That certbot_master_key must be added to the authorized keys of the nginxvm.
### Step 3: Network Strategy & Port Conversions
During the execution window, Let's Encrypt will knock on port `80` of your target public domain. Ensure your firewall (e.g., pfSense) handles traffic as follows:
* **Rule Entry:** Direct public inbound port 80 traffic for your domain to your load balancer or HAProxy server.
* **HAProxy Frontend Rule:** Match the ACME path rule (`/.well-known/acme-challenge/`) and route it directly to the ephemeral staging VM's assigned static IP: `192.168.2.9:80`.
### Step 4: Run the Process
#### Launching a Safe Staging Build (Dry-Run / Verification)
Execute the orchestration script with the parameters set to `test` using the `iso` method:
```bash
./run-certbot.sh test articles.clinilaunchresearch.in iso
```
* Monitor the terminal output. It will block gracefully while the system finishes loading the Ubuntu installer kernel, configuring storage, and configuring the runtime workspace.
* Once completed, check that your locally saved files exist at `./backup_certs/articles.clinilaunchresearch.in/`.
#### Launching a Production Build (Live Certificates Issued)
Once your staging verification completes without errors, switch to the production track:
```bash
./run-certbot.sh prod articles.clinilaunchresearch.in iso
```
* The script will pause and prompt you with a safety confirmation message.
* Press `y` to proceed. Certbot will bypass `--staging` flags, communicate with production Let's Encrypt directory servers, download valid production certificates, push them to your live server at `/etc/nginx/certs`, and automatically reload the web server daemon.

103
docs/logs.md Normal file
View File

@ -0,0 +1,103 @@
# Pipeline Logging & Observability
This section covers the diagnostic logs generated during execution, normal baseline behaviors, and troubleshooting patterns to isolate pipeline failures quickly.
---
## Healthy Pipeline Run Sample Logs
Depending on the deployment strategy executed by your automation platform, your standard output (stdout) logs will match one of the lifecycle trails detailed below.
=== "Clone-Based Execution Track"
### 1. Clone-Based Execution Track (`certbot-clone-esxi`)
When using the high-speed cloning track, the orchestration tool bypasses full system installation and outputs the following lifecycle sequence:
```text
$ ./benchmark_certgen.sh
--- STARTING BENCHMARK: CLONE VS ISO ---
Target: articles.clinilaunchresearch.in (staging)
----------------------------------------
Running Method: CLONE...
Step 1: Cleaning old runs...
Step 2: Cloning template...
Destination disk format: VMFS thin-provisioned
Cloning disk '/vmfs/volumes/app-platform/ubuntu-2404-base-template/ubuntu-2404-base-template.vmdk'...
Clone: 100% done.
Step 3: Hard-coding Static MACs and cleaning IDs...
Step 4: Starting VM...
Powering on VM:
Step 5: Waiting for Network (192.168.60.164)...
Step 6: Handing over to Packer (Mode: staging)...
==> null.certbot_vm: Using SSH communicator to connect: 192.168.60.164
==> null.certbot_vm: Waiting for SSH to become available...
==> null.certbot_vm: Connected to SSH!
==> null.certbot_vm: Uploading ./certbot-server => /home/packer/
==> null.certbot_vm: Uploading ./keys/certbot_master_key => /home/packer/.ssh/id_rsa
==> null.certbot_vm: Provisioning with shell script...
null.certbot_vm: === RUNNING CERTBOT AUTO ENGINES ===
null.certbot_vm: Target Domain: articles.clinilaunchresearch.in
null.certbot_vm: Operations Mode: staging
null.certbot_vm: Pulling/Starting Certbot container environment via Docker Compose...
null.certbot_vm: Container certbot-nginx-1 Creating
null.certbot_vm: Container certbot-nginx-1 Started
null.certbot_vm: Requesting verification tokens via ACME engine...
null.certbot_vm: Successfully received certificate.
null.certbot_vm: === SYNCING CERTIFICATES TO PRODUCTION PROXY ===
null.certbot_vm: sending incremental file list
null.certbot_vm: fullchain.pem
null.certbot_vm: privkey.pem
null.certbot_vm: === RELOADING REMOTE NGINX ---
null.certbot_vm: --- ALL DONE: articles.clinilaunchresearch.in ---
==> null.certbot_vm: Downloading /home/packer/certbot-server/certbot/conf/archive/ => ./backup_certs/
```
=== "ISO-Based Execution Track"
### 2. ISO-Based Execution Track (`certbot-iso-esxi`)
When executing a baseline OS construction build from raw installation media, the log maps out package dependency setups:
```text
==> vsphere-iso.certbot_vm: vSphere ISO image setup complete.
==> vsphere-iso.certbot_vm: Starting HTTP server on port 8017
==> vsphere-iso.certbot_vm: Powering on virtual machine...
==> vsphere-iso.certbot_vm: Waiting for SSH to become available...
==> vsphere-iso.certbot_vm: Connected to SSH!
==> vsphere-iso.certbot_vm: Provisioning with shell script...
vsphere-iso.certbot_vm: sudo apt-get update
vsphere-iso.certbot_vm: sudo apt-get install -y docker.io docker-compose rsync
vsphere-iso.certbot_vm: Fetching package archives (74.1 MB complete)...
==> vsphere-iso.certbot_vm: Uploading ./certbot-server => /home/packer/
==> vsphere-iso.certbot_vm: Provisioning with shell script...
vsphere-iso.certbot_vm: === INITIALIZING EPHEMERAL CERTBOT PIPELINE ===
vsphere-iso.certbot_vm: Saving debug log to /var/log/letsencrypt/letsencrypt.log
vsphere-iso.certbot_vm: Successfully received certificate.
vsphere-iso.certbot_vm: === SYNCING TO NGINX VM (192.168.2.13) ===
vsphere-iso.certbot_vm: privkey.pem
vsphere-iso.certbot_vm: fullchain.pem
vsphere-iso.certbot_vm: --- RELOADING REMOTE NGINX ---
vsphere-iso.certbot_vm: --- ALL DONE: articles.clinilaunchresearch.in ---
==> vsphere-iso.certbot_vm: Downloading /home/packer/certbot-server/certbot/conf/archive/articles.clinilaunchresearch.in/ => ./backup_certs/articles.clinilaunchresearch.in/
==> vsphere-iso.certbot_vm: Running shutdown command...
```
---
## Failure Mode Mitigation Matrix
If the pipeline experiences errors or stops early, check the table below to isolate the root trigger cause and identify the appropriate mitigation path:
| Observed Issue | Probable Root Trigger Cause | Mitigation Path Blueprint |
| --- | --- | --- |
| `Timeout waiting for SSH` | The OS failed to process automated autoinstall parameters accurately, or the R1 Router/MikroTik DHCP lease pool took too long to assign the target control address (`192.168.60.164`). | Open the vSphere/ESXi host client VNC console view for the worker VM to inspect for active kernel blocking warnings, installer prompts, or boot errors. Check your `http_bind_address` values. |
| `Connection timed out during ACME challenge` | The pfSense firewall or HAProxy routing rules did not forward inbound port 80 validation requests correctly to the ephemeral instance IP address setup (`192.168.2.9`). | Verify that the ephemeral worker VM's configured network interface MAC address matches the static DHCP reservation rule set on the pfSense gateway. Ensure HAProxy frontend rules map `acme_challenge_rule` over to `certbot_backend`. |
| `Permission denied (publickey)` | The target production Nginx proxy VM (`192.168.2.13`) rejected the SSH key pair (`certbot_master_key`) presented by the ephemeral automation worker. | Ensure that `certbot_master_key.pub` is pre-staged inside the target user's `~/.ssh/authorized_keys` file on the Nginx proxy, and that file permissions on the runner are explicitly restricted via `chmod 600`. |
---
## Log Management Best Practices
1. **Enable Packer Crash Dumping:** Run your builds with `PACKER_LOG=1` enabled in your orchestration environment variables if you need to trace raw API calls between Packer and your vSphere hypervisor endpoint (`192.168.60.179`).
2. **Audit Certbot Transmissions:** Let's Encrypt renewal logs are retained locally inside the ephemeral instance at `/var/log/letsencrypt/letsencrypt.log` before destruction. If an ACME error occurs, modify your script to cat this file out to stdout before the machine tears down.

View File

@ -0,0 +1,15 @@
.youtube {
color: #EE0F0F;
}
@keyframes heart {
0%, 40%, 80%, 100% {
transform: scale(1);
}
20%, 60% {
transform: scale(1.15);
}
}
.heart {
animation: heart 1000ms infinite;
}

330
docs/verification.md Normal file
View File

@ -0,0 +1,330 @@
# Architecture Verification Guide
Ensuring your pipeline runs within validated operational thresholds requires verifying infrastructure dependencies before execution begins. This guide covers:
* Pre-flight infrastructure validation
* Network and routing verification
* DNS resolution checks
* ACME challenge path testing
* Post-deployment certificate validation
---
## Pre-Flight Infrastructure Sanity Checks
Before executing production pipeline targets, validate your virtualization layer, networking stack, and routing infrastructure to guarantee stable execution flows.
---
## 1. Verify ESXi Datastore & ISO Target Paths
Access your VMware ESXi/vSphere host through SSH and confirm:
* VMFS datastores are mounted
* storage capacity is healthy
* Ubuntu installation ISOs exist
* clone template assets are accessible
!!! Danger "Infrastructure Dependency Validation"
- Missing ISOs, inaccessible templates, or datastore failures will immediately terminate Packer build execution.
### Validate Mounted Datastores
```bash
# Execute structural filesystem storage availability checks
df -h | grep -E "vmfs|vfat"
```
Expected example output:
```text
VMFS-6 110.2G 38.0G 72.2G 35% /vmfs/volumes/datastore1
VMFS-6 953.8G 371.4G 582.3G 39% /vmfs/volumes/app-platform
VMFSOS 119.8G 5.0G 114.8G 4% /vmfs/volumes/OSDATA-660af3aa-6045bb75-f1e8-a0369f2f203c
vfat 4.0G 258.9M 3.7G 6% /vmfs/volumes/BOOTBANK1
vfat 4.0G 64.0K 4.0G 0% /vmfs/volumes/BOOTBANK2
```
---
### Verify Ubuntu Installer ISO Presence
```bash
# Confirm the target Ubuntu 24.04 installer ISO exists
ls -la /vmfs/volumes/datastore1/ISOs/ubuntu-24.04.4-live-server-amd64.iso
```
---
### Verify Golden Clone Template Availability
```bash
# Confirm the golden image exists in the datastore
ls -la /vmfs/volumes/app-platform/ubuntu-2404-base-template/
```
Example output:
```text
total 5149256
drwxr-xr-x 1 root root 77824 Jun 11 21:02 .
drwxr-xr-t 1 root root 77824 Jun 13 15:29 ..
-rw------- 1 root root 21474836480 Jun 11 21:02 ubuntu-2404-base-template-flat.vmdk
-rwxr-xr-x 1 root root 3520 Jun 11 21:02 ubuntu-2404-base-template.vmx
-rw-r--r-- 1 root root 130875 Jun 11 21:02 vmware.log
```
!!! tip "Recommended Infrastructure Layout"
Maintain separate datastores for:
- installation ISOs
- golden templates
- ephemeral worker VMs
- production application workloads
This minimizes storage contention during automation execution.
---
## 2. Verify Core Network & IP Reservation Pools
Because the pipeline relies on deterministic MAC address bindings, ensure the worker IP (`192.168.60.164`) is available and not claimed by another host.
---
### Validate Target Worker IP Reachability
```bash
# Ensure the management target IP is not trapped or bound by an orphaned lease
ping -c 3 192.168.60.164
```
---
### Validate MAC Address Ownership
```bash
# Verify no conflicting host claims the worker MAC addresses
arp -a | grep -E "00:0c:29:9c:31:db|00:0c:29:a9:8c:05"
```
??? warning "Static DHCP Lease Planning Requirement"
Ensure all statically assigned worker IP addresses exist outside the active DHCP dynamic allocation pool range.
Failure to isolate these addresses may result in:
- IP collisions
- SSH handshake failures
- unstable routing behavior
- ACME challenge interruptions
- intermittent HAProxy backend failures
Example:
```text
DHCP Pool Range: 192.168.60.100 - 192.168.60.200
Static Lease Target: 192.168.60.164 ❌ CONFLICT RISK
DHCP Pool Range: 192.168.60.10 - 192.168.60.99
Static Lease Target: 192.168.60.164 âś… SAFE
```
---
## 3. Validate Production Name Resolution Paths
Ensure both internal and public DNS systems correctly resolve your application domains back toward the public ingress proxy.
### Validate Public DNS Resolution
```bash
# Verify target application domain authority mappings resolve accurately
dig +short articles.clinilaunchresearch.in
```
---
### Validate Internal Resolver Accuracy
```bash
# Verify documentation portal host resolution
nslookup articles.clinilaunchresearch.in
```
Expected result:
```text
Name: articles.clinilaunchresearch.in
Address: <public-static-ip>
```
??? Danger "DNS Resolution Requirement"
- Let's Encrypt validation depends entirely on publicly reachable DNS authority mappings.
- Incorrect DNS resolution paths will prevent HTTP-01 challenge validation from succeeding.
---
# In-Flight Live Routing Verification
To ensure pfSense and HAProxy correctly intercept ACME challenge requests and forward them toward the ephemeral worker backend, perform a live routing test.
---
## Simulating an ACME Challenge Handshake
Execute a manual request against the standard Let's Encrypt validation path.
```bash
curl -Iv http://articles.clinilaunchresearch.in/.well-known/acme-challenge/test-token
```
---
## ACME Routing Flow
```text
[Public Web Client / Let's Encrypt Engine]
│
â–Ľ
[pfSense Firewall Gateway]
│
â–Ľ
[HAProxy SSL/HTTP Routing Layer]
│
├── Match ACL:
│ /.well-known/acme-challenge/*
│
â–Ľ
[Ephemeral Worker VM Backend]
192.168.2.9:80
```
---
## Deciphering Validation Responses
### Expected Healthy Result
```text
HTTP/1.1 503 Service Unavailable
```
or
```text
HTTP/1.1 502 Bad Gateway
```
This confirms:
* HAProxy successfully intercepted the ACME path
* ACL matching rules are functioning correctly
* traffic attempted backend forwarding
* the ephemeral worker VM is currently offline
This is considered healthy behavior when the worker node is not active.
---
### Incorrect Routing Result
```text
HTTP/1.1 301 Moved Permanently
```
If the request redirects immediately to HTTPS:
* the `not_acme` redirect rule executed first
* ACME ACL matching failed
* challenge traffic bypassed the backend routing logic
??? Danger "Routing Control Logic Execution Profile"
- ACME challenge traffic must always bypass HTTPS redirect enforcement.
- If challenge requests are redirected into HTTPS chains, Let's Encrypt validation will fail.
---
# Post-Deployment Delivery Validation
After the Packer workflow finishes successfully, verify that the generated certificates:
* downloaded locally
* synchronized remotely
* loaded correctly by Nginx
---
## 1. Check Local Windows Backup Cache
Confirm that Packer successfully downloaded certificate artifacts onto the execution machine.
```cmd
:: Run on your local Windows shell
dir .\\backup_certs\\articles.clinilaunchresearch.in\\
```
Expected artifacts:
```text
fullchain.pem
privkey.pem
chain.pem
cert.pem
```
---
## 2. Verify Target Nginx Proxy Storage
Log into the production Nginx reverse proxy and verify certificate deployment.
```bash
# Verify the presence of synced SSL certificates
ls -la /etc/nginx/certs/articles.clinilaunchresearch.in/
```
---
## 3. Validate Certificate Expiration Dates
```bash
openssl x509 \
-in /etc/nginx/certs/articles.clinilaunchresearch.in/fullchain.pem \
-text -noout | grep -A 2 "Validity"
```
Expected output:
```text
Validity
Not Before: Apr 27 06:10:10 2026 GMT
Not After : Jul 26 06:10:09 2026 GMT
```
---
!!! success "Pipeline Operational Threshold"
A healthy execution cycle will contain explicit confirmations for:
- `Successfully received certificate`
- `SYNCING TO NGINX VM`
Successful completion confirms:
- ACME routing logic executed correctly
- certificate issuance succeeded
- synchronization completed successfully
- deployment targets accepted the updated certificate chain

View File

@ -0,0 +1,2 @@
*[HTML]: Hyper Text Markup Language
*[W3C]: World Wide Web Consortium

Some files were not shown because too many files have changed in this diff Show More