-
Notifications
You must be signed in to change notification settings - Fork 4.5k
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
[Security] Add support for SPIFFE Bundle Maps in XDS bundles #8180
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #8180 +/- ##
==========================================
- Coverage 82.42% 82.12% -0.31%
==========================================
Files 393 410 +17
Lines 39162 40371 +1209
==========================================
+ Hits 32280 33154 +874
- Misses 5571 5855 +284
- Partials 1311 1362 +51
🚀 New features to boost your workflow:
|
@@ -96,3 +102,79 @@ func (s) TestFailingProvider(t *testing.T) { | |||
t.Errorf("EmptyCall() got err: %s, want err to contain: %s", err, wantErr) | |||
} | |||
} | |||
|
|||
func (s) TestSPIFFEVerifyFuncMismatchedCert(t *testing.T) { |
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/Should these tests be e2e style as well? That way, we can actually verify that the error returned to the user (as part of the RPC) has enough details in it for the user to take meaningful action.
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.
You mean should we replicate these tests in bundle_ext_test.go and actually do the client/server call rather than just this inner call? We have one failure case test where there is no bundle for the peer certificates trust domain, I can expand and add these cases?
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.
I went on and expanded the end2end tests, PTAL
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.
Mostly LGTM. Just minor comments this time around.
const wantBundleSize = 2 | ||
if len(bundles) != wantBundleSize { | ||
t.Fatalf("LoadSPIFFEBundleMap(%v) did not parse correct bundle length. got %v want %v", spiffeBundleFile, len(bundles), wantBundleSize) | ||
t.Fatalf("BundleMapFromBytes(%v) did not parse correct bundle length. got %v want %v", spiffeBundleFile, len(bundles), wantBundleSize) | ||
} | ||
if bundles["example.com"] == nil { | ||
t.Fatalf("LoadSPIFFEBundleMap(%v) got no bundle for example.com", spiffeBundleFile) | ||
t.Fatalf("BundleMapFromBytes(%v) got no bundle for example.com", spiffeBundleFile) | ||
} | ||
if bundles["test.example.com"] == nil { | ||
t.Fatalf("LoadSPIFFEBundleMap(%v) got no bundle for test.example.com", spiffeBundleFile) | ||
t.Fatalf("BundleMapFromBytes(%v) got no bundle for test.example.com", spiffeBundleFile) | ||
} | ||
|
||
expectedExampleComCert := loadX509Cert(t, testdata.Path("spiffe/spiffe_cert.pem")) | ||
expectedTestExampleComCert := loadX509Cert(t, testdata.Path("spiffe/server1_spiffe.pem")) | ||
if !bundles["example.com"].X509Authorities()[0].Equal(expectedExampleComCert) { | ||
t.Fatalf("LoadSPIFFEBundleMap(%v) parsed wrong cert for example.com.", spiffeBundleFile) | ||
wantExampleComCert := loadX509Cert(t, testdata.Path("spiffe/spiffe_cert.pem")) | ||
wantTestExampleComCert := loadX509Cert(t, testdata.Path("spiffe/server1_spiffe.pem")) | ||
if !bundles["example.com"].X509Authorities()[0].Equal(wantExampleComCert) { | ||
t.Fatalf("BundleMapFromBytes(%v) parsed wrong cert for example.com.", spiffeBundleFile) | ||
} | ||
if !bundles["test.example.com"].X509Authorities()[0].Equal(expectedTestExampleComCert) { | ||
t.Fatalf("LoadSPIFFEBundleMap(%v) parsed wrong cert for test.example.com", spiffeBundleFile) | ||
if !bundles["test.example.com"].X509Authorities()[0].Equal(wantTestExampleComCert) { | ||
t.Fatalf("BundleMapFromBytes(%v) parsed wrong cert for test.example.com", spiffeBundleFile) | ||
} |
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.
Instead of individual comparison of fields, would you be able to construct a single wantBundles
of type map[string]*spiffebundle.Bundle
and directly compare it with the result from BundleMapFromBytes
?
See: go/go-style/decisions#compare-full-structures
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 main way of creating a spiffebundle.Bundle
is loading it from the bytes/file, which is largely what we are wrapping/testing. I could create one manually using the spiffebundle APIs in the test, but I think the readability would suffer significantly.
I could also manually craft more spiffebundle files that are bundles and not a larger bundle map as well, then load those using the spiffebundle
library, but I think that also suffers from more confusion, readability issues, and bloat. In addition, that's more files that would need to be manually created and kept in sync with an update.
I'm happy to make it work if you feel very strongly, but I think this is a case where creating a full known struct to compare to is quite a bit more complex than comparing the fields that we care about. Let me know
CertFile: cfg.CertificateFile, | ||
KeyFile: cfg.PrivateKeyFile, | ||
RootFile: cfg.CACertificateFile, | ||
CertFile: cfg.CertificateFile, |
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.
It would be great if you could file an issue to track this. Otherwise, we will definitely forget about it. Thanks. We could even get someone from BLR to work on it if we have the it described in detail in an issue.
ss := stubserver.StubServer{ | ||
Address: server.Address, | ||
EmptyCallF: func(context.Context, *testpb.Empty) (*testpb.Empty, error) { return &testpb.Empty{}, nil }, | ||
} | ||
server = stubserver.StartTestService(t, &ss, serverCredentials) |
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 restartable listener type provides a Stop
and Restart
method. When Stop
is called, existing connections are closed and new connections are not accepted, and when Restart
is called, new connections are accepted. Therefore, once Restart
is called, we should see another handshake.
This adds support for configuring SPIFFE Bundle Maps inside of credentials via xds bundles.
See the gRFC for more detail grpc/proposal#462
RELEASE NOTES: N/A