From 41e4cdf036adb959e583c127e5bd52e7998c9dc4 Mon Sep 17 00:00:00 2001 From: greg pereira Date: Mon, 21 Aug 2023 10:31:34 -0700 Subject: [PATCH] SECURESIGN 12 | Enable Podman build for TUF server image Signed-off-by: greg pereira --- cmd/tuf/server/main.go | 194 ++++++++++++++++++++++------------------- pkg/build/build.go | 15 ++++ pkg/tuf/tuf.go | 50 +++++++++++ 3 files changed, 169 insertions(+), 90 deletions(-) create mode 100644 pkg/build/build.go create mode 100644 pkg/tuf/tuf.go diff --git a/cmd/tuf/server/main.go b/cmd/tuf/server/main.go index 655fb7272..41c5e891f 100644 --- a/cmd/tuf/server/main.go +++ b/cmd/tuf/server/main.go @@ -17,15 +17,15 @@ package main import ( "bytes" "flag" - "fmt" "net/http" "os" "path/filepath" "strings" - "github.com/sigstore/scaffolding/pkg/certs" + "github.com/sigstore/scaffolding/pkg/build" "github.com/sigstore/scaffolding/pkg/repo" "github.com/sigstore/scaffolding/pkg/secret" + "github.com/sigstore/scaffolding/pkg/tuf" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "knative.dev/pkg/logging" @@ -43,104 +43,118 @@ var ( func main() { flag.Parse() - - ns := os.Getenv("NAMESPACE") - if ns == "" { - panic("env variable NAMESPACE must be set") - } ctx := signals.NewContext() versionInfo := version.GetVersionInfo() logging.FromContext(ctx).Infof("running create_repo Version: %s GitCommit: %s BuildDate: %s", versionInfo.GitVersion, versionInfo.GitCommit, versionInfo.BuildDate) - config, err := rest.InClusterConfig() - if err != nil { - logging.FromContext(ctx).Panicf("Failed to get InClusterConfig: %v", err) - } - clientset, err := kubernetes.NewForConfig(config) - if err != nil { - logging.FromContext(ctx).Panicf("Failed to get clientset: %v", err) - } + buildEnv := build.GetBuildMethod() + if buildEnv == "kubernetes" { + ns := os.Getenv("NAMESPACE") + if ns == "" { + panic("env variable NAMESPACE must be set") + } - tufFiles, err := os.ReadDir(*dir) - if err != nil { - logging.FromContext(ctx).Fatalf("failed to read dir %s: %v", *dir, err) - } - trimDir := strings.TrimSuffix(*dir, "/") - files := map[string][]byte{} - for _, file := range tufFiles { - if !file.IsDir() { - logging.FromContext(ctx).Infof("Got file %s", file.Name()) - // Kubernetes adds some extra files here that are prefixed with - // .., for example '..data' so skip those. - if strings.HasPrefix(file.Name(), "..") { - logging.FromContext(ctx).Infof("Skipping .. file %s", file.Name()) - continue - } - fileName := fmt.Sprintf("%s/%s", trimDir, file.Name()) - fileBytes, err := os.ReadFile(fileName) - if err != nil { - logging.FromContext(ctx).Fatalf("failed to read file %s/%s: %v", fileName, err) - } - // If it's a TSA file, we need to split it into multiple TUF - // targets. - if strings.Contains(file.Name(), "tsa") { - logging.FromContext(ctx).Infof("Splitting TSA certchain into individual certs") - - certFiles, err := certs.SplitCertChain(fileBytes, "tsa") - if err != nil { - logging.FromContext(ctx).Fatalf("failed to parse %s/%s: %v", fileName, err) - } - for k, v := range certFiles { - logging.FromContext(ctx).Infof("Got tsa cert file %s", k) - files[k] = v - } - } else { - files[file.Name()] = fileBytes - } + config, err := rest.InClusterConfig() + if err != nil { + logging.FromContext(ctx).Panicf("Failed to get InClusterConfig: %v", err) + } + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + logging.FromContext(ctx).Panicf("Failed to get clientset: %v", err) } - } - // Create a new TUF root with the listed artifacts. - local, dir, err := repo.CreateRepo(ctx, files) - if err != nil { - logging.FromContext(ctx).Panicf("Failed to create repo: %v", err) - } - meta, err := local.GetMeta() - if err != nil { - logging.FromContext(ctx).Panicf("Getting meta: %v", err) - } - rootJSON, ok := meta["root.json"] - if !ok { - logging.FromContext(ctx).Panicf("Getting root: %v", err) - } + tufFiles, err := os.ReadDir(*dir) + if err != nil { + logging.FromContext(ctx).Fatalf("failed to read dir %s: %v", *dir, err) + } + trimDir := strings.TrimSuffix(*dir, "/") + files := map[string][]byte{} + files = tuf.ProcessTufFiles(ctx, tufFiles, trimDir) - // Add the initial 1.root.json to secrets. - data := make(map[string][]byte) - data["root"] = rootJSON + local, dir, err := repo.CreateRepo(ctx, files) + if err != nil { + logging.FromContext(ctx).Panicf("Failed to create repo: %v", err) + } - // Then compress the root directory and put it into a secret - // Secrets have 1MiB and the repository as tested goes to about ~3k, so no - // worries here. - var compressed bytes.Buffer - if err := repo.CompressFS(os.DirFS(dir), &compressed, map[string]bool{"keys": true, "staged": true}); err != nil { - logging.FromContext(ctx).Fatalf("Failed to compress the repo: %v", err) - } - data["repository"] = compressed.Bytes() + meta, err := local.GetMeta() + if err != nil { + logging.FromContext(ctx).Panicf("Getting meta: %v", err) + } + rootJSON, ok := meta["root.json"] + if !ok { + logging.FromContext(ctx).Panicf("Getting root: %v", err) + } - nsSecret := clientset.CoreV1().Secrets(ns) - if err := secret.ReconcileSecret(ctx, *secretName, ns, data, nsSecret); err != nil { - logging.FromContext(ctx).Panicf("Failed to reconcile secret %s/%s: %v", ns, *secretName, err) - } - // Serve the TUF repository. - logging.FromContext(ctx).Infof("tuf repository was created in: %s", dir) - serveDir := filepath.Join(dir, "repository") - logging.FromContext(ctx).Infof("tuf repository was created in: %s serving tuf root at %s", dir, serveDir) - fs := http.FileServer(http.Dir(serveDir)) - http.Handle("/", fs) - - /* #nosec G114 */ - if err := http.ListenAndServe(":8080", nil); err != nil { - panic(err) + data := make(map[string][]byte) + data["root"] = rootJSON + + // Then compress the root directory and put it into a secret + // Secrets have 1MiB and the repository as tested goes to about ~3k, so no + // worries here. + var compressed bytes.Buffer + if err := repo.CompressFS(os.DirFS(dir), &compressed, map[string]bool{"keys": true, "staged": true}); err != nil { + logging.FromContext(ctx).Fatalf("Failed to compress the repo: %v", err) + } + data["repository"] = compressed.Bytes() + + nsSecret := clientset.CoreV1().Secrets(ns) + if err := secret.ReconcileSecret(ctx, *secretName, ns, data, nsSecret); err != nil { + logging.FromContext(ctx).Panicf("Failed to reconcile secret %s/%s: %v", ns, *secretName, err) + } + // Serve the TUF repository. + logging.FromContext(ctx).Infof("tuf repository was created in: %s", dir) + serveDir := filepath.Join(dir, "repository") + logging.FromContext(ctx).Infof("tuf repository was created in: %s serving tuf root at %s", dir, serveDir) + fs := http.FileServer(http.Dir(serveDir)) + http.Handle("/", fs) + + /* #nosec G114 */ + if err := http.ListenAndServe(":8080", nil); err != nil { + panic(err) + } + } else if buildEnv == "container" { + tufFiles, err := os.ReadDir(*dir) + if err != nil { + logging.FromContext(ctx).Fatalf("failed to read dir %s: %v", *dir, err) + } + trimDir := strings.TrimSuffix(*dir, "/") + files := map[string][]byte{} + + files = tuf.ProcessTufFiles(ctx, tufFiles, trimDir) + local, dir, err := repo.CreateRepo(ctx, files) + if err != nil { + logging.FromContext(ctx).Panicf("Failed to create repo: %v", err) + } + meta, err := local.GetMeta() + if err != nil { + logging.FromContext(ctx).Panicf("Getting meta: %v", err) + } + rootJSON, ok := meta["root.json"] + if !ok { + logging.FromContext(ctx).Panicf("Getting root: %v", err) + } + + data := make(map[string][]byte) + data["root"] = rootJSON + + // compressing the root directory and serving it from the filesystem. + + var compressed bytes.Buffer + if err := repo.CompressFS(os.DirFS(dir), &compressed, map[string]bool{"keys": true, "staged": true}); err != nil { + logging.FromContext(ctx).Fatalf("Failed to compress the repo: %v", err) + } + data["repository"] = compressed.Bytes() + + logging.FromContext(ctx).Infof("tuf repository was created in: %s", dir) + serveDir := filepath.Join(dir, "repository") + logging.FromContext(ctx).Infof("tuf repository was created in: %s serving tuf root at %s", dir, serveDir) + fs := http.FileServer(http.Dir(serveDir)) + http.Handle("/", fs) + + /* #nosec G114 */ + if err := http.ListenAndServe(":8080", nil); err != nil { + panic(err) + } } } diff --git a/pkg/build/build.go b/pkg/build/build.go new file mode 100644 index 000000000..46e6a7995 --- /dev/null +++ b/pkg/build/build.go @@ -0,0 +1,15 @@ +package build + +import ( + "os" +) + +func GetBuildMethod() string { + kubernetesServiceHost := os.Getenv("KUBERNETES_SERVICE_HOST") + kubernetesServicePort := os.Getenv("KUBERNETES_SERVICE_PORT") + if kubernetesServiceHost == "" && kubernetesServicePort == "" { + return "container" + } else { + return "kubernetes" + } +} diff --git a/pkg/tuf/tuf.go b/pkg/tuf/tuf.go new file mode 100644 index 000000000..c7b909f31 --- /dev/null +++ b/pkg/tuf/tuf.go @@ -0,0 +1,50 @@ +package tuf + +import ( + "context" + "fmt" + "io/fs" + "os" + "strings" + + "github.com/sigstore/scaffolding/pkg/certs" + "knative.dev/pkg/logging" +) + +func ProcessTufFiles(ctx context.Context, tufFiles []fs.DirEntry, dir string) map[string][]byte { + trimDir := strings.TrimSuffix(dir, "/") + files := map[string][]byte{} + for _, file := range tufFiles { + if !file.IsDir() { + logging.FromContext(ctx).Infof("Got file %s", file.Name()) + // Kubernetes adds some extra files here that are prefixed with + // .., for example '..data' so skip those. + if strings.HasPrefix(file.Name(), "..") { + logging.FromContext(ctx).Infof("Skipping .. file %s", file.Name()) + continue + } + fileName := fmt.Sprintf("%s/%s", trimDir, file.Name()) + fileBytes, err := os.ReadFile(fileName) + if err != nil { + logging.FromContext(ctx).Fatalf("failed to read file %s/%s: %v", fileName, err) + } + // If it's a TSA file, we need to split it into multiple TUF + // targets. + if strings.Contains(file.Name(), "tsa") { + logging.FromContext(ctx).Infof("Splitting TSA certchain into individual certs") + + certFiles, err := certs.SplitCertChain(fileBytes, "tsa") + if err != nil { + logging.FromContext(ctx).Fatalf("failed to parse %s/%s: %v", fileName, err) + } + for k, v := range certFiles { + logging.FromContext(ctx).Infof("Got tsa cert file %s", k) + files[k] = v + } + } else { + files[file.Name()] = fileBytes + } + } + } + return files +}