diff --git a/ansible/group_vars/bind9_servers/mcintire.me.yml b/ansible/group_vars/bind9_servers/mcintire.me.yml index 1bbd97b..ca72bc7 100644 --- a/ansible/group_vars/bind9_servers/mcintire.me.yml +++ b/ansible/group_vars/bind9_servers/mcintire.me.yml @@ -18,7 +18,7 @@ mcintire_me_zone: ip: 107.174.178.20 - name: photos ip: 204.110.191.8 - - name: "pangolin" + - name: git ip: 172.245.56.83 other_name_servers: - autodiscover.mcintire.me. IN CNAME mail.w5isp.com. diff --git a/ansible/group_vars/bind9_servers/w5isp.com.yml b/ansible/group_vars/bind9_servers/w5isp.com.yml index 4a55fd8..ef740db 100644 --- a/ansible/group_vars/bind9_servers/w5isp.com.yml +++ b/ansible/group_vars/bind9_servers/w5isp.com.yml @@ -26,8 +26,6 @@ w5isp_com_zone: ip: 204.110.191.218 - name: "vm1" ip: 172.245.56.83 - - name: "pangolin" - ip: 172.245.56.83 - name: "*" ip: 172.245.56.83 other_name_servers: diff --git a/ansible/host_vars/vm1.w5isp.com.yml b/ansible/host_vars/vm1.w5isp.com.yml index 17249be..0b404f9 100644 --- a/ansible/host_vars/vm1.w5isp.com.yml +++ b/ansible/host_vars/vm1.w5isp.com.yml @@ -6,6 +6,10 @@ ansible_ssh_common_args: '-o StrictHostKeyChecking=accept-new' public_ip: 172.245.56.83 dns_backend: bind9 +# Forgejo runner +forgejo_runner_token: "I7rqgwumFl3BjuXnaEfroto7RHxGhsIUzM0lgMmM" +forgejo_runner_name: "vm1-runner" + # This server is a secondary/slave nameserver bind_zone_role: secondary diff --git a/ansible/hosts b/ansible/hosts index 488d248..c902018 100755 --- a/ansible/hosts +++ b/ansible/hosts @@ -28,4 +28,7 @@ vm1.w5isp.com ansible_host=172.245.56.83 [dns_servers:children] bind9_servers +[forgejo_servers] +vm1.w5isp.com + [postgresql_servers] diff --git a/ansible/playbook.yml b/ansible/playbook.yml index 6ac5209..2ad89f4 100644 --- a/ansible/playbook.yml +++ b/ansible/playbook.yml @@ -287,3 +287,12 @@ # tags: syncthing # roles: # - syncthing + +- name: Configure Forgejo servers + hosts: forgejo_servers + become: yes + gather_facts: true + tags: + - forgejo + roles: + - forgejo diff --git a/ansible/regenerate-ssh-keys.yml b/ansible/regenerate-ssh-keys.yml new file mode 100644 index 0000000..0269e16 --- /dev/null +++ b/ansible/regenerate-ssh-keys.yml @@ -0,0 +1,89 @@ +--- +# One-time playbook to regenerate SSH host keys on existing hosts +# Usage: ansible-playbook -l "vm1,pangolin,camper,birdnet" regenerate-ssh-keys.yml +# +# After running this playbook, you'll need to update your local known_hosts: +# ssh-keygen -R hostname +# Or clear all affected entries and re-accept on next connection. + +- name: Regenerate SSH host keys on existing hosts + hosts: all + become: true + gather_facts: true + + tasks: + - name: Remove existing SSH host keys + file: + path: "{{ item }}" + state: absent + loop: + - /etc/ssh/ssh_host_rsa_key + - /etc/ssh/ssh_host_rsa_key.pub + - /etc/ssh/ssh_host_ecdsa_key + - /etc/ssh/ssh_host_ecdsa_key.pub + - /etc/ssh/ssh_host_ed25519_key + - /etc/ssh/ssh_host_ed25519_key.pub + - /etc/ssh/ssh_host_dsa_key + - /etc/ssh/ssh_host_dsa_key.pub + + - name: Regenerate SSH host keys (Debian/Ubuntu) + command: dpkg-reconfigure openssh-server + when: ansible_os_family == "Debian" + + - name: Regenerate SSH host keys (RHEL/CentOS) + shell: | + ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N '' + ssh-keygen -t ecdsa -b 521 -f /etc/ssh/ssh_host_ecdsa_key -N '' + ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' + when: ansible_os_family == "RedHat" + + - name: Regenerate SSH host keys (Alpine) + shell: | + ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N '' + ssh-keygen -t ecdsa -b 521 -f /etc/ssh/ssh_host_ecdsa_key -N '' + ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' + when: ansible_os_family == "Alpine" + + - name: Set correct permissions on private keys + file: + path: "{{ item }}" + mode: '0600' + loop: + - /etc/ssh/ssh_host_rsa_key + - /etc/ssh/ssh_host_ecdsa_key + - /etc/ssh/ssh_host_ed25519_key + ignore_errors: true + + - name: Set correct permissions on public keys + file: + path: "{{ item }}" + mode: '0644' + loop: + - /etc/ssh/ssh_host_rsa_key.pub + - /etc/ssh/ssh_host_ecdsa_key.pub + - /etc/ssh/ssh_host_ed25519_key.pub + ignore_errors: true + + - name: Restart SSH service + service: + name: "{{ 'ssh' if ansible_os_family == 'Debian' else 'sshd' }}" + state: restarted + + - name: Create marker file to indicate keys were regenerated + file: + path: /etc/ssh/.host_keys_regenerated + state: touch + mode: '0644' + + - name: Display new SSH host key fingerprints + shell: | + echo "=== New SSH Host Key Fingerprints for {{ inventory_hostname }} ===" + for key in /etc/ssh/ssh_host_*_key.pub; do + ssh-keygen -lf "$key" 2>/dev/null || true + done + register: fingerprints + changed_when: false + + - name: Show fingerprints + debug: + msg: "{{ fingerprints.stdout_lines }}" diff --git a/ansible/roles/base/tasks/system.yml b/ansible/roles/base/tasks/system.yml index eb8ce58..c0cd3f1 100644 --- a/ansible/roles/base/tasks/system.yml +++ b/ansible/roles/base/tasks/system.yml @@ -1,6 +1,63 @@ --- # System configuration tasks +# SSH host key regeneration for cloned VMs +# Only runs once per host (marker file prevents re-running) +- name: Check if SSH host keys have been regenerated + stat: + path: /etc/ssh/.host_keys_regenerated + register: ssh_keys_marker + +- name: Regenerate SSH host keys (first boot after clone) + when: not ssh_keys_marker.stat.exists + block: + - name: Remove existing SSH host keys + file: + path: "{{ item }}" + state: absent + loop: + - /etc/ssh/ssh_host_rsa_key + - /etc/ssh/ssh_host_rsa_key.pub + - /etc/ssh/ssh_host_ecdsa_key + - /etc/ssh/ssh_host_ecdsa_key.pub + - /etc/ssh/ssh_host_ed25519_key + - /etc/ssh/ssh_host_ed25519_key.pub + - /etc/ssh/ssh_host_dsa_key + - /etc/ssh/ssh_host_dsa_key.pub + + - name: Regenerate SSH host keys + command: dpkg-reconfigure openssh-server + args: + creates: /etc/ssh/ssh_host_ed25519_key + when: ansible_os_family == "Debian" + notify: restart ssh + + - name: Regenerate SSH host keys (RHEL) + shell: | + ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N '' + ssh-keygen -t ecdsa -b 521 -f /etc/ssh/ssh_host_ecdsa_key -N '' + ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' + args: + creates: /etc/ssh/ssh_host_ed25519_key + when: ansible_os_family == "RedHat" + notify: restart ssh + + - name: Regenerate SSH host keys (Alpine) + shell: | + ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N '' + ssh-keygen -t ecdsa -b 521 -f /etc/ssh/ssh_host_ecdsa_key -N '' + ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' + args: + creates: /etc/ssh/ssh_host_ed25519_key + when: ansible_os_family == "Alpine" + notify: restart ssh + + - name: Create marker file to prevent re-running + file: + path: /etc/ssh/.host_keys_regenerated + state: touch + mode: '0644' + - name: Install SSH banner template: src: issue.net.j2 diff --git a/ansible/roles/forgejo/defaults/main.yml b/ansible/roles/forgejo/defaults/main.yml new file mode 100644 index 0000000..8dbb883 --- /dev/null +++ b/ansible/roles/forgejo/defaults/main.yml @@ -0,0 +1,16 @@ +--- +forgejo_home: /opt/forgejo +forgejo_version: "10" +forgejo_http_port: 3000 +forgejo_ssh_port: 2222 +forgejo_domain: git.mcintire.me +forgejo_root_url: "https://{{ forgejo_domain }}" + +# App settings +forgejo_app_name: "Forgejo" + +# Runner settings +forgejo_runner_version: "6.2.2" +forgejo_runner_token: "" +forgejo_runner_name: "default-runner" +forgejo_runner_labels: "docker:docker://node:20-bookworm,ubuntu-latest:docker://ubuntu:latest,ubuntu-22.04:docker://ubuntu:22.04" diff --git a/ansible/roles/forgejo/handlers/main.yml b/ansible/roles/forgejo/handlers/main.yml new file mode 100644 index 0000000..979ade3 --- /dev/null +++ b/ansible/roles/forgejo/handlers/main.yml @@ -0,0 +1,11 @@ +--- +- name: restart forgejo + systemd: + name: forgejo + state: restarted + daemon_reload: true + +- name: restart caddy + systemd: + name: caddy + state: reloaded diff --git a/ansible/roles/forgejo/tasks/main.yml b/ansible/roles/forgejo/tasks/main.yml new file mode 100644 index 0000000..0e5fc02 --- /dev/null +++ b/ansible/roles/forgejo/tasks/main.yml @@ -0,0 +1,152 @@ +--- +# Install Docker +- name: Install prerequisites for Docker + apt: + name: + - ca-certificates + - curl + - gnupg + - lsb-release + - git + state: present + update_cache: true + +- name: Add Docker's official GPG key + ansible.builtin.get_url: + url: https://download.docker.com/linux/debian/gpg + dest: /usr/share/keyrings/docker-archive-keyring.asc + mode: '0644' + +- name: Add Docker repository + ansible.builtin.deb822_repository: + name: docker + types: deb + uris: https://download.docker.com/linux/debian + suites: "{{ ansible_distribution_release }}" + components: stable + architectures: "{{ ansible_architecture | replace('x86_64', 'amd64') }}" + signed_by: /usr/share/keyrings/docker-archive-keyring.asc + state: present + +- name: Install Docker packages + apt: + name: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-compose-plugin + state: present + update_cache: true + +- name: Ensure Docker service is started and enabled + systemd: + name: docker + state: started + enabled: true + +# Create Forgejo directories +- name: Create forgejo directories + file: + path: "{{ item }}" + state: directory + mode: '0755' + loop: + - "{{ forgejo_home }}" + - "{{ forgejo_home }}/data" + +- name: Create runner directory with correct permissions + file: + path: "{{ forgejo_home }}/runner" + state: directory + mode: '0777' + +- name: Deploy docker-compose file + template: + src: docker-compose.yml.j2 + dest: "{{ forgejo_home }}/docker-compose.yml" + mode: '0644' + notify: restart forgejo + +- name: Pull container images + command: docker compose pull + args: + chdir: "{{ forgejo_home }}" + register: pull_result + changed_when: "'Pulling' in pull_result.stdout or 'Downloaded' in pull_result.stderr" + +- name: Deploy systemd service for Forgejo + template: + src: forgejo.service.j2 + dest: /etc/systemd/system/forgejo.service + owner: root + group: root + mode: '0644' + notify: restart forgejo + +- name: Reload systemd daemon + systemd: + daemon_reload: true + +- name: Start and enable Forgejo service + systemd: + name: forgejo + state: started + enabled: true + +# Install and configure Caddy +- name: Check if Caddy GPG key exists + stat: + path: /usr/share/keyrings/caddy-stable-archive-keyring.asc + register: caddy_gpg_key + +- name: Add Caddy GPG key + ansible.builtin.get_url: + url: "https://dl.cloudsmith.io/public/caddy/stable/gpg.key" + dest: /usr/share/keyrings/caddy-stable-archive-keyring.asc + mode: '0644' + when: not caddy_gpg_key.stat.exists + +- name: Add Caddy repository + ansible.builtin.deb822_repository: + name: caddy-stable + types: deb + uris: https://dl.cloudsmith.io/public/caddy/stable/deb/debian + suites: any-version + components: main + signed_by: /usr/share/keyrings/caddy-stable-archive-keyring.asc + state: present + +- name: Install Caddy + apt: + name: caddy + state: present + update_cache: true + +- name: Configure Caddy for Forgejo + template: + src: Caddyfile.j2 + dest: /etc/caddy/Caddyfile + owner: root + group: root + mode: '0644' + notify: restart caddy + +- name: Ensure Caddy is started and enabled + systemd: + name: caddy + state: started + enabled: true + +- name: Wait for Forgejo to be ready + uri: + url: "http://localhost:{{ forgejo_http_port }}/" + method: GET + status_code: + - 200 + - 302 + validate_certs: false + timeout: 30 + register: result + until: result.status in [200, 302] + retries: 12 + delay: 5 diff --git a/ansible/roles/forgejo/templates/Caddyfile.j2 b/ansible/roles/forgejo/templates/Caddyfile.j2 new file mode 100644 index 0000000..a79cef4 --- /dev/null +++ b/ansible/roles/forgejo/templates/Caddyfile.j2 @@ -0,0 +1,3 @@ +{{ forgejo_domain }} { + reverse_proxy localhost:{{ forgejo_http_port }} +} diff --git a/ansible/roles/forgejo/templates/docker-compose.yml.j2 b/ansible/roles/forgejo/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..34bc282 --- /dev/null +++ b/ansible/roles/forgejo/templates/docker-compose.yml.j2 @@ -0,0 +1,37 @@ +--- +services: + forgejo: + image: codeberg.org/forgejo/forgejo:{{ forgejo_version }} + container_name: forgejo + restart: unless-stopped + environment: + - USER_UID=1000 + - USER_GID=1000 + - FORGEJO__server__DOMAIN={{ forgejo_domain }} + - FORGEJO__server__SSH_DOMAIN={{ forgejo_domain }} + - FORGEJO__server__ROOT_URL={{ forgejo_root_url }} + - FORGEJO__server__SSH_PORT={{ forgejo_ssh_port }} + - FORGEJO__server__SSH_LISTEN_PORT=22 + volumes: + - {{ forgejo_home }}/data:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "127.0.0.1:{{ forgejo_http_port }}:3000" + - "{{ forgejo_ssh_port }}:22" + + runner: + image: code.forgejo.org/forgejo/runner:{{ forgejo_runner_version }} + container_name: forgejo-runner + restart: unless-stopped + user: root + depends_on: + - forgejo + environment: + - DOCKER_HOST=unix:///var/run/docker.sock + volumes: + - {{ forgejo_home }}/runner:/data + - /var/run/docker.sock:/var/run/docker.sock + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + command: ["sh", "-c", "if [ ! -f /data/.runner ]; then forgejo-runner register --no-interactive --instance {{ forgejo_root_url }} --token {{ forgejo_runner_token }} --name {{ forgejo_runner_name }} --labels '{{ forgejo_runner_labels }}'; fi; forgejo-runner daemon"] diff --git a/ansible/roles/forgejo/templates/forgejo.service.j2 b/ansible/roles/forgejo/templates/forgejo.service.j2 new file mode 100644 index 0000000..a336a2d --- /dev/null +++ b/ansible/roles/forgejo/templates/forgejo.service.j2 @@ -0,0 +1,15 @@ +[Unit] +Description=Forgejo Git Service +After=docker.service +Requires=docker.service + +[Service] +Type=oneshot +RemainAfterExit=yes +WorkingDirectory={{ forgejo_home }} +ExecStart=/usr/bin/docker compose up -d +ExecStop=/usr/bin/docker compose down +TimeoutStartSec=0 + +[Install] +WantedBy=multi-user.target diff --git a/cluster/cloudflared/deploy.sh b/cluster/cloudflared/deploy.sh new file mode 100755 index 0000000..d63c866 --- /dev/null +++ b/cluster/cloudflared/deploy.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -e +cd "$(dirname "$0")" + +echo "Deploying cloudflared to Talos cluster..." +kubectl apply -f namespace.yaml +kubectl apply -f secret.yaml +kubectl apply -f deployment.yaml + +echo "Waiting for rollout..." +kubectl rollout status deployment/cloudflared -n cloudflared --timeout=120s + +echo "" +echo "Cloudflared deployed successfully!" +kubectl get pods -n cloudflared diff --git a/cluster/cloudflared/deployment.yaml b/cluster/cloudflared/deployment.yaml new file mode 100644 index 0000000..14799c3 --- /dev/null +++ b/cluster/cloudflared/deployment.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cloudflared + namespace: cloudflared +spec: + replicas: 2 + selector: + matchLabels: + app: cloudflared + template: + metadata: + labels: + app: cloudflared + spec: + containers: + - name: cloudflared + image: cloudflare/cloudflared:latest + imagePullPolicy: IfNotPresent + args: + - tunnel + - --no-autoupdate + - --metrics + - 0.0.0.0:2000 + - run + env: + - name: TUNNEL_TOKEN + valueFrom: + secretKeyRef: + name: tunnel-token + key: token + ports: + - name: metrics + containerPort: 2000 + protocol: TCP + livenessProbe: + httpGet: + path: /ready + port: 2000 + initialDelaySeconds: 10 + periodSeconds: 10 + resources: + requests: + memory: "64Mi" + cpu: "50m" + limits: + memory: "256Mi" + cpu: "200m" + restartPolicy: Always diff --git a/cluster/cloudflared/namespace.yaml b/cluster/cloudflared/namespace.yaml new file mode 100644 index 0000000..ed7917a --- /dev/null +++ b/cluster/cloudflared/namespace.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: cloudflared + labels: + pod-security.kubernetes.io/enforce: privileged diff --git a/cluster/cloudflared/secret.yaml b/cluster/cloudflared/secret.yaml new file mode 100644 index 0000000..525a08c --- /dev/null +++ b/cluster/cloudflared/secret.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: tunnel-token + namespace: cloudflared +type: Opaque +stringData: + token: "eyJhIjoiNGQxODE0OGE4MmIwYTkxZjI4OWFmYmJkMjk0NGE2MDMiLCJ0IjoiZDNkODE5YmEtOTI1Yy00ZDg0LTgwNTItNjhlZDMyYjY4NmJiIiwicyI6IlkyVTBaRGd3WlRVdFpUSXdNQzAwTkdNMkxXSmtOMk10TVdKaFpXSTBNR1l6TlRVNCJ9" diff --git a/talos/kubeconfig b/talos/kubeconfig new file mode 100644 index 0000000..920162e --- /dev/null +++ b/talos/kubeconfig @@ -0,0 +1,19 @@ +apiVersion: v1 +clusters: +- cluster: + certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpekNDQVRDZ0F3SUJBZ0lSQU5pSitIN3JtY0VEa3AxZ1BZMEpSVWt3Q2dZSUtvWkl6ajBFQXdJd0ZURVQKTUJFR0ExVUVDaE1LYTNWaVpYSnVaWFJsY3pBZUZ3MHlOakF4TVRReE56VXlNakphRncwek5qQXhNVEl4TnpVeQpNakphTUJVeEV6QVJCZ05WQkFvVENtdDFZbVZ5Ym1WMFpYTXdXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CCkJ3TkNBQVRRMUpQeWl2bjkzc0FHSUhTUzJBN0VnQTI2N3ZJM0pWcC9rMWZQWnFNRnpmNHlmRHBwTUQ5cG42SEQKWUx2SjkyazNGRkRoYXh2UDZIUTRRQVV3UW5Mcm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXdIUVlEVlIwbApCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0hRWURWUjBPCkJCWUVGTXhodGtYOHZUbEtGMkJ4THBqUXhJZGRuNzJuTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDSVFDeGNaTTQKZ09RTHplU1BrSy9HTnZaV3pueTBoSXM0ZmUrYVJOMENhN1A2UndJaEFJSHc0Ni9EaDJtTWZLQm9GS3hmTnJWTQpiaVNoekF1QzQ2THdVZXJyNmNBcQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + server: https://10.0.15.1:6443 + name: home-cluster +contexts: +- context: + cluster: home-cluster + namespace: default + user: admin@home-cluster + name: admin@home-cluster +current-context: admin@home-cluster +kind: Config +users: +- name: admin@home-cluster + user: + client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJoVENDQVNxZ0F3SUJBZ0lRTGJBMXhGT0NPa2lkbmhnaCtkb3o5VEFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSTJNREV6TVRJeE1Ua3hPRm9YRFRJM01ERXpNVEl4TVRreQpPRm93S1RFWE1CVUdBMVVFQ2hNT2MzbHpkR1Z0T20xaGMzUmxjbk14RGpBTUJnTlZCQU1UQldGa2JXbHVNRmt3CkV3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFa2pCaTRiMXl0aUd4cFpJcDVSQVhtYXlCZDU5SlhqWGsKWllRbWI4b0svL2dDeE4yaHFvUCt4dmM1dC9DVXdtTVZKQkFod2FuRnhHalA3TkplMGNYZ3BLTklNRVl3RGdZRApWUjBQQVFIL0JBUURBZ1dnTUJNR0ExVWRKUVFNTUFvR0NDc0dBUVVGQndNQ01COEdBMVVkSXdRWU1CYUFGTXhoCnRrWDh2VGxLRjJCeExwalF4SWRkbjcybk1Bb0dDQ3FHU000OUJBTUNBMGtBTUVZQ0lRQ1NJdVZ0VTYzaWowRG0KSU5ML01QZEdjY2t6WTlDMURLUGw4bytObStjVmJRSWhBT2orQnB6NUo1ZThub2pNMXI2aHFnRWlpYjF6Y1ZpSwpuaXVPZjYrNFBPU0cKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + client-key-data: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVMeHprQzVIMHBLVkxHVU93RmpoaDBPeHdZWFN2R2lIRktIbmF1L09nZllvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFa2pCaTRiMXl0aUd4cFpJcDVSQVhtYXlCZDU5SlhqWGtaWVFtYjhvSy8vZ0N4TjJocW9QKwp4dmM1dC9DVXdtTVZKQkFod2FuRnhHalA3TkplMGNYZ3BBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=