Compare commits
No commits in common. "kvm-base" and "development" have entirely different histories.
kvm-base
...
developmen
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
pyinfra-debug.log
|
|
||||||
.venv/
|
|
||||||
85
README.md
85
README.md
|
|
@ -12,88 +12,3 @@ or
|
||||||
- run `git pull` to fetch the newest version
|
- run `git pull` to fetch the newest version
|
||||||
- run `pyinfra @local deploy.py` to install/update `0x90.ssh_config` trustmebro
|
- run `pyinfra @local deploy.py` to install/update `0x90.ssh_config` trustmebro
|
||||||
- run `pyinfra --dry inventory.py deploy.py` and check that you are on the same state that is already deployed
|
- run `pyinfra --dry inventory.py deploy.py` and check that you are on the same state that is already deployed
|
||||||
|
|
||||||
|
|
||||||
# Set up alpine on hetzner
|
|
||||||
|
|
||||||
This was only tested with a cloud VPS so far.
|
|
||||||
Source: <https://gist.github.com/c0m4r/e38d41d0e31f6adda4b4c5a88ba0a453>
|
|
||||||
(but it's less of a hassle than described there)
|
|
||||||
|
|
||||||
To create an alpine server on hetzner,
|
|
||||||
you need to first create a Debian VPS or something similar.
|
|
||||||
|
|
||||||
Then you boot into the rescue system.
|
|
||||||
|
|
||||||
Get the download link of the latest VIRTUAL x86_64 alpine iso
|
|
||||||
from <https://alpinelinux.org/downloads/>.
|
|
||||||
|
|
||||||
Login to the rescue system via console or SSH,
|
|
||||||
and write the ISO to the disk:
|
|
||||||
|
|
||||||
```
|
|
||||||
ssh root@xxxx:xxxx:xxxx:xxxx::1
|
|
||||||
wipefs -a /dev/sda
|
|
||||||
wget https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/x86_64/alpine-virt-3.20.3-x86_64.iso # or whatever link you got from alpine
|
|
||||||
dd if=alpine-virt-3.20.3-x86_64.iso of=/dev/sda
|
|
||||||
reboot
|
|
||||||
```
|
|
||||||
|
|
||||||
Then open the server console (SSH doesn't work),
|
|
||||||
login to root (no password required),
|
|
||||||
and proceed with:
|
|
||||||
|
|
||||||
```
|
|
||||||
cp -r /.modloop /root
|
|
||||||
cp -r /media/sda /root
|
|
||||||
umount /.modloop /media/sda
|
|
||||||
rm /lib/modules
|
|
||||||
mv /root/.modloop/modules /lib
|
|
||||||
mv /root/sda /media
|
|
||||||
setup-alpine
|
|
||||||
```
|
|
||||||
|
|
||||||
Then select what you wish,
|
|
||||||
contrary to the guide above,
|
|
||||||
DHCP is actually fine.
|
|
||||||
The drive should be sda,
|
|
||||||
the installation type can be sys
|
|
||||||
(why go through the hassle).
|
|
||||||
|
|
||||||
Voilà! reboot and login.
|
|
||||||
Probably the first SSH login will be via root password,
|
|
||||||
as copy-pasting your public SSH key into the console doesn't work really.
|
|
||||||
Make sure the SSH config allows this
|
|
||||||
(and turn passwort root access off afterwards).
|
|
||||||
|
|
||||||
|
|
||||||
## Encrypting /var/lib/libvirt partition
|
|
||||||
|
|
||||||
**Status: tested with Hetzner VPS, not deployed in production yet**
|
|
||||||
|
|
||||||
Messing with file systems and partitions
|
|
||||||
should not be done by automation scripts,
|
|
||||||
so I created the LUKS-encrypted /dev/sdb partition manually.
|
|
||||||
|
|
||||||
(So far, /dev/sdb was added via a Hetzner volume,
|
|
||||||
but it can be any partition actually)
|
|
||||||
|
|
||||||
To create a partition in the VPS volume
|
|
||||||
(which was formatted to ext4 originally),
|
|
||||||
- I ran `fdisk /dev/sdb`,
|
|
||||||
- entered `o` to create a DOS partition table,
|
|
||||||
- added `n` to add a new primary partition, using all available space,
|
|
||||||
- and `w` to save to disk and exit.
|
|
||||||
|
|
||||||
Then I ran `cryptsetup luksFormat /dev/sdb1`
|
|
||||||
and entered the passphrase from `pass 0x90/ararat/sdb-crypt`
|
|
||||||
to create a LUKS volume.
|
|
||||||
|
|
||||||
Now I could decrypt the new volume with
|
|
||||||
`cryptsetup luksOpen /dev/sdb1 sdb_crypt`
|
|
||||||
and entering the passphrase from `pass 0x90/ararat/sdb-crypt`.
|
|
||||||
|
|
||||||
Finally, I ran `mkfs.ext4`
|
|
||||||
to create an ext4 file system
|
|
||||||
in the encrypted partition.
|
|
||||||
|
|
||||||
|
|
|
||||||
100
ararat/deploy.py
100
ararat/deploy.py
|
|
@ -1,100 +0,0 @@
|
||||||
import os
|
|
||||||
|
|
||||||
from pyinfra import host, inventory
|
|
||||||
from pyinfra.operations import server, apk, files, openrc
|
|
||||||
from pyinfra.facts.server import Mounts
|
|
||||||
|
|
||||||
from pyinfra_util import get_pass
|
|
||||||
|
|
||||||
|
|
||||||
files.replace(
|
|
||||||
name="Enable TCP forwarding via SSH server",
|
|
||||||
path="/etc/ssh/sshd_config",
|
|
||||||
text="AllowTcpForwarding no",
|
|
||||||
replace="AllowTcpForwarding yes",
|
|
||||||
)
|
|
||||||
openrc.service(
|
|
||||||
name="Restart sshd",
|
|
||||||
service="sshd",
|
|
||||||
restarted=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
files.replace(
|
|
||||||
name="Enable community repository",
|
|
||||||
path="/etc/apk/repositories",
|
|
||||||
text="#http://dl-cdn.alpinelinux.org/alpine/v3.20/community",
|
|
||||||
replace="http://dl-cdn.alpinelinux.org/alpine/v3.20/community",
|
|
||||||
)
|
|
||||||
apk.update()
|
|
||||||
apk.packages(
|
|
||||||
packages=["cryptsetup", "vim"]
|
|
||||||
)
|
|
||||||
|
|
||||||
mounts = host.get_fact(Mounts)
|
|
||||||
if "/var/lib/libvirt" not in mounts:
|
|
||||||
decryption_password = get_pass('0x90/ararat/sdb-crypt').strip()
|
|
||||||
if decryption_password:
|
|
||||||
server.shell(
|
|
||||||
name="Decrypt and mount /data",
|
|
||||||
commands=[
|
|
||||||
f" echo -n '{decryption_password}' | cryptsetup luksOpen --key-file - /dev/sdb1 sdb_crypt || true",
|
|
||||||
"mount /dev/mapper/sdb_crypt /var/lib/libvirt",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
apk.packages(
|
|
||||||
packages=["libvirt-daemon", "qemu-img", "qemu-system-x86_64", "virt-install"]
|
|
||||||
)
|
|
||||||
openrc.service(
|
|
||||||
name="Start libvirtd",
|
|
||||||
service="libvirtd",
|
|
||||||
running=True,
|
|
||||||
enabled=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
# add networking: https://wiki.alpinelinux.org/wiki/KVM#Networking
|
|
||||||
# modprobe tun
|
|
||||||
# echo "tun" >> /etc/modules-load.d/tun.conf
|
|
||||||
# cat /etc/modules | grep tun || echo tun >> /etc/modules
|
|
||||||
|
|
||||||
# if it doesn't exist, create debian base image (later: and other base images): https://mop.koeln/blog/creating-a-local-debian-vm-using-cloud-init-and-libvirt/#download-the-image
|
|
||||||
# for every active VM, if no image exists, run virt-install with the chosen base image and their cloud-init.yml file: https://mop.koeln/blog/creating-a-local-debian-vm-using-cloud-init-and-libvirt/#preparing-a-cloud-init-file
|
|
||||||
debian_image_path = "/var/lib/libvirt/images/debian-12-generic-amd64.qcow2"
|
|
||||||
files.download(
|
|
||||||
name="Download Debian 12 base image",
|
|
||||||
src="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2",
|
|
||||||
dest=debian_image_path,
|
|
||||||
)
|
|
||||||
for vm in inventory.groups.get("debian_vms"):
|
|
||||||
if os.path.isfile(f"{vm}/files/cloud-init.yml"):
|
|
||||||
files.put(
|
|
||||||
name=f"Upload {vm}-cloud-init.yml",
|
|
||||||
src=f"{vm}/files/cloud-init.yml",
|
|
||||||
dest=f"/root/{vm}-cloud-init.yml",
|
|
||||||
)
|
|
||||||
#virt-install
|
|
||||||
else:
|
|
||||||
if vm.data.get("authorized_keys"):
|
|
||||||
authorized_keys = "ssh_authorized_keys:\n - " + " - ".join(
|
|
||||||
[get_pass(f"0x90/ssh_keys/{admin}.pub") for admin in vm.data.get("authorized_keys")]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
authorized_keys = ""
|
|
||||||
files.template(
|
|
||||||
name=f"Upload {vm}-cloud-init.yml",
|
|
||||||
src="ararat/files/cloud-init.yml.j2",
|
|
||||||
dest=f"/root/{vm}-cloud-init.yml",
|
|
||||||
ssh_authorized_keys=authorized_keys,
|
|
||||||
)
|
|
||||||
memory = 1024
|
|
||||||
vcpus = 1
|
|
||||||
disk_size = 4
|
|
||||||
server.shell(
|
|
||||||
name=f"virt-install {vm}",
|
|
||||||
commands=[
|
|
||||||
f"virt-install --name {vm} --disk=size={disk_size},backing_store={debian_image_path} "
|
|
||||||
f"--memory {memory} --vcpus {vcpus} --cloud-init user-data=/root/{vm}-cloud-init.yml,disable=on "
|
|
||||||
"--network bridge=virbr0 --osinfo=debian12 || true",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
# for every active VM, make sure an IP is assigned and traffic is passed to it
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
#cloud-config
|
|
||||||
|
|
||||||
keyboard:
|
|
||||||
layout: de
|
|
||||||
variant: nodeadkeys
|
|
||||||
|
|
||||||
locale: en_US
|
|
||||||
|
|
||||||
timezone: UTC
|
|
||||||
|
|
||||||
disable_root: false
|
|
||||||
|
|
||||||
users:
|
|
||||||
- name: root
|
|
||||||
shell: /bin/bash
|
|
||||||
{{ ssh_authorized_keys }}
|
|
||||||
- name: mop
|
|
||||||
# so our user can just sudo without any password
|
|
||||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
|
||||||
shell: /bin/bash
|
|
||||||
# content from $HOME/.ssh/id_rsa.pub on your host system
|
|
||||||
ssh_authorized_keys:
|
|
||||||
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKZYJ91RLXRCQ4ZmdW6ucIltzukQ/k+lDOqlRIYwxNRv missytake@systemli.org
|
|
||||||
|
|
||||||
# Examples: https://cloudinit.readthedocs.io/en/latest/reference/examples_library.html#examples-library
|
|
||||||
16
inventory.py
16
inventory.py
|
|
@ -1,13 +1,5 @@
|
||||||
localhost = "@local"
|
targets = [
|
||||||
|
"@local",
|
||||||
hypervisor = [("95.217.163.200", dict(ssh_user="root"))]
|
("ararat.0x90.space", dict(ssh_port=42022)),
|
||||||
|
("baixun.0x90.space", dict(ssh_port=42023)),
|
||||||
debian_vms = [
|
|
||||||
# "cloud",
|
|
||||||
(
|
|
||||||
"playground",
|
|
||||||
{
|
|
||||||
"authorized_keys": ["missytake", "hagi", "vmann"],
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
Metadata-Version: 2.1
|
|
||||||
Name: pyinfra-util
|
|
||||||
Version: 0.1
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
pyproject.toml
|
|
||||||
pyinfra_util/__init__.py
|
|
||||||
pyinfra_util/util.py
|
|
||||||
pyinfra_util.egg-info/PKG-INFO
|
|
||||||
pyinfra_util.egg-info/SOURCES.txt
|
|
||||||
pyinfra_util.egg-info/dependency_links.txt
|
|
||||||
pyinfra_util.egg-info/top_level.txt
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
pyinfra_util
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
from .util import get_pass, deploy_tmux
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,56 +0,0 @@
|
||||||
"""
|
|
||||||
nginx deploy
|
|
||||||
"""
|
|
||||||
import subprocess
|
|
||||||
from pyinfra.operations import files, apt
|
|
||||||
|
|
||||||
|
|
||||||
def get_pass(filename: str) -> str:
|
|
||||||
"""Get the data from the password manager."""
|
|
||||||
try:
|
|
||||||
r = subprocess.run(["pass", "show", filename], capture_output=True)
|
|
||||||
except FileNotFoundError:
|
|
||||||
readme_url = "https://git.0x90.space/deltachat/secrets"
|
|
||||||
print(f"Please install pass and pull the latest version of our pass secrets from {readme_url}")
|
|
||||||
exit()
|
|
||||||
return r.stdout.decode('utf-8')
|
|
||||||
|
|
||||||
|
|
||||||
def deploy_tmux(home_dir="/root", escape_key="C-b", additional_config=[]):
|
|
||||||
apt.packages(
|
|
||||||
name="apt install tmux",
|
|
||||||
packages=["tmux"],
|
|
||||||
)
|
|
||||||
|
|
||||||
config = [
|
|
||||||
f"set-option -g prefix {escape_key}",
|
|
||||||
"set-option -g aggressive-resize on",
|
|
||||||
"set-option -g mouse on",
|
|
||||||
"set-option -g set-titles on",
|
|
||||||
"set-option -g set-titles-string '#I:#W - \"#H\"'",
|
|
||||||
"unbind-key C-b",
|
|
||||||
"bind-key ` send-prefix",
|
|
||||||
"bind-key a last-window",
|
|
||||||
"bind-key k kill-session",
|
|
||||||
]
|
|
||||||
for item in additional_config:
|
|
||||||
config.append(item)
|
|
||||||
for line in config:
|
|
||||||
files.line(
|
|
||||||
path=f"{home_dir}/.tmux.conf",
|
|
||||||
line=line,
|
|
||||||
)
|
|
||||||
|
|
||||||
dot_profile_add = """
|
|
||||||
# autostart tmux
|
|
||||||
if [ -t 0 -a -z "$TMUX" ]
|
|
||||||
then
|
|
||||||
test -z "$(tmux list-sessions)" && exec tmux new -s "$USER" || exec tmux new -A -s $(tty | tail -c +6) -t "$USER"
|
|
||||||
fi
|
|
||||||
"""
|
|
||||||
files.block(
|
|
||||||
name="connect to tmux session on login",
|
|
||||||
path=f"{home_dir}/.profile",
|
|
||||||
content=dot_profile_add,
|
|
||||||
try_prevent_shell_expansion=True,
|
|
||||||
)
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
[build-system]
|
|
||||||
requires = ["setuptools>=45"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
|
|
||||||
[project]
|
|
||||||
name = "pyinfra-util"
|
|
||||||
version = "0.1"
|
|
||||||
Loading…
Reference in a new issue