Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Olds committed Aug 20, 2021
1 parent d4ea4c8 commit 37c1d7d
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 1 deletion.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
# tailscale-poc
Tailscale reverse proxy proof of concept
Tailscale reverse proxy proof of concept.

Three different attempts at getting Tailscale to work in Cloudrun / GKE.


# Build and Run on CloudRun

Generate an ephemeral key.

```
gcloud builds submit --config=cloudbuild.yaml \
--substitutions=_TAILSCALE_AUTH="tskey-123456789abcedef",_TAILSCALE_ENDPOINT="http:https://[fd7a:115c:a1e0:ab12:1234:1234:1234:1234]:5000"
```
98 changes: 98 additions & 0 deletions cloudbuild.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
substitutions:
_TAILSCALE_AUTH: ''
_TAILSCALE_ENDPOINT: ''

steps:
# Build the containers
- id: 'build caddy-tailscale'
name: 'gcr.io/kaniko-project/executor:latest'
args:
- --destination=gcr.io/${PROJECT_ID}/caddy-tailscale:latest
- --context=.
- --cache=true
- --dockerfile=package/caddy-tailscale/Dockerfile
- id: 'build nginx-tailscale'
name: 'gcr.io/kaniko-project/executor:latest'
args:
- --destination=gcr.io/${PROJECT_ID}/nginx-tailscale:latest
- --context=.
- --cache=true
- --dockerfile=package/nginx-tailscale/Dockerfile
- id: 'build webapp-tailscale'
name: 'gcr.io/kaniko-project/executor:latest'
args:
- --destination=gcr.io/${PROJECT_ID}/webapp-tailscale:latest
- --context=.
- --cache=true
- --dockerfile=package/webapp-tailscale/Dockerfile

# Deploy to cloud run
- id: 'deploy caddy-tailscale'
name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-alpine'
waitFor:
- build caddy-tailscale
args:
- 'bash'
- '-eEuo'
- 'pipefail'
- '-c'
- |-
gcloud run deploy "tailscale-poc-caddy" \
--quiet \
--platform=managed \
--region=us-west1 \
--concurrency=10 \
--memory=128Mi \
--max-instances=1 \
--image="gcr.io/${PROJECT_ID}/caddy-tailscale:latest" \
--allow-unauthenticated \
--set-env-vars \
TAILSCALE_AUTH=${_TAILSCALE_AUTH} \
--set-env-vars \
TAILSCALE_ENDPOINT=${_TAILSCALE_ENDPOINT}
- id: 'deploy nginx-tailscale'
name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-alpine'
waitFor:
- build nginx-tailscale
args:
- 'bash'
- '-eEuo'
- 'pipefail'
- '-c'
- |-
gcloud run deploy "tailscale-poc-nginx" \
--quiet \
--platform=managed \
--region=us-west1 \
--concurrency=10 \
--memory=128Mi \
--max-instances=1 \
--image="gcr.io/${PROJECT_ID}/nginx-tailscale:latest" \
--allow-unauthenticated \
--set-env-vars \
TAILSCALE_AUTH=${_TAILSCALE_AUTH} \
--set-env-vars \
TAILSCALE_ENDPOINT=${_TAILSCALE_ENDPOINT}
- id: 'deploy webapp-tailscale'
name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:316.0.0-alpine'
waitFor:
- build webapp-tailscale
args:
- 'bash'
- '-eEuo'
- 'pipefail'
- '-c'
- |-
gcloud run deploy "tailscale-poc-webapp" \
--quiet \
--platform=managed \
--region=us-west1 \
--concurrency=10 \
--memory=128Mi \
--max-instances=1 \
--image="gcr.io/${PROJECT_ID}/webapp-tailscale:latest" \
--allow-unauthenticated \
--set-env-vars \
TAILSCALE_AUTH=${_TAILSCALE_AUTH} \
--set-env-vars \
TAILSCALE_ENDPOINT=${_TAILSCALE_ENDPOINT}
68 changes: 68 additions & 0 deletions cmd/fetch-headers/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Fetch Headers attempts to fetch the headers of a service routed through Tailscale.
package main

import (
"context"
"fmt"
"log"
"net/http"
"os"
"strings"
"time"
)

var client = http.DefaultClient

func main() {
log.Print("starting server...")
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
})
http.HandleFunc("/", handler)

port := os.Getenv("PORT")
if port == "" {
port = "80"
log.Printf("defaulting to port %s", port)
}

log.Printf("listening on port %s", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatal(err)
}
}

func handler(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(r.Context())
defer cancel()

endpoint := os.Getenv("TAILSCALE_ENDPOINT")

fmt.Fprintf(w, "fetching %s...\n\n", endpoint)
hdrFetch(ctx, w, endpoint)

if err := ctx.Err(); err != nil {
fmt.Fprintf(w, "context error: %v\n", err)
}
}

func hdrFetch(ctx context.Context, w http.ResponseWriter, addr string) {
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, addr, nil)
if err != nil {
fmt.Fprintf(w, "unable to create new request: %v\n", err)
return
}
res, err := client.Do(req)
if err != nil {
fmt.Fprintf(w, "unable to issue http request: %v\n", err)
return
}
defer res.Body.Close()
var sb strings.Builder
for k, v := range res.Header {
fmt.Fprintf(&sb, "%s => %q\n", k, v)
}
fmt.Fprintln(w, sb.String())
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/polds/tailscale-poc

go 1.16
17 changes: 17 additions & 0 deletions package/caddy-tailscale/Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
auto_https off
}

:{$PORT}

encode zstd gzip

