Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions images/ansible/ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[defaults]
roles_path = roles
8 changes: 8 additions & 0 deletions images/ansible/playbooks/barebones.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
- name: AX Barebones Image
hosts: all
become: yes
vars_files:
- ../vars/barebones.yml
roles:
- common
5 changes: 5 additions & 0 deletions images/ansible/roles/common/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
200 changes: 200 additions & 0 deletions images/ansible/roles/common/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
---
- name: Wait for cloud-init
command: /usr/bin/cloud-init status --wait
changed_when: false

- name: Create swap
include_tasks: swap.yml
when: ansible_swaptotal_mb == 0

- name: Update & upgrade
apt:
update_cache: yes
upgrade: dist
environment:
DEBIAN_FRONTEND: noninteractive

- name: Install required packages
apt:
name:
- fail2ban
- ufw
- net-tools
- zsh
- zsh-syntax-highlighting
- zsh-autosuggestions
- jq
- build-essential
- python3-pip
- unzip
- git
- p7zip
- libpcap-dev
- rubygems
- ruby-dev
- grc
- nmap
state: present
install_recommends: no

- name: Allow SSH and custom port in UFW
ufw:
rule: allow
port: "{{ item }}"
loop:
- '22'
- '2266'

- name: Enable UFW
ufw:
state: enabled
policy: deny

- name: Create op user
user:
name: op
groups: sudo
shell: /usr/bin/zsh
create_home: yes
append: yes

- name: Create op directories
file:
path: "/home/op/{{ item }}"
state: directory
owner: op
group: users
mode: '0755'
loop:
- .ssh
- c2
- recon
- lists
- go
- bin
- .config
- .cache
- work
- .config/amass

- name: Remove default MOTD files
file:
path: "{{ item }}"
state: absent
loop: "{{ q('fileglob', '/etc/update-motd.d/*') }}"

- name: Install Oh My Zsh (non-interactively)
shell: >
sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" --unattended
become: yes
become_user: op
args:
creates: /home/op/.oh-my-zsh

- name: Create sudo_as_admin_successful
file:
path: /home/op/.sudo_as_admin_successful
state: touch
owner: op
group: users

- name: Create legal MOTD cache
file:
path: /home/op/.cache/motd.legal-displayed
state: touch
owner: op
group: users

- name: Set passwords
user:
name: "{{ item.name }}"
password: "{{ op_random_password | password_hash('sha512') }}"
loop:
- { name: 'op' }
- { name: 'ubuntu' }
- { name: 'root' }

- name: Copy config files from tmp (matching original Packer)
copy:
src: "/tmp/configs/{{ item.src }}"
dest: "{{ item.dest }}"
owner: "{{ item.owner | default('root') }}"
group: "{{ item.group | default('root') }}"
mode: "{{ item.mode | default('0644') }}"
backup: yes
remote_src: true
loop:
- { src: 'sudoers', dest: '/etc/sudoers', owner: 'root', group: 'root', mode: '0440' }
- { src: 'bashrc', dest: '/home/op/.bashrc', owner: 'op', group: 'users', mode: '0644' }
- { src: 'zshrc', dest: '/home/op/.zshrc', owner: 'op', group: 'users', mode: '0644' }
- { src: 'sshd_config', dest: '/etc/ssh/sshd_config', owner: 'root', group: 'root', mode: '0600' }
- { src: '00-header', dest: '/etc/update-motd.d/00-header', owner: 'root', group: 'root', mode: '0755' }
- { src: 'authorized_keys', dest: '/home/op/.ssh/authorized_keys', owner: 'op', group: 'users', mode: '0600' }
- { src: 'tmux-splash.sh', dest: '/home/op/bin/tmux-splash.sh', owner: 'op', group: 'users', mode: '0755' }

- name: Set op user file ownership
file:
path: /home/op
owner: op
group: users
recurse: yes

- name: Install Golang
unarchive:
src: "https://golang.org/dl/go{{ golang_version }}.linux-amd64.tar.gz"
dest: /usr/local
remote_src: yes
creates: /usr/local/go
mode: '0755'

- name: Install Docker
shell: curl -fsSL https://get.docker.com | sh
args:
creates: /usr/bin/docker

- name: Add op user to docker group
user:
name: op
groups: docker
append: yes

