Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(kuma-cp) server for managing provided ca #473

Merged
merged 10 commits into from
Dec 11, 2019
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