Automatic Golden Image Generation using CI/CD
This article gives a detailed walk through on how to set up CI/CD pipeline to create golden image monthly
- GitLab
- Terraform
- Ansible(optional)
- AWS Cloud Platform
- Build AWS EC2 instance using Terraform.
- Provision EC2 instance using Ansible.
- Created CICD pipeline to build sequence of activities.
- Once entire provisioning is completed, then take an AMI of that instance.
- Lastly, terminate the instance.
1
2
3
4
5
variable "instance_type" {
description = "ec2 instance type"
type = string
default = "t2.micro"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
## fetch AMI ID ##
data "aws_ami" "ami_id" {
most_recent = true
filter {
name = "tag:Name"
values = ["Golden-Image_2024-06-13"]
}
}
## Fetch SG and Keypair ##
data "aws_key_pair" "keypair" {
key_name = "keypair3705"
include_public_key = true
}
data "aws_security_group" "sg" {
filter {
name = "tag:Name"
values = ["management-sg"]
}
}
## Fetch IAM role ##
data "aws_iam_role" "instance_role" {
name = "CustomEC2AdminAccess"
}
## Fetch networking details ##
data "aws_vpc" "vpc" {
filter {
name = "tag:Name"
values = ["custom-vpc"]
}
}
data "aws_subnet" "subnet" {
filter {
name = "tag:Name"
values = ["management-subnet"]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
resource "aws_iam_instance_profile" "test_profile" {
name = "InstanceProfile"
role = data.aws_iam_role.instance_role.name
}
resource "aws_instance" "ec2" {
ami = data.aws_ami.ami_id.id
instance_type = var.instance_type
associate_public_ip_address = true
availability_zone = "us-east-1a"
key_name = data.aws_key_pair.keypair.key_name
security_groups = [data.aws_security_group.sg.id, ]
iam_instance_profile = aws_iam_instance_profile.test_profile.name
subnet_id = data.aws_subnet.subnet.id
user_data = file("userdata.sh")
root_block_device {
volume_size = 15
volume_type = "gp2"
}
tags = {
"Name" = "GoldenImageVM"
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
output "ami_id" {
value = {
id = data.aws_ami.ami_id.image_id
arn = data.aws_ami.ami_id.arn
image_loc = data.aws_ami.ami_id.image_location
state = data.aws_ami.ami_id.state
creation_date = data.aws_ami.ami_id.creation_date
image_type = data.aws_ami.ami_id.image_type
platform = data.aws_ami.ami_id.platform
owner = data.aws_ami.ami_id.owner_id
root_device_name = data.aws_ami.ami_id.root_device_name
root_device_type = data.aws_ami.ami_id.root_device_type
}
}
output "ec2_details" {
value = {
arn = aws_instance.ec2.arn
id = aws_instance.ec2.id
private_dns = aws_instance.ec2.private_dns
private_ip = aws_instance.ec2.private_ip
public_dns = aws_instance.ec2.public_dns
public_ip = aws_instance.ec2.public_ip
}
}
output "key_id" {
value = {
id = data.aws_key_pair.keypair.id
fingerprint = data.aws_key_pair.keypair.fingerprint
}
}
output "sg_id" {
value = data.aws_security_group.sg.id
}
output "role_arn" {
value = {
arn = data.aws_iam_role.instance_role.arn
id = data.aws_iam_role.instance_role.id
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
!/bin/bash
sudo yum install jq -y
#Fetching gitlab password from parameter store
GITLAB_PWD=`aws ssm get-parameter --name "gitlab-runner_password" --region 'us-east-1' | jq .Parameter.Value | xargs`
#Set the password for ec2-user
PASSWORD_HASH=$(openssl passwd -1 $GITLAB_PWD)
sudo usermod --password "$PASSWORD_HASH" ec2-user
# Create gitlab-runner user and set password
USER='gitlab-runner'
sudo useradd -m -u 1001 -p $(openssl passwd -1 $GITLAB_PWD) $USER
#Copy the Gitlab SSH Key to gitlab-runner server
sudo mkdir /home/$USER/.ssh
sudo chmod 700 /home/$USER/.ssh
Ansible_SSH_Key=`aws ssm get-parameter --name "Ansible-SSH-Key" --region 'us-east-1' | jq .Parameter.Value | xargs`
sudo echo $Ansible_SSH_Key > /home/$USER/.ssh/authorized_keys
sudo chown -R $USER:$USER /home/$USER/.ssh/
sudo chmod 600 /home/$USER/.ssh/authorized_keys
sudo echo "StrictHostKeyChecking no" >> /home/$USER/.ssh/config
sudo echo "$USER ALL=(ALL) NOPASSWD : ALL" > /etc/sudoers.d/00-$USER
sudo sed -i 's/^#PermitRootLogin.*/PermitRootLogin yes/; s/^PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
sudo systemctl restart sshd
sleep 40
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
- name: Set hostname
hosts: server
become: true
gather_facts: false
vars_files:
- ../vars/variable.yml
roles:
- ../roles/hostnamectl
- name: Configure other services
hosts: server
become: true
roles:
- ../roles/ssh
- ../roles/login_banner
- ../roles/services
- ../roles/timezone
- ../roles/fs_integrity
- ../roles/firewalld
- ../roles/log_management
- ../roles/rsyslog
- ../roles/cron
- ../roles/journald
- name: Start Prepatch
hosts: server
become: true
roles:
- ../roles/prepatch
- name: Start Patching
hosts: server
become: true
roles:
- ../roles/patch
- name: Start Postpatch
hosts: server
become: true
roles:
- ../roles/postpatch
- name: Reboot the server
hosts: server
become: true
tasks:
- reboot:
msg: "Rebooting machine in 5 seconds"
- Validation
- InstanceBuild
- InstancePatching
- TakeAMI
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
default:
tags:
- anirban
stages:
- Validation
- InstanceBuild
- InstancePatching
- TakeAMI
job1:
stage: Validation
script:
- sudo chmod +x check_version.sh
- source check_version.sh
except:
changes:
- README.md
artifacts:
when: on_success
paths:
- Validation_artifacts
job2:
stage: InstanceBuild
script:
- sudo chmod +x BuildScript/1_Env.sh
- source BuildScript/1_Env.sh
- python3 BuildScript/2_CreateTFCWorkspace.py -vvv
except:
changes:
- README.md
artifacts:
paths:
- Validation_artifacts
- content.tar.gz
job3:
stage: InstancePatching
script:
- INSTANCE_PRIVATEIP=`aws ec2 describe-instances --filters "Name=tag:Name, Values=GoldenImageVM" --query Reservations[0].Instances[0].PrivateIpAddress | xargs`
- echo -e "[server]\n$INSTANCE_PRIVATEIP" > ./Ansible/inventory
- ansible-playbook ./Ansible/playbook/main.yml -i ./Ansible/inventory
- sudo chmod +x BuildScript/7_Cleanup.sh
when: manual
except:
changes:
- README.md
artifacts:
when: on_success
paths:
- Validation_artifacts
- ./Ansible/inventory
job4:
stage: TakeAMI
script:
- echo '------------Fetching Instance ID------------'
- INSTANCE_ID=`aws ec2 describe-instances --filters "Name=tag:Name, Values=GoldenImageVM" --query Reservations[0].Instances[0].InstanceId | xargs`
- echo '----------Taking an Image of Instance-----------'
- aws ec2 create-image --instance-id $INSTANCE_ID --name "GoldenImage" --description "Golden Image created on $(date -u +"%Y-%m-%dT%H:%M:%SZ")" --no-reboot --tag-specifications "ResourceType=image, Tags=[{Key=Name,Value=GoldenImage}]" "ResourceType=snapshot,Tags=[{Key=Name,Value=DiskSnaps}]"
when: manual
except:
changes:
- README.md