mirror of
https://github.com/lordmathis/dev-cluster.git
synced 2025-12-22 16:44:24 +00:00
Initial provisioning set up
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
secrets.yaml
|
||||||
99
README.md
99
README.md
@@ -1 +1,98 @@
|
|||||||
# dev-cluster
|
# Dev-Cluster GitOps Provisioning
|
||||||
|
|
||||||
|
Provisioning, configuration and manifests for my Kubernetes dev cluster on Hetzner Cloud, set up for GitOps with Flux CD.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- [Terraform](https://www.terraform.io/downloads.html) installed
|
||||||
|
- [SOPS](https://github.com/mozilla/sops) installed
|
||||||
|
- [Age](https://github.com/FiloSottile/age) installed (for encryption)
|
||||||
|
- A Hetzner Cloud account and API token
|
||||||
|
- A GitHub account and personal access token (for Flux)
|
||||||
|
|
||||||
|
## Setup Steps
|
||||||
|
|
||||||
|
1. **Generate an Age key:**
|
||||||
|
```
|
||||||
|
age-keygen -o key.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Create a `.sops.yaml` file in your project root:**
|
||||||
|
```yaml
|
||||||
|
creation_rules:
|
||||||
|
- path_regex: secrets\.enc\.yaml$
|
||||||
|
age: <your-age-public-key>
|
||||||
|
```
|
||||||
|
Replace `<your-age-public-key>` with the public key from your `key.txt` file.
|
||||||
|
|
||||||
|
3. **Create a `secrets.yaml` file with your sensitive data:**
|
||||||
|
```yaml
|
||||||
|
username: <your-username>
|
||||||
|
user_hashed_password: <your-hashed-password>
|
||||||
|
user_ssh_public_key: <your-ssh-public-key>
|
||||||
|
github_username: <your-github-username>
|
||||||
|
github_repo: <your-flux-repo-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Encrypt the secrets file:**
|
||||||
|
```
|
||||||
|
sops -e secrets.yaml > secrets.enc.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Create a `terraform.tfvars` file for your Hetzner Cloud token:**
|
||||||
|
```hcl
|
||||||
|
hcloud_token = "your-hetzner-cloud-token"
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Initialize Terraform:**
|
||||||
|
```
|
||||||
|
terraform init
|
||||||
|
```
|
||||||
|
|
||||||
|
7. **Plan your Terraform deployment:**
|
||||||
|
```
|
||||||
|
terraform plan
|
||||||
|
```
|
||||||
|
|
||||||
|
8. **Apply your Terraform configuration:**
|
||||||
|
```
|
||||||
|
terraform apply
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
- `main.tf`: Main Terraform configuration file
|
||||||
|
- `variables.tf`: Terraform variables definition
|
||||||
|
- `cloud-init.yaml`: Cloud-init configuration template
|
||||||
|
- `secrets.enc.yaml`: Encrypted secrets file (do not commit to version control)
|
||||||
|
- `terraform.tfvars`: Terraform variables values (do not commit to version control)
|
||||||
|
- `.sops.yaml`: SOPS configuration file
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
After successful provisioning, you can access your new server using SSH:
|
||||||
|
|
||||||
|
```
|
||||||
|
ssh <your-username>@<server-ip>
|
||||||
|
```
|
||||||
|
|
||||||
|
The server IP will be output by Terraform after successful application.
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
- Modify `cloud-init.yaml` to change the initial server setup.
|
||||||
|
- Adjust `main.tf` to change Hetzner Cloud resources or add additional configurations.
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
- Never commit `secrets.yaml`, `secrets.enc.yaml`, or `terraform.tfvars` to version control.
|
||||||
|
- Keep your `key.txt` file secure and backed up. Losing this file means losing access to your encrypted secrets.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If you encounter issues:
|
||||||
|
1. Check Terraform output for errors.
|
||||||
|
2. Review cloud-init logs on the server: `/var/log/cloud-init-output.log`
|
||||||
|
3. Ensure all required variables are correctly set in your encrypted secrets file.
|
||||||
|
|
||||||
|
For further assistance, please open an issue in the project repository.
|
||||||
0
apps/.git-keep
Normal file
0
apps/.git-keep
Normal file
0
cluster-config/.git-keep
Normal file
0
cluster-config/.git-keep
Normal file
80
infrastructure/cloud-init.yaml
Normal file
80
infrastructure/cloud-init.yaml
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#cloud-config
|
||||||
|
package_update: true
|
||||||
|
package_upgrade: true
|
||||||
|
package_reboot_if_required: true
|
||||||
|
|
||||||
|
users:
|
||||||
|
- name: ${username}
|
||||||
|
groups: [ sudo ]
|
||||||
|
shell: /usr/bin/zsh
|
||||||
|
hashed_passwd: ${user_hashed_password}
|
||||||
|
lock_passwd: false
|
||||||
|
ssh_authorized_keys:
|
||||||
|
- ${user_ssh_public_key}
|
||||||
|
- name: git
|
||||||
|
lock_passwd: true
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- apt-transport-https
|
||||||
|
- ca-certificates
|
||||||
|
- curl
|
||||||
|
- gnupg2
|
||||||
|
- git
|
||||||
|
- zsh
|
||||||
|
- ufw
|
||||||
|
- fail2ban
|
||||||
|
- tmux
|
||||||
|
- bat
|
||||||
|
- unzip
|
||||||
|
|
||||||
|
write_files:
|
||||||
|
- content: |
|
||||||
|
#!/bin/sh
|
||||||
|
GITEA_POD=$(kubectl --kubeconfig /home/git/.kube/config get po -n gitea -l app=gitea -o name --no-headers=true | cut -d'/' -f2)
|
||||||
|
kubectl --kubeconfig /home/git/.kube/config exec -i -n gitea $GITEA_POD -c gitea -- env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" /bin/sh "$@"
|
||||||
|
path: /usr/local/bin/gitea-shell
|
||||||
|
permissions: '0755'
|
||||||
|
- content: |
|
||||||
|
#!/bin/sh
|
||||||
|
GITEA_POD=$(kubectl --kubeconfig /home/git/.kube/config get po -n gitea -l app=gitea -o name --no-headers=true | cut -d'/' -f2)
|
||||||
|
kubectl --kubeconfig /home/git/.kube/config exec -i -n gitea $GITEA_POD -c gitea -- /usr/local/bin/gitea keys -e git -u $1 -t $2 -k $3
|
||||||
|
permissions: '0755'
|
||||||
|
path: /usr/local/bin/gitea-keys
|
||||||
|
|
||||||
|
ssh:
|
||||||
|
emit_keys_to_console: false
|
||||||
|
ssh_pwauth: false
|
||||||
|
disable_root: true
|
||||||
|
|
||||||
|
ssh_config:
|
||||||
|
Match User git:
|
||||||
|
AuthorizedKeysCommandUser: git
|
||||||
|
AuthorizedKeysCommand: /usr/local/bin/gitea-keys %u %t %k
|
||||||
|
|
||||||
|
runcmd:
|
||||||
|
# UFW
|
||||||
|
- ufw default deny incoming
|
||||||
|
- ufw default allow outgoing
|
||||||
|
- ufw allow ssh
|
||||||
|
- ufw allow http
|
||||||
|
- ufw allow https
|
||||||
|
- ufw logging on
|
||||||
|
- ufw enable
|
||||||
|
# SSH key for user
|
||||||
|
- su ${username} -c 'ssh-keygen -t ed25519 -f /home/${username}/.ssh/id_ed25519 -q -N "" '
|
||||||
|
# Expire password for user
|
||||||
|
- chage -d 0 ${username}
|
||||||
|
# SSH Passthrough for user git
|
||||||
|
- usermod -s /usr/local/bin/gitea-shell git
|
||||||
|
# k3s
|
||||||
|
- curl -sfL https://get.k3s.io | sh -s - --disable=traefik
|
||||||
|
# helm
|
||||||
|
- curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
|
||||||
|
- chmod 700 get_helm.sh
|
||||||
|
- ./get_helm.sh
|
||||||
|
# Install Flux
|
||||||
|
- curl -s https://fluxcd.io/install.sh | sudo bash
|
||||||
|
# Bootstrap Flux (adjust the GitHub details as needed)
|
||||||
|
- su ${username} -c 'flux bootstrap github --owner=${github_username} --repository=${github_repo} --path=cluster-config --personal'
|
||||||
|
|
||||||
|
final_message: "The system is finally up, after $UPTIME seconds"
|
||||||
97
infrastructure/main.tf
Normal file
97
infrastructure/main.tf
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# Configure the Hetzner Cloud Provider
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
hcloud = {
|
||||||
|
source = "hetznercloud/hcloud"
|
||||||
|
}
|
||||||
|
sops = {
|
||||||
|
source = "carlpett/sops"
|
||||||
|
version = "~> 0.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
required_version = ">= 0.13"
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "hcloud" {
|
||||||
|
token = var.hcloud_token
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "sops" {}
|
||||||
|
|
||||||
|
data "sops_file" "secrets" {
|
||||||
|
source_file = "secrets.enc.yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "cloudinit_config" "k8s_node" {
|
||||||
|
gzip = true
|
||||||
|
base64_encode = true
|
||||||
|
|
||||||
|
part {
|
||||||
|
content_type = "text/cloud-config"
|
||||||
|
content = templatefile("${path.module}/cloud-init.yaml", {
|
||||||
|
username = data.sops_file.secrets.data["username"]
|
||||||
|
user_hashed_password = data.sops_file.secrets.data["user_hashed_password"]
|
||||||
|
user_ssh_public_key = data.sops_file.secrets.data["user_ssh_public_key"]
|
||||||
|
github_username = data.sops_file.secrets.data["github_username"]
|
||||||
|
github_repo = data.sops_file.secrets.data["github_repo"]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "hcloud_server" "cluster" {
|
||||||
|
name = "auberon"
|
||||||
|
image = "ubuntu-24.04"
|
||||||
|
server_type = "cx22"
|
||||||
|
location = "nbg1"
|
||||||
|
backups = true
|
||||||
|
user_data = data.cloudinit_config.k8s_node.rendered
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "hcloud_firewall" "cluster-firewall" {
|
||||||
|
name = "cluster-firewall"
|
||||||
|
apply_to {
|
||||||
|
server = hcloud_server.cluster.id
|
||||||
|
}
|
||||||
|
rule {
|
||||||
|
direction = "in"
|
||||||
|
protocol = "icmp"
|
||||||
|
source_ips = [
|
||||||
|
"0.0.0.0/0",
|
||||||
|
"::/0"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
rule {
|
||||||
|
direction = "in"
|
||||||
|
protocol = "tcp"
|
||||||
|
port = "80"
|
||||||
|
source_ips = [
|
||||||
|
"0.0.0.0/0",
|
||||||
|
"::/0"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
rule {
|
||||||
|
direction = "in"
|
||||||
|
protocol = "tcp"
|
||||||
|
port = "443"
|
||||||
|
source_ips = [
|
||||||
|
"0.0.0.0/0",
|
||||||
|
"::/0"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
rule {
|
||||||
|
direction = "in"
|
||||||
|
protocol = "tcp"
|
||||||
|
port = "22"
|
||||||
|
source_ips = [
|
||||||
|
"0.0.0.0/0",
|
||||||
|
"::/0"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output "server_ip" {
|
||||||
|
value = hcloud_server.cluster.ipv4_address
|
||||||
|
}
|
||||||
5
infrastructure/variables.tf
Normal file
5
infrastructure/variables.tf
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
variable "hcloud_token" {
|
||||||
|
description = "Hetzner Cloud API Token"
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user