From 51895c1da47b9c8031dba1ac4a1740a507e5609a Mon Sep 17 00:00:00 2001 From: Ruide Zhang Date: Tue, 27 Feb 2024 01:44:58 +0000 Subject: [PATCH] add cloud logging --- cmd/flags.go | 16 ++++++++-- cmd/token.go | 33 +++++++++++++++++++-- cmd/token_test.go | 2 +- go.work.sum | 2 ++ launcher/agent/agent.go | 10 ++++++- launcher/agent/agent_test.go | 2 +- launcher/container_runner.go | 2 +- launcher/verifier/rest/rest_network_test.go | 2 +- 8 files changed, 59 insertions(+), 10 deletions(-) diff --git a/cmd/flags.go b/cmd/flags.go index 1bd4ad9ac..24664fb8d 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -23,6 +23,7 @@ var ( pcrs []int format string asAddress string + audience string ) type pcrsFlag struct { @@ -126,8 +127,19 @@ func addInputFlag(cmd *cobra.Command) { // Lets this command specify an Attestation Server Address. func addAsAddressFlag(cmd *cobra.Command) { - cmd.PersistentFlags().StringVar(&asAddress, "asAddr", "https://confidentialcomputing.googleapis.com", - "Attestation Service address") + cmd.PersistentFlags().StringVar(&asAddress, "verifier-endpoint", "https://confidentialcomputing.googleapis.com", + "the attestation verifier endpoint used to retrieve an attestation claims token") +} + +// Lets this command enable Cloud logging +func addCloudLoggingFlag(cmd *cobra.Command) { + cmd.Flags().Bool("cloud-log", false, "cloud logging switch") +} + +// Lets this command specify custom audience field of the attestation token +func addAudienceFlag(cmd *cobra.Command) { + cmd.PersistentFlags().StringVar(&audience, "audience", "Access and Audit", + "the audience field in the claims token") } // Lets this command specify an NVDATA index, for use with nvIndex. diff --git a/cmd/token.go b/cmd/token.go index 97e0fce2f..459fa63a1 100644 --- a/cmd/token.go +++ b/cmd/token.go @@ -10,6 +10,7 @@ import ( "time" "cloud.google.com/go/compute/metadata" + "cloud.google.com/go/logging" "github.com/containerd/containerd/namespaces" "github.com/golang-jwt/jwt/v4" "github.com/google/go-tpm-tools/client" @@ -24,6 +25,10 @@ import ( ) var mdsClient *metadata.Client +var cloudLogClient *logging.Client +var cloudLogger *logging.Logger + +const toolName = "gotpm" // If hardware technology needs a variable length teenonce then please modify the flags description var tokenCmd = &cobra.Command{ @@ -34,7 +39,7 @@ The OIDC token includes claims regarding the GCE VM, which is verified by Attest --algo flag overrides the public key algorithm for the GCE TPM attestation key. If not provided then by default rsa is used. `, Args: cobra.NoArgs, - RunE: func(*cobra.Command, []string) error { + RunE: func(cmd *cobra.Command, _ []string) error { rwc, err := openTpm() if err != nil { return err @@ -101,11 +106,21 @@ The OIDC token includes claims regarding the GCE VM, which is verified by Attest } gceAK.Close() + cloudLogEnabled, _ := cmd.Flags().GetBool("cloud-log") + if cloudLogEnabled { + cloudLogClient, err = logging.NewClient(ctx, projectID) + if err != nil { + return fmt.Errorf("failed to create Cloud Logging client: %w", err) + } + cloudLogger = cloudLogClient.Logger(toolName) + fmt.Fprintf(debugOutput(), "cloudLogger created for project: "+projectID+"\n") + } + key = "gceAK" - attestAgent := agent.CreateAttestationAgent(rwc, attestationKeys[key][keyAlgo], verifierClient, principalFetcher, nil, spec.LaunchSpec{}, nil) + attestAgent := agent.CreateAttestationAgent(rwc, attestationKeys[key][keyAlgo], verifierClient, principalFetcher, nil, spec.LaunchSpec{}, nil, cloudLogger) fmt.Fprintf(debugOutput(), "Fetching attestation verifier OIDC token\n") - token, err := attestAgent.Attest(ctx, agent.AttestAgentOpts{}) + token, err := attestAgent.Attest(ctx, agent.AttestAgentOpts{Aud: audience, TokenType: "OIDC"}) if err != nil { return fmt.Errorf("failed to retrieve attestation service token: %v", err) } @@ -142,7 +157,17 @@ The OIDC token includes claims regarding the GCE VM, which is verified by Attest } } + if cloudLogEnabled { + cloudLogger.Log(logging.Entry{Payload: map[string]string{"token": string(token)}}) + cloudLogger.Log(logging.Entry{Payload: mapClaims}) + cloudLogClient.Close() + if err != nil { + return fmt.Errorf("failed to close cloud logging client: %w", err) + } + } + fmt.Fprintf(debugOutput(), string(claimsString)+"\n"+"Note: these Claims are for debugging purpose and not verified"+"\n") + return nil }, } @@ -186,6 +211,8 @@ func init() { addOutputFlag(tokenCmd) addPublicKeyAlgoFlag(tokenCmd) addAsAddressFlag(tokenCmd) + addCloudLoggingFlag(tokenCmd) + addAudienceFlag(tokenCmd) // TODO: Add TEE hardware OIDC token generation // addTeeNonceflag(tokenCmd) // addTeeTechnology(tokenCmd) diff --git a/cmd/token_test.go b/cmd/token_test.go index 80d64256d..8247dc66a 100644 --- a/cmd/token_test.go +++ b/cmd/token_test.go @@ -72,7 +72,7 @@ func TestTokenWithGCEAK(t *testing.T) { } defer mockAttestationServer.Stop() - RootCmd.SetArgs([]string{"token", "--algo", op.algo, "--output", secretFile1, "--asAddr", mockAttestationServer.server.URL}) + RootCmd.SetArgs([]string{"token", "--algo", op.algo, "--output", secretFile1, "--verifier-endpoint", mockAttestationServer.server.URL}) if err := RootCmd.Execute(); err != nil { t.Error(err) } diff --git a/go.work.sum b/go.work.sum index 552daeb2c..5edf986cc 100644 --- a/go.work.sum +++ b/go.work.sum @@ -137,8 +137,10 @@ cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA cloud.google.com/go/lifesciences v0.9.2/go.mod h1:QHEOO4tDzcSAzeJg7s2qwnLM2ji8IRpQl4p6m5Z9yTA= cloud.google.com/go/logging v1.4.2 h1:Mu2Q75VBDQlW1HlBMjTX4X84UFR73G1TiLlRYc/b7tA= cloud.google.com/go/logging v1.4.2/go.mod h1:jco9QZSx8HiVVqLJReq7z7bVdj0P1Jb9PDFs63T+axo= +cloud.google.com/go/logging v1.8.1 h1:26skQWPeYhvIasWKm48+Eq7oUqdcdbwsCVwz5Ys0FvU= cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI= cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= +cloud.google.com/go/longrunning v0.5.2 h1:u+oFqfEwwU7F9dIELigxbe0XVnBAo9wqMuQLA50CZ5k= cloud.google.com/go/longrunning v0.5.2/go.mod h1:nqo6DQbNV2pXhGDbDMoN2bWz68MjZUzqv2YttZiveCs= cloud.google.com/go/managedidentities v1.6.2/go.mod h1:5c2VG66eCa0WIq6IylRk3TBW83l161zkFvCj28X7jn8= cloud.google.com/go/maps v1.4.1/go.mod h1:BxSa0BnW1g2U2gNdbq5zikLlHUuHW0GFWh7sgML2kIY= diff --git a/launcher/agent/agent.go b/launcher/agent/agent.go index d2a446067..44651a0d2 100644 --- a/launcher/agent/agent.go +++ b/launcher/agent/agent.go @@ -15,6 +15,7 @@ import ( "net/http" "sync" + "cloud.google.com/go/logging" "github.com/google/go-tpm-tools/cel" "github.com/google/go-tpm-tools/client" "github.com/google/go-tpm-tools/launcher/internal/oci" @@ -55,6 +56,7 @@ type agent struct { cosCel cel.CEL launchSpec spec.LaunchSpec logger *log.Logger + cloudLogger *logging.Logger sigsCache *sigsCache } @@ -65,7 +67,7 @@ type agent struct { // - principalFetcher is a func to fetch GCE principal tokens for a given audience. // - signaturesFetcher is a func to fetch container image signatures associated with the running workload. // - logger will log any partial errors returned by VerifyAttestation. -func CreateAttestationAgent(tpm io.ReadWriteCloser, akFetcher tpmKeyFetcher, verifierClient verifier.Client, principalFetcher principalIDTokenFetcher, sigsFetcher signaturediscovery.Fetcher, launchSpec spec.LaunchSpec, logger *log.Logger) AttestationAgent { +func CreateAttestationAgent(tpm io.ReadWriteCloser, akFetcher tpmKeyFetcher, verifierClient verifier.Client, principalFetcher principalIDTokenFetcher, sigsFetcher signaturediscovery.Fetcher, launchSpec spec.LaunchSpec, logger *log.Logger, cloudLogger *logging.Logger) AttestationAgent { return &agent{ tpm: tpm, client: verifierClient, @@ -74,6 +76,7 @@ func CreateAttestationAgent(tpm io.ReadWriteCloser, akFetcher tpmKeyFetcher, ver sigsFetcher: sigsFetcher, launchSpec: launchSpec, logger: logger, + cloudLogger: cloudLogger, sigsCache: &sigsCache{}, } } @@ -114,6 +117,11 @@ func (a *agent) Attest(ctx context.Context, opts AttestAgentOpts) ([]byte, error }, } + if a.cloudLogger != nil { + a.cloudLogger.Log(logging.Entry{Payload: challenge}) + a.cloudLogger.Log(logging.Entry{Payload: attestation}) + } + var signatures []oci.Signature if a.launchSpec.Experiments.EnableSignedContainerCache { signatures = a.sigsCache.get() diff --git a/launcher/agent/agent_test.go b/launcher/agent/agent_test.go index c27025b71..3280034ca 100644 --- a/launcher/agent/agent_test.go +++ b/launcher/agent/agent_test.go @@ -64,7 +64,7 @@ func TestAttest(t *testing.T) { verifierClient := fake.NewClient(fakeSigner) - agent := CreateAttestationAgent(tpm, client.AttestationKeyECC, verifierClient, tc.principalIDTokenFetcher, tc.containerSignaturesFetcher, tc.launchSpec, log.Default()) + agent := CreateAttestationAgent(tpm, client.AttestationKeyECC, verifierClient, tc.principalIDTokenFetcher, tc.containerSignaturesFetcher, tc.launchSpec, log.Default(), nil) if err := agent.Refresh(ctx); err != nil { t.Errorf("failed to fresh attestation agent: %v", err) diff --git a/launcher/container_runner.go b/launcher/container_runner.go index 024a8484e..56988a0d5 100644 --- a/launcher/container_runner.go +++ b/launcher/container_runner.go @@ -222,7 +222,7 @@ func NewRunner(ctx context.Context, cdClient *containerd.Client, token oauth2.To return &ContainerRunner{ container, launchSpec, - agent.CreateAttestationAgent(tpm, client.GceAttestationKeyECC, verifierClient, principalFetcher, sdClient, launchSpec, logger), + agent.CreateAttestationAgent(tpm, client.GceAttestationKeyECC, verifierClient, principalFetcher, sdClient, launchSpec, logger, nil), logger, serialConsole, }, nil diff --git a/launcher/verifier/rest/rest_network_test.go b/launcher/verifier/rest/rest_network_test.go index 2198ef2a0..e306af499 100644 --- a/launcher/verifier/rest/rest_network_test.go +++ b/launcher/verifier/rest/rest_network_test.go @@ -49,7 +49,7 @@ func TestWithAgent(t *testing.T) { tpm := test.GetTPM(t) defer client.CheckedClose(t, tpm) - a := agent.CreateAttestationAgent(tpm, client.AttestationKeyECC, vClient, testPrincipalIDTokenFetcher, signaturediscovery.NewFakeClient(), spec.LaunchSpec{}, log.Default()) + a := agent.CreateAttestationAgent(tpm, client.AttestationKeyECC, vClient, testPrincipalIDTokenFetcher, signaturediscovery.NewFakeClient(), spec.LaunchSpec{}, log.Default(), nil) token, err := a.Attest(context.Background(), agent.AttestAgentOpts{}) if err != nil { t.Errorf("failed to attest to Attestation Service: %v", err)