60 Commits

Author SHA1 Message Date
alexandre.pires 4cd933f9f8 feat(audit): add AWS encryption provider audit rules and update encryption provider script 2025-05-12 17:24:58 +02:00
alexandre.pires 05d1624bdd feat(terraform): update metallb version, refactor IAM policies, and enhance security 2025-05-11 20:58:05 +02:00
alexandre.pires 19f599e502 feat(secrets): replace config maps with secrets for sensitive configurations in multiple modules 2025-05-11 20:17:35 +02:00
alexandre.pires 457f2bd810 feat(encryption): implement AWS KMS integration with encryption provider and update related configurations 2025-05-11 19:41:48 +02:00
alexandre.pires 3e12b13d95 fix(backup): update security context in cron job and improve backup script logging 2025-05-10 19:40:01 +02:00
alexandre.pires 01fc509795 feat(backup): update backup script and configuration to use variable tag and change source path 2025-05-10 19:18:16 +02:00
alexandre.pires a19c71009f feat(backup): add environment variables for app name and backup retention in cron job and fix quoting in backup script 2025-05-10 19:09:21 +02:00
alexandre.pires 9e45ff6376 feat(backup): add backup script and refactor cron job to use it 2025-05-10 19:06:25 +02:00
alexandre.pires bbc4fef0e8 feat(trivy): add Trivy integration with Kubernetes, including cron job and email reporting 2025-05-10 18:16:08 +02:00
alexandre.pires 5d2f50feb9 feat(mail): add stunnel support for Dovecot and Postfix with configuration and certificate management 2025-05-10 15:37:00 +02:00
alexandre.pires a0ac55e746 feat(gitea): update Gitea version to 1.23.7 and enhance liveness probe with TLS support 2025-05-09 23:22:34 +02:00
alexandre.pires 17a54f6792 feat(gitea): refactor configuration to use structured app_config and add TLS support 2025-05-09 22:21:33 +02:00
alexandre.pires 9de7d52192 feat(sftpgo): add TLS support and internal certificate management 2025-05-08 22:36:47 +02:00
alexandre.pires 4d4f085c3e refactor: clean up environment variables and remove unused Nextcloud configurations 2025-05-08 19:18:19 +02:00
alexandre.pires d1267f816b feat(mail): add Dovecot and Getmail configurations with ingress setup for SFTPGo 2025-05-05 19:56:43 +02:00
alexandre.pires e6e85b00f7 feat(mail): enhance mail configuration with getmail and dovecot settings
- Added getmail configuration generation using template files.
- Introduced postfix and dovecot configuration checksums for deployment.
- Created new dovecot configuration file and sieve script for email handling.
- Updated main.tf to utilize local variables for configuration management.
- Removed redundant external password hasher from main.tf.

feat(nginx): improve nginx configuration management

- Centralized nginx configuration into a local variable with checksum.
- Created separate config maps for default website configurations.
- Updated deployment to utilize new configuration structure.

feat(sftpgo): add SFTPGo application deployment

- Introduced SFTPGo with Kubernetes resources including namespace, config maps, and secrets.
- Configured SFTPGo with SMTP settings and AWS credentials.
- Implemented health checks and volume mounts for persistent storage.

refactor(seafile): remove Seafile module

