Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e0a16aa
initial commit
prafullb3 Jan 7, 2026
ec33110
Added ansible role and packaer configuration
prafullb3 Jan 7, 2026
e51f12c
Added all the configuration
prafullb3 Jan 7, 2026
7220180
Added all the configuration
prafullb3 Jan 7, 2026
0488bab
fixed pipeline
prafullb3 Jan 7, 2026
2da0904
fixed pipeline
prafullb3 Jan 7, 2026
50348d0
fixed pipeline
prafullb3 Jan 7, 2026
77c3bb7
fixed ansible provisioner path
prafullb3 Jan 7, 2026
88b3f41
fixed ansible provisioner path
prafullb3 Jan 7, 2026
cd47e79
updated source block
prafullb3 Jan 7, 2026
7abb17e
corrected image sku
prafullb3 Jan 8, 2026
0f3adfd
corrected image sku
prafullb3 Jan 8, 2026
aa5803f
Added Roles path
prafullb3 Jan 8, 2026
681ab5c
Added Roles path
prafullb3 Jan 8, 2026
aac31ef
added configure.yml and roles in a folder
prafullb3 Jan 8, 2026
56219c3
modified hardening ansible role
prafullb3 Jan 8, 2026
2068950
fixed azure Monitoring agent config
prafullb3 Jan 8, 2026
153ceab
removed monitoring ansible role
prafullb3 Jan 8, 2026
1700a6d
updated ansible role hardening\tasks\main.yml
prafullb3 Jan 8, 2026
0cb5859
modified build_image.yml
prafullb3 Jan 8, 2026
ba5eede
Merge pull request #1 from prafullb3/feature1
prafullb3 Jan 8, 2026
4613e74
validate.yml
prafullb3 Jan 8, 2026
5598cf8
Merge pull request #2 from prafullb3/feature1
prafullb3 Jan 8, 2026
fa9162e
validate.yml
prafullb3 Jan 8, 2026
47bad07
validate.yml
prafullb3 Jan 8, 2026
70a93b7
Merge pull request #3 from prafullb3/feature1
prafullb3 Jan 8, 2026
c919603
added Readme File
prafullb3 Jan 17, 2026
faf3597
added Readme File
prafullb3 Jan 17, 2026
4d5e0a5
Merge pull request #4 from prafullb3/readmefix
prafullb3 Jan 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/build-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
on:
push:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Azure Login
uses: azure/login@v2
with :
creds: ${{ secrets.AZURE_CREDENTIALS }}

- name: Verify Azure Login
run: az account show

- name: Set up Packer
uses: hashicorp/setup-packer@v3

- name: Packer Initialize
run: packer init packer/ubuntu


- name: Packer Build
run: packer build -var-file=packer/ubuntu/values.pkrvars.hcl packer/ubuntu
11 changes: 11 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
on: [pull_request]

jobs:
validate:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-packer@v3
- run: packer init packer/ubuntu
- run: packer validate packer/ubuntu
129 changes: 128 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,128 @@
# Golden_OS_Images
# Golden OS Images

A project for building and managing golden (pre-configured) operating system images using Packer and Ansible, with automated deployment to Azure.

## Overview

This project automates the creation of golden Ubuntu images with hardened security configurations and monitoring setup. The built images are stored as Azure Managed Images in your resource group.

## Project Structure

```
├── ansible/ # Ansible playbooks and roles for image provisioning
│ ├── playbooks/ # Main playbooks
│ │ └── configure.yml # Image configuration playbook
│ └── roles/ # Reusable Ansible roles
│ ├── base/ # Base OS configuration
│ ├── hardening/ # Security hardening
│ └── monitoring/ # Monitoring setup
├── packer/ # Packer configurations
│ └── ubuntu/ # Ubuntu image builder
│ ├── ubuntu.pkr.hcl # Main Packer configuration
│ ├── variables.pkr.hcl # Packer variables
│ └── version.json # Version information
├── scripts/ # Utility scripts
│ ├── generate-metadata.sh # Generate image metadata
│ └── validate.sh # Validation scripts
└── .github/workflows/ # CI/CD pipelines
└── build-image.yml # Automated build workflow
```

