Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement proxy using msal-go #142

Merged
merged 1 commit into from
Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ all: manager
manager: generate fmt vet
go build -a -ldflags $(LDFLAGS) -o bin/manager cmd/webhook/main.go

# Build proxy binary
.PHONY: proxy
proxy: fmt vet
go build -a -ldflags $(LDFLAGS) -o bin/proxy cmd/proxy/main.go

# Run against the configured Kubernetes cluster in ~/.kube/config
.PHONY: run
run: generate fmt vet manifests
Expand Down Expand Up @@ -248,14 +253,18 @@ $(E2E_TEST):
# Ginkgo configurations
GINKGO_FOCUS ?=
GINKGO_SKIP ?=
GINKGO_NODES ?= 3
GINKGO_NODES ?= 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not possible to run e2e tests in parallel?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proxy test and token exchange test currently use the same service account for tests and running in parallel will cause a race. I can add trust for a new service account and enable parallel again in a follow-up PR.

GINKGO_NO_COLOR ?= false
GINKGO_TIMEOUT ?= 5m
GINKGO_ARGS ?= -focus="$(GINKGO_FOCUS)" -skip="$(GINKGO_SKIP)" -nodes=$(GINKGO_NODES) -noColor=$(GINKGO_NO_COLOR) -timeout=$(GINKGO_TIMEOUT)

# E2E configurations
KUBECONFIG ?= $(HOME)/.kube/config
E2E_ARGS := -kubeconfig=$(KUBECONFIG) -report-dir=$(PWD)/_artifacts -e2e.arc-cluster=$(ARC_CLUSTER) -e2e.token-exchange-image=$(MSAL_GO_E2E_IMAGE)
E2E_ARGS := -kubeconfig=$(KUBECONFIG) -report-dir=$(PWD)/_artifacts \
-e2e.arc-cluster=$(ARC_CLUSTER) \
-e2e.token-exchange-image=$(MSAL_GO_E2E_IMAGE) \
-e2e.proxy-image=$(PROXY_IMAGE) \
-e2e.proxy-init-image=$(INIT_IMAGE)
E2E_EXTRA_ARGS ?=

.PHONY: test-e2e-run
Expand All @@ -281,6 +290,8 @@ kind-create: $(KIND) $(KUBECTL)
kind-load-image:
$(KIND) load docker-image $(WEBHOOK_IMAGE) --name $(KIND_CLUSTER_NAME)
$(KIND) load docker-image $(MSAL_GO_E2E_IMAGE) --name $(KIND_CLUSTER_NAME)
$(KIND) load docker-image $(PROXY_IMAGE) --name $(KIND_CLUSTER_NAME)
$(KIND) load docker-image $(INIT_IMAGE) --name $(KIND_CLUSTER_NAME)

.PHONY: kind-delete
kind-delete: $(KIND)
Expand Down
106 changes: 13 additions & 93 deletions cmd/proxy/main.go
Original file line number Diff line number Diff line change
@@ -1,109 +1,29 @@
package main

import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strconv"
"strings"
"flag"

"github.com/Azure/aad-pod-managed-identity/pkg/proxy"

"github.com/pkg/errors"
"k8s.io/klog/v2"
)

const (
proxyPort = 8000
tokenExchangeURL = "https://svctokenexchange.azurewebsites.net/api/token/exchange" // #nosec
var (
proxyPort int
)

type proxy struct{}

func main() {
// TODO add handler to separate default metadata and token request
if err := http.ListenAndServe(fmt.Sprintf("localhost:%d", proxyPort), &proxy{}); err != nil {
klog.Fatalf("failed to listen and serve, error: %+v", err)
}
}

func (p *proxy) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// forward the request to the new aad endpoint
resp, err := p.sendRequest(req)
if err != nil {
http.Error(w, err.Error(), http.StatusBadGateway)
return
}
p.writeResponse(w, resp)
}
klog.InitFlags(nil)
defer klog.Flush()

func (p *proxy) sendRequest(req *http.Request) (*http.Response, error) {
klog.InfoS("received request", "method", req.Method, "uri", req.RequestURI)
clientID, resource := parseTokenRequest(req)
if clientID == "" {
return &http.Response{Status: strconv.Itoa(http.StatusBadRequest)}, errors.New("client id is not set")
}
if resource == "" {
resource = "https://management.azure.com/"
}
return doTokenRequest(clientID, resource)
}
flag.IntVar(&proxyPort, "proxy-port", 8000, "Port for the proxy to listen on")
flag.Parse()

