diff --git a/Unbound/Deployment.yaml b/Unbound/Deployment.yaml new file mode 100644 index 0000000..8289088 --- /dev/null +++ b/Unbound/Deployment.yaml @@ -0,0 +1,408 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: cronjobber-sh-config + + labels: + service: unbound-combo + +data: + updateBlockList.sh: | + #!/bin/sh + + apk add curl > /dev/null + DL_LOCATION=/blocklists + + mkdir -p $DL_LOCATION + + # LINKS="${LINKS:-https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/pro.txt + # https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/fake.txt + # https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/tif.txt + # https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/doh-vpn-proxy-bypass.txt + # https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/gambling.txt + # }" + + if [ "$(find $DL_LOCATION/ -mmin +240)" ] || ! [ "$( ls -A $DL_LOCATION/ )" ] + then + # Pro + curl -fsSL -o rpz.hagezi.fake.zone --output-dir $DL_LOCATION/ https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/pro.txt + # Fake + curl -fsSL -o rpz.hagezi.pro.zone --output-dir $DL_LOCATION/ https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/fake.txt + # Tif + curl -fsSL -o rpz.hagezi.tif.zone --output-dir $DL_LOCATION/ https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/tif.txt + # DoH + curl -fsSL -o rpz.hagezi.doh-vpn-proxy-bypass.zone --output-dir $DL_LOCATION/ https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/doh-vpn-proxy-bypass.txt + # Gacha + curl -fsSL -o rpz.hagezi.gambling.zone --output-dir $DL_LOCATION/ https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/gambling.txt + + # for i in $LINKS + # do + # curl -fsSL -O --output-dir $DL_LOCATION $i + # done + fi + + chown -R 1500:1500 $DL_LOCATION + +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: unbound-combo-blocklist-cronjob + + labels: + project: unbound-combo + +spec: + schedule: "30 */1 * * *" + concurrencyPolicy: Forbid + timeZone: Europe/Stockholm + jobTemplate: + metadata: + labels: + pod-project: unbound-combo-blocklist-cron + project-ns-name: private-srvc + spec: + # selector: + # matchLabels: + # pod-project: unbound-combo-blocklist-cron + + template: + spec: + automountServiceAccountToken: false # Container doesn't need service account token + securityContext: + appArmorProfile: + type: RuntimeDefault + # runAsNonRoot: true + fsGroup: 1500 + # runAsGroup: 1500 + # runAsUser: 1500 + restartPolicy: OnFailure + containers: + - name: cronjobber + image: alpine:3.23.2 + imagePullPolicy: IfNotPresent + env: + - name: DL_LOCATION + value: /blocklists/ + volumeMounts: + - name: cronjobber-blocklists + mountPath: /blocklists + readOnly: false + + - name: cronjobber-update-sh + mountPath: /updateBlockList.sh + subPath: updateBlockList.sh + readOnly: true + + command: ["/bin/sh", "/updateBlockList.sh"] + + volumes: + - name: cronjobber-blocklists + persistentVolumeClaim: + claimName: unbound-combo-blocklist-pvc + readOnly: false + + - name: cronjobber-update-sh + configMap: + name: cronjobber-sh-config + +--- + +apiVersion: v1 +kind: ConfigMap +metadata: + name: unbound-conf-configmap + + labels: + service: unbound-combo + +data: + unbound.conf: | + server: + # listen on + interface: 0.0.0.0 + port: 53 + do-udp: yes + do-tcp: yes + # ACL + # Basicaly allow whole RFC1918 + access-control: 10.0.0.0/8 allow + access-control: 172.16.0.0/12 allow + access-control: 192.168.0.0/16 allow + access-control: 127.0.0.0/8 allow + + module-config: "respip validator iterator" + do-not-query-localhost: no + + # If running IPv6 change these + do-ip6: no + do-ip4: yes + do-udp: yes + do-tcp: yes + + # Cache/perf + num-threads: 1 + msg-cache-size: 64m + rrset-cache-size: 128m + cache-min-ttl: 0 + cache-max-ttl: 86400 + prefetch: yes + prefetch-key: yes + outgoing-range: 950 + + # best practice or something + qname-minimisation: yes + # hide-identity: yes + hide-version: yes + + # loggning + verbosity: 1 + logfile: "" + log-queries: yes + log-replies: no + + # local domains + + # example for a local domain with redirect for all subdomains + local-zone: "example.me." redirect + local-data: "int.example.me. 60 IN A 1.2.3.4" + + + # Forwad to + forward-zone: + name: "." + forward-addr: 127.0.0.1@5053 + forward-addr: 127.0.0.1@5052 + #forward-addr: 127.0.0.1@5051 + + rpz: + name: "rpz.hagezi.fake.local." + zonefile: "/zonefiles/rpz.hagezi.fake.zone" + url: "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/fake.txt" + rpz: + name: "rpz.hagezi.pro.local." + zonefile: "/zonefiles/rpz.hagezi.pro.zone" + url: "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/pro.txt" + rpz: + name: "rpz.hagezi.tif.local." + zonefile: "/zonefiles/rpz.hagezi.tif.zone" + url: "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/tif.txt" + rpz: + name: "rpz.hagezi.doh-vpn-proxy-bypass.local." + zonefile: "/zonefiles/rpz.hagezi.doh-vpn-proxy-bypass.zone" + url: "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/doh-vpn-proxy-bypass.txt" + rpz: + name: "rpz.hagezi.gambling.local." + zonefile: "/zonefiles/rpz.hagezi.gambling.zone" + url: "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/gambling.txt" + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: unbound-combo-deployment + + labels: + project: unbound-combo + + +spec: + replicas: 4 + selector: + matchLabels: + pod-project: unbound-combo + # serviceName: pihole-statefulsets-webgui-service + minReadySeconds: 10 + template: + metadata: + labels: + pod-project: unbound-combo + project-ns-name: private-srvc + # pod-project: doh + spec: + # terminationGracePeriodSeconds: 10 + automountServiceAccountToken: false # Container doesn't need service account token + securityContext: + appArmorProfile: + type: RuntimeDefault + runAsNonRoot: true + fsGroup: 1500 + runAsGroup: 1500 + runAsUser: 1500 + initContainers: + - name: startupper + image: alpine:3.23.2 + imagePullPolicy: IfNotPresent + securityContext: + appArmorProfile: + type: RuntimeDefault + runAsNonRoot: false + readOnlyRootFilesystem: false + # fsGroup: 1500 + runAsGroup: 0 + runAsUser: 0 + env: + - name: DL_LOCATION + value: /blocklists/ + volumeMounts: + - name: cronjobber-blocklists + mountPath: /blocklists + readOnly: false + - name: cronjobber-update-sh + mountPath: /updateBlockList.sh + subPath: updateBlockList.sh + readOnly: true + command: ["/bin/sh", "/updateBlockList.sh"] + containers: + - name: unbound + image: mvance/unbound:latest + imagePullPolicy: IfNotPresent + # command: ["unbound", "-c", "/etc/unbound.conf"] + securityContext: + appArmorProfile: + type: RuntimeDefault + runAsNonRoot: false + readOnlyRootFilesystem: false + # fsGroup: 1500 + runAsGroup: 0 + runAsUser: 0 + volumeMounts: + - name: cronjobber-blocklists + mountPath: /opt/unbound/etc/unbound/zonefiles + readOnly: false + - name: unbound-config + mountPath: /opt/unbound/etc/unbound/unbound.conf # mount a single key as a file + subPath: unbound.conf + # readOnly: true + + ports: + - name: dns-tcp + containerPort: 53 + protocol: TCP + - name: dns-udp + containerPort: 53 + protocol: UDP + + startupProbe: + tcpSocket: + port: 53 + # exec: + # command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"] + initialDelaySeconds: 5 + periodSeconds: 5 + failureThreshold: 60 + livenessProbe: + tcpSocket: + port: 53 + # exec: + # command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"] + periodSeconds: 5 + failureThreshold: 4 + readinessProbe: + tcpSocket: + port: 53 + # exec: + # command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"] + periodSeconds: 10 + failureThreshold: 6 + resources: + requests: + memory: "256Mi" + cpu: "200m" + limits: + memory: "1536Mi" + # cpu: "550m" + + # https://github.com/eko/pihole-exporter + # https://github.com/letsencrypt/unbound_exporter + # - name: prom-exporter? + # image: ekofr/pihole-exporter:v1.2.0 + # imagePullPolicy: IfNotPresent + # ports: + # - name: prom-export + # containerPort: 50934 + # protocol: TCP + + + - name: cloudflare-1-1-1-1 + image: visibilityspots/cloudflared:v2025.7.0 + imagePullPolicy: IfNotPresent + ports: + - name: doh-unseiso-udp + containerPort: 5051 + protocol: UDP + - name: doh-unseiso-tcp + containerPort: 5051 + protocol: TCP + env: + - name: PORT + value: "5051" + - name: UPSTREAM1 + value: https://1.1.1.1/dns-query + - name: UPSTREAM2 + value: https://1.0.0.1/dns-query + - name: METRICS + value: "127.0.0.1:8081" + resources: + requests: + memory: "48Mi" + cpu: "100m" + + - name: cloudflare-1-1-1-2 + image: visibilityspots/cloudflared:v2025.7.0 + imagePullPolicy: IfNotPresent + ports: + - name: doh-nov-tcp + containerPort: 5052 + protocol: TCP + - name: doh-nov-udp + containerPort: 5052 + protocol: UDP + env: + - name: PORT + value: "5052" + - name: UPSTREAM1 + value: https://1.1.1.2/dns-query + - name: UPSTREAM2 + value: https://1.0.0.2/dns-query + - name: METRICS + value: "127.0.0.1:8082" + resources: + requests: + memory: "48Mi" + cpu: "100m" + + - name: cloudflare-1-1-1-3 + image: visibilityspots/cloudflared:v2025.7.0 + imagePullPolicy: IfNotPresent + ports: + - name: doh-unseiso-udp + containerPort: 5053 + protocol: UDP + - name: doh-unseiso-tcp + containerPort: 5053 + protocol: TCP + env: + - name: PORT + value: "5053" + - name: UPSTREAM1 + value: https://1.1.1.3/dns-query + - name: UPSTREAM2 + value: https://1.0.0.3/dns-query + - name: METRICS + value: "127.0.0.1:8083" + resources: + requests: + memory: "48Mi" + cpu: "100m" + + volumes: + - name: cronjobber-blocklists + persistentVolumeClaim: + claimName: unbound-combo-blocklist-pvc + - name: cronjobber-update-sh + configMap: + name: cronjobber-sh-config + - name: unbound-config + configMap: + name: unbound-conf-configmap diff --git a/Unbound/netPolicy.yaml b/Unbound/netPolicy.yaml new file mode 100644 index 0000000..8333add --- /dev/null +++ b/Unbound/netPolicy.yaml @@ -0,0 +1,70 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: unbound-netpol + labels: + project: unbound-combo + +spec: + podSelector: + matchLabels: + pod-project: unbound-combo + egress: + # Allow all egress + # - {} + + # Allow egress only to public networks + - to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: kube-system + podSelector: + matchLabels: + k8s-app: kube-dns + ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + + - to: + - ipBlock: + cidr: 0.0.0.0/0 + except: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + + ingress: + + - from: + - ipBlock: + cidr: 192.168.0.0/16 + ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + + - from: + - ipBlock: + cidr: 10.0.0.0/8 + ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + + - from: + - ipBlock: + cidr: 172.16.0.0/12 + ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + + + policyTypes: + - Ingress + - Egress \ No newline at end of file diff --git a/Unbound/pvc.yaml b/Unbound/pvc.yaml new file mode 100644 index 0000000..9d21e74 --- /dev/null +++ b/Unbound/pvc.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: unbound-combo-blocklist-pvc + labels: + project: unbound-combo +spec: + # https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes-1 + accessModes: + # - ReadOnlyMany + # - ReadWriteOnce + - ReadWriteMany + resources: + requests: + storage: 128Mi diff --git a/Unbound/service.yaml b/Unbound/service.yaml new file mode 100644 index 0000000..7285423 --- /dev/null +++ b/Unbound/service.yaml @@ -0,0 +1,31 @@ +# Main IP for DNS +apiVersion: v1 +kind: Service +metadata: + name: unbound-combo-dns-service + labels: + project: unbound-combo + annotations: + metallb.io/loadBalancerIPs: 1.2.3.4 + + +spec: + selector: + pod-project: unbound-combo + # This isn't used as Ingress is doing TLS termination + type: LoadBalancer + + # Preserve ips + externalTrafficPolicy: Local + + # type: ClusterIP + ports: + - name: unbound-dns-udp + protocol: UDP + port: 53 # <- port that will be exposed + targetPort: 53 + - name: unbound-dns-tcp + protocol: TCP + port: 53 # <- port that will be exposed + targetPort: 53 +