- name: Install uv system-wide using installer script
shell: |
curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR="/usr/local/bin" sh
args:
creates: "/usr/local/bin/uv"

- name: Install Interlace using uv tool for user op
become_user: op
shell: uv tool install git+https://github.com/codingo/Interlace.git
register: uv_install_result
changed_when: "'already installed' not in uv_install_result.stderr"
failed_when: uv_install_result.rc != 0 and 'already installed' not in uv_install_result.stderr

- name: Optimize SSH config
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^{{ item.key }} "
line: "{{ item.key }} {{ item.value }}"
validate: /usr/sbin/sshd -t -f %s
loop:
- { key: 'ClientAliveInterval', value: '60' }
- { key: 'ClientAliveCountMax', value: '60' }
- { key: 'MaxSessions', value: '100' }
notify: restart ssh

- name: Tune sysctl for high concurrency
sysctl:
name: "{{ item.name }}"
value: "{{ item.value }}"
state: present
reload: no
loop:
- { name: 'net.nf_conntrack_max', value: '1048576' }
- { name: 'net.core.somaxconn', value: '1048576' }
- { name: 'net.ipv4.ip_local_port_range', value: '1024 65535' }

- name: Clean apt
apt:
autoclean: yes
autoremove: yes
15 changes: 15 additions & 0 deletions images/ansible/roles/common/tasks/swap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
- command: fallocate -l 2G /swap
args:
creates: /swap

- file:
path: /swap
mode: '0600'

- command: mkswap /swap

- command: swapon /swap

- lineinfile:
path: /etc/fstab
line: '/swap none swap sw 0 0'
3 changes: 3 additions & 0 deletions images/ansible/vars/barebones.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
op_random_password: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}"
golang_version: "1.22.5" # Override via Packer var
20 changes: 19 additions & 1 deletion images/pkr.hcl/builders/do.pkr.hcl
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
packer {
required_plugins {
ansible = {
version = ">= 1.1.4"
source = "github.com/hashicorp/ansible"
}
}
}

variable "golang_version" {
type = string
}
Expand All @@ -18,11 +27,20 @@ source "digitalocean" "packer" {
ssh_username = "root"
snapshot_name = var.snapshot_name
api_token = var.do_key
image = "ubuntu-22-04-x64"
image = "ubuntu-24-04-x64"
region = var.region
size = var.default_size
}

variable "AXIOM_ROOT" {
type = string
default = "/root/.axiom"
}

locals {
axiom_root = var.AXIOM_ROOT
}

