234 lines
9.0 KiB
Docker
234 lines
9.0 KiB
Docker
# ───────────────────────────────────────────────────────────
|
|
# Ansible Control Node — Alpine-based, QEMU-bootable
|
|
#
|
|
# Dual-purpose image:
|
|
# 1. Run directly: docker run --rm -it ansible-node ansible-playbook ...
|
|
# 2. Convert to QEMU disk: scripts/build-qemu.sh extracts this rootfs
|
|
# into a bootable qcow2 for pc-q35-10.0
|
|
#
|
|
# Integrations:
|
|
# • Windows — pywinrm + kerberos → WinRM
|
|
# • Cisco ASA — cisco.asa + paramiko → SSH/CLI
|
|
# • Cisco Catalyst— cisco.ios + paramiko → SSH/CLI
|
|
# • Cisco NX-OS — cisco.nxos + paramiko → SSH/NX-API
|
|
# • Linux — native SSH (built-in ansible)
|
|
# • VMware — pyvmomi → vCenter/ESXi SOAP API
|
|
# • MSSQL — pymssql → SQL Server TDS
|
|
# ───────────────────────────────────────────────────────────
|
|
|
|
FROM alpine:3.20
|
|
|
|
# ── System labels ──────────────────────────────────────────
|
|
LABEL org.opencontainers.image.title="Ansible Control Node"
|
|
LABEL org.opencontainers.image.description="Minimal Ansible control node for Windows, Cisco, VMware, MSSQL, and Linux targets. QEMU-bootable via build-qemu.sh."
|
|
LABEL org.opencontainers.image.authors="ansible_testing"
|
|
|
|
# ── Kernel + base system ──────────────────────────────
|
|
# alpine-base = openrc + busybox + mdev + init scripts (no systemd)
|
|
# linux-virt = kernel optimized for VMs (virtio, no firmware)
|
|
# docker = container runtime for nested workloads
|
|
RUN apk add --no-cache \
|
|
alpine-base \
|
|
linux-virt \
|
|
e2fsprogs \
|
|
docker \
|
|
docker-openrc \
|
|
# ── Networking ────────────────────────────────────────
|
|
dhcpcd \
|
|
openssh-client \
|
|
openssh-server \
|
|
curl \
|
|
wget \
|
|
ca-certificates \
|
|
bind-tools \
|
|
# ── Kerberos (WinRM Kerberos auth to Windows) ────────
|
|
krb5 \
|
|
krb5-server \
|
|
# ── FreeTDS (pymssql → MSSQL TDS protocol) ───────────
|
|
freetds \
|
|
freetds-dev \
|
|
# ── Ansible + Python + SSH pw provider ───────────────
|
|
ansible \
|
|
sshpass \
|
|
py3-pip \
|
|
python3 \
|
|
python3-dev \
|
|
# ── Build deps for pip packages (purged after) ───────
|
|
gcc \
|
|
musl-dev \
|
|
openssl-dev \
|
|
krb5-dev \
|
|
libffi-dev \
|
|
# ── Quality-of-life ──────────────────────────────────
|
|
bash \
|
|
bash-completion \
|
|
vim \
|
|
tmux \
|
|
git \
|
|
jq \
|
|
less \
|
|
sudo
|
|
|
|
# ── Python packages for target integrations ──────────────
|
|
RUN pip3 install --no-cache-dir --break-system-packages \
|
|
# Windows: WinRM + Kerberos
|
|
'pywinrm[kerberos]>=0.4' \
|
|
requests-kerberos \
|
|
requests-ntlm \
|
|
# Cisco: SSH/NETCONF/RESTCONF
|
|
paramiko>=2.7 \
|
|
ncclient>=0.6 \
|
|
netmiko>=4.0 \
|
|
scp \
|
|
# VMware: vCenter/ESXi SOAP API
|
|
pyvmomi>=8.0 \
|
|
requests \
|
|
# MSSQL: TDS protocol
|
|
pymssql>=2.2 \
|
|
# General utilities (required by many Ansible modules)
|
|
jmespath>=1.0 \
|
|
xmltodict>=0.13 \
|
|
pyyaml>=6.0 \
|
|
cryptography>=41.0 \
|
|
packaging
|
|
|
|
# ── Ansible collections for all target types ──────────────
|
|
RUN ansible-galaxy collection install \
|
|
# Windows management
|
|
ansible.windows \
|
|
# Network common (required by Cisco collections)
|
|
ansible.netcommon \
|
|
ansible.utils \
|
|
# Cisco ASA firewalls
|
|
cisco.asa \
|
|
# Cisco Catalyst / IOS / IOS-XE switches & routers
|
|
cisco.ios \
|
|
# Cisco Nexus / NX-OS data center switches
|
|
cisco.nxos \
|
|
# VMware vCenter / ESXi
|
|
community.vmware \
|
|
# MSSQL Server
|
|
community.general \
|
|
community.mysql \
|
|
microsoft.sql \
|
|
# Crypto/certificates (needed for various modules)
|
|
community.crypto \
|
|
# Generic collection with many useful modules
|
|
community.general
|
|
|
|
# ── OpenRC: enable boot services ──────────────────────────
|
|
# sysinit — devices, logging, hardware
|
|
RUN rc-update add devfs sysinit && \
|
|
rc-update add dmesg sysinit && \
|
|
rc-update add mdev sysinit && \
|
|
rc-update add hwdrivers sysinit
|
|
# boot — modules, networking, hostname (urandom handled by bootmisc)
|
|
RUN rc-update add modules boot && \
|
|
rc-update add sysctl boot && \
|
|
rc-update add bootmisc boot && \
|
|
rc-update add hostname boot && \
|
|
rc-update add networking boot
|
|
# default — SSH, DHCP, Docker daemon
|
|
RUN rc-update add sshd default && \
|
|
rc-update add dhcpcd default && \
|
|
rc-update add docker default
|
|
|
|
# ── Serial console (ttyS0) for QEMU -nographic ────────────
|
|
RUN echo 'ttyS0::respawn:/sbin/agetty -L 115200 ttyS0 xterm-256color' \
|
|
>> /etc/inittab
|
|
|
|
# ── Hostname (hosts managed by init/dhcpcd at boot) ────────
|
|
RUN echo 'ansible-node' > /etc/hostname
|
|
|
|
# ── SSH: allow root + ansible user ────────────────────────
|
|
RUN ssh-keygen -A && \
|
|
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' \
|
|
/etc/ssh/sshd_config && \
|
|
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' \
|
|
/etc/ssh/sshd_config && \
|
|
echo 'UseDNS no' >> /etc/ssh/sshd_config
|
|
|
|
# ── Users ─────────────────────────────────────────────────
|
|
# Root password (change on first boot!)
|
|
RUN echo 'root:ansible' | chpasswd
|
|
|
|
# Ansible service user
|
|
RUN adduser -D ansible && \
|
|
echo 'ansible:ansible' | chpasswd && \
|
|
addgroup ansible wheel && \
|
|
echo '%wheel ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
|
|
|
|
# ── Docker: enable ansible user to run docker ─────────────
|
|
RUN addgroup ansible docker
|
|
|
|
# ── Working directory ─────────────────────────────────────
|
|
RUN mkdir -p /ansible/playbooks /ansible/inventory && \
|
|
chown -R ansible:ansible /ansible
|
|
|
|
# ── Ansible config ────────────────────────────────────────
|
|
RUN mkdir -p /etc/ansible && \
|
|
printf '[defaults]\n\
|
|
host_key_checking = False\n\
|
|
stdout_callback = yaml\n\
|
|
callback_whitelist = profile_tasks\n\
|
|
retry_files_enabled = False\n\
|
|
\n\
|
|
[ssh_connection]\n\
|
|
pipelining = True\n\
|
|
control_path = /tmp/ansible-%%h-%%p-%%r' \
|
|
> /etc/ansible/ansible.cfg
|
|
|
|
# ── Default inventory (placeholder) ───────────────────────
|
|
RUN printf '[windows]\n\
|
|
# win-host.example.com\n\
|
|
\n\
|
|
[cisco_asa]\n\
|
|
# asa-firewall.example.com\n\
|
|
\n\
|
|
[cisco_ios]\n\
|
|
# catalyst-switch.example.com\n\
|
|
\n\
|
|
[cisco_nxos]\n\
|
|
# nexus-switch.example.com\n\
|
|
\n\
|
|
[vmware]\n\
|
|
# vcenter.example.com\n\
|
|
\n\
|
|
[mssql]\n\
|
|
# sql-server.example.com\n\
|
|
\n\
|
|
[linux]\n\
|
|
# debian-host.example.com\n\
|
|
\n\
|
|
[all:vars]\n\
|
|
ansible_user=ansible\n' \
|
|
> /etc/ansible/hosts
|
|
|
|
# ── MOTD (friendly boot message) ──────────────────────────
|
|
RUN printf '\n\
|
|
\e[1;32m╔════════════════════════════════════════════════╗\e[0m\n\
|
|
\e[1;32m║ Ansible Control Node — Alpine Linux ║\e[0m\n\
|
|
\e[1;32m╠════════════════════════════════════════════════╣\e[0m\n\
|
|
\e[1;32m║ Windows • Cisco • VMware • MSSQL • Linux ║\e[0m\n\
|
|
\e[1;32m╠════════════════════════════════════════════════╣\e[0m\n\
|
|
\e[1;32m║ SSH: ssh ansible@<ip> -p 22 ║\e[0m\n\
|
|
\e[1;32m║ Dir: /ansible ║\e[0m\n\
|
|
\e[1;32m╚════════════════════════════════════════════════╝\e[0m\n\
|
|
' > /etc/motd
|
|
|
|
# ── First-boot: expand rootfs to fill disk, gen SSH keys ─
|
|
RUN printf '#!/bin/sh\n\
|
|
# Expand root filesystem to fill the underlying disk\n\
|
|
ROOTDEV=$(findmnt -n -o SOURCE / 2>/dev/null || echo /dev/vda)\n\
|
|
resize2fs "$ROOTDEV" 2>/dev/null || true\n\
|
|
# Re-generate SSH host keys if running from a cloned image\n\
|
|
if [ ! -f /etc/ssh/.host-keys-generated ]; then\n\
|
|
ssh-keygen -A && touch /etc/ssh/.host-keys-generated\n\
|
|
fi\n' \
|
|
> /etc/local.d/00-first-boot.start && \
|
|
chmod +x /etc/local.d/00-first-boot.start && \
|
|
rc-update add local default
|
|
|
|
WORKDIR /ansible
|
|
CMD ["/sbin/init"]
|