-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Signature discovery] Integrate signature discovery client into attestation agent. #343
Conversation
758515c
to
c78c5b1
Compare
c78c5b1
to
777c2c2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, this is the crucial bit of this feature and should go behind an experiment. Please do not submit until we have that functionality.
launcher/container_runner.go
Outdated
if err != nil { | ||
logger.Printf("failed to retrieve auth token: %v, using empty auth for image pulling\n", err) | ||
} | ||
updatedSpec, err := spec.GetLaunchSpec(mdsClient) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need to update the spec? The launcher should only ever get the spec at startup. Refetching it can lead to weird states and potential security issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rational behind updating the spec is to enable operators don't have to restart VM when new docker repos added. Even though ADMC team is ok with restarting VM when new repos added, I feel it might be nice to have this feature. But if refetching it will lead to any potential security issues, we should definitely avoid that.
launcher/container_runner.go
Outdated
@@ -236,14 +266,38 @@ func NewRunner(ctx context.Context, cdClient *containerd.Client, token oauth2.To | |||
return nil, fmt.Errorf("failed to create REST verifier client: %v", err) | |||
} | |||
|
|||
// Fetch container image signatures by using signaturediscovery client. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you don't update the spec, this func should be unnecessary. Which is good because this is tough to follow.
launcher/container_runner.go
Outdated
@@ -79,6 +82,33 @@ const ( | |||
defaultRefreshJitter = 0.1 | |||
) | |||
|
|||
func fetchContainerImageSignatures(ctx context.Context, sdClient *signaturediscovery.Client, targetRepos []string, logger *log.Logger) []internal.Signature { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not required, but it would be nice to be able to cache signatures so we don't have to fetch every time. This complicates things, so maybe add a TODO with an issue.
e3d6b05
to
d806aa7
Compare
Agree, this PR should also go behind this PR for updating v1 SDK #305 |
cc98bcd
to
62d378c
Compare
1652b48
to
042dc40
Compare
Now since V1 SDK has been merged into master, this PR is now ready for review again with client experimental flag integration. |
launcher/container_runner_test.go
Outdated
@@ -414,6 +417,71 @@ type idTokenResp struct { | |||
Token string `json:"token"` | |||
} | |||
|
|||
func TestFetchContainerImageSignatures(t *testing.T) { | |||
ctx := namespaces.WithNamespace(context.Background(), "test") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should consider using something like https://pkg.go.dev/github.com/docker/docker/testutil/registry#V2 or the mock https://pkg.go.dev/github.com/docker/docker/testutil/registry#Mock instead of actually making a network call in our unit tests
launcher/container_runner_test.go
Outdated
}, | ||
}, | ||
{ | ||
name: "fetchContainerImageSignatures success with nil target repos", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a case for a nonexistent repo and one that exists but doesn't have signatures?
launcher/container_runner.go
Outdated
@@ -230,15 +259,29 @@ func NewRunner(ctx context.Context, cdClient *containerd.Client, token oauth2.To | |||
return nil, fmt.Errorf("failed to create REST verifier client: %v", err) | |||
} | |||
|
|||
// Fetch container image signatures with specific repositories. | |||
containerSignaturesFetcher := func(targetRepos []string) []internal.Signature { | |||
sdClient := getSignatureDiscoveryClient(cdClient, token, image.Target()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we getting a new signaturediscovery Client every time we call agent.Attest? Can we make this a closure to avoid this? Alternatively, we can pass the signature discovery client in the agent and use a fake for testing.
launcher/agent/agent.go
Outdated
if a.launchSpec.Experiments.EnableSignedContainerImage { | ||
signatures := a.sigsFetcher(a.launchSpec.SignedImageRepos) | ||
if len(signatures) > 0 { | ||
req.ContainerImageSignatures = signatures | ||
a.logger.Printf("Found container image signatures: %v\n", signatures) | ||
} | ||
} | ||
|
||
resp, err := a.client.VerifyAttestation(ctx, req) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add unit test coverage here? The fake verifier client should expect to see signatures.
2fcfaef
to
d6519ea
Compare
launcher/agent/agent_test.go
Outdated
t.Run(tc.name, func(t *testing.T) { | ||
sdClient := signaturediscovery.NewFakeClient() | ||
gotSigs := fetchContainerImageSignatures(ctx, sdClient, tc.targetRepos, log.Default()) | ||
if len(gotSigs) != tc.wantLen { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: For these test cases: why not len(gotSigs) != len(tc.WantBase64Sigs)
? The only reason I can think of to have wantLen is in case we have a partial error. Which, if you can add a test case for, would be great to have! (e.g., add a repo with all invalid signatures and one with partial invalid signatures and have the fake verifier handle that).
d6519ea
to
8c1388c
Compare
8c1388c
to
634e79c
Compare
New Features: [launcher] Add experiment support google#352 [launcher] Integrate signature discovery client into attestation agent google#343 Bug Fixes: Make launcher host tmp directory before experiment fetch google#363 Other Changes: [launcher] Print kernel cmdline on builds google#268 Import latest version of go-tdx-guest google#373 [launcher] Print signature details instead of signature object google#374 [launcher] Add image tests for the experiments binary google#378 Update go-sev-guest to v0.9.3 google#381
New Features: [launcher] Add experiment support #352 [launcher] Integrate signature discovery client into attestation agent #343 Bug Fixes: Make launcher host tmp directory before experiment fetch #363 Other Changes: [launcher] Print kernel cmdline on builds #268 Import latest version of go-tdx-guest #373 [launcher] Print signature details instead of signature object #374 [launcher] Add image tests for the experiments binary #378 Update go-sev-guest to v0.9.3 #381
This PR includes the following changes:
containerImageSignaturesFetcher
to the attestation agent such that the agent can fetch any new container image signatures on refreshToken.container_runner
.