Skip to content

Commit f2b7b10

Browse files
authored
Update ContainerRunner to use REST verifier (#219)
We update the LauncherSpec to store the projectID and region. The ContainerRunner will now be able to use the REST-based verifier.Client, based on the addr flag. The flag will determine whether the endpoint is the gRPC or REST verifier. The REST verifier is used if the flag is empty or contains "http", otherwise the gRPC verifier is used.
1 parent 62ff36a commit f2b7b10

File tree

2 files changed

+78
-15
lines changed

2 files changed

+78
-15
lines changed

launcher/container_runner.go

+55-9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"net/url"
1111
"os"
1212
"path"
13+
"strings"
1314
"time"
1415

1516
"cloud.google.com/go/compute/metadata"
@@ -23,10 +24,13 @@ import (
2324
"github.com/google/go-tpm-tools/client"
2425
"github.com/google/go-tpm-tools/launcher/agent"
2526
"github.com/google/go-tpm-tools/launcher/spec"
27+
"github.com/google/go-tpm-tools/launcher/verifier"
2628
"github.com/google/go-tpm-tools/launcher/verifier/grpcclient"
29+
"github.com/google/go-tpm-tools/launcher/verifier/rest"
2730
v1 "github.com/opencontainers/image-spec/specs-go/v1"
2831
specs "github.com/opencontainers/runtime-spec/specs-go"
2932
"golang.org/x/oauth2"
33+
"golang.org/x/oauth2/google"
3034
"google.golang.org/api/impersonate"
3135
"google.golang.org/api/option"
3236
"google.golang.org/grpc"
@@ -161,14 +165,6 @@ func NewRunner(ctx context.Context, cdClient *containerd.Client, token oauth2.To
161165
return nil, fmt.Errorf("length of Args [%d] is shorter or equal to the length of the given Cmd [%d], maybe the Entrypoint is set to empty in the image?", len(containerSpec.Process.Args), len(launchSpec.Cmd))
162166
}
163167

164-
// TODO(b/212586174): Dial with secure credentials.
165-
opt := grpc.WithTransportCredentials(insecure.NewCredentials())
166-
conn, err := grpc.Dial(launchSpec.AttestationServiceAddr, opt)
167-
if err != nil {
168-
return nil, fmt.Errorf("failed to open connection to attestation service: %v", err)
169-
}
170-
verifierClient := grpcclient.NewClient(conn, logger)
171-
172168
// Fetch ID token with specific audience.
173169
// See https://cloud.google.com/functions/docs/securing/authenticating#functions-bearer-token-example-go.
174170
principalFetcher := func(audience string) ([][]byte, error) {
@@ -198,6 +194,21 @@ func NewRunner(ctx context.Context, cdClient *containerd.Client, token oauth2.To
198194
return tokens, nil
199195
}
200196

197+
asAddr := launchSpec.AttestationServiceAddr
198+
var verifierClient verifier.Client
199+
var conn *grpc.ClientConn
200+
// Temporary support for both gRPC and REST-based attestation verifier.
201+
// Use REST when empty flag or the presence of http in the addr, else gRPC.
202+
// TODO: remove once fully migrated to the REST-based verifier.
203+
if asAddr == "" || strings.Contains(asAddr, "http") {
204+
verifierClient, err = getRESTClient(ctx, asAddr, launchSpec)
205+
} else {
206+
verifierClient, conn, err = getGRPCClient(asAddr, logger)
207+
}
208+
if err != nil {
209+
return nil, fmt.Errorf("failed to create verifier client: %v", err)
210+
}
211+
201212
return &ContainerRunner{
202213
container,
203214
launchSpec,
@@ -207,6 +218,39 @@ func NewRunner(ctx context.Context, cdClient *containerd.Client, token oauth2.To
207218
}, nil
208219
}
209220

221+
// getGRPCClient returns a gRPC verifier.Client pointing to the given address.
222+
// It also returns a grpc.ClientConn for closing out the connection.
223+
func getGRPCClient(asAddr string, logger *log.Logger) (verifier.Client, *grpc.ClientConn, error) {
224+
opt := grpc.WithTransportCredentials(insecure.NewCredentials())
225+
conn, err := grpc.Dial(asAddr, opt)
226+
if err != nil {
227+
return nil, nil, fmt.Errorf("failed to open connection to gRPC attestation service: %v", err)
228+
}
229+
return grpcclient.NewClient(conn, logger), conn, nil
230+
}
231+
232+
// getRESTClient returns a REST verifier.Client that points to the given address.
233+
// It defaults to the Attestation Verifier instance at
234+
// https://confidentialcomputing.googleapis.com.
235+
func getRESTClient(ctx context.Context, asAddr string, spec spec.LauncherSpec) (verifier.Client, error) {
236+
httpClient, err := google.DefaultClient(ctx)
237+
if err != nil {
238+
return nil, fmt.Errorf("failed to create HTTP client: %v", err)
239+
}
240+
241+
opts := []option.ClientOption{option.WithHTTPClient(httpClient)}
242+
if asAddr != "" {
243+
opts = append(opts, option.WithEndpoint(asAddr))
244+
}
245+
246+
const defaultRegion = "us-central1"
247+
restClient, err := rest.NewClient(ctx, spec.ProjectID, defaultRegion, opts...)
248+
if err != nil {
249+
return nil, err
250+
}
251+
return restClient, nil
252+
}
253+
210254
// parseEnvVars parses the environment variables to the oci format
211255
func parseEnvVars(envVars []spec.EnvVar) []string {
212256
var result []string
@@ -433,5 +477,7 @@ func (r *ContainerRunner) Close(ctx context.Context) {
433477
// Exit gracefully:
434478
// Delete container and close connection to attestation service.
435479
r.container.Delete(ctx, containerd.WithSnapshotCleanup)
436-
r.attestConn.Close()
480+
if r.attestConn != nil {
481+
r.attestConn.Close()
482+
}
437483
}

launcher/spec/launcher_spec.go

+23-6
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@ const (
2828
Never RestartPolicy = "Never"
2929
)
3030

31-
const (
32-
defaultAttestationServiceEndpoint = "attestation-verifier.confidential-computing-test-org.joonix.net:9090"
33-
)
34-
3531
const (
3632
imageRefKey = "tee-image-reference"
3733
restartPolicyKey = "tee-restart-policy"
@@ -56,12 +52,15 @@ type EnvVar struct {
5652
// LauncherSpec contains specification set by the operator who wants to
5753
// launch a container.
5854
type LauncherSpec struct {
55+
// MDS-based values.
5956
ImageRef string
6057
RestartPolicy RestartPolicy
6158
Cmd []string
6259
Envs []EnvVar
6360
AttestationServiceAddr string
6461
ImpersonateServiceAccounts []string
62+
ProjectID string
63+
Region string
6564
}
6665

6766
// UnmarshalJSON unmarshals an instance attributes list in JSON format from the metadata
@@ -110,6 +109,18 @@ func (s *LauncherSpec) UnmarshalJSON(b []byte) error {
110109
return nil
111110
}
112111

112+
func getRegion(client *metadata.Client) (string, error) {
113+
zone, err := client.Zone()
114+
if err != nil {
115+
return "", fmt.Errorf("failed to retrieve zone from MDS: %v", err)
116+
}
117+
lastDash := strings.LastIndex(zone, "-")
118+
if lastDash == -1 {
119+
return "", fmt.Errorf("got malformed zone from MDS: %v", zone)
120+
}
121+
return zone[:lastDash], nil
122+
}
123+
113124
// GetLauncherSpec takes in a metadata server client, reads and parse operator's
114125
// input to the GCE instance custom metadata and return a LauncherSpec.
115126
// ImageRef (tee-image-reference) is required, will return an error if
@@ -125,8 +136,14 @@ func GetLauncherSpec(client *metadata.Client) (LauncherSpec, error) {
125136
return LauncherSpec{}, err
126137
}
127138

128-
if spec.AttestationServiceAddr == "" {
129-
spec.AttestationServiceAddr = defaultAttestationServiceEndpoint
139+
spec.ProjectID, err = client.ProjectID()
140+
if err != nil {
141+
return LauncherSpec{}, fmt.Errorf("failed to retrieve projectID from MDS: %v", err)
142+
}
143+
144+
spec.Region, err = getRegion(client)
145+
if err != nil {
146+
return LauncherSpec{}, err
130147
}
131148

132149
return *spec, nil

0 commit comments

Comments
 (0)