- Deleted Seafile module and associated resources as part of cleanup.
2025-05-05 00:47:36 +02:00
alexandre.pires 6adbd50c6d fix: Remove check for valid remote host info from CI/CD actions 2025-05-02 14:55:38 +02:00
alexandre.pires b04871a60c fix: Correct setup steps for Tofu environment and streamline system ID validation 2025-05-02 14:51:53 +02:00
alexandre.pires b961de0455 fix: Correct terraform_version to tofu_version in setup-opentofu-env action and update ansible command to ping public hosts 2025-05-02 14:46:59 +02:00
alexandre.pires 596f2b13ba fix: Correct ansible-inventory command to include --limit option for host group filtering 2025-05-02 14:40:52 +02:00
alexandre.pires 51ba9821a0 fix: Update default host group in Ansible setup and correct host entry in inventory 2025-05-02 14:34:08 +02:00
alexandre.pires 02e79deb5c fix: Update argument parser description for clarity 2025-05-02 14:24:41 +02:00
alexandre.pires 5b341c9430 feat: Update Ansible playbooks and host variables for improved organization and functionality 2025-05-02 14:24:08 +02:00
alexandre.pires 0eaadbe6a7 Reorganized folder structure 2025-04-29 22:40:27 +02:00
alexandre.pires 0d3f4a0a30 refactor: Clean up unused variables and simplify configurations across modules 2025-04-29 19:33:33 +02:00
alexandre.pires b7408fb4d8 Add Gitea and Mail modules with configuration and resources
- Created Gitea module with outputs, provider, and variables for deployment.
- Implemented Mail module including configuration for Dovecot and Postfix, along with necessary resources such as secrets, config maps, and deployments.
- Added Python script for bcrypt password hashing and integrated it into the Mail module.
- Defined persistent volumes and claims for Seafile module, along with Nginx configuration for serving content.
- Established necessary variables for all modules to ensure flexibility and configurability.
2025-04-27 22:36:18 +02:00
alexandre.pires 58fb1ea167 feat(terraform): remove websites module and add m3uproxy and nginx modules
- Deleted the websites module from the Terraform configuration.
- Introduced a new m3uproxy module with resources for Kubernetes namespace, secrets, config maps, deployments, services, and cron jobs.
- Added configuration files for m3uproxy, including JSON and playlist resources.
- Created a new nginx module with resources for Kubernetes namespace, services, config maps, deployments, and ingress.
- Added necessary variables for both m3uproxy and nginx modules.
- Updated provider configurations for m3uproxy and nginx modules to specify required versions.
2025-04-27 19:40:16 +02:00
alexandre.pires 654cf500f9 feat: Implement MariaDB and backup job modules with configuration and secrets management 2025-04-27 19:12:07 +02:00
alexandre.pires 761c183ce2 feat: Add Kubernetes website module with configuration, resources, and NGINX setup 2025-04-27 19:09:32 +02:00
alexandre.pires 3c7c95c8ee fix: Correct typo in publication description in hugo.yaml 2025-04-27 14:14:05 +02:00
alexandre.pires 89c48246fd fix: Update deployment workflow to use correct hugo_build script and improve logging 2025-04-27 14:09:06 +02:00
alexandre.pires 4e5346e2e0 feat: Enhance website deployment and build process
- Added rsync installation in setup-env action for file synchronization.
- Excluded playbook_websites.yml from ansible-apply-playbook workflow.
- Created a new workflow for building and releasing the Hugo website.
- Added submodule for Hugo theme in .gitmodules.
- Updated host_vars for production to include websites configuration.
- Introduced playbook_websites.yml for managing static files deployment.
- Implemented hugo_build script for building and archiving Hugo sites.
- Updated inventory to include a new web group for website deployment.
- Refactored Terraform configuration to support new website structure.
- Removed deprecated WordPress Terraform configuration.
- Added .gitignore files for websites and specific Hugo site.
- Created archetype and configuration files for the Hugo site.
- Added static assets including CV and images for the Hugo site.
- Integrated Hugo profile theme as a submodule for the website.
2025-04-27 14:03:56 +02:00
alexandre.pires 2fbe4dd1cc Refactor GitHub Actions workflows to standardize job names to 'iac-apply' and 'iac-validate' 2025-04-25 21:47:45 +02:00
alexandre.pires 30e2b0c440 Add GitHub Actions workflows for OpenTofu K8S Apps apply and validate; update S3 backend configuration 2025-04-25 21:44:43 +02:00
alexandre.pires 9ad18067de Remove deprecated Terraform IAC configurations and workflows 2025-04-25 21:37:45 +02:00
alexandre.pires 70988e3cf3 Remove deprecated import block from Contabo IAC configuration 2025-04-25 21:31:23 +02:00
alexandre.pires 53f3ae37cc Remove deprecated import configurations from ClouDNS IAC setup 2025-04-25 21:30:21 +02:00
alexandre.pires 85cbfb51ef Remove unused import configurations from Scaleway IAC setup 2025-04-25 21:28:08 +02:00
alexandre.pires d81590c8a1 Update workflow for OpenTofu Scaleway IAC application with Ansible setup and host info retrieval 2025-04-25 21:26:51 +02:00
alexandre.pires bd8bf86227 Add Scaleway IAC configuration with OpenTofu integration and environment setup 2025-04-25 21:21:19 +02:00
alexandre.pires cc15ff3247 Add Terraform configuration for ClouDNS IAC with OpenTofu integration 2025-04-25 19:51:17 +02:00
alexandre.pires 2d50aa1820 Set output "instances" as sensitive in Contabo IAC configuration 2025-04-25 17:50:58 +02:00
alexandre.pires 9839a3c9c6 Add Contabo IAC configuration and workflows for OpenTofu integration 2025-04-25 17:48:19 +02:00
alexandre.pires 427372da83 Remove obsolete outputs.tf file from AWS infrastructure configuration 2025-04-25 16:44:41 +02:00
alexandre.pires 6975026fc5 Add test step for OpenTofu version validation in CI/CD workflow 2025-04-25 16:42:02 +02:00
alexandre.pires eaf344f159 Add OpenTofu setup action and update workflows for OpenTofu integration 2025-04-25 16:40:39 +02:00
alexandre.pires e9c492d149 Add OpenTofu setup and configuration for AWS infrastructure
- Create action for setting up OpenTofu environment
- Update Terraform workflow to use OpenTofu for infrastructure management
- Modify backend configuration for S3 with new bucket and region
- Add S3 bucket resources with lifecycle configuration
- Update local variables and remove deprecated files
- Include required Python packages for OpenTofu
2025-04-25 16:37:01 +02:00
alexandre.pires 41ee9e0618 Refactor email configuration in Terraform files for improved clarity and consistency 2025-04-24 22:47:25 +02:00
alexandre.pires 835784a7a8 Update Ansible workflow to apply playbooks for Fail2Ban, GeoIP, and Duo Security 2025-04-24 22:27:26 +02:00
alexandre.pires d15ee52a49 Add Fail2Ban configuration for Postfix and create playbooks for Duo Security and GeoIP roles 2025-04-24 22:24:13 +02:00
alexandre.pires b4178c92a2 Add Fail2Ban playbook for Linux hosts 2025-04-24 19:53:59 +02:00
alexandre.pires 558c867bc7 Add fail2ban configuration for Postfix and adjust logging settings 2025-04-24 19:34:28 +02:00
alexandre.pires e980abcb2e Refactor RHEL7 repository installation command for better readability 2025-04-24 19:16:22 +02:00
alexandre.pires 5253d4dd41 Refactor CI/CD setup: streamline Python package installations and add bcrypt hashing for email credentials 2025-04-24 19:15:04 +02:00
alexandre.pires 4b8ad821b4 Update DMARC email address to use admin for a13labs.me and alexpires.me 2025-04-24 09:41:45 +02:00
alexandre.pires 087b5840ff Update DKIM and DMARC configurations for a13labs.me and alexpires.me; add new variables for DKIM values 2025-04-24 09:36:39 +02:00
alexandre.pires 9bbc4262b3 Add DNS records for a13labs.me and update configuration for zone management 2025-04-24 09:28:23 +02:00
alexandre.pires 4abdccef21 Remove unused kodi flags from playlist.json and add new media sources for CNNBrasil and RTPInternacional 2025-04-20 13:39:33 +02:00
alexandre.pires 25698de08f Update playlist.json: add radio tag to ignore_tags for m3upt provider 2025-04-10 23:09:03 +02:00
alexandre.pires e31cb71572 Update m3uproxy configuration: remove replace_triggered_by from lifecycle, add ignore_tags for media and group-title, and modify IPTV sources and priorities 2025-04-10 20:29:34 +02:00
205 changed files with 5987 additions and 2567 deletions
+4 -6
View File
@@ -18,7 +18,7 @@ inputs:
default: "/tmp/ssh_agent.sock"
host-group:
description: "The host group to setup the Ansible environment"
default: "all"
default: "public"
outputs:
ssh-auth-sock:
description: "The SSH_AUTH_SOCK environment variable"
@@ -30,12 +30,10 @@ outputs:
runs:
using: "composite"
steps:
- name: Install Python and required packages
- name: Install required python packages
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y python3-pip
python3 -m pip install -r requirements.txt
python3 -m pip install -r requirements/ansible.txt
- name: Prepare SSH key
shell: bash
@@ -56,7 +54,7 @@ runs:
env:
HOST_GROUP: ${{ inputs.host-group }}
run: |
ansible-inventory -i inventory/hosts --list --yaml $HOST_GROUP | grep -oP '([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}' | sort -u > /tmp/ansible_hosts
ansible-inventory -i inventory/hosts --list --yaml --limit $HOST_GROUP | grep -oP '([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}' | sort -u > /tmp/ansible_hosts
echo "hosts=$(cat /tmp/ansible_hosts)" >> $GITHUB_OUTPUT
- name: Read SSH host keys from remote hosts
+6
View File
@@ -17,3 +17,9 @@ runs:
- name: Setup Sectool
uses: a13labs/setup-sectool@v1
- name: Install Python and required packages
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y python3-pip rsync
@@ -0,0 +1,15 @@
name: Setup OpenTofu Environment
description: Prepare the environment for A13labs CI/CD pipelines
runs:
using: "composite"
steps:
- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: 1.9.1
- name: Install required python packages
shell: bash
run: |
python3 -m pip install -r requirements/opentofu.txt
@@ -8,3 +8,8 @@ runs:
uses: hashicorp/setup-terraform@v1
with:
terraform_version: 1.10.5
- name: Install required python packages
shell: bash
run: |
python3 -m pip install -r requirements/terraform.txt
+7 -3
View File
@@ -29,6 +29,9 @@ jobs:
- name: Setup Terraform environment
uses: ./.github/actions/setup-terraform-env
- name: Setup Tofu environment
uses: ./.github/actions/setup-opentofu-env
- name: Setup Kubernetes Environment
uses: ./.github/actions/setup-k8s-env
with:
@@ -50,7 +53,7 @@ jobs:
env:
ANSIBLE_USER: ${{ secrets.ANSIBLE_USER }}
run: |
ansible -i inventory/hosts -u ${{ secrets.ANSIBLE_USER }} -m ping all
ansible -i inventory/hosts -u ${{ secrets.ANSIBLE_USER }} -m ping public
- name: Test kubectl get nodes
run: |
@@ -60,6 +63,7 @@ jobs:
run: |
terraform --version
- name: Show remote host info
- name: Test opentofu
run: |
echo "System ID: ${{ steps.get-host-info.outputs.system-id }}"
tofu --version
@@ -4,7 +4,9 @@ on:
branches:
- main
paths:
- ansible/host_vars/*.yml
- ansible/host_vars/*.alexpires.me.yml
- ansible/host_vars/*.a13labs.me.yml
- ansible/host_vars/*.a13labs.pt.yml
jobs:
ansible-apply:
runs-on: ubuntu-latest
@@ -38,13 +40,14 @@ jobs:
CHANGED_FILES: ${{ steps.setup_env.outputs.CHANGED_FILES }}
run: |
cd ansible
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_login.yml
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_cis.yml --skip-tags roles::cis::suid
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_fail2ban.yml
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_geoip.yml
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_duo_security.yml
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_encryption.yml
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_microk8s.yml
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_gitea.yml
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_nextcloud.yml
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_wordpress.yml
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_websites.yml
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_m3uproxy.yml
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_monitoring.yml
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_rustdesk.yml
@@ -5,6 +5,8 @@ on:
- main
paths:
- ansible/playbook_*.yml
- '!ansible/playbook_websites.yml'
- '!ansible/playbook_hardening*.yml'
jobs:
ansible-apply:
runs-on: ubuntu-latest
+55
View File
@@ -0,0 +1,55 @@
name: Build and Release Websites
on:
push:
branches:
- main
paths:
- 'ansible/playbook_websites.yml'
- 'bin/hugo_build'
- 'websites/**'
jobs:
build:
name: Build Websites
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
submodules: true
fetch-depth: 0
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: 'latest'
- name: Setup environment
id: setup_env
uses: ./.github/actions/setup-env
- name: Setup Ansible environment
uses: ./.github/actions/setup-ansible-env
with:
project-id: ${{ secrets.BW_PROJECT_ID }}
organization-id: ${{ secrets.BW_ORGANIZATION_ID }}
access-token: ${{ secrets.BW_ACCESS_TOKEN }}
ansible-user: ${{ secrets.ANSIBLE_USER }}
trusted-hosts: ${{ secrets.TRUSTED_HOSTS }}
- name: Run hugo_build command
run: bin/hugo_build
- name: Run the playbook to deploy websites
env:
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }}
ANSIBLE_USER: ${{ secrets.ANSIBLE_USER }}
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
CHANGED_FILES: ${{ steps.setup_env.outputs.CHANGED_FILES }}
run: |
cd ansible
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_websites.yml
@@ -9,7 +9,7 @@ on:
paths:
- "terraform/aws-iac/**"
jobs:
terraform-apply:
iac-apply:
runs-on: ubuntu-latest
steps:
@@ -21,15 +21,15 @@ jobs:
- name: Setup environment
uses: ./.github/actions/setup-env
- name: Setup Terraform environment
uses: ./.github/actions/setup-terraform-env
- name: Setup OpenTofu environment
uses: ./.github/actions/setup-opentofu-env
- name: Terraform Init and Apply
- name: OpenTofu Init and Apply
env:
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }}
run: |
cd terraform/aws-iac
sectool -f ../../sectool.json exec terraform init
sectool -f ../../sectool.json exec terraform apply --auto-approve
sectool -f ../../sectool.json exec tofu init
sectool -f ../../sectool.json exec tofu apply --auto-approve
@@ -11,7 +11,7 @@ on:
- synchronize
- reopened
jobs:
terraform-validate:
iac-validate:
runs-on: ubuntu-latest
steps:
@@ -23,17 +23,17 @@ jobs:
- name: Setup environment
uses: ./.github/actions/setup-env
- name: Setup Terraform environment
uses: ./.github/actions/setup-terraform-env
- name: Setup OpenTofu environment
uses: ./.github/actions/setup-opentofu-env
- name: Terraform Init and Validate
- name: OpenTofu Init and Validate
env:
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }}
run: |
cd terraform/aws-iac
sectool -f ../../sectool.json exec terraform init
sectool -f ../../sectool.json exec terraform validate
sectool -f ../../sectool.json exec terraform fmt -check
sectool -f ../../sectool.json exec terraform plan
sectool -f ../../sectool.json exec tofu init
sectool -f ../../sectool.json exec tofu validate
sectool -f ../../sectool.json exec tofu fmt -check
sectool -f ../../sectool.json exec tofu plan
@@ -0,0 +1,35 @@
name: Terraform CLouDNS IAC Apply
on:
schedule:
- cron: "0 1 * * 0"
push:
branches:
- main
paths:
- "terraform/cloudns-iac/**"
jobs:
iac-apply:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup environment
uses: ./.github/actions/setup-env
- name: Setup OpenTofu environment
uses: ./.github/actions/setup-opentofu-env
- name: OpenTofu Init and Apply
env:
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }}
run: |
cd terraform/cloudns-iac
sectool -f ../../sectool.json exec tofu init
sectool -f ../../sectool.json exec tofu apply --auto-approve
@@ -0,0 +1,39 @@
name: Terraform ClouDNS IAC Validate on Pull Request
on:
pull_request:
branches:
- main
paths:
- "terraform/cloudns-iac/**"
types:
- opened
- synchronize
- reopened
jobs:
iac-validate:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup environment
uses: ./.github/actions/setup-env
- name: Setup OpenTofu environment
uses: ./.github/actions/setup-opentofu-env
- name: OpenTofu Init and Validate
env:
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }}
run: |
cd terraform/cloudns-iac
sectool -f ../../sectool.json exec tofu init
sectool -f ../../sectool.json exec tofu validate
sectool -f ../../sectool.json exec tofu fmt -check
sectool -f ../../sectool.json exec tofu plan
@@ -0,0 +1,35 @@
name: Terraform Contabo IAC Apply
on:
schedule:
- cron: "0 1 * * 0"
push:
branches:
- main
paths:
- "terraform/contabo-iac/**"
jobs:
iac-apply:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup environment
uses: ./.github/actions/setup-env
- name: Setup OpenTofu environment
uses: ./.github/actions/setup-opentofu-env
- name: OpenTofu Init and Apply
env:
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }}
run: |
cd terraform/contabo-iac
sectool -f ../../sectool.json exec tofu init
sectool -f ../../sectool.json exec tofu apply --auto-approve
@@ -0,0 +1,39 @@
name: Terraform Contabo IAC Validate on Pull Request
on:
pull_request:
branches:
- main
paths:
- "terraform/contabo-iac/**"
types:
- opened
- synchronize
- reopened
jobs:
iac-validate:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup environment
uses: ./.github/actions/setup-env
- name: Setup OpenTofu environment
uses: ./.github/actions/setup-opentofu-env
- name: OpenTofu Init and Validate
env:
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }}
run: |
cd terraform/contabo-iac
sectool -f ../../sectool.json exec tofu init
sectool -f ../../sectool.json exec tofu validate
sectool -f ../../sectool.json exec tofu fmt -check
sectool -f ../../sectool.json exec tofu plan
@@ -1,60 +0,0 @@
name: Terraform IAC Validate on Pull Request
on:
pull_request:
branches:
- main
paths:
- "terraform/iac/**"
types:
- opened
- synchronize
- reopened
jobs:
terraform-validate:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup environment
uses: ./.github/actions/setup-env
- name: Setup Ansible environment
uses: ./.github/actions/setup-ansible-env
with:
project-id: ${{ secrets.BW_PROJECT_ID }}
organization-id: ${{ secrets.BW_ORGANIZATION_ID }}
access-token: ${{ secrets.BW_ACCESS_TOKEN }}
ansible-user: ${{ secrets.ANSIBLE_USER }}
host-group: iac
- name: Get Host Info
uses: ./.github/actions/get-host-info
id: get-host-info
with:
project-id: ${{ secrets.BW_PROJECT_ID }}
organization-id: ${{ secrets.BW_ORGANIZATION_ID }}
access-token: ${{ secrets.BW_ACCESS_TOKEN }}
ansible-user: ${{ secrets.ANSIBLE_USER }}
target-host: iac
- name: Setup Terraform environment
uses: ./.github/actions/setup-terraform-env
- name: Terraform Init and Validate
env:
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }}
SYSTEM_ID: ${{ steps.get-host-info.outputs.system-id }}
run: |
cd terraform/iac
export TF_VAR_system_id=$SYSTEM_ID
sectool -f ../../sectool.json exec terraform init
sectool -f ../../sectool.json exec terraform validate
sectool -f ../../sectool.json exec terraform fmt -check
sectool -f ../../sectool.json exec terraform plan
@@ -1,4 +1,4 @@
name: Terraform K8S Apps apply
name: OpenTofu K8S Apps apply
on:
schedule:
@@ -9,7 +9,7 @@ on:
paths:
- "terraform/k8sapps/**"
jobs:
terraform-apply:
iac-apply:
runs-on: ubuntu-latest
steps:
@@ -31,8 +31,8 @@ jobs:
ansible-user: ${{ secrets.ANSIBLE_USER }}
host-group: microk8s
- name: Setup Terraform Environment
uses: ./.github/actions/setup-terraform-env
- name: Setup OpenTofu Environment
uses: ./.github/actions/setup-opentofu-env
- name: Setup Kubernetes Environment
uses: ./.github/actions/setup-k8s-env
@@ -42,7 +42,7 @@ jobs:
access-token: ${{ secrets.BW_ACCESS_TOKEN }}
ansible-user: ${{ secrets.ANSIBLE_USER }}
- name: Terraform Init and Apply
- name: OpenTofu Init and Apply
env:
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
@@ -51,5 +51,5 @@ jobs:
SSH_AUTH_SOCK: ${{ steps.setup_ansible_env.outputs.ssh-auth-sock }}
run: |
cd terraform/k8sapps
sectool -f ../../sectool.json exec terraform init
sectool -f ../../sectool.json exec terraform apply --auto-approve
sectool -f ../../sectool.json exec tofu init
sectool -f ../../sectool.json exec tofu apply --auto-approve
@@ -1,4 +1,4 @@
name: Terraform K8s Apps Validate on Pull Request
name: OpenTofu K8s Apps Validate on Pull Request
on:
pull_request:
@@ -11,7 +11,7 @@ on:
- synchronize
- reopened
jobs:
terraform-validate:
iac-validate:
runs-on: ubuntu-latest
steps:
@@ -33,8 +33,8 @@ jobs:
ansible-user: ${{ secrets.ANSIBLE_USER }}
host-group: microk8s
- name: Setup Terraform Environment
uses: ./.github/actions/setup-terraform-env
- name: Setup OpenTofu Environment
uses: ./.github/actions/setup-opentofu-env
- name: Setup Kubernetes Environment
uses: ./.github/actions/setup-k8s-env
@@ -44,14 +44,14 @@ jobs:
access-token: ${{ secrets.BW_ACCESS_TOKEN }}
ansible-user: ${{ secrets.ANSIBLE_USER }}
- name: Terraform Init and Validate
- name: OpenTofu Init and Validate
env:
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }}
run: |
cd terraform/k8sapps
sectool -f ../../sectool.json exec terraform init
sectool -f ../../sectool.json exec terraform validate
sectool -f ../../sectool.json exec terraform fmt -check
sectool -f ../../sectool.json exec terraform plan
sectool -f ../../sectool.json exec tofu init
sectool -f ../../sectool.json exec tofu validate
sectool -f ../../sectool.json exec tofu fmt -check
sectool -f ../../sectool.json exec tofu plan
@@ -1,4 +1,4 @@
name: Terraform IAC Apply
name: OpenTofu Scaleway IAC Apply
on:
schedule:
@@ -7,9 +7,9 @@ on:
branches:
- main
paths:
- "terraform/iac/**"
- "terraform/scaleway-iac/**"
jobs:
terraform-apply:
iac-apply:
runs-on: ubuntu-latest
steps:
@@ -40,17 +40,17 @@ jobs:
ansible-user: ${{ secrets.ANSIBLE_USER }}
target-host: iac
- name: Setup Terraform environment
uses: ./.github/actions/setup-terraform-env
- name: Setup OpenTofu environment
uses: ./.github/actions/setup-opentofu-env
- name: Terraform Init and Apply
- name: OpenTofu Init and Apply
env:
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }}
SYSTEM_ID: ${{ steps.get-host-info.outputs.system-id }}
run: |
cd terraform/iac
cd terraform/scaleway-iac
export TF_VAR_system_id=$SYSTEM_ID
sectool -f ../../sectool.json exec terraform init
sectool -f ../../sectool.json exec terraform apply --auto-approve
sectool -f ../../sectool.json exec tofu init
sectool -f ../../sectool.json exec tofu apply --auto-approve
@@ -0,0 +1,39 @@
name: Terraform Scaleway IAC Validate on Pull Request
on:
pull_request:
branches:
- main
paths:
- "terraform/scaleway-iac/**"
types:
- opened
- synchronize
- reopened
jobs:
iac-validate:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup environment
uses: ./.github/actions/setup-env
- name: Setup OpenTofu environment
uses: ./.github/actions/setup-opentofu-env
- name: OpenTofu Init and Validate
env:
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }}
run: |
cd terraform/scaleway-iac
sectool -f ../../sectool.json exec tofu init
sectool -f ../../sectool.json exec tofu validate
sectool -f ../../sectool.json exec tofu fmt -check
sectool -f ../../sectool.json exec tofu plan
+1
View File
@@ -42,3 +42,4 @@ drafts/*
.molecule
*.auto.tfvars
dev/*
.ansible
+3
View File
@@ -0,0 +1,3 @@
[submodule "websites/themes/hugo-profile"]
path = websites/themes/hugo-profile
url = https://github.com/gurusabarish/hugo-profile.git
+9
View File
@@ -18,3 +18,12 @@ code DELETE immediately. We have been warned.
# Disable maintenance
./bin/occ maintenance:mode --off
```
# Contabo CLI
Download latest version from [here](https://github.com/contabo/cntb/releases).
Setup:
```
sectool exec cntb get instances --oauth2-clientid="$CONTABO_CLIENT_ID" --oauth2-client-secret="$CONTABO_CLIENT_SECRET" --oauth2-user="$CONTABO_API_USER" --oauth2-password="$CONTABO_API_PASSWORD"
```
-1
View File
@@ -1 +0,0 @@
../repository.vault
@@ -0,0 +1,76 @@
hostname: dev-01.alexpires.local
ansible_user: "{{ lookup('env', 'ANSIBLE_USER') }}"
# Users
login_users:
- username: "{{ ansible_user }}"
comment: "Managed by Ansible"
sudoer: true
sudoer_root_only: true
sudoer_no_password: true
pubkey: "{{ lookup('file', 'keys/ansible_user.pub') }}"
password_disabled: true
- username: operator
comment: "Managed by Ansible"
sudoer: true
pubkey: "{{ lookup('file', 'keys/operator.pub') }}"
# SSH Connection and security
sshd_port: 22
ssh_allowed_networks:
- "0.0.0.0/0"
sshd_admin_net: "0.0.0.0/0"
sshd_allow_groups: "{{ ansible_user }} users"
sshd_permit_root_login: "no"
sshd_password_authentication: "no"
sshd_allow_tcp_forwarding: "yes"
# Due to an issue increase the number of max auth tries
sshd_max_auth_tries: 10
# Firewall ports
ufw_enable: true
fw_allowed_ports:
- { rule: "allow", port: "80", proto: "tcp" }
- { rule: "allow", port: "443", proto: "tcp" }
- { rule: "allow", port: "22", proto: "tcp" }
ufw_outgoing_traffic:
- 22 # SSH
- 53 # DNS
- 80 # HTTP
- 123 # NTP
- 443 # HTTPS
- 853 # DNS over TLS
ufw_default_forward_policy: "ACCEPT"
ipv4_sysctl_settings:
net.ipv4.ip_forward: 1
disable_ipv6: true
# geoip will override hosts_allow and hosts_deny (so it's disabled - CIS hardening)
custom_hosts_acls: true
# fail2ban
fail2ban_jails:
ssh:
enabled: true
port: "{{ sshd_port }}"
filter: "sshd"
logpath: "/var/log/auth.log"
maxretry: 5
findtime: 600
bantime: 3600
# aide
install_aide: false
# Unattended upgrades
unattended_reboot: true
unattended_reboot_time: "04:30"
# Duo Security
duo_users: ["*", "!provision"]
duo_api_hostname: api-7cda1654.duosecurity.com
@@ -93,6 +93,20 @@ fail2ban_jails:
maxretry: 5
findtime: 600
bantime: 3600
postfix:
enabled: true
port: "smtp,ssmtp"
filter: "postfix-k8s"
logpath: "/var/log/postfix/current"
maxretry: 3
findtime: 18000
bantime: -1
fail2ban_filters:
postfix-k8s:
Definition:
failregex: "^.*?postfix/smtps/smtpd\\[\\d+\\]:.*\\[<HOST>\\]: SASL ((?i)LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed.*$"
ignoreregex: ""
# aide
install_aide: true
@@ -124,6 +138,14 @@ encryption_volumes:
mount_service_before: snap.microk8s.daemon-kubelite.service
mount_service_wantedby: snap.microk8s.daemon-kubelite.service
mount_permission: "0755"
encryption_aws_access_key_id: "{{ lookup('env', 'KMS_ACCESS_KEY') }}"
encryption_aws_secret_access_key: "{{ lookup('env', 'KMS_SECRET_KEY') }}"
encryption_kms_arn: "arn:aws:kms:eu-west-1:001604727293:key/977d08fd-8230-40bf-8a4f-d8a3264c5990"
encryption_kms_socket: /var/run/kmsplugin/socket.sock
#audit encryption socker
auditd_encryption_kms_socket: /var/run/kmsplugin/socket.sock
auditd_max_log_file_action: rotate
# Kubernetes specific settings
microk8s_version: 1.29
@@ -135,6 +157,7 @@ microk8s_alt_names: "{{ hostname }}"
microk8s_issuer_email: c.alexandre.pires@alexpires.me
microk8s_encryption_cfg: /mnt/microk8s_config/microk8s_encryption.yaml
microk8s_encryption_secret: "{{ lookup('env', 'MICROK8S_ENCRYPTION_SECRET') }}"
microk8s_encryption_kms_socket: /var/run/kmsplugin/socket.sock
microk8s_users:
- username: operator
enabled: true
@@ -149,3 +172,7 @@ duo_api_hostname: api-7cda1654.duosecurity.com
# Apps
persistent_data: "/mnt/microk8s_persistent"
database_path: "/var/lib"
# Websites
websites:
- "alexpires.me"
-22
View File
@@ -1,22 +0,0 @@
---
- name: CIS Hardening
hosts: linux
gather_facts: true
roles:
- role: "cis"
tags:
- roles
- roles::cis
- role: "fail2ban"
tags:
- roles
- roles::fail2ban
- role: "geoip"
tags:
- roles
- roles::geoip
- role: "duo"
tags:
- roles
- roles::duosecurity
+10
View File
@@ -0,0 +1,10 @@
---
- name: Duo Security
hosts: public
gather_facts: true
roles:
- role: "duo"
tags:
- roles
- roles::duosecurity
+3 -1
View File
@@ -1,6 +1,6 @@
---
- name: Setup encrypted volumes
hosts: linux
hosts: public
gather_facts: true
roles:
@@ -8,3 +8,5 @@
tags:
- roles
- roles::encryption
- roles::encryption::kms
- roles::encryption::volume
+10
View File
@@ -0,0 +1,10 @@
---
- name: Fail2Ban
hosts: public
gather_facts: true
roles:
- role: "fail2ban"
tags:
- roles
- roles::fail2ban
+10
View File
@@ -0,0 +1,10 @@
---
- name: Fail2Ban
hosts: public
gather_facts: true
roles:
- role: "geoip"
tags:
- roles
- roles::geoip
@@ -1,6 +1,6 @@
---
- name: CIS Hardening
hosts: localnetwork
hosts: hardening
gather_facts: true
roles:
@@ -1,6 +1,6 @@
---
- name: Login setup
hosts: linux
hosts: all
gather_facts: true
roles:
@@ -1,28 +1,28 @@
---
- name: Wordpress Playbook (K8s)
hosts: wordpress
- name: SFTPGo Playbook (K8s)
hosts: sftpgo
gather_facts: true
# Specific tasks for this playbook
tasks:
- name: Set required facts
ansible.builtin.set_fact:
wordpress_home: "{{ persistent_data | default('/var/lib') }}/wordpress"
wordpress_mysql_home: "{{ database_path | default('/var/lib') }}/mysql.wordpress"
wordpress_user_id: 33
wordpress_group_id: 26
sftpgo_home: "{{ persistent_data | default('/var/lib') }}/sftpgo"
sftpgo_mysql_home: "{{ database_path | default('/var/lib') }}/mysql.sftpgo"
sftpgo_user_id: 1000
sftpgo_group_id: 1000
mysql_user_id: 999
mysql_group_id: 107
tags: always
- name: Create required wordpress data folder
- name: Create required sftpgo data folder
become: true
ansible.builtin.file:
state: directory
path: "{{ wordpress_home }}"
path: "{{ sftpgo_home }}"
mode: "0750"
owner: "{{ wordpress_user_id }}"
group: "{{ wordpress_group_id }}"
owner: "{{ sftpgo_user_id }}"
group: "{{ sftpgo_group_id }}"
tags:
- tasks
- tasks::folders
@@ -31,8 +31,8 @@
become: true
ansible.builtin.file:
state: directory
path: "{{ wordpress_mysql_home }}"
mode: "0750"
path: "{{ sftpgo_mysql_home }}"
mode: "0755"
owner: "{{ mysql_user_id }}"
group: "{{ mysql_group_id }}"
tags:
+28
View File
@@ -0,0 +1,28 @@
---
- name: Trivy Playbook (K8s)
hosts: trivy
gather_facts: true
# Specific tasks for this playbook
tasks:
- name: Set required facts
ansible.builtin.set_fact:
trivy_home: "{{ persistent_data | default('/var/lib') }}/trivy"
trivy_user_id: 1000
trivy_group_id: 1000
tags: always
- name: Create required trivy data folder
become: true
ansible.builtin.file:
state: directory
path: "{{ item }}"
mode: "0750"
owner: "{{ trivy_user_id }}"
group: "{{ trivy_group_id }}"
with_items:
- "{{ trivy_home }}"
- "{{ trivy_home }}/cache"
tags:
- tasks
- tasks::folders
+50
View File
@@ -0,0 +1,50 @@
---
- name: Websites (Static Files) Playbook (K8s)
hosts: web
gather_facts: true
# Specific tasks for this playbook
tasks:
- name: Set required facts
ansible.builtin.set_fact:
web_home: "{{ persistent_data | default('/var/lib') }}/web"
web_user_id: 1000
web_group_id: 1000
tags: always
- name: Create required web data folder
become: true
ansible.builtin.file:
state: directory
path: "{{ web_home }}"
mode: "0750"
owner: "{{ web_user_id }}"
group: "{{ web_group_id }}"
tags:
- tasks
- tasks::folders
- name: Create required web data folder
become: true
ansible.builtin.file:
state: directory
path: "{{ web_home }}/{{ item }}"
mode: "0750"
owner: "{{ web_user_id }}"
group: "{{ web_group_id }}"
with_items:
- "{{ websites | default([]) }}"
tags:
- tasks
- tasks::folders
- name: Synchronize websites
become: true
ansible.posix.synchronize:
mode: push
src: "{{ lookup('env', 'GITHUB_WORKSPACE') + '/websites/releases/' + item }}/"
dest: "{{ web_home }}/{{ item }}"
delete: true
recursive: true
with_items:
- "{{ websites | default([]) }}"
+1 -1
View File
@@ -10,6 +10,6 @@ auditd_mode: 1
auditd_num_logs: 5
auditd_space_left: 75
auditd_space_left_action: email
auditd_encryption_kms_socket:
grub_audit_backlog_cmdline: audit_backlog_limit=8192
grub_audit_cmdline: audit=1
...
+4 -1
View File
@@ -199,7 +199,10 @@
- name: Install Extras and HA for RHEL7
become: true
ansible.builtin.command: subscription-manager repos --enable "rhel-*-optional-rpms" --enable "rhel-*-extras-rpms" --enable "rhel-ha-for-rhel-*-server-rpms"
ansible.builtin.command: >
subscription-manager repos --enable "rhel-*-optional-rpms"
--enable "rhel-*-extras-rpms"
--enable "rhel-ha-for-rhel-*-server-rpms"
changed_when: false
tags:
- dnf
@@ -150,6 +150,11 @@
-w /usr/sbin/runc -p rwxa -k docker
-w /var/run/docker.sock -p rwxa -k docker
{% if auditd_encryption_kms_socket is defined %}
# AWS encryption provider
-w {{ auditd_encryption_kms_socket | dirname }} -p rwxa -k aws-encryption-provider
{% endif %}
# Group modifications
-w /etc/group -p wa -k group-modification
-w /etc/gshadow -p wa -k group-modification
@@ -2,3 +2,9 @@
encryption_volumes: []
encryption_volumes_path: /var/lib/encrypted_volumes
encryption_volumes_default_size: 1G
encryption_aws_access_key_id:
encryption_aws_secret_access_key:
encryption_kms_arn:
encryption_kms_region: eu-west-1
encryption_kms_socket: /var/run/kmsplugin/socket.sock
Binary file not shown.
+57
View File
@@ -0,0 +1,57 @@
- name: Check if required facts are set
ansible.builtin.fail:
msg: "The following variables are required: encryption_aws_access_key_id, encryption_aws_secret_access_key, encryption_kms_arn"
when:
- encryption_aws_access_key_id is not defined
- encryption_aws_secret_access_key is not defined
- encryption_kms_arn is not defined
- name: Copy aws-encryption-provider binary to the host
become: true
ansible.builtin.copy:
src: aws-encryption-provider
dest: /usr/local/bin/aws-encryption-provider
mode: '0755'
- name: Copy start script to the host
become: true
ansible.builtin.template:
src: start-encryption-provider.sh.j2
dest: /usr/local/bin/start-encryption-provider.sh
mode: '0755'
owner: root
group: root
- name: Create KMS socket directory
become: true
ansible.builtin.file:
path: /var/run/kmsplugin
state: directory
mode: '0755'
owner: root
group: root
- name: Create systemd service file for aws-encryption-provider
become: true
ansible.builtin.template:
src: aws-encryption-provider.service.j2
dest: /etc/systemd/system/aws-encryption-provider.service
mode: '0644'
- name: Reload systemd daemon
become: true
ansible.builtin.systemd:
daemon_reload: true
name: aws-encryption-provider
- name: Enable aws-encryption-provider service
become: true
ansible.builtin.systemd:
name: aws-encryption-provider
enabled: true
- name: Start aws-encryption-provider service
become: true
ansible.builtin.systemd:
name: aws-encryption-provider
state: started
+16
View File
@@ -5,8 +5,12 @@
name:
- cryptsetup
- curl
- libc6
state: present
when: ansible_os_family == 'Debian'
tags:
- roles::encryption::packages
- roles::encryption::volume
- name: Create folder to store volume
become: true
@@ -14,6 +18,8 @@
path: "{{ encryption_volumes_path }}"
state: directory
mode: "0750"
tags:
- roles::encryption::volume
- name: Copy required scripts
become: true
@@ -24,9 +30,19 @@
with_items:
- "open_volume"
- "read_system_id"
tags:
- roles::encryption::volume
- name: Create encrypted volumes
ansible.builtin.include_tasks: volume.yml
loop: "{{ encryption_volumes }}"
loop_control:
loop_var: item
tags:
- roles::encryption::volume
- name: Create KMS service
ansible.builtin.include_tasks: kms.yml
when: encryption_aws_access_key_id is defined and encryption_aws_secret_access_key is defined and encryption_kms_arn is defined
tags:
- roles::encryption::kms
+5 -32
View File
@@ -44,6 +44,7 @@
- name: Read system id
ansible.builtin.command: |
read_system_id
changed_when: false
register: system_id
- name: Download key file from Key server
@@ -88,45 +89,17 @@
- name: Create service to fetch key file and open LUKS device
become: true
ansible.builtin.copy:
ansible.builtin.template:
src: key_fetch.service.j2
dest: /etc/systemd/system/{{ key_fetch_service }}
mode: "0644"
content: |
[Unit]
Description={{ item.name }} key fetch service
After={{ fetch_key_service_after }}
Before={{ fetch_key_service_before }}
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/local/bin/open_volume "{{ key_server }}" {{ disk_image_path }} {{ device_name }}
ExecStop=/usr/sbin/cryptsetup close {{ device_name }}
[Install]
WantedBy={{ fetch_key_service_wantedby }}
- name: Create service to mount the local filesystem
become: true
ansible.builtin.copy:
ansible.builtin.template:
src: mount.service.j2
dest: /etc/systemd/system/{{ mount_service }}
mode: "0644"
content: |
[Unit]
Description={{ item.name }} mount service
After={{ key_fetch_service }}
Requires={{ key_fetch_service }}
Before={{ mount_service_before }}
[Mount]
What=/dev/mapper/{{ device_name }}
Where={{ mount_point }}
Type=ext4
Options=defaults
[Install]
WantedBy={{ mount_service_wantedby }}
- name: Reload systemd daemon
become: true
@@ -0,0 +1,13 @@
[Unit]
Description=AWS Encryption Provider
After=network.target
Before=snap.microk8s.daemon-kubelite.service
[Service]
Type=simple
ExecStart=/usr/local/bin/start-encryption-provider.sh
Restart=on-failure
User=root
[Install]
WantedBy=snap.microk8s.daemon-kubelite.service
@@ -0,0 +1,13 @@
[Unit]
Description={{ item.name }} key fetch service
After={{ fetch_key_service_after }}
Before={{ fetch_key_service_before }}
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/local/bin/open_volume "{{ key_server }}" {{ disk_image_path }} {{ device_name }}
ExecStop=/usr/sbin/cryptsetup close {{ device_name }}
[Install]
WantedBy={{ fetch_key_service_wantedby }}
@@ -0,0 +1,14 @@
[Unit]
Description={{ item.name }} mount service
After={{ key_fetch_service }}
Requires={{ key_fetch_service }}
Before={{ mount_service_before }}
[Mount]
What=/dev/mapper/{{ device_name }}
Where={{ mount_point }}
Type=ext4
Options=defaults
[Install]
WantedBy={{ mount_service_wantedby }}
@@ -0,0 +1,8 @@
#!/bin/bash
# This script is used to start the encryption provider for the application.
# Managed by Ansible.
export AWS_ACCESS_KEY_ID={{ encryption_aws_access_key_id }}
export AWS_SECRET_ACCESS_KEY={{ encryption_aws_secret_access_key }}
mkdir {{ encryption_kms_socket_dir | dirname }} }} 2>/dev/null || true
chmod 700 {{ encryption_kms_socket_dir | dirname }} 2>/dev/null
/usr/local/bin/aws-encryption-provider --key={{ encryption_kms_arn }} --region={{ encryption_kms_region }} --listen={{ encryption_kms_socket }}
+2 -1
View File
@@ -6,7 +6,7 @@ microk8s_lb_provider: "metallb"
microk8s_lb_ips: "10.2.0.40-10.2.0.49"
microk8s_lb_http_port: 80
microk8s_lb_https_port: 443
microk8s_metallb_version: 0.14.5
microk8s_metallb_version: 0.14.9
# certificate manager
microk8s_issuer_email: webmaster@localhost.localdomain
@@ -39,3 +39,4 @@ microk8s_iac_user: "provision"
microk8s_encryption_secret: "a13labs"
microk8s_encryption_cfg: "/etc/microk8s_encryption.yaml"
microk8s_encryption_kms_socket:
@@ -7,21 +7,8 @@
- name: Create encryption configuration
become: true
ansible.builtin.copy:
content: |
---
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
providers:
- aescbc:
keys:
- name: k8s-crypto
secret: {{ microk8s_encryption_secret }}
- identity: {}
ansible.builtin.template:
src: encryption-provider-config.yml.j2
dest: "{{ microk8s_encryption_cfg }}"
mode: "0600"
@@ -0,0 +1,20 @@
---
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
providers:
{% if microk8s_encryption_kms_socket is defined %}
- kms:
apiVersion: v2
name: aws-encryption-provider
endpoint: unix://{{ microk8s_encryption_kms_socket }}
timeout: 3s
{% endif %}
- aescbc:
keys:
- name: k8s-crypto
secret: {{ microk8s_encryption_secret }}
- identity: {}
+3
View File
@@ -7,3 +7,6 @@ USER_PASSWORD_OPERATOR=$USER_PASSWORD_OPERATOR
ANSIBLE_FORCE_COLOR=True
BUCKET_SUFFIX=$BUCKET_SUFFIX
MICROK8S_ENCRYPTION_SECRET=$MICROK8S_ENCRYPTION_SECRET
KMS_ACCESS_KEY=$KMS_ACCESS_KEY
KMS_SECRET_KEY=$KMS_SECRET_KEY
KMS_KEY_ARN=$KMS_KEY_ARN
Executable
+34
View File
@@ -0,0 +1,34 @@
#!/bin/bash
# This script is used to build a Hugo site and prepare it for deployment.
GITHUB_WORKSPACE=${GITHUB_WORKSPACE:-$(pwd)}
command -v hugo >/dev/null 2>&1 || { echo >&2 "Hugo is not installed. Please install Hugo to use this script."; exit 1; }
mkdir -p "$GITHUB_WORKSPACE/websites/releases"
for dir in $(find "$GITHUB_WORKSPACE/websites" -maxdepth 1 -type d | grep -vE '^\.$'); do
if [ "$dir" == "$GITHUB_WORKSPACE/websites" ]; then
echo "Skipping $dir"
continue
fi
if [ "$dir" == "$GITHUB_WORKSPACE/websites/themes" ]; then
echo "Skipping $dir"
continue
fi
if [ "$dir" == "$GITHUB_WORKSPACE/websites/releases" ]; then
echo "Skipping $dir"
continue
fi
if [ -d "$dir" ]; then
echo "Building Hugo site in $dir"
cd "$dir" || exit 1
hugo --minify --themesDir $GITHUB_WORKSPACE/websites/themes --destination $GITHUB_WORKSPACE/websites/releases/$(basename "$dir") --baseURL "https://$(basename "$dir").example.com"
if [ $? -ne 0 ]; then
echo "Hugo build failed in $dir"
exit 1
fi
echo "Hugo site built successfully in $dir"
else
echo "$dir is not a directory, skipping..."
fi
done
+1 -1
View File
@@ -24,7 +24,7 @@ def parse_ansible_inventory(inventory_file):
return inventory_dict
parser = argparse.ArgumentParser(description='Run a command on a group of hosts')
parser = argparse.ArgumentParser(description='Get host system ID')
parser.add_argument('group', type=str, help='Group of hosts to run the command on')
parser.add_argument('host', type=str, help='Host to run the command on', default=None, nargs='?')
args = parser.parse_args()
+18 -3
View File
@@ -1,19 +1,28 @@
[all]
prod-01.alexpires.me
dev-01.alexpires.dev
[linux]
[hardening]
prod-01.alexpires.me
dev-01.alexpires.dev
[ubuntu]
prod-01.alexpires.me
dev-01.alexpires.dev
[public]
prod-01.alexpires.me
[private]
dev-01.alexpires.dev
[gitea]
prod-01.alexpires.me
[wordpress]
[nextcloud]
prod-01.alexpires.me
[nextcloud]
[sftpgo]
prod-01.alexpires.me
[m3uproxy]
@@ -33,3 +42,9 @@ prod-01.alexpires.me
[mail]
prod-01.alexpires.me
[web]
prod-01.alexpires.me
[trivy]
prod-01.alexpires.me
+1
View File
@@ -0,0 +1 @@
bcrypt
+1
View File
@@ -0,0 +1 @@
bcrypt
+10
View File
@@ -0,0 +1,10 @@
AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY
AWS_SECRET_ACCESS_KEY=$AWS_SECRET_KEY
CONTABO_CLIENT_ID=$CONTABO_CLIENT_ID
CONTABO_CLIENT_SECRET=$CONTABO_CLIENT_SECRET
CONTABO_API_USER=$CONTABO_USER_NAME
CONTABO_API_PASSWORD=$CONTABO_API_PASSWORD
SCW_ACCESS_KEY=$SCALEWAY_ACCESS_KEY
SCW_SECRET_KEY=$SCALEWAY_SECRET_KEY
SCW_DEFAULT_PROJECT_ID=$SCALEWAY_PROJECT_ID
SCW_DEFAULT_ORGANIZATION_ID=$SCALEWAY_ORGANIZATION_ID
-1
View File
@@ -1 +0,0 @@
../../repository.vault
+3 -3
View File
@@ -1,7 +1,7 @@
terraform {
backend "s3" {
bucket = "a13labs.infra"
key = "aws-alarms.tfstate"
region = "us-east-1"
bucket = "a13labs.infra.eu"
key = "aws.core.infra.tfstate"
region = "eu-west-1"
}
}
+51
View File
@@ -0,0 +1,51 @@
resource "aws_s3_bucket" "infra_bucket" {
bucket = "a13labs.infra.eu"
force_destroy = true
}
resource "aws_s3_bucket_public_access_block" "infra_bucket" {
bucket = aws_s3_bucket.infra_bucket.id
block_public_acls = true
ignore_public_acls = true
block_public_policy = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_versioning" "infra_bucket" {
bucket = aws_s3_bucket.infra_bucket.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_lifecycle_configuration" "infra_bucket" {
bucket = aws_s3_bucket.infra_bucket.id
rule {
id = "clenaup"
status = "Enabled"
filter {
prefix = "/"
}
expiration {
days = 30
}
}
}
import {
id = "a13labs.infra.eu"
to = aws_s3_bucket.infra_bucket
}
import {
id = "a13labs.infra.eu"
to = aws_s3_bucket_public_access_block.infra_bucket
}
import {
id = "a13labs.infra.eu"
to = aws_s3_bucket_versioning.infra_bucket
}
+22 -2
View File
@@ -1,5 +1,25 @@
locals {
region = "us-east-1"
billing_alarm_limit = 20
billing_alarm_emails = "c.alexandre.pires@gmail.com"
billing_alarm_emails = "c.alexandre.pires@alexpires.me"
instance_ips = [
"${local.vps_1.ip}/32",
]
vps_1 = {
id = data.terraform_remote_state.contabo.outputs.instances[0].id
name = data.terraform_remote_state.contabo.outputs.instances[0].name
ip = data.terraform_remote_state.contabo.outputs.instances[0].ip_config[0].v4[0].ip
}
}
data "terraform_remote_state" "contabo" {
backend = "s3"
config = {
bucket = "a13labs.infra.eu"
key = "contabo.core.infra.tfstate"
region = "eu-west-1"
}
}
data "aws_caller_identity" "current" {}
+83
View File
@@ -0,0 +1,83 @@
data "aws_iam_policy_document" "kms_key_policy" {
statement {
sid = "Enable IAM User Permissions"
effect = "Allow"
actions = ["kms:*"]
resources = ["*"]
principals {
type = "AWS"
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
}
}
statement {
sid = "Allow IAM User Access"
effect = "Allow"
actions = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
resources = ["*"]
principals {
type = "AWS"
identifiers = [aws_iam_user.k8s_secrets_user.arn]
}
condition {
# Only allow from specific IP addresses
test = "IpAddress"
variable = "aws:SourceIp"
values = ["${join(",", local.instance_ips)}"]
}
}
}
resource "aws_kms_key" "k8s_secrets" {
description = "KMS key for encrypting Kubernetes secrets"
deletion_window_in_days = 30
enable_key_rotation = true
policy = data.aws_iam_policy_document.kms_key_policy.json
}
resource "aws_iam_user" "k8s_secrets_user" {
name = "alexpires-me-microk8s"
}
resource "aws_iam_access_key" "k8s_secrets_user_key" {
user = aws_iam_user.k8s_secrets_user.name
}
data "aws_iam_policy_document" "k8s_secrets_user_policy" {
statement {
effect = "Allow"
actions = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
resources = [aws_kms_key.k8s_secrets.arn]
condition {
# Only allow from specific IP addresses
test = "IpAddress"
variable = "aws:SourceIp"
values = ["${join(",", local.instance_ips)}"]
}
}
}
resource "aws_iam_user_policy" "k8s_secrets_user_policy" {
name = "alexpires-me-microk8s-policy"
user = aws_iam_user.k8s_secrets_user.name
policy = data.aws_iam_policy_document.k8s_secrets_user_policy.json
}
-17
View File
@@ -1,17 +0,0 @@
#
# Copyright 2019 Alexandre Pires (alexandre.pires@mov.ai)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# File: outputs.tf
+1 -1
View File
@@ -1,4 +1,4 @@
variable "region" {
description = "AWS Default region"
default = "us-east-1"
default = "eu-west-1"
}
-3
View File
@@ -1,3 +0,0 @@
terraform {
required_version = ">= 0.13"
}
+7
View File
@@ -0,0 +1,7 @@
terraform {
backend "s3" {
bucket = "a13labs.infra.eu"
key = "cloudns.core.infra.tfstate"
region = "eu-west-1"
}
}
+202
View File
@@ -0,0 +1,202 @@
locals {
vps_1 = {
id = data.terraform_remote_state.contabo.outputs.instances[0].id
name = data.terraform_remote_state.contabo.outputs.instances[0].name
ip = data.terraform_remote_state.contabo.outputs.instances[0].ip_config[0].v4[0].ip
}
default_ttl = "3600"
domains = {
"a13labs.me" = [
{
type = "A"
value = local.vps_1.ip
},
{
type = "MX"
priority = "10"
value = "mail-pt.securemail.pro"
},
{
type = "TXT"
value = "v=spf1 include:_spf.tem.scaleway.com include:spf.webapps.net ~all"
},
{
name = "imap"
type = "CNAME"
value = "${local.vps_1.name}.a13labs.me"
},
{
name = "mail"
type = "CNAME"
value = "mail-pt.securemail.pro"
},
{
name = "smtp"
type = "CNAME"
value = "${local.vps_1.name}.a13labs.me"
},
{
name = "_dmarc"
type = "TXT"
value = "v=DMARC1; p=none; rua=mailto:admin@a13labs.me"
},
{
name = local.vps_1.name
type = "A"
value = local.vps_1.ip
},
{
name = "_imap._tcp"
type = "SRV"
priority = "0"
weight = "1"
port = "993"
value = "imap.a13labs.me"
},
{
name = "_smtp._tcp"
type = "SRV"
priority = "0"
weight = "1"
port = "465"
value = "smtp.a13labs.me"
},
{
name = "${var.scaleway_dkim_key}._domainkey"
type = "TXT"
value = "v=DKIM1; h=sha256; k=rsa; p=${var.a13labs_me_scaleway_dkim_value}"
},
],
"alexpires.me" = [
{
type = "A"
value = local.vps_1.ip
},
{
name = ""
type = "MX"
priority = "10"
value = "mail-pt.securemail.pro"
},
{
type = "TXT"
value = "v=spf1 include:_spf.tem.scaleway.com include:spf.webapps.net ~all"
},
{
name = "tv"
type = "CNAME"
value = "${local.vps_1.name}.alexpires.me"
},
{
name = "www"
type = "CNAME"
value = "${local.vps_1.name}.alexpires.me"
},
{
name = "blog"
type = "CNAME"
value = "${local.vps_1.name}.alexpires.me"
},
{
name = "code"
type = "CNAME"
value = "${local.vps_1.name}.alexpires.me"
},
{
name = "imap"
type = "CNAME"
value = "${local.vps_1.name}.alexpires.me"
},
{
name = "mail"
type = "CNAME"
value = "mail-pt.securemail.pro"
},
{
name = "smtp"
type = "CNAME"
value = "${local.vps_1.name}.alexpires.me"
},
{
name = "cloud"
type = "CNAME"
value = "${local.vps_1.name}.alexpires.me"
},
{
name = "_dmarc"
type = "TXT"
value = "v=DMARC1; p=none; rua=mailto:admin@alexpires.me"
},
{
name = "prod-01"
type = "CNAME"
value = "${local.vps_1.name}.alexpires.me"
},
{
name = "_keybase"
type = "TXT"
value = "keybase-site-verification=${var.keybase_site_verification}"
},
{
name = "rustdesk"
type = "CNAME"
value = "${local.vps_1.name}.alexpires.me"
},
{
name = local.vps_1.name
type = "A"
value = local.vps_1.ip
},
{
name = "_imap._tcp"
type = "SRV"
priority = "0"
weight = "1"
port = "993"
value = "imap.alexpires.me"
},
{
name = "_smtp._tcp"
type = "SRV"
priority = "0"
weight = "1"
port = "465"
value = "smtp.alexpires.me"
},
{
name = "${var.scaleway_dkim_key}._domainkey"
type = "TXT"
value = "v=DKIM1; h=sha256; k=rsa; p=${var.alexpires_me_scaleway_dkim_value}"
},
{
name = "webdav"
type = "CNAME"
value = "${local.vps_1.name}.alexpires.me"
},
]
}
records = flatten([for domain, records in local.domains : [
for record in records : {
name = lookup(record, "name", "")
zone = domain
type = record.type
value = record.value
priority = lookup(record, "priority", null)
weight = lookup(record, "weight", null)
port = lookup(record, "port", null)
}
]])
}
data "terraform_remote_state" "contabo" {
backend = "s3"
config = {
bucket = "a13labs.infra.eu"
key = "contabo.core.infra.tfstate"
region = "eu-west-1"
}
}
+14
View File
@@ -0,0 +1,14 @@
terraform {
required_version = "~>1.8"
required_providers {
cloudns = {
source = "ClouDNS/cloudns"
version = "~>1.0"
}
}
}
provider "cloudns" {
auth_id = var.cloudns_auth_id
password = var.cloudns_password
}
+26
View File
@@ -0,0 +1,26 @@
resource "cloudns_dns_zone" "zones" {
for_each = local.domains
domain = each.key
type = "master"
}
import {
for_each = local.domains
to = cloudns_dns_zone.zones[each.key]
id = each.key
}
resource "cloudns_dns_record" "records" {
for_each = {
for i, record in local.records :
i => record
}
name = each.value.name
zone = each.value.zone
type = each.value.type
value = each.value.value
priority = lookup(each.value, "priority", null)
weight = lookup(each.value, "weight", null)
port = lookup(each.value, "port", null)
ttl = lookup(each.value, "ttl", local.default_ttl)
}
+8
View File
@@ -0,0 +1,8 @@
AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY
AWS_SECRET_ACCESS_KEY=$AWS_SECRET_KEY
TF_VAR_cloudns_auth_id=$CLOUDNS_AUTH_ID
TF_VAR_cloudns_password=$CLOUDNS_PASSWORD
TF_VAR_scaleway_dkim_key=$SCALEWAY_DKIM_KEY
TF_VAR_alexpires_me_scaleway_dkim_value=$ALEXPIRES_ME_SCALEWAY_DKIM_VALUE
TF_VAR_a13labs_me_scaleway_dkim_value=$A13LABS_ME_SCALEWAY_DKIM_VALUE
TF_VAR_keybase_site_verification=$KEYBASE_SITE_VERIFICATION
+36
View File
@@ -0,0 +1,36 @@
variable "cloudns_auth_id" {
description = "Cloudns Auth ID"
type = string
sensitive = true
}
variable "cloudns_password" {
description = "Cloudns Password"
type = string
sensitive = true
}
variable "scaleway_dkim_key" {
description = "Scaleway DKIM key"
type = string
sensitive = true
}
variable "alexpires_me_scaleway_dkim_value" {
description = "Scaleway DKIM value (alexpires.me)"
type = string
sensitive = true
}
variable "a13labs_me_scaleway_dkim_value" {
description = "Scaleway DKIM value (a13labs.me)"
type = string
sensitive = true
}
variable "keybase_site_verification" {
description = "Keybase site verification"
type = string
sensitive = true
}
+7
View File
@@ -0,0 +1,7 @@
terraform {
backend "s3" {
bucket = "a13labs.infra.eu"
key = "contabo.core.infra.tfstate"
region = "eu-west-1"
}
}
+3
View File
@@ -0,0 +1,3 @@
resource "contabo_instance" "vps_1" {
}
+18
View File
@@ -0,0 +1,18 @@
output "instances" {
value = [
{
cpu_cores = contabo_instance.vps_1.cpu_cores
disk_mb = contabo_instance.vps_1.disk_mb
id = contabo_instance.vps_1.id
image_id = contabo_instance.vps_1.image_id
ip_config = contabo_instance.vps_1.ip_config
mac_address = contabo_instance.vps_1.mac_address
name = contabo_instance.vps_1.name
os_type = contabo_instance.vps_1.os_type
ram_mb = contabo_instance.vps_1.ram_mb
v_host_id = contabo_instance.vps_1.v_host_id
},
]
description = "VPS instances details"
sensitive = true
}
+17
View File
@@ -0,0 +1,17 @@
terraform {
required_version = "~>1.8"
required_providers {
contabo = {
source = "contabo/contabo"
version = ">= 0.1.31"
}
}
}
provider "contabo" {
oauth2_client_id = var.contabo_client_id
oauth2_client_secret = var.contabo_client_secret
oauth2_user = var.contabo_api_user
oauth2_pass = var.contabo_api_password
}
+6
View File
@@ -0,0 +1,6 @@
AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY
AWS_SECRET_ACCESS_KEY=$AWS_SECRET_KEY
TF_VAR_contabo_client_id=$CONTABO_CLIENT_ID
TF_VAR_contabo_client_secret=$CONTABO_CLIENT_SECRET
TF_VAR_contabo_api_password=$CONTABO_API_PASSWORD
TF_VAR_contabo_api_user=$CONTABO_USER_NAME
+23
View File
@@ -0,0 +1,23 @@
variable "contabo_client_id" {
description = "Contabo Client ID"
type = string
sensitive = true
}
variable "contabo_client_secret" {
description = "Contabo Client Secret"
type = string
sensitive = true
}
variable "contabo_api_password" {
description = "Contabo API Password"
type = string
sensitive = true
}
variable "contabo_api_user" {
description = "Contabo API User"
type = string
sensitive = true
}
-1
View File
@@ -1 +0,0 @@
../../repository.vault
-150
View File
@@ -1,150 +0,0 @@
resource "cloudns_dns_record" "alexpires_me_microk8s" {
name = local.contabo_instance.name
zone = local.alexpires_me_zone
type = "A"
value = local.contabo_instance.ip
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_code" {
name = "code"
zone = local.alexpires_me_zone
type = "CNAME"
value = "${cloudns_dns_record.alexpires_me_microk8s.name}.${local.alexpires_me_zone}"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_cloud" {
name = "cloud"
zone = local.alexpires_me_zone
type = "CNAME"
value = "${cloudns_dns_record.alexpires_me_microk8s.name}.${local.alexpires_me_zone}"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_tv" {
name = "tv"
zone = local.alexpires_me_zone
type = "CNAME"
value = "${cloudns_dns_record.alexpires_me_microk8s.name}.${local.alexpires_me_zone}"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_blog" {
name = "blog"
zone = local.alexpires_me_zone
type = "CNAME"
value = "${cloudns_dns_record.alexpires_me_microk8s.name}.${local.alexpires_me_zone}"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_www" {
name = "www"
zone = local.alexpires_me_zone
type = "CNAME"
value = "${cloudns_dns_record.alexpires_me_microk8s.name}.${local.alexpires_me_zone}"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_rustdesk" {
name = "rustdesk"
zone = local.alexpires_me_zone
type = "CNAME"
value = "${cloudns_dns_record.alexpires_me_microk8s.name}.${local.alexpires_me_zone}"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_prod_01" {
name = "prod-01"
zone = local.alexpires_me_zone
type = "CNAME"
value = "${cloudns_dns_record.alexpires_me_microk8s.name}.${local.alexpires_me_zone}"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_imaps" {
name = "imap"
zone = local.alexpires_me_zone
type = "CNAME"
value = "${cloudns_dns_record.alexpires_me_microk8s.name}.${local.alexpires_me_zone}"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_smtps" {
name = "smtp"
zone = local.alexpires_me_zone
type = "CNAME"
value = "${cloudns_dns_record.alexpires_me_microk8s.name}.${local.alexpires_me_zone}"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_root" {
name = ""
zone = local.alexpires_me_zone
type = "A"
value = local.contabo_instance.ip
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_spf" {
name = ""
zone = local.alexpires_me_zone
type = "TXT"
value = "v=spf1 include:_spf.tem.scaleway.com include:spf.webapps.net ~all"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_dkim" {
name = "${var.scaleway_dkim_key}._domainkey"
zone = local.alexpires_me_zone
type = "TXT"
value = "v=DKIM1; h=sha256; k=rsa; p=${var.scaleway_dkim_value}"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_dmarc" {
name = "_dmarc"
zone = local.alexpires_me_zone
type = "TXT"
value = "v=DMARC1; p=none; rua=mailto:admin@${local.alexpires_me_zone}"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_mx" {
name = ""
zone = local.alexpires_me_zone
type = "MX"
priority = "10"
value = "mail-pt.securemail.pro"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_mail" {
name = "mail"
zone = local.alexpires_me_zone
type = "CNAME"
value = "mail-pt.securemail.pro"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_mail_smtp_srv" {
name = "_smtp._tcp"
zone = local.alexpires_me_zone
type = "SRV"
priority = 0
weight = 1
port = 465
value = "smtp.${local.alexpires_me_zone}"
ttl = "3600"
}
resource "cloudns_dns_record" "alexpires_me_mail_imap_srv" {
name = "_imap._tcp"
zone = local.alexpires_me_zone
type = "SRV"
priority = 0
weight = 1
port = 993
value = "imap.${local.alexpires_me_zone}"
ttl = "3600"
}
-7
View File
@@ -1,7 +0,0 @@
terraform {
backend "s3" {
bucket = "a13labs.infra"
key = "a13labs-iac.tfstate"
region = "us-east-1"
}
}
-6
View File
@@ -1,6 +0,0 @@
locals {
instance_ips = [
"${local.contabo_instance.ip}/32",
]
alexpires_me_zone = "alexpires.me"
}
-14
View File
@@ -1,14 +0,0 @@
# Contabo is down for now, so we can't use it for now
# data "contabo_instance" "microk8s" {
# id = "201912751"
# }
locals {
contabo_instance = {
id = "201912751"
name = "vmi1912751" # data.contabo_instance.microk8s.name
hostname = "microk8s"
ip = "147.78.131.194" # data.contabo_instance.microk8s.ip_config[0].v4[0].ip
}
}
-41
View File
@@ -1,41 +0,0 @@
terraform {
required_version = "~>1.8"
required_providers {
scaleway = {
source = "scaleway/scaleway"
version = "~>2.13"
}
# Contabo provider is not working for now, so we can't use it
# contabo = {
# source = "contabo/contabo"
# version = "0.1.26"
# }
cloudns = {
source = "ClouDNS/cloudns"
version = "~>1.0"
}
}
}
provider "cloudns" {
auth_id = var.cloudns_auth_id
password = var.cloudns_password
}
provider "scaleway" {
zone = "fr-par-2"
region = "fr-par"
access_key = var.scaleway_access_key
secret_key = var.scaleway_secret_key
organization_id = var.scaleway_organization_id
}
# Configure your Contabo API credentials
# provider "contabo" {
# oauth2_client_id = var.contabo_client_id
# oauth2_client_secret = var.contabo_client_secret
# oauth2_user = var.contabo_api_user
# oauth2_pass = var.contabo_api_password
# }
-94
View File
@@ -1,94 +0,0 @@
variable "scaleway_access_key" {
description = "Scaleway Access key"
type = string
sensitive = true
}
variable "scaleway_secret_key" {
description = "Scaleway Secret key"
type = string
sensitive = true
}
variable "scaleway_project_id" {
description = "Scaleway Project Id"
type = string
sensitive = true
}
variable "scaleway_organization_id" {
description = "Scaleway Organization Id"
type = string
sensitive = true
}
variable "scaleway_user_id" {
description = "Scaleway User Id"
type = string
sensitive = true
}
# variable "contabo_client_id" {
# description = "Contabo Client ID"
# type = string
# sensitive = true
# }
# variable "contabo_client_secret" {
# description = "Contabo Client Secret"
# type = string
# sensitive = true
# }
# variable "contabo_api_password" {
# description = "Contabo API Password"
# type = string
# sensitive = true
# }
# variable "contabo_api_user" {
# description = "Contabo API User"
# type = string
# }
variable "encryption_key" {
description = "Encryption key for sensitive data"
type = string
sensitive = true
}
variable "bucket_suffix" {
description = "Suffix for bucket names"
type = string
sensitive = true
}
variable "system_id" {
description = "System ID"
type = string
sensitive = true
}
variable "cloudns_auth_id" {
description = "Cloudns Auth ID"
type = string
sensitive = true
}
variable "cloudns_password" {
description = "Cloudns Password"
type = string
sensitive = true
}
variable "scaleway_dkim_key" {
description = "Scaleway DKIM key"
type = string
sensitive = true
}
variable "scaleway_dkim_value" {
description = "Scaleway DKIM value"
type = string
sensitive = true
}
+130
View File
@@ -0,0 +1,130 @@
module "websites" {
source = "../modules/apps/nginx"
persistent_folder = local.persistent_folder
websites = local.websites
}
module "rustdesk" {
source = "../modules/apps/rustdesk"
persistent_folder = local.persistent_folder
fqdn = local.rustdesk_fqdn
public_key = var.rustdesk_public_key
private_key = var.rustdesk_private_key
}
module "m3uproxy" {
source = "../modules/apps/m3uproxy"
persistent_folder = local.persistent_folder
tag = local.m3uproxy_version
fqdn = local.m3uproxy_fqdn
# Secret and password for M3UProxy
secret = var.m3uproxy_secret
admin_password = var.m3uproxy_admin_password
# GeoIP settings
maxmind_account_id = var.maxmind_account_id
maxmind_license_key = var.maxmind_license_key
geoip_cron_schedule = local.geoip_cron_schedule
geoip_editions = local.geoip_editions
# Wireguard settings (VPN)
wireguard_private_key = var.wireguard_private_key
wireguard_public_key = var.wireguard_public_key
}
module "mail" {
source = "../modules/apps/mail"
persistent_folder = local.persistent_folder
primary_domain = local.primary_domain
email_accounts = local.email_accounts
relay_smtp_host = local.scaleway_smtp_host
relay_smtp_port = 465
relay_smtp_username = var.scaleway_project_id
relay_smtp_password = scaleway_iam_api_key.mail_app_api.secret_key
fetch_emails_schedule = local.fetch_emails_schedule
mail_crypt_private_key = var.mail_crypt_private_key
mail_crypt_public_key = var.mail_crypt_public_key
ca_pem = var.root_ca_pem
}
module "gitea" {
source = "../modules/apps/gitea"
persistent_folder = local.persistent_folder
database_folder = local.database_folder
backup_folder = local.gitea_backup_path
backup_retention_days = local.local_backup_retention_days
backup_cron_schedule = local.gitea_sql_backup_cron_schedule
db_root_password = var.mysql_root_password
tag = local.gitea_version
fqdn = local.gitea_fqdn
app_config = {
app_name = "A13Labs git repository"
domain = local.gitea_fqdn
lfs_jwt_secret = var.gitea_lfs_jwt_secret
db_passwd = var.gitea_mysql_password
jwt_secret = var.gitea_jwt_secret
mail_from = "gitea@${local.primary_domain}"
no_reply_address = "no-reply@${local.primary_domain}"
smtp_user = var.scaleway_project_id
db_password = var.gitea_mysql_password
smtp_host = local.scaleway_smtp_host
smtp_port = local.scaleway_smtp_port
smtp_user = var.scaleway_project_id
smtp_passwd = scaleway_iam_api_key.mail_app_api.secret_key
secret_key = var.gitea_secret_key
internal_token = var.gitea_internal_token
disable_ssh = false
ssh_port = 22
disable_registration = true
}
}
module "sftpgo" {
source = "../modules/apps/sftpgo"
persistent_folder = local.persistent_folder
backup_folder = local.sftpgo_backup_path
admin_username = "admin"
admin_password = var.sftpgo_admin_password
tag = local.sftpgo_version
fqdn = local.sftpgo_fqdn
smtp_host = local.scaleway_smtp_host
smtp_port = local.scaleway_smtp_port
smtp_username = var.scaleway_project_id
smtp_password = scaleway_iam_api_key.mail_app_api.secret_key
from_email = "sftpgo@${local.primary_domain}"
access_key = scaleway_iam_api_key.sftpgo_app_api.access_key
secret_key = scaleway_iam_api_key.sftpgo_app_api.secret_key
}
module "trivy" {
source = "../modules/utils/trivy"
persistent_folder = local.persistent_folder
cron_schedule = local.trivy_cronjob_schedule
smtp_host = local.scaleway_smtp_host
smtp_port = local.scaleway_smtp_port
smtp_username = var.scaleway_project_id
smtp_password = scaleway_iam_api_key.mail_app_api.secret_key
from_email = "trivy@${local.primary_domain}"
to_email = "c.alexandre.pires@${local.primary_domain}"
}
+3 -3
View File
@@ -1,7 +1,7 @@
terraform {
backend "s3" {
bucket = "a13labs.infra"
key = "alexpires.me-k8sapps.tfstate"
region = "us-east-1"
bucket = "a13labs.infra.eu"
key = "k8sapps.core.infra.tfstate"
region = "eu-west-1"
}
}
+58
View File
@@ -0,0 +1,58 @@
module "mail_backup" {
source = "../modules/utils/scw_rclone"
namespace = module.mail.namespace
app_name = module.mail.app_name
scaleway_organization_id = var.scaleway_organization_id
scaleway_project_id = var.scaleway_organization_id
access_key = scaleway_iam_api_key.backup_app_api.access_key
secret_key = scaleway_iam_api_key.backup_app_api.secret_key
bucket_name = scaleway_object_bucket.backup.name
retention_days = local.local_backup_retention_days
cron_schedule = local.mail_files_backup_cron_schedule
source_folder = module.mail.path
target_folder = local.mail_backup_path
}
module "gitea_backup" {
source = "../modules/utils/scw_rclone"
namespace = module.gitea.namespace
app_name = module.gitea.app_name
scaleway_organization_id = var.scaleway_organization_id
scaleway_project_id = var.scaleway_organization_id
access_key = scaleway_iam_api_key.backup_app_api.access_key
secret_key = scaleway_iam_api_key.backup_app_api.secret_key
bucket_name = scaleway_object_bucket.backup.name
retention_days = local.local_backup_retention_days
cron_schedule = local.gitea_files_backup_cron_schedule
source_folder = module.gitea.path
target_folder = local.gitea_backup_path
}
module "sftpgo_backup" {
source = "../modules/utils/scw_rclone"
namespace = module.sftpgo.namespace
app_name = module.sftpgo.app_name
scaleway_organization_id = var.scaleway_organization_id
scaleway_project_id = var.scaleway_organization_id
access_key = scaleway_iam_api_key.backup_app_api.access_key
secret_key = scaleway_iam_api_key.backup_app_api.secret_key
bucket_name = scaleway_object_bucket.backup.name
retention_days = local.local_backup_retention_days
cron_schedule = local.sftpgo_files_backup_cron_schedule
source_folder = module.sftpgo.path
target_folder = local.sftpgo_backup_path
}
+21 -63
View File
@@ -30,16 +30,6 @@ resource "scaleway_object_bucket" "backup" {
}
}
lifecycle_rule {
id = "nextcloud-clean"
prefix = "nextcloud-backup/"
enabled = true
expiration {
days = local.cloud_backup_retention_days
}
}
lifecycle_rule {
id = "mail-clean"
prefix = "mail-backup/"
@@ -81,20 +71,25 @@ resource "scaleway_object_bucket_policy" "backup" {
Resource = [
scaleway_object_bucket.backup.name,
"${scaleway_object_bucket.backup.name}/*",
]
],
Condition = {
IpAddress = {
"aws:SourceIp" = local.instance_ips
}
},
},
]
})
}
resource "scaleway_object_bucket" "nextcloud" {
name = "a13labs-nextcloud-${random_string.bucket_suffix.result}"
resource "scaleway_object_bucket" "sftpgo" {
name = "a13labs-sftpgo-${random_string.bucket_suffix.result}"
project_id = var.scaleway_project_id
region = "fr-par"
}
resource "scaleway_object_bucket_policy" "nextcloud" {
bucket = scaleway_object_bucket.nextcloud.name
resource "scaleway_object_bucket_policy" "sftpgo" {
bucket = scaleway_object_bucket.sftpgo.name
policy = jsonencode({
Version = "2023-04-17",
Id = "AllowAccess",
@@ -108,8 +103,8 @@ resource "scaleway_object_bucket_policy" "nextcloud" {
SCW = "user_id:${var.scaleway_user_id}"
}
Resource = [
scaleway_object_bucket.nextcloud.name,
"${scaleway_object_bucket.nextcloud.name}/*",
scaleway_object_bucket.sftpgo.name,
"${scaleway_object_bucket.sftpgo.name}/*",
]
},
{
@@ -118,54 +113,17 @@ resource "scaleway_object_bucket_policy" "nextcloud" {
"s3:*",
]
Principal = {
SCW = "application_id:${scaleway_iam_application.nextcloud_app.id}"
SCW = "application_id:${scaleway_iam_application.sftpgo_app.id}"
}
Resource = [
scaleway_object_bucket.nextcloud.name,
"${scaleway_object_bucket.nextcloud.name}/*",
]
},
]
})
}
resource "scaleway_object_bucket" "dovecot" {
name = "a13labs-dovecot-${random_string.bucket_suffix.result}"
project_id = var.scaleway_project_id
region = "fr-par"
}
resource "scaleway_object_bucket_policy" "dovecot" {
bucket = scaleway_object_bucket.dovecot.name
policy = jsonencode({
Version = "2023-04-17",
Id = "AllowAccess",
Statement = [
{
Effect = "Allow"
Action = [
"s3:*",
]
Principal = {
SCW = "user_id:${var.scaleway_user_id}"
}
Resource = [
scaleway_object_bucket.dovecot.name,
"${scaleway_object_bucket.dovecot.name}/*",
]
},
{
Effect = "Allow"
Action = [
"s3:*",
]
Principal = {
SCW = "application_id:${scaleway_iam_application.dovecot_app.id}"
}
Resource = [
scaleway_object_bucket.dovecot.name,
"${scaleway_object_bucket.dovecot.name}/*",
]
scaleway_object_bucket.sftpgo.name,
"${scaleway_object_bucket.sftpgo.name}/*",
],
Condition = {
IpAddress = {
"aws:SourceIp" = local.instance_ips
}
},
},
]
})
+79 -42
View File
@@ -1,38 +1,35 @@
locals {
domain_name = "alexpires.me"
# general
# storage
persistent_folder = "/mnt/microk8s_persistent"
database_folder = "/var/lib"
# apps
wordpress_version = "6.7.2"
wordpress_fqdns = ["blog.${local.domain_name}", "www.${local.domain_name}", "${local.domain_name}"]
wordpress_sql_backup_cron_schedule = "0 2 * * *"
wordpress_files_backup_cron_schedule = "10 2 * * *"
# domains
primary_domain = "alexpires.me"
websites = {
"alexpires.me" = {
domain_name = "alexpires.me"
fqdn = ["blog.alexpires.me", "www.alexpires.me", "alexpires.me"]
tls = true
issuer = "internal-ca"
custom_snippet = file("${path.module}/resources/alexpires.me.conf")
}
}
gitea_version = "1.23.4"
gitea_fqdn = "code.${local.domain_name}"
gitea_sql_backup_cron_schedule = "20 2 * * *"
gitea_files_backup_cron_schedule = "30 2 * * *"
# gitea
gitea_version = "1.23.7"
gitea_fqdn = "code.${local.primary_domain}"
nextcloud_version = "30.0.0-apache"
nextcloud_fqdn = "cloud.${local.domain_name}"
nextcloud_sql_backup_cron_schedule = "40 2 * * *"
nextcloud_files_backup_cron_schedule = "50 2 * * *"
# monitoring
influxdb_version = "1.8-alpine"
kapacitor_version = "1.6-alpine"
fluent_bit_version = "3.1"
telegraf_version = "1.32-alpine"
chronograf_version = "1.9-alpine"
# sftpgo
sftpgo_version = "2.6.x"
sftpgo_fqdn = "webdav.${local.primary_domain}"
# m3uproxy
m3uproxy_version = "latest"
wireguard_version = "1.0.20210914-r4-ls54"
squid_version = "6.1-23.10_edge"
m3uproxy_fqdn = "tv.${local.domain_name}"
geoip_image = "maxmindinc/geoipupdate"
geoip_version = "latest"
m3uproxy_version = "latest"
m3uproxy_fqdn = "tv.${local.primary_domain}"
# geoip
geoip_cron_schedule = "0 0 * * *"
geoip_editions = [
"GeoLite2-Country",
@@ -40,29 +37,69 @@ locals {
"GeoLite2-ASN"
]
# rustdesk
rustdesk_version = "latest"
rustdesk_fqdn = "rustdesk.${local.domain_name}"
rustdesk_fqdn = "rustdesk.${local.primary_domain}"
# trivy
trivy_cronjob_schedule = "0 1 1/15 * *"
# backup
local_backup_retention_days = 2
cloud_backup_retention_days = 3
local_backup_retention_days = 2
cloud_backup_retention_days = 3
mail_backup_path = "${local.persistent_folder}/backup.mail"
gitea_backup_path = "${local.persistent_folder}/backup.gitea"
sftpgo_backup_path = "${local.persistent_folder}/backup.sftpgo"
gitea_sql_backup_cron_schedule = "20 2 * * *"
gitea_files_backup_cron_schedule = "30 2 * * *"
sftpgo_files_backup_cron_schedule = "50 2 * * *"
mail_files_backup_cron_schedule = "0 3 * * *"
# notification
scaleway_smtp_host = "smtp.tem.scw.cloud"
scaleway_smtp_port = 587
# mail settings
getmail_version = "v0.0.1-6.19.07"
fetch_emails_schedule = "*/2 * * * *"
mail_files_backup_cron_schedule = "0 3 * * *"
# email settings
fetch_emails_schedule = "*/2 * * * *"
scaleway_smtp_host = "smtp.tem.scw.cloud"
scaleway_smtp_port = 587
email_accounts = [
{
domain = "alexpires.me"
recipient = "c.alexandre.pires"
receive = {
type = "imap"
server = "mail-pt.securemail.pro"
port = 993
}
send = {
server = "smtp-pt.securemail.pro"
port = 465
}
username = var.alexpires_me_email_username
password = var.alexpires_me_email_password
mailboxes = ["INBOX", "Sent", "Drafts", "Trash", "Spam"]
}
]
instance_ips = [
"${local.vps_1.ip}/32",
]
vps_1 = {
id = data.terraform_remote_state.contabo.outputs.instances[0].id
name = data.terraform_remote_state.contabo.outputs.instances[0].name
ip = data.terraform_remote_state.contabo.outputs.instances[0].ip_config[0].v4[0].ip
}
# storage
persistent_folder = "/mnt/microk8s_persistent"
database_folder = "/var/lib"
}
data "scaleway_account_project" "default" {
project_id = var.scaleway_project_id
organization_id = var.scaleway_organization_id
}
data "terraform_remote_state" "contabo" {
backend = "s3"
config = {
bucket = "a13labs.infra.eu"
key = "contabo.core.infra.tfstate"
region = "eu-west-1"
}
}
@@ -154,7 +154,7 @@ resource "kubernetes_config_map" "nextcloud_apache_config" {
# Setup MariaDB database
#
module "nextcloud_database" {
source = "./modules/k8s_mariadb"
source = "../modules/db/mariadb"
namespace = kubernetes_namespace.nextcloud.metadata[0].name
app_name = "nextcloud"
@@ -169,29 +169,6 @@ module "nextcloud_database" {
backup_folder = local.nextcloud_backup_path
}
#
# Setup rsync backup job to scaleway bucket
#
module "nextcloud_backup" {
source = "./modules/scw_backup_job"
namespace = kubernetes_namespace.nextcloud.metadata[0].name
app_name = "nextcloud"
scaleway_organization_id = var.scaleway_organization_id
scaleway_project_id = var.scaleway_organization_id
access_key = scaleway_iam_api_key.backup_app_api.access_key
secret_key = scaleway_iam_api_key.backup_app_api.secret_key
bucket_name = scaleway_object_bucket.backup.name
retention_days = local.local_backup_retention_days
cron_schedule = local.nextcloud_files_backup_cron_schedule
source_folder = local.nextcloud_path
target_folder = local.nextcloud_backup_path
}
#
# Nextcloud service, ingress, deployment and file backup job
#
@@ -0,0 +1,46 @@
server {
listen 8080;
server_name localhost;
root /tmp/site;
resolver kube-dns.kube-system.svc.cluster.local valid=10s;
gzip on;
gzip_comp_level 9;
gzip_types
text/html
text/plain
text/css
text/js
text/xml
text/javascript
application/javascript
application/json
application/xml
application/rss+xml
image/svg+xml;
location ^~ /storage {
proxy_pass http://http.sftpgo.svc.cluster.local:8080/storage;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
location / {
index index.html index.htm;
}
location ~* ^/([^/]+) {
index index.html index.htm;
error_page 404 = @error;
}
error_page 404 /404.html;
location @error {
try_files /$1/404.html /404.html =404;
}
}

Some files were not shown because too many files have changed in this diff Show More