From bd1c17b09bc85566c09c0a57b093510d86113cd5 Mon Sep 17 00:00:00 2001 From: Ian Keane Date: Sat, 22 Aug 2026 14:33:10 -0400 Subject: [PATCH] Add oauth proxy and supporting ecr infra --- Makefile | 10 ++- charts/mcp-auth-proxy/Chart.yaml | 5 ++ .../templates/external-secret.yaml | 17 +++++ .../templates/mcp-auth-proxy-git.yaml | 74 +++++++++++++++++++ images/mcp-auth-proxy/Dockerfile | 26 +++++++ images/mcp-auth-proxy/README.md | 11 +++ manifests/mcp/mcp-auth-proxy.yaml | 20 +++++ scripts/post-apply.sh | 4 + terraform/ecr.tf | 33 +++++++++ terraform/iam.tf | 22 ++++++ terraform/terraform.tfvars | 2 +- 11 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 charts/mcp-auth-proxy/Chart.yaml create mode 100644 charts/mcp-auth-proxy/templates/external-secret.yaml create mode 100644 charts/mcp-auth-proxy/templates/mcp-auth-proxy-git.yaml create mode 100644 images/mcp-auth-proxy/Dockerfile create mode 100644 images/mcp-auth-proxy/README.md create mode 100644 manifests/mcp/mcp-auth-proxy.yaml create mode 100644 terraform/ecr.tf diff --git a/Makefile b/Makefile index 0eecfb4..1fa456a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: init plan apply destroy clean kubeconfig talosconfig argocd-password bootstrap decrypt post-apply +.PHONY: init plan apply destroy clean kubeconfig talosconfig argocd-password bootstrap decrypt post-apply build-mcp-auth-proxy SECRET ?= dumpnet TF_DIR=terraform @@ -39,6 +39,14 @@ bootstrap: kubectl apply -f apps/apps.yaml @echo "ArgoCD will now manage apps/ directory - future group changes are self-healing via git push" +# Images +build-mcp-auth-proxy: + $(eval ECR=$(shell cd $(TF_DIR) && terraform output -raw ecr_registry)) + aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $(ECR) + docker build -t $(ECR):latest images/mcp-auth-proxy/ + docker push $(ECR):latest + @echo "Pushed mcp-auth-proxy to $(ECR):latest" + # Credentials talosconfig: aws secretsmanager get-secret-value --secret-id $(SECRET) \ diff --git a/charts/mcp-auth-proxy/Chart.yaml b/charts/mcp-auth-proxy/Chart.yaml new file mode 100644 index 0000000..a615349 --- /dev/null +++ b/charts/mcp-auth-proxy/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: mcp-auth-proxy +description: OAuth/password proxy for MCP servers +type: application +version: 0.1.0 diff --git a/charts/mcp-auth-proxy/templates/external-secret.yaml b/charts/mcp-auth-proxy/templates/external-secret.yaml new file mode 100644 index 0000000..15f720b --- /dev/null +++ b/charts/mcp-auth-proxy/templates/external-secret.yaml @@ -0,0 +1,17 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: mcp-auth-proxy-secrets + namespace: mcp +spec: + refreshInterval: 1h + secretStoreRef: + name: aws-secrets-manager + kind: ClusterSecretStore + target: + name: mcp-auth-proxy-secrets + data: + - secretKey: PASSWORD + remoteRef: + key: dumpnet + property: mcp_auth_proxy.password diff --git a/charts/mcp-auth-proxy/templates/mcp-auth-proxy-git.yaml b/charts/mcp-auth-proxy/templates/mcp-auth-proxy-git.yaml new file mode 100644 index 0000000..77df160 --- /dev/null +++ b/charts/mcp-auth-proxy/templates/mcp-auth-proxy-git.yaml @@ -0,0 +1,74 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mcp-auth-proxy-git + namespace: mcp +spec: + replicas: 1 + selector: + matchLabels: + app: mcp-auth-proxy-git + template: + metadata: + labels: + app: mcp-auth-proxy-git + spec: + containers: + - name: mcp-auth-proxy + image: 024762953732.dkr.ecr.us-east-1.amazonaws.com/dumpnet/mcp-auth-proxy:latest + args: + - --external-url=https://git-mcp-oauth.dumpnet.chat + - --no-auto-tls=true + - --listen=:8080 + - http://forgejo-mcp.mcp.svc.cluster.local/mcp + env: + - name: DATA_PATH + value: /tmp/data + envFrom: + - secretRef: + name: mcp-auth-proxy-secrets + ports: + - containerPort: 8080 + volumeMounts: + - name: tmp + mountPath: /tmp + volumes: + - name: tmp + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: mcp-auth-proxy-git + namespace: mcp +spec: + selector: + app: mcp-auth-proxy-git + ports: + - port: 80 + targetPort: 8080 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: mcp-auth-proxy-git + namespace: mcp + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod +spec: + ingressClassName: nginx + tls: + - hosts: + - git-mcp-oauth.dumpnet.chat + secretName: mcp-auth-proxy-git-tls + rules: + - host: git-mcp-oauth.dumpnet.chat + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: mcp-auth-proxy-git + port: + number: 80 diff --git a/images/mcp-auth-proxy/Dockerfile b/images/mcp-auth-proxy/Dockerfile new file mode 100644 index 0000000..e62b2e8 --- /dev/null +++ b/images/mcp-auth-proxy/Dockerfile @@ -0,0 +1,26 @@ +FROM golang:1.22-bookworm AS builder + +ENV GOTOOLCHAIN=auto + +# Pin to a specific release tag +ARG VERSION=v2.10.2 + +WORKDIR /app +RUN git clone --depth 1 --branch ${VERSION} https://github.com/sigbit/mcp-auth-proxy . +RUN go mod download + +ARG TARGETARCH +ARG TARGETOS +RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH \ + go build -trimpath -ldflags "-w -s" -o /app/bin/mcp-auth-proxy . + +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates curl \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /app/bin/mcp-auth-proxy /usr/local/bin/mcp-auth-proxy +ENV DATA_PATH=/data + +ENTRYPOINT ["/usr/local/bin/mcp-auth-proxy"] diff --git a/images/mcp-auth-proxy/README.md b/images/mcp-auth-proxy/README.md new file mode 100644 index 0000000..31b2589 --- /dev/null +++ b/images/mcp-auth-proxy/README.md @@ -0,0 +1,11 @@ +# mcp-auth-proxy image + +Builds [sigbit/mcp-auth-proxy](https://github.com/sigbit/mcp-auth-proxy) v2.10.2 for the dumpnet ECR registry. + +To update the version, change `ARG VERSION` in the Dockerfile and rebuild. + +## Build & Push + +```bash +make build-mcp-auth-proxy +``` diff --git a/manifests/mcp/mcp-auth-proxy.yaml b/manifests/mcp/mcp-auth-proxy.yaml new file mode 100644 index 0000000..d75a047 --- /dev/null +++ b/manifests/mcp/mcp-auth-proxy.yaml @@ -0,0 +1,20 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: mcp-auth-proxy + namespace: argocd +spec: + project: default + source: + repoURL: https://forge.keane.sh/ian/dumpnet-argo.git + targetRevision: HEAD + path: charts/mcp-auth-proxy + destination: + server: https://kubernetes.default.svc + namespace: mcp + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/scripts/post-apply.sh b/scripts/post-apply.sh index 5cf3263..d0ff9bf 100755 --- a/scripts/post-apply.sh +++ b/scripts/post-apply.sh @@ -21,6 +21,10 @@ cd .. echo "==> Bootstrapping ArgoCD App of Apps..." make bootstrap +echo "" +echo "==> Building and pushing custom images to ECR..." +make build-mcp-auth-proxy + echo "" echo "Done! ArgoCD should be available at https://argocd.dumpnet.chat shortly." echo "Get your password with: make argocd-password" diff --git a/terraform/ecr.tf b/terraform/ecr.tf new file mode 100644 index 0000000..92d3c77 --- /dev/null +++ b/terraform/ecr.tf @@ -0,0 +1,33 @@ +resource "aws_ecr_repository" "dumpnet" { + name = "dumpnet/mcp-auth-proxy" + image_tag_mutability = "MUTABLE" + + image_scanning_configuration { + scan_on_push = true + } + + encryption_configuration { + encryption_type = "AES256" + } +} + +resource "aws_ecr_lifecycle_policy" "dumpnet" { + repository = aws_ecr_repository.dumpnet.name + + policy = jsonencode({ + rules = [{ + rulePriority = 1 + description = "Keep last 5 images per tag prefix" + selection = { + tagStatus = "any" + countType = "imageCountMoreThan" + countNumber = 5 + } + action = { type = "expire" } + }] + }) +} + +output "ecr_registry" { + value = aws_ecr_repository.dumpnet.repository_url +} diff --git a/terraform/iam.tf b/terraform/iam.tf index 822377c..e4a516c 100644 --- a/terraform/iam.tf +++ b/terraform/iam.tf @@ -57,3 +57,25 @@ resource "aws_iam_role_policy" "node_secrets_manager" { }) } + +# ECR pull access for node (to pull custom images like mcp-auth-proxy) +resource "aws_iam_role_policy" "node_ecr" { + name = "ecr-pull" + role = aws_iam_role.node.id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage", + "ecr:BatchCheckLayerAvailability", + "ecr:GetAuthorizationToken" + ] + Resource = "*" + } + ] + }) +} diff --git a/terraform/terraform.tfvars b/terraform/terraform.tfvars index 0cffbf1..a700577 100644 --- a/terraform/terraform.tfvars +++ b/terraform/terraform.tfvars @@ -1,2 +1,2 @@ hosted_zone_id = "Z068835512G0ZQJ9SJGOI" -dns_records = ["argocd", "todo", "git-mcp"] +dns_records = ["argocd", "todo", "git-mcp", "git-mcp-oauth"]