Compare commits
No commits in common. "test-docs" and "main" have entirely different histories.
@ -1,3 +0,0 @@
|
|||||||
hi
|
|
||||||
bye
|
|
||||||
I am browser
|
|
||||||
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 23 KiB |
@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"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
@ -1 +0,0 @@
|
|||||||
site/
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
Before Width: | Height: | Size: 202 KiB |
|
Before Width: | Height: | Size: 638 KiB |
@ -1,324 +0,0 @@
|
|||||||
```
|
|
||||||
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
|
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
```
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
## 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**.
|
|
||||||
@ -1,516 +0,0 @@
|
|||||||
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
|
|
||||||
```
|
|
||||||
---
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 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.
|
|
||||||
@ -1,418 +0,0 @@
|
|||||||
# 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) |
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 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 |
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
*(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:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
#### 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`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 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:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
##### 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` |
|
|
||||||
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
!!! 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
|
|
||||||
```
|
|
||||||
|
Before Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 327 KiB |
|
Before Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 25 KiB |
415
docs/index.md
@ -1,415 +0,0 @@
|
|||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
@ -1,617 +0,0 @@
|
|||||||
# 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
|
|
||||||
```
|
|
||||||
---
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 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
@ -1,103 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
.youtube {
|
|
||||||
color: #EE0F0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes heart {
|
|
||||||
0%, 40%, 80%, 100% {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
20%, 60% {
|
|
||||||
transform: scale(1.15);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.heart {
|
|
||||||
animation: heart 1000ms infinite;
|
|
||||||
}
|
|
||||||
@ -1,330 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
*[HTML]: Hyper Text Markup Language
|
|
||||||
*[W3C]: World Wide Web Consortium
|
|
||||||