Read TUF config from flags and add to helm chart
The values in the local helm chart are for the dev root
This commit is contained in:
@@ -25,6 +25,22 @@ spec:
|
||||
- --client-ca-file={{ .Values.clientCAFile }}
|
||||
{{- end }}
|
||||
- --port={{ .Values.port }}
|
||||
{{- if .Values.tufRoot }}
|
||||
- --tuf-root={{ .Values.tufRoot }}
|
||||
{{- end }}
|
||||
{{- if .Values.tufMetadataSource }}
|
||||
- --tuf-metadata-source={{ .Values.tufMetadataSource }}
|
||||
{{- end }}
|
||||
{{- if .Values.tufTargetsSource }}
|
||||
- --tuf-targets-source={{ .Values.tufTargetsSource }}
|
||||
{{- end }}
|
||||
{{- if .Values.localPolicyDir }}
|
||||
- --local-policy-dir={{ .Values.localPolicyDir }}
|
||||
{{- end }}
|
||||
{{- if .Values.policyCacheDir }}
|
||||
- --policy-cache-dir={{ .Values.policyCacheDir }}
|
||||
{{- end }}
|
||||
|
||||
ports:
|
||||
- containerPort: {{ .Values.port }}
|
||||
protocol: TCP
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
certDir: /certs
|
||||
clientCAFile: /tmp/gatekeeper/ca.crt
|
||||
port: 8090
|
||||
tufRoot: dev
|
||||
tufMetadataSource: https://docker.github.io/tuf-dev/metadata
|
||||
tufTargetsSource: https://docker.github.io/tuf-dev/targets
|
||||
provider:
|
||||
timeout: 30
|
||||
tls:
|
||||
|
||||
56
main.go
56
main.go
@@ -32,6 +32,24 @@ var (
|
||||
certDir string
|
||||
clientCAFile string
|
||||
port int
|
||||
|
||||
tufRoot string
|
||||
tufoutputPath string
|
||||
metadataURL string
|
||||
targetsURL string
|
||||
|
||||
policyDir string
|
||||
policyCacheDir string
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMetadataURL = "registry-1.docker.io/docker/tuf-metadata:latest"
|
||||
defaultTargetsURL = "registry-1.docker.io/docker/tuf-targets"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultTUFOutputPath = filepath.Join("/tuf_temp", ".docker", "tuf")
|
||||
defaultPolicyCacheDir = filepath.Join("/tuf_temp", ".docker", "policy")
|
||||
)
|
||||
|
||||
var timeoutError = string(utils.GatekeeperError("operation timed out"))
|
||||
@@ -41,13 +59,47 @@ func init() {
|
||||
flag.StringVar(&certDir, "cert-dir", "", "path to directory containing TLS certificates")
|
||||
flag.StringVar(&clientCAFile, "client-ca-file", "", "path to client CA certificate")
|
||||
flag.IntVar(&port, "port", defaultPort, "Port for the server to listen on")
|
||||
flag.StringVar(&tufRoot, "tuf-root", "staging", "specify embedded tuf root [dev, staging], default [staging]")
|
||||
|
||||
if tufRoot != "dev" && tufRoot != "staging" {
|
||||
klog.Errorf("invalid tuf root: %s", tufRoot)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
flag.StringVar(&metadataURL, "tuf-metadata-source", defaultMetadataURL, "source (URL or repo) for TUF metadata")
|
||||
flag.StringVar(&targetsURL, "tuf-targets-source", defaultTargetsURL, "source (URL or repo) for TUF targets")
|
||||
flag.StringVar(&tufoutputPath, "tuf-output-path", defaultTUFOutputPath, "local dir to store TUF repo metadata")
|
||||
|
||||
flag.StringVar(&policyDir, "local-policy-dir", "", "path to local policy directory (overrides TUF policy)")
|
||||
flag.StringVar(&policyCacheDir, "policy-cache-dir", defaultPolicyCacheDir, "path to store policy downloaded from TUF")
|
||||
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func main() {
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("POST /validate", http.TimeoutHandler(handler.Validate(), handlerTimeout, timeoutError))
|
||||
mux.Handle("POST /mutate", http.TimeoutHandler(handler.Mutate(), handlerTimeout, timeoutError))
|
||||
|
||||
validateHandler, err := handler.NewValidateHandler(&handler.ValidateHandlerOptions{
|
||||
TUFRoot: tufRoot,
|
||||
TUFOutputPath: tufoutputPath,
|
||||
TUFMetadataURL: metadataURL,
|
||||
TUFTargetsURL: targetsURL,
|
||||
PolicyDir: policyDir,
|
||||
PolicyCacheDir: policyCacheDir,
|
||||
})
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to create validate handler")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
mutateHandler, err := handler.NewMutateHandler()
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to create validate handler")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
mux.Handle("POST /validate", http.TimeoutHandler(validateHandler, handlerTimeout, timeoutError))
|
||||
mux.Handle("POST /mutate", http.TimeoutHandler(mutateHandler, handlerTimeout, timeoutError))
|
||||
|
||||
server := &http.Server{
|
||||
Addr: fmt.Sprintf(":%d", port),
|
||||
|
||||
@@ -15,11 +15,13 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
func Mutate() http.Handler {
|
||||
return http.HandlerFunc(mutate)
|
||||
type mutateHandler struct{}
|
||||
|
||||
func NewMutateHandler() (http.Handler, error) {
|
||||
return &mutateHandler{}, nil
|
||||
}
|
||||
|
||||
func mutate(w http.ResponseWriter, req *http.Request) {
|
||||
func (h *mutateHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
klog.Error(string(debug.Stack()))
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/docker/attest/pkg/tuf"
|
||||
"github.com/open-policy-agent/gatekeeper-external-data-provider/internal/embed"
|
||||
)
|
||||
|
||||
func createTufClient(outputPath string) (*tuf.TufClient, error) {
|
||||
// using oci tuf metadata and targets
|
||||
metadataURI := "registry-1.docker.io/docker/tuf-metadata:latest"
|
||||
targetsURI := "registry-1.docker.io/docker/tuf-targets"
|
||||
// example using http tuf metadata and targets
|
||||
// metadataURI := "https://docker.github.io/tuf-staging/metadata"
|
||||
// targetsURI := "https://docker.github.io/tuf-staging/targets"
|
||||
|
||||
return tuf.NewTufClient(embed.StagingRoot, outputPath, metadataURI, targetsURI, tuf.NewVersionChecker())
|
||||
}
|
||||
@@ -5,14 +5,15 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/docker/attest/pkg/attest"
|
||||
"github.com/docker/attest/pkg/oci"
|
||||
"github.com/docker/attest/pkg/policy"
|
||||
"github.com/docker/attest/pkg/tuf"
|
||||
intoto "github.com/in-toto/in-toto-golang/in_toto"
|
||||
"github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
|
||||
"github.com/open-policy-agent/gatekeeper-external-data-provider/internal/embed"
|
||||
"github.com/open-policy-agent/gatekeeper-external-data-provider/pkg/utils"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
@@ -24,11 +25,50 @@ type ValidationResult struct {
|
||||
Violations []policy.Violation `json:"violations"`
|
||||
}
|
||||
|
||||
func Validate() http.Handler {
|
||||
return http.HandlerFunc(validate)
|
||||
type ValidateHandlerOptions struct {
|
||||
TUFRoot string
|
||||
TUFOutputPath string
|
||||
TUFMetadataURL string
|
||||
TUFTargetsURL string
|
||||
|
||||
PolicyDir string
|
||||
PolicyCacheDir string
|
||||
}
|
||||
|
||||
func validate(w http.ResponseWriter, req *http.Request) {
|
||||
type validateHandler struct {
|
||||
opts *ValidateHandlerOptions
|
||||
}
|
||||
|
||||
func NewValidateHandler(opts *ValidateHandlerOptions) (http.Handler, error) {
|
||||
handler := &validateHandler{opts: opts}
|
||||
|
||||
// a TUF client can only be used once, so we need to create a new one for each request.
|
||||
// we create this one up front to ensure that the TUF root is valid and to pre-load the metadata.
|
||||
// TODO: this pre-loading works for the root, targets, snapshot, and timestamp roles, but not for delegated roles.
|
||||
_, err := handler.createTUFClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
klog.Infof("validate handler initialized with %s TUF root", opts.TUFRoot)
|
||||
|
||||
return handler, nil
|
||||
}
|
||||
|
||||
func (h *validateHandler) createTUFClient() (*tuf.TufClient, error) {
|
||||
var rootBytes []byte
|
||||
switch h.opts.TUFRoot {
|
||||
case "dev":
|
||||
rootBytes = embed.DevRoot
|
||||
case "staging":
|
||||
rootBytes = embed.StagingRoot
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid tuf root: %s", h.opts.TUFRoot)
|
||||
}
|
||||
return tuf.NewTufClient(rootBytes, h.opts.TUFOutputPath, h.opts.TUFMetadataURL, h.opts.TUFTargetsURL, tuf.NewVersionChecker())
|
||||
}
|
||||
|
||||
func (h *validateHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
klog.Error(string(debug.Stack()))
|
||||
@@ -36,6 +76,10 @@ func validate(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
}()
|
||||
|
||||
ctx := req.Context()
|
||||
debug := true
|
||||
ctx = policy.WithPolicyEvaluator(ctx, policy.NewRegoEvaluator(debug))
|
||||
|
||||
// read request body
|
||||
requestBody, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
@@ -53,16 +97,19 @@ func validate(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
results := make([]externaldata.Item, 0)
|
||||
|
||||
// create a tuf client
|
||||
tufOutputPath := filepath.Join("/tuf_temp", ".docker", "tuf")
|
||||
tufClient, err := createTufClient(tufOutputPath)
|
||||
tufClient, err := h.createTUFClient()
|
||||
if err != nil {
|
||||
utils.SendResponse(nil, err.Error(), w)
|
||||
utils.SendResponse(nil, fmt.Sprintf("unable to create TUF client: %v", err), w)
|
||||
return
|
||||
}
|
||||
|
||||
policyOpts := &policy.PolicyOptions{
|
||||
TufClient: tufClient,
|
||||
LocalTargetsDir: h.opts.PolicyCacheDir,
|
||||
LocalPolicyDir: h.opts.PolicyDir,
|
||||
}
|
||||
|
||||
results := make([]externaldata.Item, 0)
|
||||
for _, key := range providerRequest.Request.Keys {
|
||||
platform := "linux/amd64"
|
||||
src, err := oci.ParseImageSpec(key, oci.WithPlatform(platform))
|
||||
@@ -71,16 +118,7 @@ func validate(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
opts := &policy.PolicyOptions{
|
||||
TufClient: tufClient,
|
||||
LocalTargetsDir: filepath.Join("/tuf_temp", ".docker", "policy"), // location to store policy files downloaded from TUF
|
||||
LocalPolicyDir: "", // overrides TUF policy for local policy files if set
|
||||
}
|
||||
|
||||
ctx := req.Context()
|
||||
debug := true
|
||||
ctx = policy.WithPolicyEvaluator(ctx, policy.NewRegoEvaluator(debug))
|
||||
result, err := attest.Verify(ctx, src, opts)
|
||||
result, err := attest.Verify(ctx, src, policyOpts)
|
||||
if err != nil {
|
||||
utils.SendResponse(nil, err.Error(), w)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user