Skip to content

Commit

Permalink
enable setup common name whitelist for tls checking
Browse files Browse the repository at this point in the history
Signed-off-by: Frank Yang <[email protected]>
  • Loading branch information
yyb196 committed Apr 2, 2018
1 parent 85d808d commit 4ada4ac
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 57 deletions.
91 changes: 51 additions & 40 deletions apis/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,53 +24,53 @@ func initRoute(s *Server) http.Handler {
r := mux.NewRouter()

// system
addRoute(r, http.MethodGet, "/_ping", s.ping)
addRoute(r, http.MethodGet, "/info", s.info)
addRoute(r, http.MethodGet, "/version", s.version)
addRoute(r, http.MethodPost, "/auth", s.auth)
s.addRoute(r, http.MethodGet, "/_ping", s.ping)
s.addRoute(r, http.MethodGet, "/info", s.info)
s.addRoute(r, http.MethodGet, "/version", s.version)
s.addRoute(r, http.MethodPost, "/auth", s.auth)

// daemon, we still list this API into system manager.
addRoute(r, http.MethodPost, "/daemon/update", s.updateDaemon)
s.addRoute(r, http.MethodPost, "/daemon/update", s.updateDaemon)

// container
addRoute(r, http.MethodPost, "/containers/create", s.createContainer)
addRoute(r, http.MethodPost, "/containers/{name:.*}/start", s.startContainer)
addRoute(r, http.MethodPost, "/containers/{name:.*}/stop", s.stopContainer)
addRoute(r, http.MethodPost, "/containers/{name:.*}/attach", s.attachContainer)
addRoute(r, http.MethodGet, "/containers/json", s.getContainers)
addRoute(r, http.MethodGet, "/containers/{name:.*}/json", s.getContainer)
addRoute(r, http.MethodDelete, "/containers/{name:.*}", s.removeContainers)
addRoute(r, http.MethodPost, "/containers/{name:.*}/exec", s.createContainerExec)
addRoute(r, http.MethodPost, "/exec/{name:.*}/start", s.startContainerExec)
addRoute(r, http.MethodPost, "/containers/{name:.*}/rename", s.renameContainer)
addRoute(r, http.MethodPost, "/containers/{name:.*}/restart", s.restartContainer)
addRoute(r, http.MethodPost, "/containers/{name:.*}/pause", s.pauseContainer)
addRoute(r, http.MethodPost, "/containers/{name:.*}/unpause", s.unpauseContainer)
addRoute(r, http.MethodPost, "/containers/{name:.*}/update", s.updateContainer)
addRoute(r, http.MethodPost, "/containers/{name:.*}/upgrade", s.upgradeContainer)
addRoute(r, http.MethodGet, "/containers/{name:.*}/top", s.topContainer)
addRoute(r, http.MethodGet, "/containers/{name:.*}/logs", s.logsContainer)
addRoute(r, http.MethodPost, "/containers/{name:.*}/resize", s.resizeContainer)
addRoute(r, http.MethodPost, "/containers/{name:.*}/restart", s.restartContainer)
s.addRoute(r, http.MethodPost, "/containers/create", s.createContainer)
s.addRoute(r, http.MethodPost, "/containers/{name:.*}/start", s.startContainer)
s.addRoute(r, http.MethodPost, "/containers/{name:.*}/stop", s.stopContainer)
s.addRoute(r, http.MethodPost, "/containers/{name:.*}/attach", s.attachContainer)
s.addRoute(r, http.MethodGet, "/containers/json", s.getContainers)
s.addRoute(r, http.MethodGet, "/containers/{name:.*}/json", s.getContainer)
s.addRoute(r, http.MethodDelete, "/containers/{name:.*}", s.removeContainers)
s.addRoute(r, http.MethodPost, "/containers/{name:.*}/exec", s.createContainerExec)
s.addRoute(r, http.MethodPost, "/exec/{name:.*}/start", s.startContainerExec)
s.addRoute(r, http.MethodPost, "/containers/{name:.*}/rename", s.renameContainer)
s.addRoute(r, http.MethodPost, "/containers/{name:.*}/restart", s.restartContainer)
s.addRoute(r, http.MethodPost, "/containers/{name:.*}/pause", s.pauseContainer)
s.addRoute(r, http.MethodPost, "/containers/{name:.*}/unpause", s.unpauseContainer)
s.addRoute(r, http.MethodPost, "/containers/{name:.*}/update", s.updateContainer)
s.addRoute(r, http.MethodPost, "/containers/{name:.*}/upgrade", s.upgradeContainer)
s.addRoute(r, http.MethodGet, "/containers/{name:.*}/top", s.topContainer)
s.addRoute(r, http.MethodGet, "/containers/{name:.*}/logs", s.logsContainer)
s.addRoute(r, http.MethodPost, "/containers/{name:.*}/resize", s.resizeContainer)
s.addRoute(r, http.MethodPost, "/containers/{name:.*}/restart", s.restartContainer)

// image
addRoute(r, http.MethodPost, "/images/create", s.pullImage)
addRoute(r, http.MethodPost, "/images/search", s.searchImages)
addRoute(r, http.MethodGet, "/images/json", s.listImages)
addRoute(r, http.MethodDelete, "/images/{name:.*}", s.removeImage)
addRoute(r, http.MethodGet, "/images/{name:.*}/json", s.getImage)
s.addRoute(r, http.MethodPost, "/images/create", s.pullImage)
s.addRoute(r, http.MethodPost, "/images/search", s.searchImages)
s.addRoute(r, http.MethodGet, "/images/json", s.listImages)
s.addRoute(r, http.MethodDelete, "/images/{name:.*}", s.removeImage)
s.addRoute(r, http.MethodGet, "/images/{name:.*}/json", s.getImage)

// volume
addRoute(r, http.MethodGet, "/volumes", s.listVolume)
addRoute(r, http.MethodPost, "/volumes/create", s.createVolume)
addRoute(r, http.MethodGet, "/volumes/{name:.*}", s.getVolume)
addRoute(r, http.MethodDelete, "/volumes/{name:.*}", s.removeVolume)
s.addRoute(r, http.MethodGet, "/volumes", s.listVolume)
s.addRoute(r, http.MethodPost, "/volumes/create", s.createVolume)
s.addRoute(r, http.MethodGet, "/volumes/{name:.*}", s.getVolume)
s.addRoute(r, http.MethodDelete, "/volumes/{name:.*}", s.removeVolume)

// network
addRoute(r, http.MethodGet, "/networks", s.listNetwork)
addRoute(r, http.MethodPost, "/networks/create", s.createNetwork)
addRoute(r, http.MethodGet, "/networks/{name:.*}", s.getNetwork)
addRoute(r, http.MethodDelete, "/networks/{name:.*}", s.deleteNetwork)
s.addRoute(r, http.MethodGet, "/networks", s.listNetwork)
s.addRoute(r, http.MethodPost, "/networks/create", s.createNetwork)
s.addRoute(r, http.MethodGet, "/networks/{name:.*}", s.getNetwork)
s.addRoute(r, http.MethodDelete, "/networks/{name:.*}", s.deleteNetwork)

// metrics
r.Path(versionMatcher + "/metrics").Methods(http.MethodGet).Handler(prometheus.Handler())
Expand All @@ -81,8 +81,8 @@ func initRoute(s *Server) http.Handler {
return r
}

func addRoute(r *mux.Router, mothod string, path string, f func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error) {
r.Path(versionMatcher + path).Methods(mothod).Handler(filter(f))
func (s *Server) addRoute(r *mux.Router, mothod string, path string, f func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error) {
r.Path(versionMatcher + path).Methods(mothod).Handler(filter(f, s))
}

func profilerSetup(mainRouter *mux.Router) {
Expand All @@ -100,13 +100,24 @@ func profilerSetup(mainRouter *mux.Router) {

type handler func(context.Context, http.ResponseWriter, *http.Request) error

func filter(handler handler) http.HandlerFunc {
func filter(handler handler, s *Server) http.HandlerFunc {
pctx := context.Background()

return func(w http.ResponseWriter, req *http.Request) {
ctx, cancel := context.WithCancel(pctx)
defer cancel()

s.lock.RLock()
if len(s.ManagerWhiteList) > 0 && req.TLS != nil && len(req.TLS.PeerCertificates) > 0 {
if _, isManager := s.ManagerWhiteList[req.TLS.PeerCertificates[0].Subject.CommonName]; !isManager {
s.lock.RUnlock()
w.WriteHeader(http.StatusForbidden)
w.Write([]byte("tls verified error."))
return
}
}
s.lock.RUnlock()

t := time.Now()
clientInfo := req.RemoteAddr
defer func() {
Expand Down
33 changes: 25 additions & 8 deletions apis/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http"
"os"
"strings"
"sync"
"syscall"

"github.com/alibaba/pouch/apis/plugins"
Expand All @@ -19,14 +20,16 @@ import (

// Server is a http server which serves restful api to client.
type Server struct {
Config *config.Config
ContainerMgr mgr.ContainerMgr
SystemMgr mgr.SystemMgr
ImageMgr mgr.ImageMgr
VolumeMgr mgr.VolumeMgr
NetworkMgr mgr.NetworkMgr
listeners []net.Listener
ContainerPlugin plugins.ContainerPlugin
Config *config.Config
ContainerMgr mgr.ContainerMgr
SystemMgr mgr.SystemMgr
ImageMgr mgr.ImageMgr
VolumeMgr mgr.VolumeMgr
NetworkMgr mgr.NetworkMgr
listeners []net.Listener
ContainerPlugin plugins.ContainerPlugin
ManagerWhiteList map[string]struct{}
lock sync.RWMutex
}

// Start setup route table and listen to specified address which currently only supports unix socket and tcp address.
Expand All @@ -51,6 +54,7 @@ func (s *Server) Start() (err error) {
if s.Config.TLS.VerifyRemote {
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
}
SetupManagerWhitelist(s)
}

for _, one := range s.Config.Listen {
Expand All @@ -70,6 +74,19 @@ func (s *Server) Start() (err error) {
return <-errCh
}

// SetupManagerWhitelist enables users to setup which common name can access this server
func SetupManagerWhitelist(server *Server) {
if server.Config.TLS.ManagerWhiteList != "" {
server.lock.Lock()
defer server.lock.Unlock()
arr := strings.Split(server.Config.TLS.ManagerWhiteList, ",")
server.ManagerWhiteList = make(map[string]struct{}, len(arr))
for _, cn := range arr {
server.ManagerWhiteList[cn] = struct{}{}
}
}
}

// Stop will shutdown http server by closing all listeners.
func (s *Server) Stop() error {
for _, one := range s.listeners {
Expand Down
15 changes: 7 additions & 8 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ type APIClient struct {

// TLSConfig contains information of tls which users can specify
type TLSConfig struct {
CA string `json:"tlscacert,omitempty"`
Cert string `json:"tlscert,omitempty"`
Key string `json:"tlskey,omitempty"`
VerifyRemote bool
CA string `json:"tlscacert,omitempty"`
Cert string `json:"tlscert,omitempty"`
Key string `json:"tlskey,omitempty"`
VerifyRemote bool
ManagerWhiteList string
}

// NewAPIClient initializes a new API client for the given host
Expand Down Expand Up @@ -185,10 +186,8 @@ func GenTLSConfig(key, cert, ca string) (*tls.Config, error) {
if ca == "" {
return tlsConfig, nil
}
cp, err := x509.SystemCertPool()
if err != nil {
return nil, fmt.Errorf("failed to read system certificates: %v", err)
}

cp := x509.NewCertPool()
pem, err := ioutil.ReadFile(ca)
if err != nil {
return nil, fmt.Errorf("failed to read CA certificate %q: %v", ca, err)
Expand Down
3 changes: 2 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ func setupFlags(cmd *cobra.Command) {
flagSet.StringVar(&cfg.TLS.Key, "tlskey", "", "Specify key file of TLS")
flagSet.StringVar(&cfg.TLS.Cert, "tlscert", "", "Specify cert file of TLS")
flagSet.StringVar(&cfg.TLS.CA, "tlscacert", "", "Specify CA file of TLS")
flagSet.BoolVar(&cfg.TLS.VerifyRemote, "tlsverify", false, "Use TLS and verify remote")
flagSet.BoolVar(&cfg.TLS.VerifyRemote, "tlsverify", false, "Use TLS and verify re")
flagSet.StringVar(&cfg.TLS.ManagerWhiteList, "manager-whitelist", "", "Set tls name whitelist, multiple values are separated by commas")
flagSet.BoolVarP(&printVersion, "version", "v", false, "Print daemon version")
flagSet.StringVar(&cfg.DefaultRuntime, "default-runtime", "runc", "Default OCI Runtime")
flagSet.BoolVar(&cfg.IsLxcfsEnabled, "enable-lxcfs", false, "Enable Lxcfs to make container to isolate /proc")
Expand Down

0 comments on commit 4ada4ac

Please sign in to comment.