Restructure and clean up code
This commit is contained in:
parent
660191ab42
commit
6dd363a2a8
37 changed files with 17 additions and 1423 deletions
47
scripts/bootstrap.sh
Executable file
47
scripts/bootstrap.sh
Executable file
|
@ -0,0 +1,47 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
servername="${1-}"
|
||||
|
||||
hostname="${2-}"
|
||||
|
||||
if [ -z "$servername" ] || [ -z "$hostname" ]
|
||||
then
|
||||
echo "Usage: $0 SERVERNAME HOSTNAME"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
confirmation="Yes, wipe ${servername}."
|
||||
|
||||
echo "⚠️ This will wipe ${servername} completely! ⚠️"
|
||||
echo "Confirm by typing: \"${confirmation}\""
|
||||
read response
|
||||
|
||||
if [ "$response" != "$confirmation" ]; then
|
||||
echo "Aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create a temporary directory
|
||||
temp=$(mktemp -d)
|
||||
|
||||
# Function to cleanup temporary directory on exit
|
||||
cleanup() {
|
||||
rm -rf "$temp"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# Create directory where age key will go.
|
||||
# Nixos-anywhere creates a kind of overlay and retains this structure on the final file system.
|
||||
mkdir -p "$temp/root/.config/sops/age"
|
||||
|
||||
# Extract and copy server's age key.
|
||||
sops -d --extract "[\"${servername}\"]" secrets/serverKeys.yaml > "$temp/root/.config/sops/age/keys.txt"
|
||||
|
||||
# Set the correct permissions
|
||||
chmod 600 "$temp/root/.config/sops/age/keys.txt"
|
||||
|
||||
# Install NixOS to the host system with our age identity
|
||||
nixos-anywhere --extra-files "$temp" --flake ".#${servername}" "root@${hostname}"
|
97
scripts/default.nix
Normal file
97
scripts/default.nix
Normal file
|
@ -0,0 +1,97 @@
|
|||
{ self, nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
createScript = { name, runtimeInputs, scriptPath, extraWrapperFlags ? "", ... }:
|
||||
let
|
||||
script = (pkgs.writeScriptBin name (builtins.readFile scriptPath)).overrideAttrs (old: {
|
||||
buildCommand = "${old.buildCommand}\n patchShebangs $out";
|
||||
});
|
||||
in
|
||||
pkgs.symlinkJoin {
|
||||
inherit name;
|
||||
paths = [ script ] ++ runtimeInputs;
|
||||
buildInputs = [ pkgs.makeWrapper ];
|
||||
postBuild = "wrapProgram $out/bin/${name} --set PATH $out/bin ${extraWrapperFlags}";
|
||||
};
|
||||
in
|
||||
{
|
||||
packages.bootstrap = createScript {
|
||||
name = "bootstrap";
|
||||
runtimeInputs = with pkgs; [ sops coreutils nixos-anywhere ];
|
||||
scriptPath = ./bootstrap.sh;
|
||||
};
|
||||
|
||||
packages.gen-k3s-cert = createScript {
|
||||
name = "create-k3s-cert";
|
||||
runtimeInputs = with pkgs; [ openssl coreutils openssh yq ];
|
||||
scriptPath = ./gen-k3s-cert.sh;
|
||||
};
|
||||
|
||||
packages.prefetch-container-images =
|
||||
let
|
||||
imagesJSON = builtins.toFile "images.json" (builtins.toJSON self.globals.images);
|
||||
in
|
||||
pkgs.writers.writePython3Bin "prefetch-container-images.py"
|
||||
{ } ''
|
||||
import json
|
||||
import subprocess
|
||||
import tempfile
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
|
||||
prefetch_docker_cmd = "${pkgs.lib.getExe pkgs.nix-prefetch-docker}" # noqa: E501
|
||||
nix_cmd = "${pkgs.lib.getExe pkgs.nix}" # noqa: E501
|
||||
images_file_name = "${imagesJSON}"
|
||||
|
||||
results = defaultdict(lambda: defaultdict(dict))
|
||||
|
||||
with open(images_file_name, 'r') as file:
|
||||
data = json.load(file)
|
||||
|
||||
for image_name, image_ref in data.items():
|
||||
[name, tag] = image_ref.split(":", maxsplit=1)
|
||||
print(f"Prefetching image {image_ref}", file=sys.stderr)
|
||||
|
||||
digest = ""
|
||||
if "@" in tag:
|
||||
[tag, digest] = tag.split("@", maxsplit=1)
|
||||
|
||||
prefetch_args = [
|
||||
prefetch_docker_cmd,
|
||||
"--os", "linux",
|
||||
"--arch", "amd64",
|
||||
"--image-name", name,
|
||||
"--image-tag", tag,
|
||||
"--json",
|
||||
"--quiet"
|
||||
]
|
||||
|
||||
if digest:
|
||||
prefetch_args.extend(["--image-digest", digest])
|
||||
|
||||
result = subprocess.run(prefetch_args,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True)
|
||||
|
||||
prefetch_data = json.loads(result.stdout)
|
||||
results[image_name] = prefetch_data
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w+', suffix='.json') as temp_file:
|
||||
json.dump(results, temp_file, indent=4)
|
||||
temp_file.flush()
|
||||
|
||||
to_nix_args = [
|
||||
nix_cmd,
|
||||
"eval",
|
||||
"--impure",
|
||||
"--expr", f'builtins.fromJSON (builtins.readFile {temp_file.name})'
|
||||
]
|
||||
result = subprocess.run(to_nix_args,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True)
|
||||
|
||||
print(result.stdout)
|
||||
'';
|
||||
})
|
88
scripts/gen-k3s-cert.sh
Normal file
88
scripts/gen-k3s-cert.sh
Normal file
|
@ -0,0 +1,88 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
username="${1-}"
|
||||
host="${2-}"
|
||||
output_path="${3:-.}"
|
||||
|
||||
if [ -z "$username" ] || [ -z "$host" ]
|
||||
then
|
||||
echo "Usage: $0 USERNAME HOST [OUTPUTPATH]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create a temporary directory
|
||||
temp=$(mktemp -d)
|
||||
|
||||
# Function to cleanup temporary directory on exit
|
||||
cleanup() {
|
||||
rm -rf "$temp"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo Generating the private key
|
||||
openssl genpkey -algorithm ed25519 -out "$temp/key.pem"
|
||||
|
||||
echo Generating the certificate request
|
||||
openssl req -new -key "$temp/key.pem" -out "$temp/req.csr" -subj "/CN=$username"
|
||||
|
||||
echo Creating K8S CSR manifest
|
||||
csr="$(cat "$temp/req.csr" | base64 | tr -d '\n')"
|
||||
k8s_csr="apiVersion: certificates.k8s.io/v1
|
||||
kind: CertificateSigningRequest
|
||||
metadata:
|
||||
name: $username-csr
|
||||
spec:
|
||||
request: $csr
|
||||
expirationSeconds: 307584000 # 10 years
|
||||
signerName: kubernetes.io/kube-apiserver-client
|
||||
usages:
|
||||
- digital signature
|
||||
- key encipherment
|
||||
- client auth
|
||||
"
|
||||
|
||||
echo Creating K8S CSR resource
|
||||
ssh "root@$host" "echo \"$k8s_csr\" | k3s kubectl apply -f -"
|
||||
|
||||
echo Approving K8S CSR
|
||||
ssh "root@$host" "k3s kubectl certificate approve $username-csr"
|
||||
|
||||
echo Retrieving approved certificate
|
||||
encoded_cert="$(ssh root@"$host" "k3s kubectl get csr $username-csr -o jsonpath='{.status.certificate}'")"
|
||||
|
||||
echo Retrieving default K3S kubeconfig
|
||||
base_kubeconfig="$(ssh root@"$host" "cat /etc/rancher/k3s/k3s.yaml")"
|
||||
|
||||
echo Getting certificate authority data from default kubeconfig
|
||||
cert_authority_data="$(echo -n "$base_kubeconfig" | yq -r '.clusters[0].cluster."certificate-authority-data"')"
|
||||
|
||||
echo Generating final kubeconfig
|
||||
result_kubeconfig="apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: $cert_authority_data
|
||||
server: https://$host:6443
|
||||
name: default
|
||||
contexts:
|
||||
- context:
|
||||
cluster: default
|
||||
user: $username
|
||||
name: default
|
||||
current-context: default
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: $username
|
||||
user:
|
||||
client-certificate: $username.crt
|
||||
client-key: $username.key
|
||||
"
|
||||
|
||||
echo Writing resulting files to "$output_path"
|
||||
echo -n "$encoded_cert" | base64 -d > $output_path/$username.crt
|
||||
echo -n "$result_kubeconfig" > $output_path/config
|
||||
cp $temp/key.pem $output_path/$username.key
|
||||
|
Reference in a new issue