— devops, tech, cloudops — 4 min read
You can hear it by many names: jump box/jump server/bastion. I will use jump box or jumpbox from now on.
No, not this box, engineer is not physically healthy enough to jump this box
Imagine that you are a ultra rich man, who have no trust on the goverment and banking institutions, so you want your assets & property within your sight and your security team. You live in a large mansion which have fences all around the premises. The only way in and out is via the main gate where security guards always check for anyone's identity card, only authorized people allow to get inside the premises and granted with a special access card. From that, they can only access to rooms that match their access card.
The main gate/jumpbox is where your first state your identity before entering the premises/infrastructure, only authorized people/privileged account allowed to access the rooms/resources inside. For every group of people/account, there is a card/rule to define what they can do and where they can go.
In short:
A jump server is a server that is used to access other servers. It is also known as a bastion host. It is a server that is accessible from the internet and is used to access other servers that are not accessible from the internet.
Like the way you want to protect your mansion from outsider, noone should freely take a look and make changes to your precious cloud infrastructure. A jumpbox acts as an intermediate gate between the private network and the internet. Only an authorized engineer/administrator is allowed to access to jumpbox and further access to private resources via private network. This help to add a barrier to prevent unauthorized accesses. Moreover, from a jumpbox, we can supervise any access by implementing monitoring and logging on a central channel. And even auditing after incident/breach in worst case scenarios.
If you have already read Part 1 , you may already know that I use devbox for every project I have worked on. A devbox is not any different than a jumpbox, but it is equiped with development tools that provide a remote workspace so that I can work from any laptop that can connect to my devbox via SSH from trusted network. Which make jumpbox/devbox an essential setup step for CloudOps.
Now you know what a jumpbox is, it is time to make one. This is a great starting point to practice what we learnt on the last post
Manual way is the trusted way, every ec2 launch requires a specific set of requirements:
IaC speaking, you can refer to the example at https://github.com/tienvu461/CloudOps-with-a-touch-of-automation/tree/main/01-jump-your-first-box/terraform/my-ground-breaking-application
1data "cloudinit_config" "jumpbox_cloudinit" {2 gzip = true3 base64_encode = true4 part {5 content_type = "text/cloud-config"6 content = file("path/to/scripts/jumpbox_cloudinit.yaml")7 }8}9
10resource "aws_instance" "jumpbox" {11 ami = "ami-abcd1234"12 availability_zone = "ap-southeast-1a"13 ebs_optimized = false14 instance_type = "t3a.micro"15 monitoring = false16 key_name = "jumpbox"17 subnet_id = "subnet-abcd1234"18 vpc_security_group_ids = [sg-abcd1234]19 associate_public_ip_address = true20 source_dest_check = true21 iam_instance_profile = "your_instance_profile_name"22
23 root_block_device {24 volume_type = "gp3"25 volume_size = 3026 delete_on_termination = true27 }28
29 user_data = data.cloudinit_config.jumpbox_cloudinit.rendered30 tags = {31 "Name" = "your-jumpbox"32 "AUTO_DNS_ZONE" = "YOURZONEID"33 "AUTO_DNS_NAME" = "jumpbox.example.com"34 }35}
You might have been noticing the weird tag keys AUTO_DNS_NAME, AUTO_DNS_ZONE above. At the time I was working the content of this blogpost, I read the news of AWS will begin to charge on public IPv4 with a rate of $0.005/hr from Feb, 2024 :evil: and with the initial of cost saving in mind, I decided to pump this tutorial one level higher.
This is the plan:
1#!/bin/bash2# Extract information about the Instance3echo "Updating jumpbox record"4status_code=$(curl -s -o /dev/null -w "%{http_code}" http://169.254.169.254/latest/meta-data/)5if [[ "$status_code" -eq 200 ]]6then7 INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id/)8 AZ=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone/)9 MY_IP=$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4/)10else11 TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`12 INSTANCE_ID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id/)13 AZ=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/availability-zone/)14 MY_IP=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-ipv4/)15fi16# Extract tags associated with instance17ZONE_TAG=$(aws ec2 describe-tags --region ${AZ::-1} --filters "Name=resource-id,Values=${INSTANCE_ID}" --query 'Tags[?Key==`AUTO_DNS_ZONE`].Value' --output text)18NAME_TAG=$(aws ec2 describe-tags --region ${AZ::-1} --filters "Name=resource-id,Values=${INSTANCE_ID}" --query 'Tags[?Key==`AUTO_DNS_NAME`].Value' --output text)19
20# Update Route 53 Record Set based on the Name tag to the current Public IP address of the Instance21aws route53 change-resource-record-sets --hosted-zone-id $ZONE_TAG --change-batch '{"Changes":[{"Action":"UPSERT","ResourceRecordSet":{"Name":"'$NAME_TAG'","Type":"A","TTL":300,"ResourceRecords":[{"Value":"'$MY_IP'"}]}}]}'
All of the mentioned settings are implemented into the example terraform code with a small modification to make sure it run per-boot, because dynamic public IPv4 is re-assigned everytime the machine start. Although this is a very good solution, but it poses some security risks with assigned iam role, there are rooms for optimisation.
Now simply click "Launch" if you are using AWS console, or run 'terraform apply' if your setup is terraform. Bada bing, bada boom, your devbox is now in the room.
In the next article, I will write some python code to handle events from sources (EventBridge, Cloudwatch, ...) and using lambda, I can forward those notification to webhook (Slack, Discord, MS Teams), api, ... And I call it SNS Integration Forwarder Function - SNIFF
Title | URL |
---|---|
Part 1: CloudOps with a touch of Automation | Here |
Part 2: Jump Your First Box | Here |
Part 3: SNS Integration Forwarder Function - SNIFF | Here |
Part 4: Automation Start Stop Enhanced System - ASSES | Here |