Files
attest-provider/pkg/handler/handler.go

111 lines
3.4 KiB
Go
Raw Normal View History

2024-05-23 10:19:55 -05:00
package handler
import (
2024-05-23 10:52:35 -05:00
"context"
2024-05-23 10:19:55 -05:00
"encoding/json"
"fmt"
"io"
"net/http"
2024-05-23 10:52:35 -05:00
"path/filepath"
2024-05-23 10:19:55 -05:00
2024-05-23 10:52:35 -05:00
"github.com/docker/attest/pkg/attest"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/policy"
"github.com/docker/attest/pkg/tuf"
2024-05-23 10:19:55 -05:00
"github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
2024-05-23 10:52:35 -05:00
"github.com/open-policy-agent/gatekeeper-external-data-provider/internal/embed"
2024-05-23 10:19:55 -05:00
"github.com/open-policy-agent/gatekeeper-external-data-provider/pkg/utils"
"k8s.io/klog/v2"
)
func Handler(w http.ResponseWriter, req *http.Request) {
// only accept POST requests
if req.Method != http.MethodPost {
utils.SendResponse(nil, "only POST is allowed", w)
return
}
// read request body
requestBody, err := io.ReadAll(req.Body)
if err != nil {
utils.SendResponse(nil, fmt.Sprintf("unable to read request body: %v", err), w)
return
}
klog.InfoS("received request", "body", requestBody)
// parse request body
var providerRequest externaldata.ProviderRequest
err = json.Unmarshal(requestBody, &providerRequest)
if err != nil {
utils.SendResponse(nil, fmt.Sprintf("unable to unmarshal request body: %v", err), w)
return
}
results := make([]externaldata.Item, 0)
2024-05-23 10:52:35 -05:00
// create a tuf client
tufOutputPath := filepath.Join("/tuf_temp", ".docker", "tuf")
tufClient, err := createTufClient(tufOutputPath)
if err != nil {
utils.SendResponse(nil, err.Error(), w)
}
2024-05-23 10:19:55 -05:00
// iterate over all keys
for _, key := range providerRequest.Request.Keys {
2024-05-23 10:52:35 -05:00
// create a resolver for remote attestations
platform := "linux/amd64"
resolver := &oci.RegistryResolver{
Image: key, // path to image index in OCI registry containing image attestations
Platform: platform, // platform of subject image (image that attestations are being verified against)
}
2024-05-23 10:19:55 -05:00
2024-05-23 10:52:35 -05:00
// configure policy options
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
2024-05-23 10:19:55 -05:00
}
2024-05-23 10:52:35 -05:00
// verify attestations
ctx := context.TODO()
debug := true
ctx = policy.WithPolicyEvaluator(ctx, policy.NewRegoEvaluator(debug))
policy, err := attest.Verify(ctx, opts, resolver)
if err != nil {
2024-05-23 10:19:55 -05:00
results = append(results, externaldata.Item{
Key: key,
2024-05-23 10:52:35 -05:00
Error: "admit: false, error: " + err.Error(),
2024-05-23 10:19:55 -05:00
})
2024-05-23 10:52:35 -05:00
continue
}
if policy {
klog.Infof("policy passed: %v\n", policy)
2024-05-23 10:19:55 -05:00
// valid key will have "_valid" appended as return value
results = append(results, externaldata.Item{
Key: key,
2024-05-23 10:52:35 -05:00
Value: "admit: true, message: policy passed",
2024-05-23 10:19:55 -05:00
})
2024-05-23 10:52:35 -05:00
continue // passed policy
2024-05-23 10:19:55 -05:00
}
2024-05-23 10:52:35 -05:00
// no policy found for image
klog.Infof("no policy for image")
results = append(results, externaldata.Item{
Key: key,
Value: "admit: true, message: no policy",
})
2024-05-23 10:19:55 -05:00
}
utils.SendResponse(&results, "", w)
}
2024-05-23 10:52:35 -05:00
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)
}