respond /healthz "ok" 200
respond /debug/healthz "ok" 200 # Since cloudrun doesn't allow /healthz

reverse_proxy {
to {$TAILSCALE_ENDPOINT}

header_up -X-Forwarded-Proto
header_up -X-Forwarded-For
}
23 changes: 23 additions & 0 deletions package/caddy-tailscale/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# From https://tailscale.com/kb/1108/cloudrun/
FROM alpine:latest as tailscale
WORKDIR /app
COPY . ./
ENV TSFILE=tailscale_1.12.3_amd64.tgz
RUN wget https://pkgs.tailscale.com/stable/${TSFILE} && \
tar xzf ${TSFILE} --strip-components=1
COPY . ./

FROM caddy:2.4.3-alpine
RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/*

# Copy binary to production image
COPY package/caddy-tailscale/start.sh /app/start.sh
COPY package/caddy-tailscale/Caddyfile /etc/caddy/Caddyfile
COPY --from=tailscale /app/tailscaled /app/tailscaled
COPY --from=tailscale /app/tailscale /app/tailscale
RUN mkdir -p /var/run/tailscale /var/cache/tailscale /var/lib/tailscale

EXPOSE 80
# Run on container startup.
RUN chmod +x /app/start.sh
CMD ["/app/start.sh"]
9 changes: 9 additions & 0 deletions package/caddy-tailscale/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh

/app/tailscaled --tun=userspace-networking --socks5-server=localhost:1055 &
until /app/tailscale up --authkey=${TAILSCALE_AUTH} --hostname=edge-${HOSTNAME} --accept-routes --advertise-exit-node
do
sleep 0.1
done
echo Tailscale started
ALL_PROXY=socks5:https://localhost:1055/ caddy run --config=/etc/caddy/Caddyfile --adapter=caddyfile
24 changes: 24 additions & 0 deletions package/nginx-tailscale/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# From https://tailscale.com/kb/1108/cloudrun/
FROM alpine:latest as tailscale
WORKDIR /app
COPY . ./
ENV TSFILE=tailscale_1.12.3_amd64.tgz
RUN wget https://pkgs.tailscale.com/stable/${TSFILE} && \
tar xzf ${TSFILE} --strip-components=1
COPY . ./

FROM nginx:stable-alpine
RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/*

# Copy binary to production image
COPY --from=tailscale /app/tailscaled /app/tailscaled
COPY --from=tailscale /app/tailscale /app/tailscale
COPY package/nginx-tailscale/start.sh /app/start.sh
COPY package/nginx-tailscale/nginx.conf /etc/nginx/conf.d/test.template

RUN mkdir -p /var/run/tailscale /var/cache/tailscale /var/lib/tailscale

EXPOSE 80
# Run on container startup.
RUN chmod +x /app/start.sh
CMD ["/app/start.sh"]
14 changes: 14 additions & 0 deletions package/nginx-tailscale/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
server {
listen ${PORT};
location ~ ^/(healthz|debug/healthz) {
return 200 'ok';
add_header Content-Type text/plain;
}
# Just a quick test to make sure our environment correctly supports forwarding packets.
location /ip {
proxy_pass http:https://icanhazip.com:80;
}
location / {
proxy_pass ${TAILSCALE_ENDPOINT};
}
}
9 changes: 9 additions & 0 deletions package/nginx-tailscale/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh

/app/tailscaled --tun=userspace-networking --socks5-server=localhost:1055 &
until /app/tailscale up --authkey=${TAILSCALE_AUTH} --hostname=edge-${HOSTNAME} --accept-routes --advertise-exit-node
do
sleep 0.1
done
echo Tailscale started
ALL_PROXY=socks5:https://localhost:1055/ envsubst '${TAILSCALE_ENDPOINT} ${PORT}' < /etc/nginx/conf.d/test.template > /etc/nginx/conf.d/default.conf && nginx -g "daemon off;"
36 changes: 36 additions & 0 deletions package/webapp-tailscale/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# From https://tailscale.com/kb/1108/cloudrun/
FROM golang:1.16.2-alpine3.13 as builder
WORKDIR /app
COPY . ./

RUN go build \
-a \
-ldflags "-s -w -extldflags 'static'" \
-installsuffix cgo \
-tags netgo \
-o /bin/app \
cmd/fetch-headers/*.go

FROM alpine:latest as tailscale
WORKDIR /app
COPY . ./
ENV TSFILE=tailscale_1.12.3_amd64.tgz
RUN wget https://pkgs.tailscale.com/stable/${TSFILE} && \
tar xzf ${TSFILE} --strip-components=1
COPY . ./

FROM alpine
RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/*

# Copy binary to production image
COPY --from=builder /bin/app /bin/app
COPY --from=tailscale /app/tailscaled /app/tailscaled
COPY --from=tailscale /app/tailscale /app/tailscale
COPY package/webapp-tailscale/start.sh /app/start.sh

RUN mkdir -p /var/run/tailscale /var/cache/tailscale /var/lib/tailscale

EXPOSE 80
# Run on container startup.
RUN chmod +x /app/start.sh
CMD ["/app/start.sh"]
9 changes: 9 additions & 0 deletions package/webapp-tailscale/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh

/app/tailscaled --tun=userspace-networking --socks5-server=localhost:1055 &
until /app/tailscale up --authkey=${TAILSCALE_AUTH} --hostname=edge-${HOSTNAME} --accept-routes --advertise-exit-node
do
sleep 0.1
done
echo Tailscale started
ALL_PROXY=socks5:https://localhost:1055/ /bin/app

0 comments on commit 37c1d7d

Please sign in to comment.