func (p *proxy) writeResponse(w http.ResponseWriter, res *http.Response) {
for name, values := range res.Header {
w.Header()[name] = values
}
// Set a special header to notify that the proxy actually serviced the request.
w.Header().Set("Server", "pi-sidecar-proxy")
w.WriteHeader(res.StatusCode)
_, _ = io.Copy(w, res.Body)
res.Body.Close()

klog.InfoS("request complete", "status", res.StatusCode)
}

func parseTokenRequest(r *http.Request) (clientID, resource string) {
vals := r.URL.Query()
if vals != nil {
clientID = vals.Get("client_id")
resource = vals.Get("resource")
}
return
}

// TODO this will be replaced by the SDK when available
func doTokenRequest(clientID, resource string) (*http.Response, error) {
// get the service account jwt token
tokenFile := os.Getenv("TOKEN_FILE_PATH")
if tokenFile == "" {
return nil, errors.New("TOKEN_FILE_PATH not set")
}
if _, err := os.Stat(tokenFile); err != nil {
return nil, errors.New("token file not found")
}
token, err := os.ReadFile(tokenFile)
p, err := proxy.NewProxy(proxyPort)
if err != nil {
return nil, errors.Wrap(err, "failed to get token")
klog.Fatalf("failed to get proxy, error: %+v", err)
}

httpClient := http.Client{}

reqBody, err := json.Marshal(map[string]string{
"subjectToken": strings.TrimSuffix(string(token), "\n"),
"clientId": clientID,
"scopes": resource,
})
if err != nil {
return nil, errors.Wrap(err, "failed to marshal req body")
}

req, err := http.NewRequest(http.MethodPost, tokenExchangeURL, bytes.NewBuffer(reqBody))
if err != nil {
return nil, errors.Wrap(err, "failed to create http request")
if err = p.Run(); err != nil {
klog.Fatalf("failed to run proxy, error: %+v", err)
}
req.Header.Set("Content-Type", "application/json")

resp, err := httpClient.Do(req)
return resp, err
}
2 changes: 1 addition & 1 deletion cmd/webhook/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func main() {
// Setup a manager
entryLog.Info("setting up manager")
config := ctrl.GetConfigOrDie()
config.UserAgent = version.GetUserAgent()
config.UserAgent = version.GetUserAgent("webhook")

// log the user agent as it makes it easier to debug issues
entryLog.Info(config.UserAgent)
Expand Down
4 changes: 2 additions & 2 deletions docker/init.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM alpine:latest
FROM k8s.gcr.io/build-image/debian-iptables:buster-v1.6.6

RUN apk update && apk add iptables
RUN clean-install ca-certificates
COPY ./init/init-iptables.sh /bin/
RUN chmod +x /bin/init-iptables.sh

Expand Down
12 changes: 10 additions & 2 deletions docker/proxy.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
FROM golang:1.16 as builder

ARG LDFLAGS

WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download

# Copy the go source
COPY cmd/proxy/main.go main.go
COPY pkg/ pkg/

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o proxy main.go
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -ldflags "${LDFLAGS:--X github.com/Azure/aad-pod-managed-identity/pkg/version.BuildVersion=latest}" -o proxy main.go

FROM alpine:latest
# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder /workspace/proxy .
USER nonroot:nonroot
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ go 1.16

require (
github.com/Azure/go-autorest/autorest v0.11.12
github.com/Azure/go-autorest/autorest/adal v0.9.5
github.com/AzureAD/microsoft-authentication-library-for-go v0.3.0
github.com/gorilla/mux v1.8.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/onsi/ginkgo v1.16.4
github.com/onsi/gomega v1.13.0
Expand Down
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-library-for-go v0.3.0 h1:2iUGNrLWpRaZ8EFbrU6LxwcJuPkBxus5z5BHaBfu0lo=
github.com/AzureAD/microsoft-authentication-library-for-go v0.3.0/go.mod h1:5aEdWF4KzHyRg5i5ItqNcv12iMQr/kYTYaX+GpdEcj8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20200415212048-7901bc822317/go.mod h1:DF8FZRxMHMGv/vP2lQP6h+dYzzjpuRn24VeRiYn3qjQ=
Expand Down Expand Up @@ -143,6 +145,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
Expand Down Expand Up @@ -323,6 +326,7 @@ github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
Expand Down Expand Up @@ -404,6 +408,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
Expand Down Expand Up @@ -510,6 +516,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand Down
Loading