/
plugin.go
110 lines (94 loc) · 2.85 KB
/
plugin.go
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
package main
import (
"bytes"
"encoding/json"
"regexp"
// dockerapi "github.com/docker/docker/api"
// dockerclient "github.com/docker/engine-api/client"
"github.com/AuthZPlugin/api"
"github.com/AuthZPlugin/authz"
"github.com/AuthZPlugin/impl"
dockerclient "github.com/samalba/dockerclient"
"github.com/docker/go-connections/tlsconfig"
)
var startRegExp = regexp.MustCompile(`/containers/(.*)/start$`)
var aclsAPI api.ACLsBackAPI
type authzPlugin struct {
client *dockerclient.DockerClient
}
func newPlugin(dockerHost string) (*authzPlugin, error) {
c, _ := tlsconfig.Client(tlsconfig.Options{InsecureSkipVerify: true})
client, err := dockerclient.NewDockerClient(dockerHost, c)
if err != nil {
return nil, err
}
aclsAPI = new(impl.ACLsBackDefaultImpl)
return &authzPlugin{client: client}, nil
}
//Before passing request to manager
func (p *authzPlugin) AuthZReq(req authz.Request) authz.Response {
if req.RequestBody != nil {
var containerConfig dockerclient.ContainerConfig
if err := json.NewDecoder(bytes.NewReader(req.RequestBody)).Decode(&containerConfig); err != nil {
return authz.Response{Err: err.Error()}
}
//Container config may be empty - also sometime we may use another sturct?
isAllowed := aclsAPI.ValidateRequest(req, containerConfig)
if !isAllowed {
return authz.Response{Msg: "Put some message here"}
}
return authz.Response{Allow: true}
}
return authz.Response{Msg: "Put some message here"}
}
//Before returning response to client
func (p *authzPlugin) AuthZRes(req authz.Request) authz.Response {
return authz.Response{Allow: true}
}
/*
//An example with volumes...
func (p *authzPlugin) AuthZReq(req authz.Request) authz.Response {
if req.RequestMethod == "POST" && startRegExp.MatchString(req.RequestURI) {
// this is deprecated in docker, remove once hostConfig is dropped to
// being available at start time
if req.RequestBody != nil {
type vfrom struct {
VolumesFrom []string
}
vf := &vfrom{}
if err := json.NewDecoder(bytes.NewReader(req.RequestBody)).Decode(vf); err != nil {
return authz.Response{Err: err.Error()}
}
if len(vf.VolumesFrom) > 0 {
goto noallow
}
}
res := startRegExp.FindStringSubmatch(req.RequestURI)
if len(res) < 1 {
return authz.Response{Err: "unable to find container name"}
}
container, err := p.client.ContainerInspect(res[1])
if err != nil {
return authz.Response{Err: err.Error()}
}
image, _, err := p.client.ImageInspectWithRaw(container.Image, false)
if err != nil {
return authz.Response{Err: err.Error()}
}
if len(image.Config.Volumes) > 0 {
goto noallow
}
for _, m := range container.Mounts {
if m.Driver != "" {
goto noallow
}
}
if len(container.HostConfig.VolumesFrom) > 0 {
goto noallow
}
}
return authz.Response{Allow: true}
noallow:
return authz.Response{Msg: "volumes are not allowed"}
}
*/