Creating Golden Images with Packer for Multi-Cloud Environments Using Ansible and GitHub Actions
In today’s multi-cloud environment, having consistent and reliable infrastructure is crucial for scalability, reliability, and security. Golden images play a vital role in achieving this by providing a standardized base configuration across different cloud providers. In this medium document, we’ll explore the concept of golden images and demonstrate how to create them using Packer, a versatile tool for automating the creation of machine images.
Introduction:
As organizations embrace multi-cloud strategies to leverage the strengths of various cloud providers, managing infrastructure efficiently becomes increasingly challenging. Golden images, also known as base images or machine images, serve as the foundation for creating virtual machines (VMs) or containers across different cloud platforms. These images contain pre-configured operating system settings, software packages, security configurations, and other customizations tailored to an organization’s requirements.
Creating and maintaining golden images manually can be time-consuming and error-prone. Packer simplifies this process by enabling automated image creation across multiple cloud platforms, ensuring consistency and reproducibility. Ansible complements Packer by automating configuration management tasks, such as software installation and system configuration, within the golden image.
Integrating Packer, Ansible, and GitHub Actions streamlines the workflow, enabling end-to-end automation from image creation to deployment. This approach enhances efficiency, reliability, and consistency in multi-cloud environments.
+---------------------+
| GitHub Repository |
+---------------------+
|
|
v
+---------------------+
| GitHub Actions CI/CD|
+---------------------+
| | |
v v v
+---------+ +---------+ +---------+
| Azure | | AWS | | GCP |
| Builder | | Builder | | Builder |
+---------+ +---------+ +---------+
| | |
v v v
+---------------------------------+
| Azure VM Image AWS AMI GCP Image |
| (VHD, etc.) (EC2 Image) (GCP Image) |
+---------------------------------+
Understanding Packer & Ansible:
Packer automates the creation of machine images for multiple platforms using a JSON or HCL template. The template specifies the base operating system, provisioners for installing software and configuring the system, and post-processors for optimizing and distributing the resulting image.
Ansible is a powerful configuration management tool that automates software provisioning, configuration, and application deployment. It uses YAML-based playbooks to define tasks and roles for managing system configuration, package installation, file management, and more.
By combining Packer and Ansible, you can leverage Packer’s image creation capabilities with Ansible’s configuration management capabilities to create fully customized golden images for multi-cloud environments.
Integrating Ansible with Packer:
To integrate Ansible with Packer for image configuration:
- Define Ansible Playbooks:
Create Ansible playbooks to define the desired configuration for the golden image. Specify tasks to install software packages, configure system settings, set up security policies, and perform other customization tasks. - Configure Packer Template:
Update the Packer template to include Ansible as a provisioner. Specify the path to the Ansible playbooks and any additional variables or parameters required for configuration. - Execute Ansible Provisioning:
During the Packer build process, Packer will execute the specified Ansible playbooks on the base image. Ansible will apply the defined configuration, ensuring the resulting image meets the desired state. - Validate Image Configuration:
After the Packer build completes, validate the resulting golden image to ensure that the Ansible provisioning was successful. Verify that the image configuration aligns with the requirements defined in the Ansible playbooks.
Integrating GitHub Actions:
GitHub Actions provides a powerful platform for automating software workflows directly within GitHub repositories. By leveraging GitHub Actions, you can seamlessly integrate Packer image creation into your CI/CD pipeline, enabling automatic builds triggered by events such as code commits or pull requests.
To integrate Packer with GitHub Actions:
- Define Workflow:
Create a.github/workflows
directory in your repository and add a YAML file (e.g.,packer-build.yaml
) to define your workflow. Specify the event triggers, such aspush
orpull_request
, and the steps to execute during the workflow. - Configure Packer Build:
Within the workflow file, add a step to execute the Packer build command (packer build
) with the path to your Packer template. You can pass variables or secrets as environment variables to customize the build process for different environments. - Trigger Events:
Configure the workflow to trigger on specific events, such as code commits to the main branch or pull requests. You can define filters to restrict workflow execution based on branch names, file paths, or other criteria. - Handle Outputs:
Optionally, capture the output artifacts generated by the Packer build process, such as the resulting image files or logs. You can upload these artifacts as workflow artifacts or publish them to external repositories for further use. - Review and Test:
Review the workflow configuration to ensure it meets your requirements and test it by triggering the defined events or workflows. Verify that the Packer builds execute successfully and produce the expected golden images.
Creating Golden Images with Packer:
To demonstrate the creation of golden images with Packer for multi-cloud environments, let’s walk through a basic example:
- Install Packer:
Begin by installing Packer on your local machine or build server. Packer provides binaries for various operating systems, or you can compile it from source [ But in this doscument we will use GitHub actions]. - Define Packer Template:
Create a Packer template in JSON or HCL format. This template defines the builders, provisioners, and post-processors needed to create the golden image. Specify the desired cloud platform(s) and configuration details such as instance type, disk size, and network settings. - Configure Builders:
Configure the builder section of the template to define the target cloud platform(s) and specific settings for each platform. For example, you may specify AWS EC2 for Amazon Web Services or Azure ARM for Microsoft Azure. - Add Provisioners:
Use provisioners to install and configure software on the base image. Packer supports various provisioners such as shell scripts, Ansible, Chef, and Puppet. Define the necessary steps to customize the image according to your requirements. - Include Post-Processors:
Optionally, include post-processors to perform tasks such as compressing the image, uploading it to a cloud storage bucket, or creating a VM snapshot. Post-processors enable you to automate additional actions after image creation. - Build the Image:
Once the template is configured, run thepacker build
command with the path to your template file. Packer will execute the defined steps to create the golden image for each specified cloud platform. - Validate and Test:
After the image creation process completes, validate the resulting images to ensure they meet your requirements. Test the images by launching VM instances or containers from them in your target cloud environment. - Update and Maintain: Regularly update and maintain your golden images to incorporate security patches, software updates, and configuration changes. Use version control systems to track changes to your Packer templates and collaborate with team members.
Workload Identity Federation:
We will use OIDC for AWS and GCP, Workload Identity Federation enhances security by providing seamless authentication and access control across cloud environments. This is secured and secretless authentication :)
Below is the code for Golden Image pipeline:build.pkr.hcl
################## AZURE #####################
variable "client_id" {
type = string
default = "your_default_client_id"
}
variable "client_secret" {
type = string
default = "your_default_client_secret"
}
variable "subscription_id" {
type = string
default = "your_default_subscription_id"
}
variable "tenant_id" {
type = string
default = "your_default_tenant_id"
}
variable "image_sku_ubuntu" {
type = string
default = "22_04-lts"
}
variable "resource_group_name" {
type = string
default = "CICD"
}
variable "az_regions" {
type = list(string)
default = ["eastus"]
}
################## GCP #####################
variable "pkr_project_id" {
type = string
}
variable "pkr_source_image" {
type = string
}
variable "pkr_image_name" {
type = string
}
variable "pkr_image_family" {
type = string
}
variable "pkr_instance_zone" {
type = string
}
variable "pkr_image_storage_locations" {
type = string
}
variable "pkr_instance_name" {
type = string
}
variable "pkr_network" {
type = string
}
variable "pkr_subnetwork" {
type = string
}
variable "pkr_network_project_id" {
type = string
}
variable "pkr_use_internal_ip" {
type = bool
default = true
}
variable "pkr_omit_external_ip" {
type = bool
default = true
}
variable "pkr_use_iap" {
type = bool
default = true
}
variable "pkr_use_os_login" {
type = bool
default = true
}
variable "pkr_enable_secure_boot" {
type = bool
default = true
}
variable "pkr_instance_tags" {
type = string
}
variable "pkr_instance_type" {
type = string
default = "n1-standard-1"
}
variable "pkr_image_description" {
type = string
default = "Ubuntu2204 with Apache and Java Hardening."
}
variable "pkr_disk_size" {
type = number
default = 20
}
variable "pkr_skip_create_image" {
type = bool
default = false
}
############# Builder ###############
# Azure Builder
source "azure-arm" "ubuntu22" {
image_offer = "0001-com-ubuntu-server-jammy"
image_publisher = "canonical"
image_sku = var.image_sku_ubuntu
location = var.az_regions[0]
managed_image_name = "myPackerImage"
managed_image_resource_group_name = var.resource_group_name
os_type = "Linux"
vm_size = "Standard_DS2_v2"
client_id = var.client_id
client_secret = var.client_secret
subscription_id = var.subscription_id
tenant_id = var.tenant_id
}
# GCP Builder
source "googlecompute" "ubuntu2204-goldenimage" {
project_id = var.pkr_project_id
source_image = var.pkr_source_image
image_name = format("%s-{{timestamp}}",var.pkr_image_name)
image_family = var.pkr_image_family
image_storage_locations = split(",",var.pkr_image_storage_locations)
image_description = var.pkr_image_description
image_labels = {
"os" : "ubuntu"
"version" : "2204"
}
ssh_username = "packer-sa"
instance_name = format("%s-{{timestamp}}",var.pkr_instance_name)
machine_type = var.pkr_instance_type
zone = var.pkr_instance_zone
network = var.pkr_network
subnetwork = var.pkr_subnetwork
network_project_id = var.pkr_network_project_id
use_internal_ip = var.pkr_use_internal_ip
omit_external_ip = var.pkr_omit_external_ip
use_iap = var.pkr_use_iap
use_os_login = var.pkr_use_os_login
enable_secure_boot = var.pkr_enable_secure_boot
disk_size = var.pkr_disk_size
skip_create_image = var.pkr_skip_create_image
metadata = {
block-project-ssh-keys = "true"
}
tags = split(",",var.pkr_instance_tags)
}
# AWS Builder
source "amazon-ebs" "aws" {
ami_name = "Goldenami-v1"
instance_type = "t2.micro"
region = "us-east-1"
run_tags = {
Name = "Goldenami-v1"
}
source_ami = "ami-0aa7d40eeae50c9a9"
ssh_username = "ec2-user"
subnet_id = "subnet-0b8f9a7b97fd1edf0"
iam_instance_profile = "ssm"
ssh_interface = "session_manager"
communicator = "ssh"
tags = {
Base_AMI_Name = "Goldenami-v1"
}
}
build {
sources = [ "source.amazon-ebs.aws_builder", "source.azure-arm.ubuntu22", "source.googlecompute.ubuntu2204-goldenimage"]
provisioner "file" {
source = "./azure/ubuntu-2004-scripts/"
destination = "/tmp/"
}
provisioner "shell" {
inline = [
"sudo apt update -y && sudo apt upgrade -y",
"sudo apt install ansible -y",
"sudo ansible --version"
]
}
provisioner "shell" {
scripts = [
"./azure/ubuntu-2004-scripts/img-lin-ubuntu-2004-package-installation-script.sh",
"./azure/ubuntu-2004-scripts/img-lin-ubuntu-2004-os-hardening-script.sh",
"./azure/ubuntu-2004-scripts/img-lin-ubuntu-2004-package-removal-script.sh"
]
}
provisioner "shell" {
inline = [
"sudo apt remove ansible -y",
"sudo apt autoremove -y",
"sudo apt clean -y"
]
}
}
plugins.pkr.hcl
packer {
required_plugins {
amazon = {
source = "github.com/hashicorp/amazon"
version = ">= 3.0.0"
}
google = {
source = "github.com/hashicorp/google"
version = ">= 3.0.0"
}
azure = {
source = "github.com/hashicorp/azure"
version = ">= 2.0.0"
}
}
}
variables.pkr.hcl
############### GCP ###################
pkr_project_id = "<your project ID>"
pkr_source_image = "ubuntu-pro-2204-jammy-v20230921"
pkr_image_name = "ubuntu2204-apachejava-hardened"
pkr_image_family = "ubuntu-pro-2204-lts"
pkr_image_storage_locations = "asia-south1"
pkr_instance_zone = "asia-south1-a"
pkr_instance_name = "ubuntu-2204-build"
pkr_network = "projects/<your project ID>/global/networks/vpc-img-hardening"
pkr_subnetwork = "projects/<your project ID>/regions/asia-south1/subnetworks/sub-shrd--img-hardening"
pkr_network_project_id = "<your project ID>"
pkr_use_internal_ip = true
pkr_omit_external_ip = true
pkr_use_iap = true
pkr_use_os_login = true
pkr_enable_secure_boot = true
pkr_skip_create_image = false
pkr_instance_tags = "packer,ubuntu2204,iap-ssh"
############### AZURE ###################
variable "az_region_uswest" {
type = string
default = "West US 2"
}
variable "az_region_parent_img" {
type = string
default = "eastus"
}
variable "az_region_useast" {
type = string
default = "East US"
}
variable "pkr_bucket_name" {
type = string
default = "ubuntu22-nginx"
}
# Ubuntu
variable "image_version" {
type = string
default = "v02"
}
variable "storage_account" {
type = string
default = "e2esapackerimages"
}
variable "az_image_gallery" {
type = string
default = "packer"
}
variable "az_gallery_img_def_name" {
type = string
default = "ubuntu22"
}
############### AWS ###################
variable "instance_type" {
type = string
default = "t2.micro"
}
variable "region" {
type = string
default = "us-east-1"
}
variable "source_ami" {
type = string
default = "ami-0aa7d40XXXXXXXXX9"
}
variable "subnet_id" {
type = string
default = "subnet-0b8XXXXXXXedf0"
}
variable "ssh_interface" {
type = string
default = "session_manager"
}
Create a folder for ansible playbook as “ubuntu-2004-ansible”
ubuntu-2004-ansible-playbook.yml
- hosts: localhost
collections:
- devsec.hardening
roles:
- devsec.hardening.os_hardening
- devsec.hardening.ssh_hardening
ubuntu-2004-ansible-requirements.yaml
collections:
- name: devsec.hardening
version: ">=9.0.0"
Create a folder for scripts “ubuntu-2004-scripts”
ubuntu-2004-os-hardening-script.sh
#!/bin/bash
auditctl_function()
{
sudo echo "-D" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-b 8192" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-f 1" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/selinux/ -p wa -k MAC-policy" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a exit,always -F arch=b64 -S execve" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a exit,always -F arch=b32 -S execve" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b32 -S mount -F auid>=1000 -F auid!=unset -F key=perm_mod" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b64 -S mount -F auid>=1000 -F auid!=unset -F key=perm_mod" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b32 -S sethostname,setdomainname -F key=audit_rules_networkconfig_modification" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b64 -S sethostname,setdomainname -F key=audit_rules_networkconfig_modification" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/issue -p wa -k audit_rules_networkconfig_modification" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/issue.net -p wa -k audit_rules_networkconfig_modification" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/hosts -p wa -k audit_rules_networkconfig_modification" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /var/run/utmp -p wa -k session" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /var/log/btmp -p wa -k session" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /var/log/wtmp -p wa -k session" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/sudoers -p wa -k actions" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/sudoers.d/ -p wa -k actions" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/group -p wa -k audit_rules_usergroup_modification" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/gshadow -p wa -k audit_rules_usergroup_modification" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/shadow -p wa -k audit_rules_usergroup_modification" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b32 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b32 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b64 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b32 -S fremovexattr -S fsetxattr -S lremovexattr -S lsetxattr -S removexattr -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b64 -S fremovexattr -S fsetxattr -S lremovexattr -S lsetxattr -S removexattr -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b32 -S rename -S renameat -S unlink -S unlinkat -F auid>=1000 -F auid!=unset -F key=delete" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b64 -S rename -S renameat -S unlink -S unlinkat -F auid>=1000 -F auid!=unset -F key=delete" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b32 -S creat -S ftruncate -S open -S openat -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b64 -S creat -S ftruncate -S open -S openat -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b32 -S creat -S ftruncate -S open -S openat -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b64 -S creat -S ftruncate -S open -S openat -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b32 -S delete_module -F auid>=1000 -F auid!=unset -F key=module-change" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b64 -S delete_module -F auid>=1000 -F auid!=unset -F key=module-change" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b32 -S init_module -F auid>=1000 -F auid!=unset -F key=module-change" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b64 -S init_module -F auid>=1000 -F auid!=unset -F key=module-change" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /var/run/faillock -p wa -k logins" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /var/log/lastlog -p wa -k logins" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /sbin/insmod -p x -k modules" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /sbin/modprobe -p x -k modules" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /sbin/rmmod -p x -k modules" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b32 -S adjtimex -S settimeofday -S stime -F key=audit_time_rules" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b64 -S adjtimex -S settimeofday -F key=audit_time_rules" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b32 -S clock_settime -F a0=0x0 -F key=time-change" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-a always,exit -F arch=b64 -S clock_settime -F a0=0x0 -F key=time-change" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/localtime -p wa -k audit_time_rules" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-e 2" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /opt/traps -p wa -k cortex-files-watcher" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /etc/panw -p wa -k cortex-files-watcher" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo echo "-w /opt/rapid7 -p wa -k rapid7-files-watcher" | sudo tee -a /etc/audit/rules.d/auditctl.rules;
sudo chmod 640 /etc/audit/rules.d/auditctl.rules;
sudo augenrules --load;
sudo systemctl restart auditd.service;
sudo systemctl status auditd.service;
}
sudo timedatectl set-timezone Asia/Kolkata;
echo "export HISTTIMEFORMAT=\"[%c] [\`whoami\`] \"" | sudo tee -a /etc/bash.bashrc;
wget -q https://github.com/ComplianceAsCode/content/releases/download/v0.1.71/scap-security-guide-0.1.71.zip;
unzip -q scap-security-guide-0.1.71.zip;
sudo oscap xccdf eval --remediate --profile xccdf_org.ssgproject.content_profile_cis_level2_server --fetch-remote-resources --results ~/Ubuntu2004-CIS-L2-Before-Hardening-No-ARF-Result.xml --report ~/Ubuntu2204-CIS-L2-Before-Hardening-Report-`date +%d%m%Y`.html ~/scap-security-guide-0.1.71/ssg-ubuntu2004-ds.xml;
sudo oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_cis_level2_server --fetch-remote-resources --results ~/Ubuntu2004-CIS-L2-After-Hardening-No-ARF-Result.xml --report ~/Ubuntu2004-CIS-L2-After-Hardening-Report-`date +%d%m%Y`.html ~/scap-security-guide-0.1.71/ssg-ubuntu2004-ds.xml;
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db;
sudo echo "5 8 * * 0 /usr/bin/aide --check --config /etc/aide/aide.conf" | sudo crontab -;
auditctl_function;
sudo rm -rf ~/*.html ~/*.xml ~/*.yml;
sudo rm -rf ~/scap-security-guide-0.1.71*;
ubuntu-2004-package-installation-script.sh
#!/bin/bash
sudo apt install unzip libopenscap8 auditd -y;
ubuntu-2004-ilt20-package-removal-script.sh
#!/bin/bash
sudo apt remove unzip libopenscap8 -y;
sudo apt purge unzip libopenscap8 -y;
GitHub workflow file with actions and workload identity for both AWS and GCP , I tried to get it implement federated creds for azure but packer is not supporting for the same so I am using client secret :(
build.yml
---
name: Build Golden Image with Packer
on:
push:
branches:
- main
permissions:
contents: read
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup Packer
uses: hashicorp/setup-packer@main
id: setup
- name: Azure CLI login
uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Debug Secrets
run: |
echo "Azure Client ID: ${{ secrets.AZURE_CLIENT_ID }}"
echo "Azure Client Secret: ${{ secrets.AZURE_CLIENT_SECRET }}"
echo "Azure Subscription ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}"
echo "Azure Tenant ID: ${{ secrets.AZURE_TENANT_ID }}"
- name: Connecting GitHub Actions To AWS Using OIDC - Roles
uses: aws-actions/configure-aws-credentials@master
with:
role-to-assume: arn:aws:iam::<your account ID>:role/GIT_PIPELINE_ROLE
role-session-name: github-actions-session
aws-region: ap-south-1
- run: aws sts get-caller-identity
- id: auth
uses: google-github-actions/auth@v1
with:
workload_identity_provider: ${{env.WORKLOAD_IDENTITY_PROVIDER}}
service_account: ${{env.SERVICE_ACCOUNT}}
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v1
with:
version: ${{env.GCLOUD_VERSION}}
- name: Use gcloud CLI
run: gcloud info
- name: Run packer init
id: init
run: |
pwd
ls -l ./builder/
packer init ./builder/
- name: Run packer validate
run: packer validate ./builder/.
- name: Run Packer Build
run: |
packer build \
-var "client_id=${{ secrets.AZURE_CLIENT_ID }}" \
-var "client_secret=${{ secrets.AZURE_CLIENT_SECRET }}" \
-var "subscription_id=${{ secrets.AZURE_SUBSCRIPTION_ID }}" \
-var "tenant_id=${{ secrets.AZURE_TENANT_ID }}" \
./builder/build.pkr.hcl
Do some troubleshooting in your workflow file if any errors encountered ;)
Conclusion:
By integrating Packer, Ansible, and GitHub Actions, organizations can automate the creation and configuration of golden images for multi-cloud environments. This approach streamlines infrastructure management, enhances consistency and reliability, and accelerates deployment workflows. By following best practices and leveraging automation tools, organizations can optimize their operations and adapt to the dynamic requirements of multi-cloud environments effectively.
In this medium document, we’ve introduced the concept of golden images and demonstrated how to create them using Packer and Ansible, integrated with GitHub Actions for automation. By combining these technologies, organizations can achieve seamless image creation, configuration, and deployment across multiple cloud platforms, ensuring a standardized foundation for their applications in today’s complex IT landscape.
References:
- Packer Documentation
- Ansible Documentation
- GitHub Actions Documentation
- HashiCorp Configuration Language (HCL)
- Multi-Cloud Strategies: Best Practices and Considerations
- Authenticate GITHUB actions to AWS using Identity Providers
- Authenticate GITHUB actions to GCP using Workload Identity Federation
That’s It folks!! Please provide your feedback in comments and if this article is helpful give a like (clap) :)