diff options
30 files changed, 295 insertions, 303 deletions
@@ -6,6 +6,7 @@ import subprocess import requests import getpass import textwrap +import yaml from dataclasses import dataclass from typing import Dict, Optional from abc import ABC, abstractmethod @@ -28,8 +29,7 @@ class Config: GROUP_VARS = Path("group_vars/") NGINX_SITES_ENABLED = ANSIBLE_ROLES / Path("outbound/templates/proxy/nginx/conf.d") - LABDNS_GROUP_VARS = GROUP_VARS / Path("labdns.yml") - LABDNS_DELIMITER = "internal_services:" + "\n" + MESH_GROUP_VARS = GROUP_VARS / Path("all.yml") EXTERNAL_LOADBALANCER_HOST = "outbound.liz.coffee" LOADBALANCER_INVENTORY_LINE = textwrap.dedent( """\ @@ -81,22 +81,24 @@ class CloudflareDns: @dataclass class HomelabDns: group_vars: Path - delimiter: str + start_delimiter: str + end_delimiter: str def put_internal(self, dns_prefix: str) -> bool: new_lines = [] with self.group_vars.open("r") as f: lines = f.readlines() try: - internal_services = lines.index(self.delimiter) + mesh_start = lines.index(self.start_delimiter) + mesh_end = lines.index(self.end_delimiter) except ValueError: - logger.error(f"Cannot find delimiter {self.delimiter} in {self.group_vars}") + logger.error(f"Cannot find delimiters") return False - new_lines = ( - lines[0:internal_services + 1] - + [f" - {dns_prefix}.{{{{ domain }}}}\n"] - + lines[internal_services + 1:] - ) + mesh = yaml.safe_load("\n".join(lines[mesh_start:mesh_end])) + mesh['liz']['private_records'] += [{"type": "A", "name": dns_prefix + ".{{ domain }}", "ip": "{{ loadbalancer_ip }}"}] + new_mesh = yaml.dump(mesh) + new_lines = lines[0:mesh_start] + [self.start_delimiter, yaml.dump(mesh)] + [mesh_end:] + if not new_lines: return False with self.group_vars.open("w") as f: @@ -291,7 +293,9 @@ def main(): if args.internal: logger.info("Configuring internal DNS via LabDNS...") dns = HomelabDns( - group_vars=Config.LABDNS_GROUP_VARS, delimiter=Config.LABDNS_DELIMITER + group_vars=Config.MESH_GROUP_VARS + start_delimiter="# -- <mesh> --\n", + end_delimiter="# -- </mesh> --\n" ) success = dns.put_internal(args.service_name) if not success: diff --git a/group_vars/all.yml b/group_vars/all.yml index 717a983..74f626e 100644 --- a/group_vars/all.yml +++ b/group_vars/all.yml @@ -1,36 +1,115 @@ --- -# first deployment? -homelab_build: false -#homelab_build: true +# -- <misc> -- +timezone: "America/Los_Angeles" +# -- </misc> -- +# -- <target_user> -- ansible_user: serve +# -- </target_user> -- +# -- <networking> -- loadbalancer_ip: "10.128.0.200" -homelab_network: "10.0.0.0/8" +homelab_network: "10.128.0.0/16" +swarm_network: "10.0.0.0/16" docker_network: "172.16.0.0/12" headnet_network: "100.64.0.0/10" rfc1918_cgnat_networks: - - "{{ homelab_network }}" + - 10.0.0.0/8 - "{{ docker_network }}" - 192.168.0.0/16 - "{{ headnet_network }}" +# -- </networking> -- -timezone: "America/Los_Angeles" - +# -- <shared_services> -- domain: "liz.coffee" idm_domain: "idm.{{ domain }}" headscale_host: "vpn.{{ domain }}" mail_domain: "mail.{{ domain }}" oci_domain: "oci.{{ domain }}" passwd_domain: "passwd.{{ domain }}" +# -- </shared_services> -- +# -- <notifcation_email> -- info_mail_user: "info" info_mail: "{{ info_mail_user }}@{{ domain }}" +# see secret for info mail password +# -- </notifcation_email> -- +# -- <certs> -- traextor_base: "{{ swarm_base }}/traextor" letsencrypt_certs: "{{ traextor_base }}/volumes/certs/letsencrypt" +# -- </certs> -- +# -- <region_build> -- +# first deployment? +homelab_build: false +#homelab_build: true +# -- </region_build> -- + +# -- <unique_deployment> -- deployment_time: "{{ now(utc=true,fmt='%s') }}" +# -- </unique_deployment> -- +# -- <keys> -- me_lizcoffee_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDRHu3h9mDjQyFbojcxGKW0hPUDfgUmb2WCzd4Dv2qISM3GGt9LjD8o0IbWRNaTf5UyId5lu7wNHtygs5ZDfUVnlfxrI1CmoExuqkYFjy+R9Cu0x1J2w7+MrKPBd5akLCuKTTnXbyv79T0tLb07rCpGHojW8HH6wdDtg0siVqsPqZVTjg7WGbBYqiqlA5p8s+V9xN1q8lTOZrRI0PdgoU8W+1oIr9OHSG1ZeUBQx60izTEwMnWBxY2aA8SQolIVvsJCcMMc/EAnaz/rdJ5IkeqXGslIhUI7WCPHnPWN8CSdwMOLi5BNaOAK7Y2FkfKTUlO7I52BL87Cl3YpMxR0mTDrfSJTSp0B3ZAbUIXDA7biSh04YLwGQVI799vcyJf355A60btPaiuiBgI0am3h0WxnOACg7K6eV023EiUQ24UjlQ8pufHcJ1oDW8v6LHlp/atCWOl9KQIun9UUg8DD8/BLPprc0wzAV6Nco0ZIedouxZuUhduYYvUrLJ+ICpaZg6oPGitVJPIgyyI+WTfjRN4WTj/Z3Yhuj0RqF8b5ea4FNWuJtfF724t7SVnZsYlZGSCqL8gaEzbIATVe3THn5VwbK+S4ELD/9W6MOd6aZcTOK2yP3jlwjcjnW8sLuX+2qNwtSVVa4o5VsRZU40Da+3flzoBsyUwSE3H2PsFPH29lIQ== lizzy@yubikey" +# -- </keys> -- + +# -- <mesh> -- +mesh: + lucina: + gateway: "10.128.0.44" + domain: "lucina.cloud" + forward_dns: true + private_records: [] + liz: + gateway: "{{ loadbalancer_ip }}" + domain: "{{ domain }}" + forward_dns: false + private_records: + - type: "A" + name: "oci.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "ci.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "test.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "bin.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "ci.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "idm.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "kanban.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "loadbalancer.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "notes.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "passwd.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "pihole.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "proxy.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "src.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "swarm.{{ domain }}" + ip: "{{ loadbalancer_ip }}" + - type: "A" + name: "traefik.{{ domain }}" + ip: "{{ loadbalancer_ip }}" +# -- </mesh> -- diff --git a/group_vars/ceph.yml b/group_vars/ceph.yml index 5c985ca..a3d406f 100644 --- a/group_vars/ceph.yml +++ b/group_vars/ceph.yml @@ -1,6 +1,5 @@ --- -# ceph_secret: <keep it safe in the vault> cephfs_name: cephfs ceph_mon_host: "[v2:10.128.0.101:3300/0,v1:10.128.0.101:6789/0] [v2:10.128.0.103:3300/0,v1:10.128.0.103:6789/0] [v2:10.128.0.102:3300/0,v1:10.128.0.102:6789/0]" ceph_fsid: "ee994518-d7f3-4a7b-b148-09dba7f3dd4d" diff --git a/group_vars/labdns.yml b/group_vars/labdns.yml index d0b0c6a..2be9e47 100644 --- a/group_vars/labdns.yml +++ b/group_vars/labdns.yml @@ -2,19 +2,7 @@ labdns_base: "{{ swarm_base }}/labdns" -internal_services: - - oci.{{ domain }} - - ci.{{ domain }} - - test.{{ domain }} - - bin.{{ domain }} - - ci.{{ domain }} - - idm.{{ domain }} - - kanban.{{ domain }} - - loadbalancer.{{ domain }} - - notes.{{ domain }} - - passwd.{{ domain }} - - pihole.{{ domain }} - - proxy.{{ domain }} - - src.{{ domain }} - - swarm.{{ domain }} - - traefik.{{ domain }} +forward_addrs: + - "9.9.9.9@853#dns.quad9.net" + - "1.0.0.1@853#cloudflare-dns.com" + - "1.1.1.1@853#cloudflare-dns.com" diff --git a/group_vars/oci.yml b/group_vars/oci.yml index 7bc2db0..97d130e 100644 --- a/group_vars/oci.yml +++ b/group_vars/oci.yml @@ -1,3 +1,7 @@ --- oci_base: "{{ swarm_base }}/oci" +oci_repos: + - "emprespresso" + +ci_user: "ci" diff --git a/group_vars/outbound.yml b/group_vars/outbound.yml index d9b65bb..759872f 100644 --- a/group_vars/outbound.yml +++ b/group_vars/outbound.yml @@ -19,3 +19,16 @@ auth_key_expiration: '2y' auth_key_user: 'pocketmonsters' oauth_user_suffix: '@idm.{{ domain }}' + +# being in this list just means you'll have access to your own devices. +# the vpn_users oauth claim decides whether or not you're authorized to actually +# use the vpn. +vpn_users: + - liz + - lucina + - riley + +# but... there's no way to membership sync the groups that i know of... D: +vpn_admins: + - liz + - lucina diff --git a/group_vars/src.yml b/group_vars/src.yml index 3d8689a..efad903 100644 --- a/group_vars/src.yml +++ b/group_vars/src.yml @@ -3,3 +3,5 @@ src_domain: src.liz.coffee src_base: "{{ swarm_base }}/src" src_admin_keys: "{{ me_lizcoffee_key }}" + +laminar_host: "laminard:9997" diff --git a/playbooks/roles/ci/templates/stacks/docker-compose.yml b/playbooks/roles/ci/templates/stacks/docker-compose.yml index 38e1b1c..3aee1da 100644 --- a/playbooks/roles/ci/templates/stacks/docker-compose.yml +++ b/playbooks/roles/ci/templates/stacks/docker-compose.yml @@ -1,23 +1,20 @@ --- services: - laminard: - image: oci.liz.coffee/img/laminar-ciworker:latest + worker: + image: oci.liz.coffee/@emprespresso/ci-worker:release volumes: - - {{ ci_base }}/volumes/laminar:/var/lib/laminar - /var/run/docker.sock:/var/run/docker.sock - healthcheck: - test: ["CMD-SHELL", "/usr/bin/laminarc show-jobs"] - timeout: 15s - interval: 30s - retries: 3 - start_period: 5s + - {{ ci_base }}/volumes/laminar:/var/lib/laminar/ + - /var/lib/laminar/cfg # don't overwrite cfg jobs & scripts environment: - - BW_CLIENTID={{ vaultwarden_client_id }} - - BW_CLIENTSECRET={{ vaultwarden_client_secret }} - - BW_PASSWORD={{ vaultwarden_master_password }} - TZ={{ timezone }} - DEPLOYMENT_TIME={{ deployment_time }} + - BW_SERVER=https://{{ passwd_domain }} + - BW_CLIENTID={{ passwd_client_id }} + - BW_CLIENTSECRET={{ passwd_client_secret }} + - BW_PASSWORD={{ passwd_master_password }} + - LAMINAR_BIND_RPC=*:9997 networks: - ci - proxy @@ -39,9 +36,28 @@ services: - traefik.http.routers.ci.entrypoints=websecure - traefik.http.services.ci.loadbalancer.server.port=8080 + cihooks: + image: oci.liz.coffee/@emprespresso/ci-hooks:release + environment: + - LAMINAR_HOST=worker:9997 + - LAMINAR_URL=worker:9997 + - TZ={{ timezone }} + - DEPLOYMENT_TIME={{ deployment_time }} + networks: + - ci + deploy: + mode: replicated + update_config: + parallelism: 1 + failure_action: rollback + order: start-first + delay: 5s + monitor: 10s + networks: ci: driver: overlay attachable: true + name: ci proxy: external: true diff --git a/playbooks/roles/ci/templates/volumes/laminar/jobs/build_image.run b/playbooks/roles/ci/templates/volumes/laminar/jobs/build_image.run deleted file mode 100755 index ed7bf21..0000000 --- a/playbooks/roles/ci/templates/volumes/laminar/jobs/build_image.run +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# usage: laminarc queue build_publish_image registry="oci.liz.coffee" \ -# repo="src/cgit" tag="latest" remote="ssh://src.liz.coffee:2222/cgit" \ -# rev="<sha>" image_file="Dockerfile" - -set -e - -declare -a args=("$registry" "$repo" "$tag" "$remote" "$rev" "$image_file") -for arg in "${args[@]}" -do - if [[ ! "$arg" =~ ^[[:alnum:]:_\.\/\-]*$ ]]; then - echo "Invalid argument format. Don't be sneaky snek (-_-)." - exit 1 - fi -done - -log "Logging into registry $registry" -registry_username="$(get_secret $registry | jq -r ".login.username")" -get_secret $registry | jq -r ".login.password" \ - | docker login --username "$registry_username" --password-stdin "$registry" - -log "Cloning remote $remote" -r=$(echo "build-$(date --iso-8601=seconds)") -git clone "$remote" "$r" && cd "$r" -git checkout "$rev" - -image_tag="$registry/$repo:$tag" -log "Building image $image_tag" -env -i HOME="$HOME" bash -l -c "docker build . -t '$image_tag' -f '$image_file'" - -log "Pushing $image_tag" -docker push "$image_tag" - -cd - -rm -rf "$r" -docker logout "$registry" diff --git a/playbooks/roles/ci/templates/volumes/laminar/jobs/playbook.run b/playbooks/roles/ci/templates/volumes/laminar/jobs/playbook.run deleted file mode 100755 index 181a050..0000000 --- a/playbooks/roles/ci/templates/volumes/laminar/jobs/playbook.run +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -# usage: laminarc queue playbook remote="ssh://src.liz.coffee:2222/infra" playbooks="deploy.yml playbooks/labdns.yml" - -set -e - -declare -a args=("$remote" "$playbooks") -for arg in "${args[@]}" -do - if [[ ! "$arg" =~ ^[[:alnum:]:_\ \.\/\-]*$ ]]; then - echo "Invalid argument format. Don't be sneaky snek (-_-)." - exit 1 - fi -done - -log "Cloning remote $remote" -r=$(echo "ansible-$(date --iso-8601=seconds)") -git clone "$remote" "$r" && cd "$r" - -get_secret "ansible_secrets" | jq -r '.notes' > secrets.yml -private_key=$(get_secret "ssh_key" | jq -r '.notes') - -env -i HOME="$HOME" ssh-agent bash -c "ssh-add <(echo \"$private_key\") && ansible-playbook -e @secrets.yml $playbooks" - -cd - -rm -rf "$r" diff --git a/playbooks/roles/ci/templates/volumes/laminar/scripts/get_secret b/playbooks/roles/ci/templates/volumes/laminar/scripts/get_secret deleted file mode 100755 index 2774651..0000000 --- a/playbooks/roles/ci/templates/volumes/laminar/scripts/get_secret +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -bw config server "https://{{ passwd_domain }}" -bw login --apikey --quiet -bw unlock --passwordenv BW_PASSWORD --quiet - -# https://github.com/bitwarden/clients/issues/3366 -function bw_get() { - local pwd - local count - local organisation=${2:-notnull} - - count=$(bw list items --pretty --organizationid ${organisation} | jq -r '[.[] | select(.name=="'$1'")] | length') - - if [[ "$count" -gt 1 ]]; then - echo "Multiple items found" - return 1 - fi - - if [[ "$count" -lt 1 ]]; then - echo "No items found" - return 1 - fi - - pwd=$(bw list items --pretty --organizationid ${organisation} | jq -r '.[] | select(.name=="'$1'")') - if [[ -z "$pwd" ]]; then - echo "Password not found" - return 1 - fi - - echo "$pwd" -} - -bw_get $@ -bw --quiet lock diff --git a/playbooks/roles/ci/templates/volumes/laminar/scripts/log b/playbooks/roles/ci/templates/volumes/laminar/scripts/log deleted file mode 100755 index 180fa33..0000000 --- a/playbooks/roles/ci/templates/volumes/laminar/scripts/log +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -echo `date +"%d-%m-%Y %H:%M:%S"` " - " "${@}" diff --git a/playbooks/roles/kanidm/templates/stacks/docker-compose.yml b/playbooks/roles/kanidm/templates/stacks/docker-compose.yml index 36ec4f5..f9d8cbe 100644 --- a/playbooks/roles/kanidm/templates/stacks/docker-compose.yml +++ b/playbooks/roles/kanidm/templates/stacks/docker-compose.yml @@ -1,6 +1,6 @@ services: kanidm: - image: kanidm/server + image: kanidm/server:latest volumes: - {{ kanidm_base }}/volumes/data:/data - {{ letsencrypt_certs }}:/certs:ro @@ -17,12 +17,6 @@ services: /sbin/kanidmd server -c /data/server.toml healthcheck: disable: true -{% else %} - healthcheck: - test: ["CMD-SHELL", "curl --fail -k https://localhost:8443/status"] - retries: 1 - timeout: 2s - interval: 30s {% endif %} environment: - TZ={{ timezone }} diff --git a/playbooks/roles/kanidm/templates/volumes/data/server.toml b/playbooks/roles/kanidm/templates/volumes/data/server.toml index dd13e1c..afaf0f1 100644 --- a/playbooks/roles/kanidm/templates/volumes/data/server.toml +++ b/playbooks/roles/kanidm/templates/volumes/data/server.toml @@ -1,6 +1,7 @@ +version = "2" + bindaddress = "[::]:8443" ldapbindaddress = "[::]:3636" -trust_x_forward_for = true db_path = "/data/kanidm.db" tls_chain = "/certs/{{ idm_domain }}.pem" tls_key = "/certs/{{ idm_domain }}.key" @@ -8,3 +9,8 @@ log_level = "info" domain = "{{ idm_domain }}" origin = "https://{{ idm_domain }}" + +# soon... once https://github.com/kanidm/kanidm/commit/b5cdf9dcf20114ed291700d99e8531226025f197 released >:D +# x-forward-for = ["{{ swarm_network }}"] +[http_client_address_info] +x-forward-for-all-source-trusted = [] diff --git a/playbooks/roles/labdns/templates/volumes/unbound/a-records.conf b/playbooks/roles/labdns/templates/volumes/unbound/a-records.conf index d0c9517..95d2b85 100644 --- a/playbooks/roles/labdns/templates/volumes/unbound/a-records.conf +++ b/playbooks/roles/labdns/templates/volumes/unbound/a-records.conf @@ -1,8 +1,9 @@ -# {{ domain }} -{% for service in internal_services %} -local-data: "{{ service }}. A {{ loadbalancer_ip }}" +{% for meshpoint in mesh.values() %} +# {{ meshpoint.domain }} +{% for record in meshpoint.private_records %} +{% if record["type"] == "A" %} +local-data: "{{ record['name'] }}. A {{ record['ip'] }}" +{% endif %} +{% endfor %} {% endfor %} -# TODO: for lucina.cloud, for now... -local-zone: "lucina.cloud." redirect -local-data: "lucina.cloud. A 10.128.0.44" diff --git a/playbooks/roles/labdns/templates/volumes/unbound/forward-records.conf b/playbooks/roles/labdns/templates/volumes/unbound/forward-records.conf index 19af327..0f5af53 100644 --- a/playbooks/roles/labdns/templates/volumes/unbound/forward-records.conf +++ b/playbooks/roles/labdns/templates/volumes/unbound/forward-records.conf @@ -1,5 +1,20 @@ forward-zone: name: "." - forward-addr: 1.1.1.1@853#cloudflare-dns.com - forward-addr: 1.0.0.1@853#cloudflare-dns.com +{% for forward_addr in forward_addrs %} + forward-addr: "{{ forward_addr }}" forward-tls-upstream: yes +{% endfor %} + +{% for meshpoint in mesh.values() %} +{% if meshpoint.forward_dns %} +# {{ meshpoint.domain }} +forward-zone: + name: "{{ meshpoint.domain }}" + forward-addr: "{{ meshpoint.gateway }}" +{% endif %} +{% endfor %} + +server: +{% for meshpoint in mesh.values() %} + private-domain: "{{ meshpoint.domain }}" +{% endfor %} diff --git a/playbooks/roles/mail/templates/volumes/data/dms/config/dovecot.cf b/playbooks/roles/mail/templates/volumes/data/dms/config/dovecot.cf index 62d0550..2ed6354 100644 --- a/playbooks/roles/mail/templates/volumes/data/dms/config/dovecot.cf +++ b/playbooks/roles/mail/templates/volumes/data/dms/config/dovecot.cf @@ -1,4 +1,4 @@ -haproxy_trusted_networks = {{ homelab_network }} +haproxy_trusted_networks = {{ swarm_network }} service imap-login { inet_listener imap { diff --git a/playbooks/roles/oci/templates/volumes/config.toml b/playbooks/roles/oci/templates/volumes/config.toml index 6d2f199..520d6f6 100644 --- a/playbooks/roles/oci/templates/volumes/config.toml +++ b/playbooks/roles/oci/templates/volumes/config.toml @@ -18,18 +18,21 @@ root_dir = "/images" endpoint = "http://127.0.0.1:4317" sampling_rate = 1.0 -[identity.ci] -username = "ci" -password = "{{ simple_registry_password_argon_encoded }}" +[identity.{{ ci_user }}] +username = "{{ ci_user }}" +password = "{{ ci_user_registry_password_argon_encoded }}" [identity.readonly] username = "readonly" -password = "$argon2i$v=19$m=16,t=2,p=1$TjJyTEdIZUJ6dFZkdlZvSg$qf8vG09O93Z/9vUMCgWNtA" # readonly +password = "$argon2i$v=19$m=16,t=2,p=1$TjJyTEdIZUJ6dFZkdlZvSg$qf8vG09O93Z/9vUMCgWNtA" # hash for "readonly" -[repository."img"] +{% for repo in oci_repos %} +[repository."{{ repo }}"] -[repository."img".access_policy] +[repository."{{ repo }}".access_policy] default_allow = false rules = [ 'request.action.startsWith("get-") || request.action.startsWith("list-") || identity.id == "ci"' ] +{% endfor %} + diff --git a/playbooks/roles/outbound/templates/headscale/config/acl.json b/playbooks/roles/outbound/templates/headscale/config/acl.json index 242d01e..dcdd954 100644 --- a/playbooks/roles/outbound/templates/headscale/config/acl.json +++ b/playbooks/roles/outbound/templates/headscale/config/acl.json @@ -1,9 +1,13 @@ { "groups": { - "group:coffee_admins": ["liz{{ oauth_user_suffix }}", "lucina{{ oauth_user_suffix }}"], + "group:vpn_admins": [ +{% for user in vpn_admins %} + "{{ user }}{{ oauth_user_suffix }}"{{ ", " if not loop.last else "" }} +{% endfor %} + ] }, "acls": [ -{% for user in ["liz", "lucina", "riley"] %} +{% for user in vpn_users %} { "action": "accept", "src": ["{{ user }}{{ oauth_user_suffix }}"], @@ -15,9 +19,16 @@ "src": ["{{ auth_key_user }}"], "dst": ["{{ auth_key_user }}:*", "{{ loadbalancer_ip }}/32:*"] }, +{% for user, m in mesh.items() %} + { + "action": "accept", + "src": ["{{ user }}{{ oauth_user_suffix }}"], + "dst": ["{{ m.gateway }}/32:*]" + }, +{% endfor %} { "action": "accept", - "src": ["group:coffee_admins"], + "src": ["group:vpn_admins"], "dst": ["{{ loadbalancer_ip }}/32:*"] } ] diff --git a/playbooks/roles/src/templates/stacks/docker-compose.yml b/playbooks/roles/src/templates/stacks/docker-compose.yml index 547020d..3ac70f9 100644 --- a/playbooks/roles/src/templates/stacks/docker-compose.yml +++ b/playbooks/roles/src/templates/stacks/docker-compose.yml @@ -1,46 +1,16 @@ services: - frontend: - image: emarcs/nginx-cgit - volumes: - - {{ src_base }}/volumes/data/repos:/srv/git:ro - - {{ src_base }}/volumes/cgit/:/usr/share/cgit:ro - - {{ src_base }}/volumes/cgit.nginx.conf:/etc/nginx/sites-available/default - environment: - CGIT_TITLE: '{{ src_domain }}' - CGIT_DESC: '<3 {{ domain }}' - CGIT_VROOT: '/cgit' - CGIT_SECTION_FROM_STARTPATH: 1 - CGIT_MAX_REPO_COUNT: 100 - networks: - - proxy - healthcheck: - test: ["CMD-SHELL", "curl --fail http://localhost"] - timeout: 15s - interval: 30s - retries: 3 - start_period: 5s - deploy: - mode: replicated - update_config: - parallelism: 1 - failure_action: rollback - order: start-first - monitor: 10s - labels: - - traefik.enable=true - - traefik.swarm.network=proxy - - traefik.http.routers.src.tls=true - - traefik.http.routers.src.tls.certResolver=letsencrypt - - traefik.http.routers.src.rule=Host(`{{ src_domain }}`) - - traefik.http.routers.src.entrypoints=websecure - - traefik.http.services.src.loadbalancer.server.port=80 + # TODO: own cgit fork src: image: charmcli/soft-serve volumes: - - {{ src_base }}/volumes/data:/soft-serve + - {{ src_base }}/volumes/soft-serve:/soft-serve ports: - "2222:2222" +{% if not homelab_build %} + networks: + - ci +{% endif %} environment: - TZ={{ timezone }} - DEPLOYMENT_TIME={{ deployment_time }} @@ -56,7 +26,7 @@ services: healthcheck: test: ["CMD-SHELL", "netstat -tuln | grep 2222"] timeout: 15s - interval: 30s + interval: 10s retries: 3 start_period: 5s deploy: @@ -69,5 +39,10 @@ services: replicas: 1 networks: +{% if not homelab_build %} + ci: + external: true + name: ci +{% endif %} proxy: external: true diff --git a/playbooks/roles/src/templates/volumes/cgit.nginx.conf b/playbooks/roles/src/templates/volumes/cgit.nginx.conf deleted file mode 100644 index 5abe189..0000000 --- a/playbooks/roles/src/templates/volumes/cgit.nginx.conf +++ /dev/null @@ -1,49 +0,0 @@ -server { - listen 80; - server_name localhost; - - #charset koi8-r; - #access_log /var/log/nginx/log/host.access.log main; - - location / { - root /usr/share/cgit/; - } - - location /cgit { - try_files $uri @cgit; - } - - location @cgit { - fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi; - - fastcgi_param HTTP_HOST $server_name; - fastcgi_split_path_info ^(/cgit/?)(.+)$; - fastcgi_param PATH_INFO $fastcgi_path_info; - fastcgi_param QUERY_INFO $uri; - - include fastcgi_params; - - fastcgi_pass unix:/var/run/fcgiwrap.socket; - } - - location /cgit-css/ { - rewrite ^/cgit-css(/.*)$ $1 break; - root /usr/share/cgit/cgit-css/; - } - - error_page 404 /404.html; - error_page 401 /401.html; - - # redirect server error pages to the static page /50x.html - error_page 500 502 503 504 /50x.html; - location = /50x.html { - root /usr/share/nginx/html; - } - - # deny access to .htaccess files, if Apache's document root - # concurs with nginx's one - # - location ~ /\.ht { - deny all; - } -} diff --git a/playbooks/roles/src/templates/volumes/cgit/cgit-css/cgit.png b/playbooks/roles/src/templates/volumes/cgit/cgit-css/cgit.png Binary files differdeleted file mode 100644 index bb7ffa1..0000000 --- a/playbooks/roles/src/templates/volumes/cgit/cgit-css/cgit.png +++ /dev/null diff --git a/playbooks/roles/src/templates/volumes/cgit/index.html b/playbooks/roles/src/templates/volumes/cgit/index.html deleted file mode 100644 index 4b06983..0000000 --- a/playbooks/roles/src/templates/volumes/cgit/index.html +++ /dev/null @@ -1 +0,0 @@ -<h1>hai</h1> diff --git a/playbooks/roles/src/templates/volumes/data/.gitkeep b/playbooks/roles/src/templates/volumes/data/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/playbooks/roles/src/templates/volumes/data/.gitkeep +++ /dev/null diff --git a/playbooks/roles/src/templates/volumes/data/hooks/update b/playbooks/roles/src/templates/volumes/data/hooks/update deleted file mode 100755 index 5723dc5..0000000 --- a/playbooks/roles/src/templates/volumes/data/hooks/update +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh -# - -refname="$1" -oldrev="$2" -newrev="$3" - -# Safety check -if [ -z "$GIT_DIR" ]; then - echo "Don't run this script from the command line." >&2 - echo " (if you want, you could supply GIT_DIR then run" >&2 - echo " $0 <ref> <oldrev> <newrev>)" >&2 - exit 1 -fi - -if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then - echo "usage: $0 <ref> <oldrev> <newrev>" >&2 - exit 1 -fi - -# Check types -# if $newrev is 0000...0000, it's a commit to delete a ref. -zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0') -if [ "$newrev" = "$zero" ]; then - newrev_type=delete -else - newrev_type=$(git cat-file -t $newrev) -fi - -echo "Hi from Soft Serve update hook!" -echo "$GITDIR" -echo "RefName: $refname" -echo "Change Type: $newrev_type" -echo "Old SHA1: $oldrev" -echo "New SHA1: $newrev" - -exit 0 diff --git a/playbooks/roles/ci/templates/volumes/data/.gitkeep b/playbooks/roles/src/templates/volumes/soft-serve/.gitkeep index e69de29..e69de29 100644 --- a/playbooks/roles/ci/templates/volumes/data/.gitkeep +++ b/playbooks/roles/src/templates/volumes/soft-serve/.gitkeep diff --git a/playbooks/roles/src/templates/volumes/soft-serve/hooks/update b/playbooks/roles/src/templates/volumes/soft-serve/hooks/update new file mode 100755 index 0000000..a97e5f9 --- /dev/null +++ b/playbooks/roles/src/templates/volumes/soft-serve/hooks/update @@ -0,0 +1,68 @@ +#!/bin/bash + +# -- <logo> -- +function logo() { + git config --global color.ui auto + +cat <<'EOF' +--| |-- +--| ~ welcome to ~ |-- +--| |-- +--| .-. _ .--. .--. |-- +--| :.: :_; : .-': .-' |-- +--| :.: .-..---. .--. .--. : `; : `;.--. .--. |-- +--| :.:_ : :`-'_.' _ ' ..'' .; :: : : :' '_.'' '_.' |-- +--| `.__;:_;`.___;:_;`.__.'`.__.':_; :_;`.__.'`.__.' |-- +--| |-- +--| ~₊˚⊹ ⋆˚✿˖°~ -────୨ৎ────- ~₊˚⊹ ⋆˚✿˖°~ |-- +--| ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ |-- +--| ⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠒⠉⠉⠉⣀⣂⣅⠬⡉⠭⢛⠿⢟⡶⣄⡀⠀⠀⠀⠀ we'll get brewing |-- +--| ⠀⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⣄⢎⢩⢸⢉⣵⡖⢰⣶⣮⢹⣦⣡⢊⢻⡿⣦⠀⠀⠀ right away! |-- +--| ⠀⠀⠀⠀⠀⠀⢠⡇⠀⠀⢎⠕⢭⢪⡶⠈⢿⣷⣿⠟⣋⣚⣯⣒⣣⡑⢨⢻⡇⠀⣀⣀⠀⠀⠀ |-- +--| ⠀⠀⠀⠀⠀⣀⡼⣧⠀⠄⡊⢼⡩⣾⢌⠳⡜⣉⡠⡜⡞⣵⣊⡧⡠⠝⣣⡾⠁⠀⠻⠿⠗⠀⠀ /) /) (\ (\ |-- +--| ⠀⠀⠀⣢⣾⡟⣥⠻⣷⣌⡀⠬⡘⢅⡟⡇⡮⣷⡾⡿⢋⣉⢣⢔⣎⠿⠊⠀⠀⡴⣛⠆⠌⠀⠀ ( . .) (. . ) |-- +--| ⠀⢀⣶⡟⣡⣿⣿⣟⢯⣟⢿⣷⣶⣯⣬⣵⣾⣷⣶⡾⠧⠞⠓⠉⠀⠀⠀⢀⠘⠈⠀⠠⢘⡤⠀ ( づ ˚♡︎˖ ⊂ ) |-- +--| ⠄⣾⠏⣐⣛⡻⢿⣿⣯⣿⣿⣿⣾⣽⣛⣍⢃⡂⢄⠀⡀⠀⡀⠄⢂⠄⠡⢈⠒⡈⢒⠘⠴⢀⠀ |-- +--| ⢰⣿⠀⠈⠻⣜⣄⠈⢙⣾⢿⣿⣿⣿⡿⣜⢣⡜⢢⠁⠄⡐⢠⢉⠂⠌⠀⡀⠄⠐⡀⠄⠐⠀⢐ ___ |-- +--| ⠸⣟⠀⡐⡅⠈⠑⠀⠊⠝⠈⢖⡿⠿⣿⣾⡱⢊⠅⡌⡰⢌⢆⠣⠈⢀⠐⠀⠄⠂⠠⡈⠠⣈⡧ (...) |-- +--| ⠀⢿⣆⠱⣘⣧⣤⣀⣀⡀⢒⡥⣑⢨⠒⡰⠯⠾⡼⠶⠙⢈⠀⣀⠂⡄⢂⣁⢢⣑⣶⡽⣳⠟⠁ _ \ _ |-- +--| ⠀⠀⠻⣧⡜⢹⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣴⡀⡀⠀⠛⠺⢿⣶⣿⣾⣷⣿⣿⣿⢟⣵⠏⠀⠀ ('> <') |-- +--| ⠀⠀⠀⠈⠿⣶⣉⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣧⣤⢀⠀⠀⠈⠉⠙⠻⣯⡷⠟⠁⠀⠀⠀ (v) (v) |-- +--| ⠀⠀⠀⠀⠀⠈⠙⠿⣶⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣞⣤⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀\(__w w__)/ |-- +--| ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠛⠛⠛⠿⠿⠿⠿⠿⠿⠛⠛⠛⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ |-- +--| |-- +--| |-- +EOF +} +# -- </logo> -- + +# -- <continuous_integration> -- +refname="$1" +_oldrev="$2" +rev="$3" + +function post_trigger_ci_jobs() { + local host="cihooks" + local port="9000" + local path="/job" + local json_payload=$(printf '{"type": "ci_pipeline", "arguments": {"remote": "%s", "rev": "%s", "refname": "%s"}}' "$1" "$2" "$3") + + echo "> $json_payload" + + which curl 2&>/dev/null || apk add -q curl + + curl --silent --show-error -X POST \ + -H "Content-Type: application/json" \ -H "Connection: close" \ + -d "$json_payload" \ + "http://$host:$port$path" + + echo "... Done!" +} +# -- </continuous_integration> -- + +# -- <main> -- +remote="ssh://{{ src_domain }}:2222/$(basename "$PWD")" + +logo +post_trigger_ci_jobs "$remote" "$rev" "$refname" +# -- </main> -- diff --git a/playbooks/roles/swarm_cluster/tasks/main.yml b/playbooks/roles/swarm_cluster/tasks/main.yml index 961d6f5..b3173d5 100644 --- a/playbooks/roles/swarm_cluster/tasks/main.yml +++ b/playbooks/roles/swarm_cluster/tasks/main.yml @@ -3,7 +3,7 @@ - name: Enable Local Swarm Communications community.general.ufw: rule: allow - from: "{{ homelab_network }}" + from: "{{ swarm_network }}" state: enabled - name: Set swarm initializer variable diff --git a/playbooks/roles/traefik/templates/stacks/traefik.yml b/playbooks/roles/traefik/templates/stacks/traefik.yml index 3b9f680..09588b3 100644 --- a/playbooks/roles/traefik/templates/stacks/traefik.yml +++ b/playbooks/roles/traefik/templates/stacks/traefik.yml @@ -11,7 +11,7 @@ entryPoints: address: ":80" forwardedHeaders: trustedIPs: - - "{{ homelab_network }}" + - "{{ swarm_network }}" - "{{ docker_network }}" http: redirections: @@ -22,7 +22,7 @@ entryPoints: address: ":443" forwardedHeaders: trustedIPs: - - "{{ homelab_network }}" + - "{{ swarm_network }}" - "{{ docker_network }}" serversTransport: diff --git a/secrets.txt b/secrets.txt index e23eeba..26af908 100644 --- a/secrets.txt +++ b/secrets.txt @@ -17,7 +17,7 @@ roundcube_oauth2_client_basic_secret info_mail_password yubico_client_id yubico_secret_key -simple_registry_password_argon_encoded -vaultwarden_client_id -vaultwarden_client_secret -vaultwarden_master_password +ci_user_registry_password_argon_encoded +passwd_client_id +passwd_client_secret +passwd_master_password |