diff --git a/argocd/apps/tailscale-operator.yaml b/argocd/apps/tailscale-operator.yaml new file mode 100644 index 0000000..041f676 --- /dev/null +++ b/argocd/apps/tailscale-operator.yaml @@ -0,0 +1,22 @@ +# ArgoCD Application for Tailscale Kubernetes Operator +# Note: OAuth secret is managed separately (not in git) +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: tailscale-operator + namespace: argocd +spec: + project: default + source: + repoURL: ssh://forgejo@indri.tail8d86e.ts.net:2200/eblume/blumeops.git + targetRevision: feature/k8s-phase1-kickoff + path: argocd/manifests/tailscale-operator + destination: + server: https://kubernetes.default.svc + namespace: tailscale + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/argocd/manifests/argocd/repo-forge-secret.yaml.tpl b/argocd/manifests/argocd/repo-forge-secret.yaml.tpl new file mode 100644 index 0000000..f4a2d53 --- /dev/null +++ b/argocd/manifests/argocd/repo-forge-secret.yaml.tpl @@ -0,0 +1,27 @@ +# ArgoCD repository secret for forge SSH access +# +# IMPORTANT: Use ?ssh-format=openssh to get OpenSSH format (required by ArgoCD) +# +# Create the secret with: +# +# PRIV_KEY=$(op read "op://vg6xf6vvfmoh5hqjjhlhbeoaie/csjncynh6htjvnh2l2da65y32q/private key?ssh-format=openssh")$'\n' && \ +# kubectl create secret generic repo-forge -n argocd \ +# --from-literal=type=git \ +# --from-literal=url='ssh://forgejo@indri.tail8d86e.ts.net:2200/eblume/blumeops.git' \ +# --from-literal=insecure=true \ +# --from-literal=sshPrivateKey="$PRIV_KEY" && \ +# kubectl label secret repo-forge -n argocd argocd.argoproj.io/secret-type=repository +# +apiVersion: v1 +kind: Secret +metadata: + name: repo-forge + namespace: argocd + labels: + argocd.argoproj.io/secret-type: repository +stringData: + type: git + url: ssh://forgejo@indri.tail8d86e.ts.net:2200/eblume/blumeops.git + insecure: "true" + sshPrivateKey: | + # Key from 1Password: op://vg6xf6vvfmoh5hqjjhlhbeoaie/csjncynh6htjvnh2l2da65y32q/private key diff --git a/argocd/manifests/tailscale-operator/dnsconfig.yaml b/argocd/manifests/tailscale-operator/dnsconfig.yaml new file mode 100644 index 0000000..867d3dd --- /dev/null +++ b/argocd/manifests/tailscale-operator/dnsconfig.yaml @@ -0,0 +1,16 @@ +# DNSConfig for resolving MagicDNS names from within the cluster +# Deploys a nameserver that resolves ts.net names to egress proxy IPs +# +# Requires CoreDNS/kube-dns configuration to forward ts.net queries. +# See: https://tailscale.com/kb/1438/kubernetes-operator-cluster-egress +--- +apiVersion: tailscale.com/v1alpha1 +kind: DNSConfig +metadata: + name: ts-dns + namespace: tailscale +spec: + nameserver: + image: + repo: docker.io/tailscale/k8s-nameserver + tag: stable diff --git a/argocd/manifests/tailscale-operator/egress-forge.yaml b/argocd/manifests/tailscale-operator/egress-forge.yaml new file mode 100644 index 0000000..8705eea --- /dev/null +++ b/argocd/manifests/tailscale-operator/egress-forge.yaml @@ -0,0 +1,20 @@ +# Egress proxy to expose Forgejo (forge) to the cluster +# Forge runs on indri:3001, exposed via Tailscale Serve as forge.tail8d86e.ts.net +# We target indri directly since egress can't reach Tailscale Serve hostnames +# +# See: https://tailscale.com/kb/1438/kubernetes-operator-cluster-egress +--- +apiVersion: v1 +kind: Service +metadata: + name: forge + namespace: tailscale + annotations: + tailscale.com/tailnet-fqdn: indri.tail8d86e.ts.net + tailscale.com/proxy-class: "default" +spec: + type: ExternalName + externalName: placeholder + ports: + - port: 3001 + targetPort: 3001 diff --git a/pulumi/policy.hujson b/pulumi/policy.hujson index 10ded63..c575037 100644 --- a/pulumi/policy.hujson +++ b/pulumi/policy.hujson @@ -67,6 +67,13 @@ "dst": ["tag:registry"], "ip": ["tcp:443"], }, + // k8s workloads (e.g., ArgoCD) can access forge on indri for GitOps + // HTTP on 3001, SSH on 2200 + { + "src": ["tag:k8s"], + "dst": ["tag:homelab"], + "ip": ["tcp:3001", "tcp:2200"], + }, ], // ============== SSH Access ============== @@ -133,10 +140,10 @@ "src": "tag:homelab", "accept": ["tag:homelab:22", "tag:nas:445"], }, - // K8s workloads can reach registry + // K8s workloads can reach registry and forge (on indri:3001 HTTP, :2200 SSH) { "src": "tag:k8s", - "accept": ["tag:registry:443"], + "accept": ["tag:registry:443", "tag:homelab:3001", "tag:homelab:2200"], }, ], }