Skip to content

Commit

Permalink
enbable TLS
Browse files Browse the repository at this point in the history
Signed-off-by: YZ775 <yuzuki-mimura@cybozu.co.jp>
  • Loading branch information
YZ775 committed Sep 28, 2023
1 parent 5bc211e commit 0c62615
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 5 deletions.
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
ETCD_VERSION = 3.5.7
GO_FILES=$(shell find -name '*.go' -not -name '*_test.go')
BUILT_TARGET=sabakan sabactl sabakan-cryptsetup
IMAGE ?= quay.io/cybozu/sabakan
TAG ?= latest

.PHONY: all
all: build
Expand Down Expand Up @@ -61,3 +63,9 @@ etcd:
$(SUDO) mv /tmp/etcd/etcd /usr/local/bin/; \
rm -rf /tmp/etcd-v${ETCD_VERSION}-linux-amd64.tar.gz /tmp/etcd; \
fi

.PHONY: docker-build
docker-build:build
cp sabactl sabakan sabakan-cryptsetup LICENSE ./docker/
docker build -t $(IMAGE):$(TAG) ./docker
rm ./docker/sabactl ./docker/sabakan ./docker/sabakan-cryptsetup ./docker/LICENSE
12 changes: 12 additions & 0 deletions pkg/sabakan-cryptsetup/cmd/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package cmd
import (
"context"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"errors"
"net"
"net/http"
Expand Down Expand Up @@ -35,6 +37,13 @@ type Driver struct {
// It may return nil when the serial code of the machine cannot be identified,
// or sabakanURL is not valid.
func NewDriver(sabakanURL, cipher string, keySize int, tpmdev string, disks []Disk) (*Driver, error) {
crt, err := os.ReadFile("/etc/sabakan/neco.crt")
if err != nil {
return nil, err
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(crt)

hc := &http.Client{
Transport: &http.Transport{
DialContext: (&net.Dialer{
Expand All @@ -45,6 +54,9 @@ func NewDriver(sabakanURL, cipher string, keySize int, tpmdev string, disks []Di
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
RootCAs: caCertPool,
},
},
}
saba, err := sabakan.NewClient(sabakanURL, hc)
Expand Down
10 changes: 10 additions & 0 deletions pkg/sabakan-cryptsetup/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package cmd
import (
"errors"
"fmt"
"log"

Check failure on line 6 in pkg/sabakan-cryptsetup/cmd/root.go

View workflow job for this annotation

GitHub Actions / Build

log package must not be imported
"net/url"
"os"

"github.com/cybozu-go/well"
Expand Down Expand Up @@ -71,6 +73,14 @@ func init() {
if sabaURL == "" {
sabaURL = defaultSabakanURL
}
u, err := url.Parse(sabaURL)
if err != nil {
log.Fatal(err)
}
u.Scheme = "https"
u.Host = u.Hostname() + ":10443"
sabaURL = u.String()

rootCmd.Flags().StringVar(&opts.sabakanURL, "server", sabaURL, "URL of sabakan server")
rootCmd.Flags().StringVar(&opts.tpmdev, "tpmdev", defaultTPMDev, "device file path of tpm")
rootCmd.Flags().StringVar(&opts.cipher, "cipher", defaultCipher, "cipher specification")
Expand Down
3 changes: 3 additions & 0 deletions pkg/sabakan/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "github.com/cybozu-go/etcdutil"

const (
defaultListenHTTP = "0.0.0.0:10080"
defaultListenHTTPS = "0.0.0.0:10443"
defaultListenMetrics = "0.0.0.0:10081"
defaultEtcdPrefix = "/sabakan/"
defaultDHCPBind = "0.0.0.0:10067"
Expand All @@ -18,6 +19,7 @@ var (
func newConfig() *config {
return &config{
ListenHTTP: defaultListenHTTP,
ListenHTTPS: defaultListenHTTPS,
ListenMetrics: defaultListenMetrics,
DHCPBind: defaultDHCPBind,
IPXEPath: defaultIPXEPath,
Expand All @@ -29,6 +31,7 @@ func newConfig() *config {

type config struct {
ListenHTTP string `json:"http"`
ListenHTTPS string `json:"https"`
ListenMetrics string `json:"metrics"`
DHCPBind string `json:"dhcp-bind"`
IPXEPath string `json:"ipxe-efi-path"`
Expand Down
17 changes: 16 additions & 1 deletion pkg/sabakan/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (

var (
flagHTTP = flag.String("http", defaultListenHTTP, "<Listen IP>:<Port number>")
flagHTTPS = flag.String("https", defaultListenHTTPS, "<Listen IP>:<Port number>")
flagMetrics = flag.String("metrics", defaultListenMetrics, "<Listen IP>:<Port number>")
flagDHCPBind = flag.String("dhcp-bind", defaultDHCPBind, "bound ip addresses and port for dhcp server")
flagIPXEPath = flag.String("ipxe-efi-path", defaultIPXEPath, "path to ipxe.efi")
Expand Down Expand Up @@ -87,6 +88,7 @@ func subMain(ctx context.Context) error {
cfg.DataDir = *flagDataDir
cfg.IPXEPath = *flagIPXEPath
cfg.ListenHTTP = *flagHTTP
cfg.ListenHTTPS = *flagHTTPS
cfg.Playground = *flagPlayground
cfg.ListenMetrics = *flagMetrics

Expand Down Expand Up @@ -167,7 +169,7 @@ func subMain(ctx context.Context) error {
return err
}
counter := metrics.NewCounter()
webServer := web.NewServer(model, cfg.IPXEPath, cryptsetupPath, advertiseURL, allowedIPs, cfg.Playground, counter)
webServer := web.NewServer(model, cfg.IPXEPath, cryptsetupPath, advertiseURL, allowedIPs, cfg.Playground, counter, false)
s := &well.HTTPServer{
Server: &http.Server{
Addr: cfg.ListenHTTP,
Expand All @@ -178,6 +180,19 @@ func subMain(ctx context.Context) error {
}
s.ListenAndServe()

//sabakan TLS
counter = metrics.NewCounter()
webServerHTTPS := web.NewServer(model, cfg.IPXEPath, cryptsetupPath, advertiseURL, allowedIPs, cfg.Playground, counter, true)
ss := &well.HTTPServer{
Server: &http.Server{
Addr: cfg.ListenHTTPS,
Handler: webServerHTTPS,
},
ShutdownTimeout: 3 * time.Minute,
Env: env,
}
ss.ListenAndServeTLS("/etc/sabakan/sabakan-tls.crt", "/etc/sabakan/sabakan-tls.key")

// Metrics
collector := metrics.NewCollector(&model)
metricsHandler := metrics.GetHandler(collector)
Expand Down
2 changes: 1 addition & 1 deletion web/machines_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ func testMachinesDelete(t *testing.T) {

func testMachinesGraphQL(t *testing.T) {
m := mock.NewModel()
handler := NewServer(m, "", "", nil, nil, false, nil)
handler := NewServer(m, "", "", nil, nil, false, nil, false)

m.Machine.Register(context.Background(), []*sabakan.Machine{
sabakan.NewMachine(sabakan.MachineSpec{
Expand Down
2 changes: 1 addition & 1 deletion web/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func newTestServer(m sabakan.Model) *Server {
// https://golang.org/src/net/http/httptest/httptest.go?s=1162:1230#L31
_, ipnet, _ := net.ParseCIDR("192.0.2.1/24")
u, _ := url.Parse(testMyURL)
return NewServer(m, "", "", u, []*net.IPNet{ipnet}, false, nil)
return NewServer(m, "", "", u, []*net.IPNet{ipnet}, false, nil, false)
}

func testWithIPAM(t *testing.T, m sabakan.Model) *sabakan.IPAMConfig {
Expand Down
41 changes: 39 additions & 2 deletions web/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ type Server struct {

graphQL http.Handler
playground http.HandlerFunc

TLSEnabled bool
}

// NewServer constructs Server instance
func NewServer(model sabakan.Model, ipxePath, cryptsetupPath string,
advertiseURL *url.URL, allowedIPs []*net.IPNet, enablePlayground bool, counter *metrics.APICounter) *Server {
advertiseURL *url.URL, allowedIPs []*net.IPNet, enablePlayground bool, counter *metrics.APICounter, tlsEnabled bool) *Server {
graphQL := handler.NewDefaultServer(generated.NewExecutableSchema(
generated.Config{
Resolvers: &graph.Resolver{Model: model},
Expand All @@ -70,6 +72,7 @@ func NewServer(model sabakan.Model, ipxePath, cryptsetupPath string,
AllowedRemotes: allowedIPs,
Counter: counter,
graphQL: graphQL,
TLSEnabled: tlsEnabled,
}

if enablePlayground {
Expand All @@ -81,7 +84,11 @@ func NewServer(model sabakan.Model, ipxePath, cryptsetupPath string,
// ServeHTTP implements http.Handler.ServeHTTP
func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w2 := &recorderWriter{ResponseWriter: w}
s.serveHTTP(w2, r)
if s.TLSEnabled {
s.serveHTTPS(w2, r)
} else {
s.serveHTTP(w2, r)
}
if s.Counter != nil {
s.Counter.Inc(w2.statusCode, r.URL.Path, r.Method)
}
Expand Down Expand Up @@ -116,6 +123,18 @@ func (s Server) serveHTTP(w http.ResponseWriter, r *http.Request) {
renderError(r.Context(), w, APIErrNotFound)
}

func (s Server) serveHTTPS(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api/v1/") {
s.handleAPIV1HTTPS(w, r)
return
}
if r.URL.Path == "/test" {
w.Write([]byte("response from sabakan TLS\n"))
return
}
renderError(r.Context(), w, APIErrNotFound)
}

func auditContext(r *http.Request) context.Context {
ctx := r.Context()

Expand Down Expand Up @@ -186,6 +205,24 @@ func (s Server) handleAPIV1(w http.ResponseWriter, r *http.Request) {
}
}

func (s Server) handleAPIV1HTTPS(w http.ResponseWriter, r *http.Request) {
p := r.URL.Path[len("/api/v1/"):]

if !s.hasPermission(r) {
renderError(r.Context(), w, APIErrForbidden)
return
}

r = r.WithContext(auditContext(r))

switch {
case strings.HasPrefix(p, "crypts/"):
s.handleCrypts(w, r)
default:
renderError(r.Context(), w, APIErrNotFound)
}
}

// hasPermission returns true if the request has a permission to the resource
func (s Server) hasPermission(r *http.Request) bool {
p := r.URL.Path[len("/api/v1/"):]
Expand Down

0 comments on commit 0c62615

Please sign in to comment.