Home Lab 8 - Minimalist Container host with autoscale and gitops
In the last blog I tried to get going with RancherOS as a secure base for running all my applications on a proxmox worker node. Well, when it came down to actually securing the system I found it was going to take a long time to install NIDS/SIEM agents, and then learned it was unsupported by the Rancher team. In this blog I'll actually come up with a solution. I'll cover Architecture and setup of the Alpine container host in this blog. If you follow the series the end result will be a minamalist container host with AlpineOS with efficient hardware usage thanks to autoscaling via Traefik/Sablier and automatic secure updates thanks to Gitops via Gitea/Woodpecker/Portainer.
Architecture
Requirements
- Secure base OS that I could install NIDS/HIDS/SIEM agents onto
- Easy to run and manage on Proxmox
- Single Container Runtime
- Efficient use of hardware (Scale services to 0 when not in use)
- Gitops
OS Stack
Service Stack
Where the magic comes in is within the container environment. I've swapped out nginx for Traefik which enables the autoscaling feature and added portainer to gain Gitops.
GitOps
When I say GitOps
I'm referring to the ability to update infrastructure through interacting with nothing but git
. To achieve this On Premises without Kubernetes, I'll be using Portainer, Woodpecker and Gitea. Here's how it works:
Autoscaling
What I'm looking for here is for services to be scaled to 0 when they're not in use for some duration. Then, when a request hits Traefik for that service hostname the container is started up. This is how it works:
Background
AlpineOS
What is Alpine Linux anyway? Alpine Linux is a free and open-source Linux distribution based on the musl C library and BusyBox utilities. It is designed to be lightweight and security-focused, with a small disk footprint and minimal attack surface. Alpine Linux is widely used as a base image for containers, due to its small size, speed and security features. It is also used as a minimalist distribution for servers and other systems that require a highly secure and minimal operating environment. The distribution uses its own package manager, apk-tools, which is designed to be simple and efficient, with a focus on security. Alpine Linux also uses a read-only root file system, which helps to prevent tampering and improve overall system security.
Portainer
What is Portainer? I actually used this within it's first few releases and had a terrible experience, although it wasn't entirely portainer's fault, it was mostly due to the instability of Docker Swarm. Portainer is a open-source management solution for Docker and Swarm-based container environments. It provides a simple and intuitive web-based interface for managing and monitoring Docker containers, images, networks, and volumes, as well as managing and deploying Swarm stacks. With Portainer, users can easily manage containers, images, networks, and volumes, perform basic operations such as start, stop, and restart containers, view logs, and monitor resource usage. It also provides a visual representation of the containers and their relationships, making it easier to understand and manage complex container environments. Portainer is lightweight and can be run as a standalone container, making it easy to deploy and manage. It also provides role-based access control and a RESTful API, making it suitable for use in large, multi-user environments. Overall, Portainer offers a simple and user-friendly solution for managing and monitoring Docker and Swarm environments, and is a popular choice for users looking for a graphical interface for managing containers. Personally, a GUI is nice but I don't mind sticking in a shell - what I'm going to gain out of this is hopefully a Gitops integration where I can make all my infrastructure changes in a Git repo and just use the GUI to watch the changes rollout or do debug.
Traefik
Traefik is a popular open-source reverse proxy and load balancer that is designed to handle incoming network traffic and distribute it to multiple services or containers in a dynamic and efficient way. It is often used in cloud-native and containerized environments, such as Kubernetes clusters, where it can automatically discover and configure routes for new services as they are deployed or removed. Traefik is known for its easy-to-use configuration syntax, powerful routing capabilities, and support for a wide variety of backends, including HTTP, TCP, and UDP services. It also supports a range of features like SSL termination, rate limiting, circuit breaking, and request retries, making it a versatile tool for managing network traffic. Traefik is written in Go and is available under the permissive MIT license, making it an attractive option for organizations and developers who want a high-performance and reliable proxy that they can customize and extend to meet their specific needs.
Sablier
Sablier is a middleware plugin for Traefik that enables the use of dynamic timeouts for HTTP requests. It is designed to help manage and optimize the use of resources by setting appropriate timeouts for requests, based on the expected response time of the upstream service. In traditional load balancing, timeouts are usually set statically for all requests, which can lead to either slow response times or increased resource usage. Sablier helps address this issue by dynamically setting timeouts for each request, based on its expected response time, which can lead to better resource utilization and faster response times. Sablier works by using the Time-Based One-Time Password (TOTP) algorithm to generate a unique timeout value for each request. The generated value is used as the timeout duration for the request, and it is calculated based on the expected response time of the upstream service. Sablier is easy to configure with Traefik, and it can be used in conjunction with other middleware plugins and features to create a powerful and flexible load balancing solution. It is available as open-source software under the permissive MIT license.
Alpine Installation
Create Proxmox VM
Upload the Alpine Virtual ISO to Proxmox.
Create a VM from the .iso
Note: Before creating this, I generated a MAC and used it to create a DHCP lease and DNS record on pfSense so it would be accessable via hostname rightaway.
Proxmox VNC Console
Login as root, no password. Execute setup-alpine
which will walk through initial setup.
In my configuration I added a vlan tagged interface, so I can just setup eth0
and get going from my DHCP lease. You may have a different network configuration.
Set a temporary root password (change this after you get a shell you can paste into). The mirro doesn't overly matter, try to pick one closest to you.
Setup a user for yourself, leave ssh key unpopulated for now as we'll add this later and set defaults for ssh config.
Choose sys
for disk type, the other options run from RAM.
Reboot when the installation finishes, you can remove the iso
from the mount path in proxmox if you want now.
Initial Configuration
Now we can log in via SSH!
# Give yourself root priv for setup over ssh (Clean up later)
su root
adduser -g "matt" matt
adduser matt wheel
apk add doas
echo "permit persist :wheel" >> /etc/doas.d/doas.conf
exit
# Disable root account login
doas vi /etc/passwd
# Change:
# root:x:0:0:root:/root:/bin/ash
# to
# root:x:0:0:root:/root:/sbin/nologin
# Test
doas su root
This account is not available
# Add our SSH key
cd ~ && mkdir .ssh
chmod 700 .ssh
cd .ssh && touch authorized_keys
chmod 600 authorized_keys
cat << EOF > authorized_keys
YOUR_SSH_KEYS
EOF
# Harden OpenSSH configuration
doas vi /etc/ssh/sshd_config
# Add:
# PermitEmptyPasswords no
# PermitRootLogin no
# Protocol 2
# ClientAliveInterval 300
# ClientAliveCountMax 2
# PasswordAuthentication no
# PubkeyAuthentication yes
# AllowUsers YOUR_USERNAME
# X11Forwarding no
# Restart sshd
doas service sshd restart
# Logout to test ssh config
exit
# Check that we cannot login as root
ssh root@container0.salmon.sec
root@container0.salmon.sec: Permission denied (publickey,keyboard-interactive).
# Check that we cannot login as user without a ssh key (no password auth)
ssh -o PasswordAuthentication=yes -o PreferredAuthentications=keyboard-interactive,password -o PubkeyAuthentication=no matt@container0.salmon.sec
matt@container0.salmon.sec: Permission denied (publickey,keyboard-interactive).
# Log in with our key
ssh -o PasswordAuthentication=no -o PreferredAuthentications=publickey -o PubkeyAuthentication=yes matt@container0.salmon.sec
Docker installation
Ensure community
repo is enabled in /etc/apk/repositories
Install and configure:
# Install Docker & Compose
doas apk update
doas apk add docker docker-cli-compose
# Enable at boot and right away
doas rc-update add docker boot
doas service docker start
Next
In the next blog we install Portainer, Traefik and Sablier to configure a stack deployment environment (Portainer) and configure our routing (Traefik) and autoscale mechanism (Sablier).