## Prerequisites

- **Packer** >= 1.8.0
- **Ansible** >= 2.9
- **Azure CLI** for authentication and image management
- **Azure Subscription** with appropriate permissions
- **GitHub Secrets** configured (see Configuration section)

## Getting Started

### 1. Configure Azure Credentials

Set the following secret in your GitHub repository:
- `AZURE_CREDENTIALS` - Azure service principal credentials (JSON format)

### 2. Local Testing

To build the image locally:

```bash
cd packer/ubuntu
packer build -var-file="variables.pkr.hcl" ubuntu.pkr.hcl
```

### 3. Automated Build via GitHub Actions

Push to the `main` branch to trigger the automated build workflow:

```bash
git push origin main
```

The workflow will:
1. Check out the code
2. Authenticate with Azure
3. Build the golden image with Packer
4. Run Ansible provisioning (base, hardening, monitoring)
5. Upload the image to Azure Storage (if configured)


### Roles

- **base**: Installs and configures base OS components
- **hardening**: Applies security hardening policies (SSH configuration, firewall, etc.)
- **monitoring**: Sets up monitoring agents and logging

Customize these roles by editing the corresponding `tasks/main.yml` and `defaults/main.yml` files.

### Variables

Edit `packer/ubuntu/variables.pkr.hcl` to customize:
- `image_name` - Base image name
- `location` - Azure region
- `resource_group` - Target resource group
- `image_sku` - Ubuntu version

## Usage

### Building a Golden Image

```bash
packer build packer/ubuntu
```

### Validating Configuration

```bash
bash scripts/validate.sh
```

### Generating Metadata

```bash
bash scripts/generate-metadata.sh
```

## Output

- **Azure Managed Image**: Stored in the specified resource group, named with format: `{image_name}-golden-{date}`
- **Azure Storage (optional)**: VHD file uploaded with timestamp for archival and sharing

## CI/CD Pipeline
The GitHub Actions workflow automates the entire process:
- Triggers on push to `main` branch
- Builds image with Packer
- Provisions with Ansible
- Uploads to storage (optional)


- **Packer Build Fails**: Check Azure credentials and ensure the service principal has necessary permissions
- **Ansible Provisioning Fails**: Verify Ansible syntax with `ansible-playbook --syntax-check`
- **Upload Fails**: Ensure storage account name and container name are correctly set in GitHub secrets

## Contribution
1. Create a feature branch: `git checkout -b feature/your-feature`
2. Make changes and test locally
3. Push and create a pull request
4. Merge to `main` to trigger the build pipeline
9 changes: 9 additions & 0 deletions ansible/playbooks/configure.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
- name: Configure Azure Golden Image
hosts: all
become: yes
vars:
ansible_python_interpreter: /usr/bin/python3
roles:
- base
- hardening
12 changes: 12 additions & 0 deletions ansible/playbooks/roles/base/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
timezone: UTC

base_packages:
- git
- curl
- wget
- apt-transport-https
- unzip
- net-tools
- ca-certificates
- gnupg
- software-properties-common
Empty file.
32 changes: 32 additions & 0 deletions ansible/playbooks/roles/base/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---

- name: Set Timezone to UTC
command: timedatectl set-timezone {{ timezone | default('UTC') }}
args:
creates: "/etc/timezone"

- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600

- name: Upgrade all packages
apt:
upgrade: dist

- name: Install base packages
apt:
name: "{{ base_packages }}"
state: present

- name: Enable automatice security updates
apt:
name: unattended-upgrades
state: present

