Skip to content

Commit

Permalink
feat(kuma-cp) server for managing provided ca (#473)
Browse files Browse the repository at this point in the history
  • Loading branch information
jakubdyszkiewicz authored Dec 11, 2019
1 parent 57e210b commit ae3d687
Show file tree
Hide file tree
Showing 46 changed files with 1,498 additions and 496 deletions.
10 changes: 5 additions & 5 deletions app/kuma-cp/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ package cmd
import (
"fmt"
ui_server "github.com/Kong/kuma/app/kuma-ui/pkg/server"
admin_server "github.com/Kong/kuma/pkg/admin-server"
api_server "github.com/Kong/kuma/pkg/api-server"
"github.com/Kong/kuma/pkg/config"
kuma_cp "github.com/Kong/kuma/pkg/config/app/kuma-cp"
"github.com/Kong/kuma/pkg/core"
"github.com/Kong/kuma/pkg/core/bootstrap"
sds_server "github.com/Kong/kuma/pkg/sds/server"
token_server "github.com/Kong/kuma/pkg/tokens/builtin/server"
xds_server "github.com/Kong/kuma/pkg/xds/server"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -63,10 +63,6 @@ func newRunCmdWithOpts(opts runCmdOpts) *cobra.Command {
runLog.Error(err, "unable to set up SDS server")
return err
}
if err := token_server.SetupServer(rt); err != nil {
runLog.Error(err, "unable to set up Dataplane Token server")
return err
}
if err := xds_server.SetupServer(rt); err != nil {
runLog.Error(err, "unable to set up xDS server")
return err
Expand All @@ -75,6 +71,10 @@ func newRunCmdWithOpts(opts runCmdOpts) *cobra.Command {
runLog.Error(err, "unable to set up API server")
return err
}
if err := admin_server.SetupServer(rt); err != nil {
runLog.Error(err, "unable to set up Admin server")
return err
}
if err := ui_server.SetupServer(rt); err != nil {
runLog.Error(err, "unable to set up GUI server")
return err
Expand Down
2 changes: 1 addition & 1 deletion app/kumactl/cmd/apply/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import (
"github.com/Kong/kuma/api/mesh/v1alpha1"
"github.com/Kong/kuma/app/kumactl/cmd"
kumactl_cmd "github.com/Kong/kuma/app/kumactl/pkg/cmd"
"github.com/Kong/kuma/pkg/api-server/types"
"github.com/Kong/kuma/pkg/core/resources/apis/mesh"
"github.com/Kong/kuma/pkg/core/rest/errors/types"
test_store "github.com/Kong/kuma/pkg/test/store"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
Expand Down
2 changes: 1 addition & 1 deletion app/kumactl/pkg/errors/formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package errors

import (
"fmt"
"github.com/Kong/kuma/pkg/api-server/types"
"github.com/Kong/kuma/pkg/core/rest/errors/types"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
Expand Down
2 changes: 1 addition & 1 deletion app/kumactl/pkg/errors/formatter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package errors_test

import (
kumactl_errors "github.com/Kong/kuma/app/kumactl/pkg/errors"
"github.com/Kong/kuma/pkg/api-server/types"
"github.com/Kong/kuma/pkg/core/rest/errors/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
Expand Down
2 changes: 1 addition & 1 deletion app/kumactl/pkg/resources/dataplane_overview_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
"net/http"
"net/url"

"github.com/Kong/kuma/pkg/api-server/types"
config_proto "github.com/Kong/kuma/pkg/config/app/kumactl/v1alpha1"
"github.com/Kong/kuma/pkg/core/resources/apis/mesh"
"github.com/Kong/kuma/pkg/core/rest/errors/types"
"github.com/Kong/kuma/pkg/plugins/resources/remote"
kuma_http "github.com/Kong/kuma/pkg/util/http"
"github.com/pkg/errors"
Expand Down
37 changes: 20 additions & 17 deletions app/kumactl/pkg/tokens/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package tokens_test
import (
"fmt"
"github.com/Kong/kuma/app/kumactl/pkg/tokens"
admin_server "github.com/Kong/kuma/pkg/admin-server"
admin_server_config "github.com/Kong/kuma/pkg/config/admin-server"
config_kumactl "github.com/Kong/kuma/pkg/config/app/kumactl/v1alpha1"
token_server "github.com/Kong/kuma/pkg/config/token-server"
"github.com/Kong/kuma/pkg/core/xds"
"github.com/Kong/kuma/pkg/sds/auth"
"github.com/Kong/kuma/pkg/test"
Expand Down Expand Up @@ -45,23 +46,25 @@ var _ = Describe("Tokens Client", func() {
Expect(err).ToNot(HaveOccurred())
publicPort = p

srv := server.DataplaneTokenServer{
Config: &token_server.DataplaneTokenServerConfig{
Enabled: true,
Local: &token_server.LocalDataplaneTokenServerConfig{
Port: uint32(port),
},
Public: &token_server.PublicDataplaneTokenServerConfig{
Enabled: true,
Port: uint32(publicPort),
Interface: "localhost",
TlsCertFile: filepath.Join("..", "..", "..", "..", "pkg", "tokens", "builtin", "server", "testdata", "server-cert.pem"),
TlsKeyFile: filepath.Join("..", "..", "..", "..", "pkg", "tokens", "builtin", "server", "testdata", "server-key.pem"),
ClientCertsDir: filepath.Join("..", "..", "..", "..", "pkg", "tokens", "builtin", "server", "testdata", "authorized-clients"),
adminCfg := admin_server_config.AdminServerConfig{
Apis: &admin_server_config.AdminServerApisConfig{
DataplaneToken: &admin_server_config.DataplaneTokenApiConfig{
Enabled: true,
},
},
Issuer: &staticTokenIssuer{},
Local: &admin_server_config.LocalAdminServerConfig{
Port: uint32(port),
},
Public: &admin_server_config.PublicAdminServerConfig{
Enabled: true,
Port: uint32(publicPort),
Interface: "localhost",
TlsCertFile: filepath.Join("..", "..", "..", "..", "pkg", "admin-server", "testdata", "server-cert.pem"),
TlsKeyFile: filepath.Join("..", "..", "..", "..", "pkg", "admin-server", "testdata", "server-key.pem"),
ClientCertsDir: filepath.Join("..", "..", "..", "..", "pkg", "admin-server", "testdata", "authorized-clients"),
},
}
srv := admin_server.NewAdminServer(adminCfg, server.NewWebservice(&staticTokenIssuer{}))

ch := make(chan struct{})
errCh := make(chan error)
Expand Down Expand Up @@ -105,8 +108,8 @@ var _ = Describe("Tokens Client", func() {
return fmt.Sprintf("https://localhost:%d", publicPort)
},
config: &config_kumactl.Context_DataplaneTokenApiCredentials{
ClientCert: filepath.Join("..", "..", "..", "..", "pkg", "tokens", "builtin", "server", "testdata", "authorized-client-cert.pem"),
ClientKey: filepath.Join("..", "..", "..", "..", "pkg", "tokens", "builtin", "server", "testdata", "authorized-client-key.pem"),
ClientCert: filepath.Join("..", "..", "..", "..", "pkg", "admin-server", "testdata", "authorized-client-cert.pem"),
ClientKey: filepath.Join("..", "..", "..", "..", "pkg", "admin-server", "testdata", "authorized-client-key.pem"),
},
}),
)
Expand Down
191 changes: 191 additions & 0 deletions pkg/admin-server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package admin_server

import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
admin_server "github.com/Kong/kuma/pkg/config/admin-server"
config_core "github.com/Kong/kuma/pkg/config/core"
"github.com/Kong/kuma/pkg/core"
ca_provided_rest "github.com/Kong/kuma/pkg/core/ca/provided/rest"
"github.com/Kong/kuma/pkg/core/runtime"
"github.com/Kong/kuma/pkg/tokens/builtin"
tokens_server "github.com/Kong/kuma/pkg/tokens/builtin/server"
"github.com/emicklei/go-restful"
"github.com/pkg/errors"
"go.uber.org/multierr"
"io/ioutil"
"net/http"
"path/filepath"
"strings"
)

var (
log = core.Log.WithName("admin-server")
)

type AdminServer struct {
cfg admin_server.AdminServerConfig
container *restful.Container
}

func NewAdminServer(cfg admin_server.AdminServerConfig, services ...*restful.WebService) *AdminServer {
container := restful.NewContainer()
for _, service := range services {
container.Add(service)
}
return &AdminServer{
cfg: cfg,
container: container,
}
}

func (a *AdminServer) Start(stop <-chan struct{}) error {
httpServer, httpErrChan := a.startHttpServer()

var httpsServer *http.Server
var httpsErrChan chan error
if a.cfg.Public.Enabled {
httpsServer, httpsErrChan = a.startHttpsServer()
} else {
httpsErrChan = make(chan error)
}

select {
case <-stop:
log.Info("stopping")
var multiErr error
if err := httpServer.Shutdown(context.Background()); err != nil {
multiErr = multierr.Combine(err)
}
if httpsServer != nil {
if err := httpsServer.Shutdown(context.Background()); err != nil {
multiErr = multierr.Combine(err)
}
}
return multiErr
case err := <-httpErrChan:
return err
case err := <-httpsErrChan:
return err
}
}

func (a *AdminServer) startHttpServer() (*http.Server, chan error) {
server := &http.Server{
Addr: fmt.Sprintf("127.0.0.1:%d", a.cfg.Local.Port),
Handler: a.container,
}

errChan := make(chan error)

go func() {
defer close(errChan)
if err := server.ListenAndServe(); err != nil {
if err != http.ErrServerClosed {
log.Error(err, "http server terminated with an error")
errChan <- err
return
}
}
log.Info("http server terminated normally")
}()
log.Info("starting server", "port", a.cfg.Local.Port)
return server, errChan
}

func (a *AdminServer) startHttpsServer() (*http.Server, chan error) {
errChan := make(chan error)

tlsConfig, err := requireClientCerts(a.cfg.Public.ClientCertsDir)
if err != nil {
errChan <- err
}

server := &http.Server{
Addr: fmt.Sprintf("%s:%d", a.cfg.Public.Interface, a.cfg.Public.Port),
Handler: a.container,
TLSConfig: tlsConfig,
}

go func() {
defer close(errChan)
if err := server.ListenAndServeTLS(a.cfg.Public.TlsCertFile, a.cfg.Public.TlsKeyFile); err != nil {
if err != http.ErrServerClosed {
log.Error(err, "https server terminated with an error")
errChan <- err
return
}
}
log.Info("https server terminated normally")
}()
log.Info("starting server", "interface", a.cfg.Public.Interface, "port", a.cfg.Public.Port, "tls", true)
return server, errChan
}

func requireClientCerts(certsDir string) (*tls.Config, error) {
files, err := ioutil.ReadDir(certsDir)
if err != nil {
return nil, err
}
clientCertPool := x509.NewCertPool()
for _, file := range files {
if file.IsDir() {
continue
}
if !strings.HasSuffix(file.Name(), ".pem") {
continue
}
path := filepath.Join(certsDir, file.Name())
caCert, err := ioutil.ReadFile(path)
if err != nil {
return nil, errors.Wrapf(err, "could not read certificate %s", path)
}
clientCertPool.AppendCertsFromPEM(caCert)
}
tlsConfig := &tls.Config{
ClientCAs: clientCertPool,
ClientAuth: tls.RequireAndVerifyClientCert,
}
tlsConfig.BuildNameToCertificate()
return tlsConfig, nil
}

func SetupServer(rt runtime.Runtime) error {
var webservices []*restful.WebService

ws := ca_provided_rest.NewWebservice(rt.ProvidedCaManager())
webservices = append(webservices, ws)

ws, err := dataplaneTokenWs(rt)
if err != nil {
return err
}
if ws != nil {
webservices = append(webservices, ws)
}

srv := NewAdminServer(*rt.Config().AdminServer, webservices...)
return rt.Add(srv)
}

func dataplaneTokenWs(rt runtime.Runtime) (*restful.WebService, error) {
if !rt.Config().AdminServer.Apis.DataplaneToken.Enabled {
log.Info("Dataplane Token Webservice is disabled. Dataplane Tokens won't be verified.")
return nil, nil
}

switch env := rt.Config().Environment; env {
case config_core.KubernetesEnvironment:
return nil, nil
case config_core.UniversalEnvironment:
generator, err := builtin.NewDataplaneTokenIssuer(rt)
if err != nil {
return nil, err
}
return tokens_server.NewWebservice(generator), nil
default:
return nil, errors.Errorf("unknown environment type %s", env)
}
}
13 changes: 13 additions & 0 deletions pkg/admin-server/server_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package admin_server_test

import (
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

func TestAdminServer(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Admin Server Suite")
}
Loading

0 comments on commit ae3d687

Please sign in to comment.