Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions cmd/timestamp-server/app/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ import (
)

var (
cfgFile string
logType string
enablePprof bool
cfgFile string
logType string
enablePprof bool
httpPingOnly bool
)

// rootCmd represents the base command when called without any subcommands
Expand Down Expand Up @@ -56,7 +57,7 @@ func init() {
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.timestamp-server.yaml)")
rootCmd.PersistentFlags().StringVar(&logType, "log-type", "dev", "logger type to use (dev/prod)")
rootCmd.PersistentFlags().BoolVar(&enablePprof, "enable-pprof", false, "enable pprof for profiling on port 6060")

rootCmd.PersistentFlags().BoolVar(&httpPingOnly, "http-ping-only", false, "serve only /ping in the http server")
rootCmd.PersistentFlags().String("timestamp-signer", "memory", "Timestamping authority signer. Valid options include: [kms, tink, memory, file]. Memory and file-based signers should only be used for testing")
// KMS flags
rootCmd.PersistentFlags().String("kms-key-resource", "", "KMS key for signing timestamp responses. Valid options include: [gcpkms://resource, azurekms://resource, hashivault://resource, awskms://resource]")
Expand Down
3 changes: 1 addition & 2 deletions cmd/timestamp-server/app/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ var serveCmd = &cobra.Command{
host := viper.GetString("host")
port := int(viper.GetUint("port"))
scheme := viper.GetStringSlice("scheme")

server := server.NewRestAPIServer(host, port, scheme, readTimeout, writeTimeout)
server := server.NewRestAPIServer(host, port, scheme, httpPingOnly, readTimeout, writeTimeout)
defer func() {
if err := server.Shutdown(); err != nil {
log.Logger.Error(err)
Expand Down
27 changes: 26 additions & 1 deletion pkg/generated/restapi/configure_timestamp_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"crypto/tls"
"net/http"
"strconv"
"strings"
"time"

"github.com/go-chi/chi/middleware"
Expand All @@ -33,6 +34,7 @@ import (
pkgapi "github.com/sigstore/timestamp-authority/pkg/api"
"github.com/sigstore/timestamp-authority/pkg/generated/restapi/operations"
"github.com/sigstore/timestamp-authority/pkg/generated/restapi/operations/timestamp"
"github.com/sigstore/timestamp-authority/pkg/internal/cmdparams"
"github.com/sigstore/timestamp-authority/pkg/log"
)

Expand Down Expand Up @@ -101,14 +103,37 @@ func (l *logAdapter) Print(v ...interface{}) {
log.Logger.Info(v...)
}

const pingPath = "/ping"

// httpPingOnly custom middleware prohibits all entrypoints except
// "/ping" on the http (non-HTTPS) server.
func httpPingOnly() func(http.Handler) http.Handler {
f := func(h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
if r.URL.Scheme != "https" && !strings.EqualFold(r.URL.Path, pingPath) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("http server supports only the " + pingPath + " entrypoint")) //nolint:errcheck
return
}
h.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
return f
}

// The middleware configuration happens before anything, this middleware also applies to serving the swagger.json document.
// So this is a good place to plug in a panic handling middleware, logging and metrics.
func setupGlobalMiddleware(handler http.Handler) http.Handler {
middleware.DefaultLogger = middleware.RequestLogger(
&middleware.DefaultLogFormatter{Logger: &logAdapter{}})
returnHandler := middleware.Logger(handler)
returnHandler = middleware.Recoverer(returnHandler)
returnHandler = middleware.Heartbeat("/ping")(returnHandler)
returnHandler = middleware.Heartbeat(pingPath)(returnHandler)
if cmdparams.IsHTTPPingOnly {
returnHandler = httpPingOnly()(returnHandler)
}

handleCORS := cors.Default().Handler
returnHandler = handleCORS(returnHandler)
Expand Down
23 changes: 23 additions & 0 deletions pkg/internal/cmdparams/cmdparams.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// Copyright 2023 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmdparams

// IsHTTPPingOnly is set off the command-line flag to enforce limiting
// the non-mTLS http server to only serving the /ping entrypoint.
// It should be set only once when processing command-line flags
// and then used only in pkg/generated/restapi/configure_timestamp_server.go
// and as read-only.
var IsHTTPPingOnly bool
19 changes: 19 additions & 0 deletions pkg/internal/cmdparams/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Copyright 2023 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package cmdparams contains variables to propagate from command-line
// flags to their handling in
// pkg/generated/restapi/configure_timestamp_server.go.
package cmdparams
1 change: 0 additions & 1 deletion pkg/ntpmonitor/config.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//
// Copyright 2022 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
9 changes: 7 additions & 2 deletions pkg/server/restapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,15 @@ import (
"github.com/sigstore/timestamp-authority/pkg/api"
"github.com/sigstore/timestamp-authority/pkg/generated/restapi"
"github.com/sigstore/timestamp-authority/pkg/generated/restapi/operations"
"github.com/sigstore/timestamp-authority/pkg/internal/cmdparams"
)

// NewRestAPIServer creates a server for serving the rest API TSA service
func NewRestAPIServer(host string, port int, scheme []string, readTimeout, writeTimeout time.Duration) *restapi.Server {
func NewRestAPIServer(host string,
port int,
scheme []string,
httpReadOnly bool,
readTimeout, writeTimeout time.Duration) *restapi.Server {
doc, _ := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
server := restapi.NewServer(operations.NewTimestampServerAPI(doc))

Expand All @@ -33,7 +38,7 @@ func NewRestAPIServer(host string, port int, scheme []string, readTimeout, write
server.EnabledListeners = scheme
server.ReadTimeout = readTimeout
server.WriteTimeout = writeTimeout

cmdparams.IsHTTPPingOnly = httpReadOnly
api.ConfigureAPI()
server.ConfigureAPI()

Expand Down
2 changes: 1 addition & 1 deletion pkg/tests/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
func createServer(t *testing.T) string {
viper.Set("timestamp-signer", "memory")
// unused port
apiServer := server.NewRestAPIServer("localhost", 0, []string{"http"}, 10*time.Second, 10*time.Second)
apiServer := server.NewRestAPIServer("localhost", 0, []string{"http"}, false, 10*time.Second, 10*time.Second)
server := httptest.NewServer(apiServer.GetHandler())
t.Cleanup(server.Close)

Expand Down