forked from simon3z/image-inspector
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwebdav.go
More file actions
151 lines (129 loc) · 4.25 KB
/
Copy pathwebdav.go
File metadata and controls
151 lines (129 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package imageserver
import (
"encoding/json"
"fmt"
"log"
"net/http"
"syscall"
"golang.org/x/net/webdav"
docker "github.com/fsouza/go-dockerclient"
kauthapi "k8s.io/kubernetes/pkg/apis/authorization"
krestclient "k8s.io/kubernetes/pkg/client/restclient"
kclient "k8s.io/kubernetes/pkg/client/unversioned"
)
const (
// CHROOT_SERVE_PATH is the path to server if we are performing a chroot
// this probably does not belong here.
CHROOT_SERVE_PATH = "/"
)
// webdavImageServer implements ImageServer.
type webdavImageServer struct {
opts ImageServerOptions
chroot bool
}
// ensures this always implements the interface or fail compilation.
var _ ImageServer = &webdavImageServer{}
// NewWebdavImageServer creates a new webdav image server.
func NewWebdavImageServer(opts ImageServerOptions, chroot bool) ImageServer {
return &webdavImageServer{
opts: opts,
chroot: chroot,
}
}
// ServeImage Serves the image.
func (s *webdavImageServer) ServeImage(imageMetadata *docker.Image) error {
servePath := s.opts.ImageServeURL
if s.chroot {
if err := syscall.Chroot(s.opts.ImageServeURL); err != nil {
return fmt.Errorf("Unable to chroot into %s: %v\n", s.opts.ImageServeURL, err)
}
servePath = CHROOT_SERVE_PATH
} else {
log.Printf("!!!WARNING!!! It is insecure to serve the image content without changing")
log.Printf("root (--chroot). Absolute-path symlinks in the image can lead to disclose")
log.Printf("information of the hosting system.")
}
log.Printf("Serving image content %s on webdav://%s%s", s.opts.ImageServeURL, s.opts.ServePath, s.opts.ContentURL)
http.HandleFunc(s.opts.HealthzURL, func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok\n"))
})
http.HandleFunc(s.opts.APIURL, s.handlerFuncAuth(func(w http.ResponseWriter, r *http.Request) {
body, err := json.MarshalIndent(s.opts.APIVersions, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write(body)
}))
http.HandleFunc(s.opts.MetadataURL, s.handlerFuncAuth(func(w http.ResponseWriter, r *http.Request) {
body, err := json.MarshalIndent(imageMetadata, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write(body)
}))
http.Handle(s.opts.ContentURL, s.newAuthenticatedHandler(&webdav.Handler{
Prefix: s.opts.ContentURL,
FileSystem: webdav.Dir(servePath),
LockSystem: webdav.NewMemLS(),
}))
return http.ListenAndServe(s.opts.ServePath, nil)
}
func (s *webdavImageServer) authenticate(r *http.Request) (bool, error) {
authenticator, ok := map[AuthenticationType]func(*http.Request) (bool, error){
AllowAll: allowAll,
KubernetesToken: kubernetesTokenAuth,
}[s.opts.AuthType]
if !ok {
return false, fmt.Errorf("%s is not a recognize authentication method", s.opts.AuthType)
}
return authenticator(r)
}
func allowAll(r *http.Request) (bool, error) {
return true, nil
}
func kubernetesTokenAuth(r *http.Request) (bool, error) {
conf, err := krestclient.InClusterConfig()
if err != nil {
return false, err
}
conf.BearerToken = r.Header.Get("Authorization")
kc, err := kclient.New(conf)
if err != nil {
return false, err
}
result := &kauthapi.SubjectAccessReview{}
sar := &kauthapi.SubjectAccessReview{}
sar.Kind = "SubjectAccessReview"
sar.APIVersion = "v1"
sar.Spec.ResourceAttributes.Verb = "GET"
sar.Spec.ResourceAttributes.Resource = "images"
err = kc.Get().Resource("subjectAccessReview").Body(sar).Do().Into(result)
if err != nil {
return false, err
}
return result.Status.Allowed, nil
}
func (s *webdavImageServer) handlerFuncAuth(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if allowed, err := s.authenticate(r); allowed && err == nil {
f(w, r)
} else {
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
} else {
http.Error(w, "Unauthorazied Access!", http.StatusForbidden)
}
}
}
}
type authenticatedHandler struct {
serveHttp func(http.ResponseWriter, *http.Request)
}
func (ah *authenticatedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ah.serveHttp(w, r)
}
func (s *webdavImageServer) newAuthenticatedHandler(h http.Handler) http.Handler {
return &authenticatedHandler{serveHttp: s.handlerFuncAuth(h.ServeHTTP)}
}