I want to secure Docker daemon REST API using Go reverse proxy server. I found this article very relevant. I have never used Go so not sure how to implement basic authentication to this with static username and password. I tried all possible ways i happened to find over Google but none worked for me.
Could some please help adding static basicAuth authentication to following code so that request so that Docker daemon API is only reachable if the request includes username and password: https://github.com/ben-lab/blog-material/blob/master/golang-reverse-proxy-2/reverse-proxy.go
package main
import (
"fmt"
"io"
"log"
"net/http"
"time"
"github.com/tv42/httpunix"
)
func handleHTTP(w http.ResponseWriter, req *http.Request) {
fmt.Printf("Requested : %s\n", req.URL.Path)
u := &httpunix.Transport{
DialTimeout: 100 * time.Millisecond,
RequestTimeout: 1 * time.Second,
ResponseHeaderTimeout: 1 * time.Second,
}
u.RegisterLocation("docker-socket", "/var/run/docker.sock")
req.URL.Scheme = "http+unix"
req.URL.Host = "docker-socket"
resp, err := u.RoundTrip(req)
if err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
defer resp.Body.Close()
copyHeader(w.Header(), resp.Header)
w.WriteHeader(resp.StatusCode)
io.Copy(w, resp.Body)
}
func copyHeader(dst, src http.Header) {
for k, vv := range src {
for _, v := range vv {
dst.Add(k, v)
}
}
}
func main() {
server := &http.Server{
Addr: ":8888",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handleHTTP(w, r) }),
}
log.Fatal(server.ListenAndServe())
}
https://github.com/ben-lab/blog-material/blob/master/golang-reverse-proxy-2/reverse-proxy.go
You can access the basic auth header values by calling BasicAuth()
on your
req *http.Request object
like:
user, pass, _ := req.BasicAuth()
Then compare user and pass with the static values you have.
https://golang.org/pkg/net/http/#Request.BasicAuth
Update:
func handleHTTP(w http.ResponseWriter, req *http.Request) {
user, pass, _ := req.BasicAuth()
if user != "muuser" || pass != "mysecret" {
// you have to import "errors"
http.Error(w, errors.New("not authoized!!"), http. StatusUnauthorized)
return
}
fmt.Printf("Requested : %s\n", req.URL.Path)
u := &httpunix.Transport{
DialTimeout: 100 * time.Millisecond,
RequestTimeout: 1 * time.Second,
ResponseHeaderTimeout: 1 * time.Second,
}
u.RegisterLocation("docker-socket", "/var/run/docker.sock")
req.URL.Scheme = "http+unix"
req.URL.Host = "docker-socket"
resp, err := u.RoundTrip(req)
if err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
defer resp.Body.Close()
copyHeader(w.Header(), resp.Header)
w.WriteHeader(resp.StatusCode)
io.Copy(w, resp.Body)
}
can you please share how to call BasicAuth from re *http.Request object as i tried look at some example code on google but couldn't make it work. Thanks in advance
Updated my answer to show how to do it in your code. Please not you have to import "errors"
imported "errors" but unable to build due to following error: reverse-proxy.go:17:31: cannot use errors.New("not authoized!!") (type error) as type string in argument to http.Error
it worked like charm, thanks a lot for the help mate. Just had to change: http.Error(w, errors.New("not authoized!!"), http. StatusUnauthorized) to http.Error(w, errors.New("not authoized!!").Error(), http. StatusUnauthorized)
Need one more help, could you please guide me how to connect using docker client? It works fine with curl, but doesn't work with docker client. I tried it using docker login but i think getting unauthorized 401 error. Could you please help me with that too? Like how can i add credentials to this command? docker -H=127.0.0.1:8888 container ls