- name: Configure unattended-upgrades
copy:
dest: /etc/apt/apt.conf.d/20auto-upgrades
content: |
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
7 changes: 7 additions & 0 deletions ansible/playbooks/roles/hardening/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
ufw_enabled: true
ufw_allow_ssh: true
ufw_ssh_port: 22
ufw_default_incoming: deny
ufw_default_outgoing: allow
ufw_allowed_ports: []
5 changes: 5 additions & 0 deletions ansible/playbooks/roles/hardening/handlers/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
- name: Restart SSH
service:
name: ssh
state: restarted
6 changes: 6 additions & 0 deletions ansible/playbooks/roles/hardening/tasks/enable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
- name: Enable UFW safely
command: ufw --force enable
async: 30
poll: 0
when: ufw_enabled | default(true)
6 changes: 6 additions & 0 deletions ansible/playbooks/roles/hardening/tasks/install.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
- name: Install UFW
apt:
name: ufw
state: present
update_cache: yes
4 changes: 4 additions & 0 deletions ansible/playbooks/roles/hardening/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
- import_tasks: install.yml
- import_tasks: rules.yml
- import_tasks: enable.yml
27 changes: 27 additions & 0 deletions ansible/playbooks/roles/hardening/tasks/rules.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
# Allow SSH first to prevent lockout
- name: Allow SSH
ufw:
rule: allow
port: "{{ ssh_port | default(22) }}"
proto: tcp

# Optional extra ports (if defined in defaults/main.yml)
- name: Allow additional ports
ufw:
rule: allow
port: "{{ item.port }}"
proto: "{{ item.proto | default('tcp') }}"
loop: "{{ ufw_allowed_ports | default([]) }}"
when: ufw_allowed_ports | length > 0

# Set default incoming and outgoing policies
- name: Set default incoming policy
ufw:
direction: incoming
policy: "{{ ufw_default_incoming | default('deny') }}"

- name: Set default outgoing policy
ufw:
direction: outgoing
policy: "{{ ufw_default_outgoing | default('allow') }}"
39 changes: 39 additions & 0 deletions packer/ubuntu/ubuntu.pkr.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
packer {
required_plugins {
azure = {
source = "github.com/hashicorp/azure"
version = "~> 2.0"
}
}

required_plugins {
ansible = {
source = "github.com/hashicorp/ansible"
version = "~> 1.0"
}
}
}

source "azure-arm" "ubuntu" {
use_azure_cli_auth = true

managed_image_resource_group_name = var.resource_group
managed_image_name = "${var.image_name}-golden-${formatdate("DDMMMYY", timestamp())}"

os_type = var.os_type
image_publisher = "Canonical"
image_offer = "0001-com-ubuntu-server-jammy"
image_sku = var.image_sku

location = var.location
vm_size = "Standard_B1s"
}

build {
sources = ["sources.azure-arm.ubuntu"]

provisioner "ansible" {
playbook_file = "ansible/playbooks/configure.yml"
roles_path= "ansible/roles"
}
}
5 changes: 5 additions & 0 deletions packer/ubuntu/values.pkrvars.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
resource_group = "TResourceGroup"
location= "West Europe"
image_name="ubuntu-22_04-lts"
os_type="Linux"
image_sku="22_04-lts-gen2"
19 changes: 19 additions & 0 deletions packer/ubuntu/variables.pkr.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
variable "image_name" {
default = "ubuntu-22_04-lts"
}

variable "location" {
default = "West Europe"
}

variable "resource_group" {
default = "TResourceGroup"
}

variable "os_type" {
default = "Linux"
}

variable "image_sku" {
default = "22.04-lts"
}
6 changes: 6 additions & 0 deletions packer/ubuntu/version.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"os": "ubuntu-22.04",
"version": "1.0.0",
"build_date": "" ,
"git_commit": ""
}
3 changes: 3 additions & 0 deletions scripts/generate-metadata.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export VERSION=$(jq -r '.version' ../packer/ubuntu/version.json)
export BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
export GIT_COMMIT=$(git rev-parse --short HEAD)