diff options
Diffstat (limited to 'playbooks/roles')
20 files changed, 331 insertions, 78 deletions
diff --git a/playbooks/roles/ci/templates/stacks/docker-compose.yml b/playbooks/roles/ci/templates/stacks/docker-compose.yml index e2358e5..38e1b1c 100644 --- a/playbooks/roles/ci/templates/stacks/docker-compose.yml +++ b/playbooks/roles/ci/templates/stacks/docker-compose.yml @@ -1,69 +1,26 @@ -services: - db: - image: postgres - environment: - POSTGRES_DB: concourse - POSTGRES_PASSWORD: concourse_pass - POSTGRES_USER: concourse_user - PGDATA: /database - POSTGRES_HOST_AUTH_METHOD: trust - healthcheck: - test: ["CMD-SHELL", "pg_isready -U concourse_user -d concourse"] - interval: 3s - timeout: 3s - retries: 5 - networks: - - ci - - worker: - image: concourse/concourse - command: worker - privileged: true - depends_on: - web: - condition: service_healthy - volumes: - - {{ ci_base }}/volumes/keys/worker:/concourse-keys - networks: - - ci - stop_signal: SIGUSR2 - environment: - CONCOURSE_TSA_HOST: web:2222 - CONCOURSE_GARDEN_DNS_PROXY_ENABLE: "true" +--- - web: - image: concourse - depends_on: - db: - condition: service_healthy +services: + laminard: + image: oci.liz.coffee/img/laminar-ciworker:latest volumes: - - {{ ci_base }}/volumes/keys/web:/concourse-keys + - {{ 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 environment: + - BW_CLIENTID={{ vaultwarden_client_id }} + - BW_CLIENTSECRET={{ vaultwarden_client_secret }} + - BW_PASSWORD={{ vaultwarden_master_password }} - TZ={{ timezone }} - DEPLOYMENT_TIME={{ deployment_time }} - - CONCOURSE_POSTGRES_HOST: db - - CONCOURSE_POSTGRES_USER: concourse_user - - CONCOURSE_POSTGRES_PASSWORD: concourse_pass - - CONCOURSE_POSTGRES_DATABASE: concourse - - CONCOURSE_EXTERNAL_URL: https://{{ ci_domain }} - - - # instead of relying on the default "detect" - - CONCOURSE_WORKER_BAGGAGECLAIM_DRIVER=overlay - - CONCOURSE_CLUSTER_NAME={{ ci_domain }} - - - CONCOURSE_OIDC_DISPLAY_NAME={{ domain }} <3 - - CONCOURSE_OIDC_CLIENT_ID=concourse - - CONCOURSE_OIDC_CLIENT_SECRET={{ concourse_secret_key }} - - CONCOURSE_OID_ISSUER=https://{{ idm_domain }}/oauth2/openid/concourse/ networks: - ci - proxy - healthcheck: - test: ["CMD-SHELL", "curl", "--fail", "http://localhost:8080"] - timeout: 15s - interval: 30s - retries: 3 - start_period: 5s deploy: mode: replicated update_config: @@ -84,5 +41,7 @@ services: networks: ci: + driver: overlay + attachable: true proxy: external: true diff --git a/playbooks/roles/ci/templates/volumes/laminar/.gitkeep b/playbooks/roles/ci/templates/volumes/laminar/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/playbooks/roles/ci/templates/volumes/laminar/.gitkeep diff --git a/playbooks/roles/ci/templates/volumes/laminar/jobs/build_image.run b/playbooks/roles/ci/templates/volumes/laminar/jobs/build_image.run new file mode 100755 index 0000000..ed7bf21 --- /dev/null +++ b/playbooks/roles/ci/templates/volumes/laminar/jobs/build_image.run @@ -0,0 +1,36 @@ +#!/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 new file mode 100755 index 0000000..181a050 --- /dev/null +++ b/playbooks/roles/ci/templates/volumes/laminar/jobs/playbook.run @@ -0,0 +1,25 @@ +#!/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 new file mode 100755 index 0000000..2774651 --- /dev/null +++ b/playbooks/roles/ci/templates/volumes/laminar/scripts/get_secret @@ -0,0 +1,35 @@ +#!/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 new file mode 100755 index 0000000..180fa33 --- /dev/null +++ b/playbooks/roles/ci/templates/volumes/laminar/scripts/log @@ -0,0 +1,3 @@ +#!/bin/bash + +echo `date +"%d-%m-%Y %H:%M:%S"` " - " "${@}" diff --git a/playbooks/roles/labdns/templates/volumes/unbound/a-records.conf b/playbooks/roles/labdns/templates/volumes/unbound/a-records.conf index 5eefeb5..d0c9517 100644 --- a/playbooks/roles/labdns/templates/volumes/unbound/a-records.conf +++ b/playbooks/roles/labdns/templates/volumes/unbound/a-records.conf @@ -3,6 +3,6 @@ local-data: "{{ service }}. A {{ loadbalancer_ip }}" {% endfor %} -# lucina.cloud +# 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/mail/templates/stacks/docker-compose.yml b/playbooks/roles/mail/templates/stacks/docker-compose.yml index 38e63cb..d7f8984 100644 --- a/playbooks/roles/mail/templates/stacks/docker-compose.yml +++ b/playbooks/roles/mail/templates/stacks/docker-compose.yml @@ -1,7 +1,6 @@ services: roundcube: image: roundcube/roundcubemail:latest - restart: always volumes: - {{ mail_base }}/volumes/data/roundcube/db:/var/roundcube/db - {{ mail_base }}/volumes/data/roundcube/config:/var/roundcube/config/ @@ -38,9 +37,9 @@ services: mailserver: image: ghcr.io/docker-mailserver/docker-mailserver:latest hostname: {{ mail_domain }} +{% if homelab_build %} command: - /scripts/wait-for-cert.sh -{% if homelab_build %} healthcheck: disable: true {% else %} @@ -59,7 +58,6 @@ services: - '4190:4190' - '110:110' - '995:995' - stop_grace_period: 30s deploy: mode: replicated replicas: 1 @@ -104,8 +102,6 @@ services: - SASLAUTHD_MECHANISMS=rimap - SASLAUTHD_MECH_OPTIONS=127.0.0.1 - - DOVECOT_USER_FILTER={{ dovecot_user_filter }} - - ENABLE_OAUTH2=1 - OAUTH2_INTROSPECTION_URL={{ roundcube_oauth2_user_uri }} diff --git a/playbooks/roles/mail/templates/volumes/data/dms/config/dovecot-ldap.conf b/playbooks/roles/mail/templates/volumes/data/dms/config/dovecot-ldap.conf index 6a14553..e55a861 100644 --- a/playbooks/roles/mail/templates/volumes/data/dms/config/dovecot-ldap.conf +++ b/playbooks/roles/mail/templates/volumes/data/dms/config/dovecot-ldap.conf @@ -8,3 +8,5 @@ dnpass = {{ email_ldap_api_token }} auth_bind = yes auth_bind_userdn = {{ dovecot_auth_bind_userdn }} +user_filter = {{ dovecot_user_filter }} +pass_filter = {{ dovecot_user_filter }} diff --git a/playbooks/roles/oci/tasks/main.yml b/playbooks/roles/oci/tasks/main.yml new file mode 100644 index 0000000..d9c3b56 --- /dev/null +++ b/playbooks/roles/oci/tasks/main.yml @@ -0,0 +1,8 @@ +--- + +- name: Deploy oci + ansible.builtin.import_tasks: manage-docker-swarm-service.yml + vars: + service_name: oci + template_render_dir: "../templates" + service_destination_dir: "{{ oci_base }}" diff --git a/playbooks/roles/oci/templates/stacks/docker-compose.yml b/playbooks/roles/oci/templates/stacks/docker-compose.yml new file mode 100644 index 0000000..8b40356 --- /dev/null +++ b/playbooks/roles/oci/templates/stacks/docker-compose.yml @@ -0,0 +1,48 @@ +services: + valkey: + image: valkey/valkey:8.0.2 + networks: + - oci + + oci: + image: ghcr.io/simple-registry/simple-registry:main + command: "server" + volumes: + - {{ oci_base }}/volumes/config.toml:/config.toml + - {{ oci_base }}/volumes/images:/images + environment: + - TZ={{ timezone }} + - DEPLOYMENT_TIME={{ deployment_time }} + - RUST_LOG=info + networks: + - proxy + - oci + healthcheck: + test: ["CMD", "/simple-registry", "scrub"] + timeout: 10s + interval: 30s + retries: 2 + start_period: 5s + deploy: + mode: replicated + update_config: + parallelism: 1 + failure_action: rollback + order: start-first + monitor: 5s + replicas: 1 + labels: + - traefik.enable=true + - traefik.swarm.network=proxy + - traefik.http.routers.oci.tls=true + - traefik.http.routers.oci.tls.certResolver=letsencrypt + - traefik.http.routers.oci.rule=Host(`{{ oci_domain }}`) + - traefik.http.routers.oci.entrypoints=websecure + - traefik.http.services.oci.loadbalancer.server.port=8000 + +networks: + oci: + attachable: true + driver: overlay + proxy: + external: true diff --git a/playbooks/roles/oci/templates/volumes/config.toml b/playbooks/roles/oci/templates/volumes/config.toml new file mode 100644 index 0000000..6d2f199 --- /dev/null +++ b/playbooks/roles/oci/templates/volumes/config.toml @@ -0,0 +1,35 @@ +[server] +bind_address = "0.0.0.0" +port = 8000 +streaming_chunk_size = "5MiB" + +[lock_store.redis] +url = "redis://valkey:6379" +ttl = 5 + +[cache_store.redis] +url = "redis://valkey:6379" +ttl = 5 + +[storage.fs] +root_dir = "/images" + +[observability.tracing] +endpoint = "http://127.0.0.1:4317" +sampling_rate = 1.0 + +[identity.ci] +username = "ci" +password = "{{ simple_registry_password_argon_encoded }}" + +[identity.readonly] +username = "readonly" +password = "$argon2i$v=19$m=16,t=2,p=1$TjJyTEdIZUJ6dFZkdlZvSg$qf8vG09O93Z/9vUMCgWNtA" # readonly + +[repository."img"] + +[repository."img".access_policy] +default_allow = false +rules = [ + 'request.action.startsWith("get-") || request.action.startsWith("list-") || identity.id == "ci"' +] diff --git a/playbooks/roles/oci/templates/volumes/images/.gitkeep b/playbooks/roles/oci/templates/volumes/images/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/playbooks/roles/oci/templates/volumes/images/.gitkeep diff --git a/playbooks/roles/outbound/templates/headscale/config/acl.json b/playbooks/roles/outbound/templates/headscale/config/acl.json index 449207d..242d01e 100644 --- a/playbooks/roles/outbound/templates/headscale/config/acl.json +++ b/playbooks/roles/outbound/templates/headscale/config/acl.json @@ -1,17 +1,24 @@ { "groups": { - "group:internal": ["liz{{ oauth_user_suffix }}", "lucina{{ oauth_user_suffix }}", "riley{{ oauth_user_suffix }}"], + "group:coffee_admins": ["liz{{ oauth_user_suffix }}", "lucina{{ oauth_user_suffix }}"], }, "acls": [ +{% for user in ["liz", "lucina", "riley"] %} + { + "action": "accept", + "src": ["{{ user }}{{ oauth_user_suffix }}"], + "dst": ["{{ user }}{{ oauth_user_suffix }}:*"] + }, +{% endfor %} { "action": "accept", "src": ["{{ auth_key_user }}"], - "dst": ["{{ auth_key_user }}:*", "10.0.0.0/8:*"] + "dst": ["{{ auth_key_user }}:*", "{{ loadbalancer_ip }}/32:*"] }, { "action": "accept", - "src": ["group:internal"], - "dst": ["10.0.0.0/8:*"] + "src": ["group:coffee_admins"], + "dst": ["{{ loadbalancer_ip }}/32:*"] } ] } diff --git a/playbooks/roles/outbound/templates/proxy/nginx/conf.d/oci.conf b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/oci.conf new file mode 100644 index 0000000..5e68fc3 --- /dev/null +++ b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/oci.conf @@ -0,0 +1,19 @@ +server { + listen 80; + server_name oci.liz.coffee; + + real_ip_header X-Forwarded-For; + real_ip_recursive on; + set_real_ip_from {{ docker_network }}; + + location / { + proxy_pass https://{{ loadbalancer_ip }}; + proxy_ssl_verify off; + proxy_http_version 1.1; + 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 Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} diff --git a/playbooks/roles/src/templates/stacks/docker-compose.yml b/playbooks/roles/src/templates/stacks/docker-compose.yml index 46f253d..547020d 100644 --- a/playbooks/roles/src/templates/stacks/docker-compose.yml +++ b/playbooks/roles/src/templates/stacks/docker-compose.yml @@ -1,4 +1,40 @@ 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 + src: image: charmcli/soft-serve volumes: @@ -17,8 +53,6 @@ services: - SOFT_SERVE_INITIAL_ADMIN_KEYS={{ src_admin_keys }} - SOFT_SERVE_GIT_MAX_CONNECTIONS=20 - SOFT_SERVE_LOG_FORMAT=json - networks: - - proxy healthcheck: test: ["CMD-SHELL", "netstat -tuln | grep 2222"] timeout: 15s @@ -33,14 +67,6 @@ services: order: stop-first monitor: 10s replicas: 1 - 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=8000 networks: proxy: diff --git a/playbooks/roles/src/templates/volumes/cgit.nginx.conf b/playbooks/roles/src/templates/volumes/cgit.nginx.conf new file mode 100644 index 0000000..5abe189 --- /dev/null +++ b/playbooks/roles/src/templates/volumes/cgit.nginx.conf @@ -0,0 +1,49 @@ +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 differnew file mode 100644 index 0000000..bb7ffa1 --- /dev/null +++ b/playbooks/roles/src/templates/volumes/cgit/cgit-css/cgit.png diff --git a/playbooks/roles/src/templates/volumes/cgit/index.html b/playbooks/roles/src/templates/volumes/cgit/index.html new file mode 100644 index 0000000..4b06983 --- /dev/null +++ b/playbooks/roles/src/templates/volumes/cgit/index.html @@ -0,0 +1 @@ +<h1>hai</h1> diff --git a/playbooks/roles/swarm_cluster/tasks/main.yml b/playbooks/roles/swarm_cluster/tasks/main.yml index d2507af..961d6f5 100644 --- a/playbooks/roles/swarm_cluster/tasks/main.yml +++ b/playbooks/roles/swarm_cluster/tasks/main.yml @@ -18,3 +18,7 @@ when: ansible_hostname != swarm_initializer_host ansible.builtin.import_tasks: swarm_join/tasks/main.yml +- name: Login to OCI + when: not homelab_build + ansible.builtin.command: "docker login {{ oci_domain }} --username {{ oci_username }} --password {{ oci_password }}" + |