Skip to content

Commit 1376677

Browse files
erock2112SkCQ
authored andcommitted
[attest] Use google APIs, refactor client, verify signatures
I finally figured out how to make the APIs work. I still don't have permission to access the container notes, and presumably the service account doesn't either. Bug: b/432211966 Change-Id: I701d7690ab65211e1ca03dd2cb8683fbdd72a9b4 Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/1024840 Commit-Queue: Eric Boren <borenet@google.com> Reviewed-by: Kaylee Lubick <kjlubick@google.com>
1 parent 7742438 commit 1376677

18 files changed

Lines changed: 1050 additions & 666 deletions

File tree

.mockery.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ packages:
88
go.skia.org/infra/am/go/alertclient:
99
interfaces:
1010
APIClient:
11+
go.skia.org/infra/attest/go/types:
12+
interfaces:
13+
Client:
1114
go.skia.org/infra/autoroll/go/config/db:
1215
interfaces:
1316
DB:

WORKSPACE

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,11 @@ go_googleapis_compatibility_hack(
102102
# Needed by @com_github_bazelbuild_remote_apis.
103103
http_archive(
104104
name = "com_google_protobuf",
105-
sha256 = "b8ab9bbdf0c6968cf20060794bc61e231fae82aaf69d6e3577c154181991f576",
106-
strip_prefix = "protobuf-3.18.1",
105+
sha256 = "da288bf1daa6c04d03a9051781caa52aceb9163586bff9aa6cfb12f69b9395aa",
106+
strip_prefix = "protobuf-27.0",
107107
urls = gcs_mirror_url(
108108
sha256 = "b8ab9bbdf0c6968cf20060794bc61e231fae82aaf69d6e3577c154181991f576",
109-
url = "https://github.com/protocolbuffers/protobuf/releases/download/v3.18.1/protobuf-all-3.18.1.tar.gz",
109+
url = "https://github.com/protocolbuffers/protobuf/releases/download/v27.0/protobuf-27.0.tar.gz",
110110
),
111111
)
112112

@@ -118,6 +118,15 @@ http_archive(
118118
# The protobuf_deps() macro brings in a bunch of dependencies, but by copying the macro body here
119119
# and removing dependencies one by one, "rules_proto" was identified as the only dependency that is
120120
# required to build this repository.
121+
122+
http_archive(
123+
name = "com_google_absl",
124+
sha256 = "f49929d22751bf70dd61922fb1fd05eb7aec5e7a7f870beece79a6e28f0a06c1",
125+
strip_prefix = "abseil-cpp-4a2c63365eff8823a5221db86ef490e828306f9d",
126+
# Abseil LTS 20240116.0
127+
urls = ["https://github.com/abseil/abseil-cpp/archive/4a2c63365eff8823a5221db86ef490e828306f9d.zip"],
128+
)
129+
121130
http_archive(
122131
name = "rules_proto",
123132
sha256 = "6fb6767d1bef535310547e03247f7518b03487740c11b6c6adb7952033fe1295",
@@ -137,6 +146,10 @@ load("@rules_proto//proto:toolchains.bzl", "rules_proto_toolchains")
137146

138147
rules_proto_toolchains()
139148

149+
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
150+
151+
protobuf_deps()
152+
140153
# Needed by @com_github_bazelbuild_remote_apis for the googleapis protos.
141154
http_archive(
142155
name = "googleapis",
@@ -320,10 +333,10 @@ esbuild_register_toolchains(
320333
# See https://github.com/bazelbuild/rules_pkg/tree/main/pkg.
321334
http_archive(
322335
name = "rules_pkg",
323-
sha256 = "038f1caa773a7e35b3663865ffb003169c6a71dc995e39bf4815792f385d837d",
336+
sha256 = "8a298e832762eda1830597d64fe7db58178aa84cd5926d76d5b744d6558941c2",
324337
urls = [
325-
"https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.4.0/rules_pkg-0.4.0.tar.gz",
326-
"https://github.com/bazelbuild/rules_pkg/releases/download/0.4.0/rules_pkg-0.4.0.tar.gz",
338+
"https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.7.0/rules_pkg-0.7.0.tar.gz",
339+
"https://github.com/bazelbuild/rules_pkg/releases/download/0.7.0/rules_pkg-0.7.0.tar.gz",
327340
],
328341
)
329342

attest/go/attest/BUILD.bazel

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
2-
load("//bazel/go:go_test.bzl", "go_test")
32

43
go_library(
54
name = "attest_lib",
65
srcs = ["main.go"],
76
importpath = "go.skia.org/infra/attest/go/attest",
87
visibility = ["//visibility:private"],
98
deps = [
9+
"//attest/go/attestation",
10+
"//attest/go/types",
1011
"//go/common",
11-
"//go/gcloud/binaryauthorization",
1212
"//go/httputils",
13-
"//go/skerr",
1413
"//go/sklog",
15-
"@org_golang_x_oauth2//google",
1614
],
1715
)
1816

@@ -21,10 +19,3 @@ go_binary(
2119
embed = [":attest_lib"],
2220
visibility = ["//visibility:public"],
2321
)
24-
25-
go_test(
26-
name = "attest_test",
27-
srcs = ["main_test.go"],
28-
embed = [":attest_lib"],
29-
deps = ["@com_github_stretchr_testify//require"],
30-
)

attest/go/attest/main.go

Lines changed: 10 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,102 +3,44 @@ package main
33
import (
44
"context"
55
"flag"
6-
"fmt"
76
"net/http"
8-
"regexp"
9-
"strings"
107

8+
"go.skia.org/infra/attest/go/attestation"
9+
"go.skia.org/infra/attest/go/types"
1110
"go.skia.org/infra/go/common"
12-
"go.skia.org/infra/go/gcloud/binaryauthorization"
1311
"go.skia.org/infra/go/httputils"
14-
"go.skia.org/infra/go/skerr"
1512
"go.skia.org/infra/go/sklog"
16-
"golang.org/x/oauth2/google"
1713
)
1814

1915
var (
2016
// Flags.
21-
attestorProject = flag.String("attestor_project", "", "ID of the project containing the attestor")
22-
attestor = flag.String("attestor", "", "ID of the attestor")
23-
host = flag.String("host", "localhost", "HTTP service host")
24-
port = flag.String("port", ":8000", "HTTP service port (e.g., ':8000')")
25-
promPort = flag.String("prom_port", ":20000", "Metrics service address (e.g., ':10110')")
26-
local = flag.Bool("local", false, "Running locally if true. As opposed to in production.")
27-
28-
// Global Binary Authorization API client.
29-
binauthClient binaryauthorization.Client
17+
attestor = flag.String("attestor", "", "Fully-qualified resource name of the attestor (e.g., 'projects/my-project/attestors/my-attestor')")
18+
host = flag.String("host", "localhost", "HTTP service host")
19+
port = flag.String("port", ":8000", "HTTP service port (e.g., ':8000')")
20+
promPort = flag.String("prom_port", ":20000", "Metrics service address (e.g., ':10110')")
21+
local = flag.Bool("local", false, "Running locally if true. As opposed to in production.")
3022
)
3123

32-
func checkAttestation(ctx context.Context, attestorProject, attestor, imageID string) (bool, error) {
33-
split := strings.Split(imageID, "@sha256:")
34-
if len(split) != 2 {
35-
return false, skerr.Fmt("incorrect image format")
36-
}
37-
attestations, err := binauthClient.ListAttestations(ctx, attestorProject, attestor, split[1])
38-
if err != nil {
39-
return false, skerr.Wrap(err)
40-
}
41-
return len(attestations) > 0, nil
42-
}
43-
44-
var validImageRegex = regexp.MustCompile(`[0-9A-Za-z_.]+\/[0-9A-Za-z_-]+\/[0-9A-Za-z_-]+@sha256:[0-9a-f]{64}`)
45-
46-
func handler(w http.ResponseWriter, r *http.Request) {
47-
values := r.URL.Query()["image"]
48-
if len(values) != 1 {
49-
http.Error(w, "expected a single value for `image`", http.StatusBadRequest)
50-
return
51-
}
52-
imageID := values[0]
53-
if !validImageRegex.MatchString(imageID) {
54-
http.Error(w, "expected image of the form gcr.io/project/repository@sha256:digest", http.StatusBadRequest)
55-
return
56-
}
57-
hasAttestation, err := checkAttestation(r.Context(), *attestorProject, *attestor, imageID)
58-
if err != nil {
59-
sklog.Errorf("Failed checking attestation of %s: %s", imageID, err)
60-
http.Error(w, "internal server error", http.StatusInternalServerError)
61-
return
62-
}
63-
if !hasAttestation {
64-
// TODO(borenet): We could consider using a different status code here,
65-
// for example 200 (or possibly 204 No Content) but still return
66-
// "no attestation found", to differentiate from a typical 404.
67-
http.Error(w, "no attestation found", http.StatusNotFound)
68-
return
69-
}
70-
_, _ = fmt.Fprintln(w, "found valid attestation")
71-
}
72-
7324
func main() {
7425
common.InitWithMust(
7526
"attest",
7627
common.PrometheusOpt(promPort),
7728
)
7829
defer common.Defer()
7930

80-
if *attestorProject == "" {
81-
sklog.Fatal("--attestor_project is required.")
82-
}
83-
84-
if *attestor == "" {
85-
sklog.Fatal("--attestor is required.")
86-
}
87-
8831
serverURL := "https://" + *host
8932
if *local {
9033
serverURL = "http://" + *host + *port
9134
}
9235

9336
ctx := context.Background()
94-
ts, err := google.DefaultTokenSource(ctx, binaryauthorization.Scope)
37+
client, err := attestation.NewClient(ctx, *attestor)
9538
if err != nil {
9639
sklog.Fatal(err)
9740
}
98-
httpClient := httputils.DefaultClientConfig().WithTokenSource(ts).With2xxAnd3xx().Client()
99-
binauthClient = (*binaryauthorization.ApiClient)(httpClient)
41+
server := types.NewServer(client)
10042

101-
h := httputils.LoggingRequestResponse(http.HandlerFunc(handler))
43+
h := httputils.LoggingRequestResponse(server)
10244
h = httputils.XFrameOptionsDeny(h)
10345
if !*local {
10446
h = httputils.HealthzAndHTTPS(h)

attest/go/attest/main_test.go

Lines changed: 0 additions & 15 deletions
This file was deleted.

attest/go/attestation/BUILD.bazel

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library")
2+
3+
go_library(
4+
name = "attestation",
5+
srcs = ["attestation.go"],
6+
importpath = "go.skia.org/infra/attest/go/attestation",
7+
visibility = ["//visibility:public"],
8+
deps = [
9+
"//attest/go/types",
10+
"//go/skerr",
11+
"//go/sklog",
12+
"//go/util",
13+
"@com_google_cloud_go_binaryauthorization//apiv1",
14+
"@com_google_cloud_go_binaryauthorization//apiv1/binaryauthorizationpb",
15+
"@com_google_cloud_go_containeranalysis//apiv1beta1",
16+
"@com_google_cloud_go_containeranalysis//apiv1beta1/grafeas/grafeaspb",
17+
"@org_golang_google_api//iterator",
18+
"@org_golang_google_api//option",
19+
"@org_golang_google_genproto//googleapis/grafeas/v1:grafeas",
20+
"@org_golang_x_oauth2//google",
21+
],
22+
)

0 commit comments

Comments
 (0)