build {
sources = [
"source.digitalocean.packer"
Expand Down
20 changes: 20 additions & 0 deletions images/pkr.hcl/provisioners/ansible-barebones.pkr.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
provisioner "file" {
source = "./configs"
destination = "/tmp/configs"
}

provisioner "ansible" {
playbook_file = "${var.AXIOM_ROOT}/images/ansible/playbooks/barebones.yml"

ansible_env_vars = [
"ANSIBLE_CONFIG=${var.AXIOM_ROOT}/images/ansible/ansible.cfg"
]
}

provisioner "shell" {
inline = [
"echo CkNvbmdyYXR1bGF0aW9ucywgeW91ciBidWlsZCBpcyBhbG1vc3QgZG9uZSEKCiDilojilojilojilojilojilZcg4paI4paI4pWXICDilojilojilZcgICAg4paI4paI4paI4paI4paI4paI4pWXIOKWiOKWiOKVlyAgIOKWiOKWiOKVl+KWiOKWiOKVl+KWiOKWiOKVlyAgICAg4paI4paI4paI4paI4paI4paI4pWXCuKWiOKWiOKVlOKVkOKVkOKWiOKWiOKVl+KVmuKWiOKWiOKVl+KWiOKWiOKVlOKVnSAgICDilojilojilZTilZDilZDilojilojilZfilojilojilZEgICDilojilojilZHilojilojilZHilojilojilZEgICAgIOKWiOKWiOKVlOKVkOKVkOKWiOKWiOKVlwrilojilojilojilojilojilojilojilZEg4pWa4paI4paI4paI4pWU4pWdICAgICDilojilojilojilojilojilojilZTilZ3ilojilojilZEgICDilojilojilZHilojilojilZHilojilojilZEgICAgIOKWiOKWiOKVkSAg4paI4paI4pWRCuKWiOKWiOKVlOKVkOKVkOKWiOKWiOKVkSDilojilojilZTilojilojilZcgICAgIOKWiOKWiOKVlOKVkOKVkOKWiOKWiOKVl+KWiOKWiOKVkSAgIOKWiOKWiOKVkeKWiOKWiOKVkeKWiOKWiOKVkSAgICAg4paI4paI4pWRICDilojilojilZEK4paI4paI4pWRICDilojilojilZHilojilojilZTilZ0g4paI4paI4pWXICAgIOKWiOKWiOKWiOKWiOKWiOKWiOKVlOKVneKVmuKWiOKWiOKWiOKWiOKWiOKWiOKVlOKVneKWiOKWiOKVkeKWiOKWiOKWiOKWiOKWiOKWiOKVl+KWiOKWiOKWiOKWiOKWiOKWiOKVlOKVnQrilZrilZDilZ0gIOKVmuKVkOKVneKVmuKVkOKVnSAg4pWa4pWQ4pWdICAgIOKVmuKVkOKVkOKVkOKVkOKVkOKVnSAg4pWa4pWQ4pWQ4pWQ4pWQ4pWQ4pWdIOKVmuKVkOKVneKVmuKVkOKVkOKVkOKVkOKVkOKVneKVmuKVkOKVkOKVkOKVkOKVkOKVnQoKTWFpbnRhaW5lcjogMHh0YXZpYW4KCvCdk7LwnZO38J2TvPCdk7nwnZOy8J2Tu/Cdk67wnZOtIPCdk6vwnZSCIPCdk6rwnZSB8J2TsvCdk7jwnZO2OiDwnZO98J2TsfCdk64g8J2TrfCdlILwnZO38J2TqvCdk7bwnZOy8J2TrCDwnZOy8J2Tt/Cdk6/wnZO78J2TqvCdk7zwnZO98J2Tu/Cdk77wnZOs8J2TvfCdk77wnZO78J2TriDwnZOv8J2Tu/Cdk6rwnZO28J2TrvCdlIDwnZO48J2Tu/Cdk7Qg8J2Tr/Cdk7jwnZO7IPCdk67wnZO/8J2TrvCdk7vwnZSC8J2Tq/Cdk7jwnZOt8J2UgiEgLSBA8J2TufCdk7vwnZSCMPCdk6zwnZOsIEAw8J2UgfCdk73wnZOq8J2Tv/Cdk7LwnZOq8J2TtwoKUmVhZCB0aGVzZSB3aGlsZSB5b3UncmUgd2FpdGluZyB0byBnZXQgc3RhcnRlZCA6KQoKICAgIC0gTmV3IFdpa2k6IGh0dHBzOi8vYXgtZnJhbWV3b3JrLmdpdGJvb2suaW8vd2lraS8KICAgIC0gRXhpc3RpbmcgVXNlcnM6IGh0dHBzOi8vYXgtZnJhbWV3b3JrLmdpdGJvb2suaW8vd2lraS9vdmVydmlldy9leGlzdGluZy11c2VycwogICAgLSBCcmluZyBZb3VyIE93biBQcm92aXNpb25lcjogaHR0cHM6Ly9heC1mcmFtZXdvcmsuZ2l0Ym9vay5pby93aWtpL2Z1bmRhbWVudGFscy9icmluZy15b3VyLW93bi1wcm92aXNpb25lciAKICAgIC0gRmlsZXN5c3RlbSBVdGlsaXRpZXM6IGh0dHBzOi8vYXgtZnJhbWV3b3JrLmdpdGJvb2suaW8vd2lraS9mdW5kYW1lbnRhbHMvZmlsZXN5c3RlbS11dGlsaXRpZXMKICAgIC0gRmxlZXRzOiBodHRwczovL2F4LWZyYW1ld29yay5naXRib29rLmlvL3dpa2kvZnVuZGFtZW50YWxzL2ZsZWV0cwogICAgLSBTY2FuczogaHR0cHM6Ly9heC1mcmFtZXdvcmsuZ2l0Ym9vay5pby93aWtpL2Z1bmRhbWVudGFscy9zY2FuCg== | base64 -d"
]
}

}