-
Notifications
You must be signed in to change notification settings - Fork 485
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
Introduce the aws_s3
BundlePublisher plugin
#4355
Introduce the aws_s3
BundlePublisher plugin
#4355
Conversation
Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
# # object_key: The object key inside the bucket. Default: "". | ||
# # object_key = "example.org" | ||
|
||
# # format: Format in which the trust bundle is stored, <spiffe | jwks | pem>. Default: "". |
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.
What format is defaulted to when unset?
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 plugin requires that a format is explicitly configured, so there is not a default format set.
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.
Do you think a default would make sense here, pem
for instance since it's the most well understood format?
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 we have a default, I would probably suggest to be the spiffe
format. PEM does not allow the encoding of JWT authorities, which may be needed. Also, agents can be configured to use spiffe
format for the initial SPIRE Server trust bundle.
The idea behind requiring a value here is to avoid the inadvertently misconfiguration of the plugin, but we can revisit that decision.
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 idea behind requiring a value here is to avoid the inadvertently misconfiguration of the plugin
No, that's ok. I think this convinced me to be honest.
config *Config | ||
configMtx sync.RWMutex |
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.
Please excuse my ignorance, but how is the config updated dynamically in a way that would require a RWLock
?
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 configuration can be updated at any time by a different thread if the Configure function is called.
Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
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.
thanks Agustin!! this looks great!
# BundlePublisher "aws_s3" { | ||
# plugin_data { | ||
# # region: AWS region to store the trust bundle. Default: "". | ||
# # region = "us-east-1" |
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.
in another examples we have region empty
| region | AWS region to store the trust bundle. | | | ||
| bucket | The Amazon S3 bucket name to which the trust bundle is uploaded. | | | ||
| object_key | The object key inside the bucket. | | | ||
| format | Format in which the trust bundle is stored, <spiffe | jwks | pem>. See [Supported bundle formats](#supported-bundle-formats) for more details. | | |
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.
may we add a (required) here?
log hclog.Logger | ||
} | ||
|
||
func (p *Plugin) SetLogger(log hclog.Logger) { |
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: since another public functions has a comment, can you add a comment here too?
return &configv1.ConfigureResponse{}, nil | ||
} | ||
|
||
// PublishBundle puts the bundle in the specified S3 bucket and key. |
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.
what is that and key
? may we reword this to make sure readers understand that the key is for the published bucket object?
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 key
refers to the object key of the configured bucket name. I'll update the comment.
currentBundle := p.getBundle() | ||
if proto.Equal(req.Bundle, currentBundle) { | ||
// Bundle not changed. No need to publish. | ||
return &bundlepublisherv1.PublishBundleResponse{}, nil |
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.
is it possible that the bundle does not changed, but someone changed the format? (we are not reloading configs yet
but maybe in a future)
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.
That's an interesting scenario, good catch. I'll clean the current bundle when Configure() is called, to make sure that the content is refreshed.
func parseAndValidateConfig(c string) (*Config, error) { | ||
config := new(Config) | ||
|
||
if err := hcl.Decode(config, c); err != nil { |
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.
is not region a required field?
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.
Yes! Thanks, I'll add that check.
if tt.config != nil { | ||
plugintest.Load(t, builtin(p), nil, options...) | ||
require.NoError(t, err) | ||
p.s3Client.(*fakeClient).expectBucket = aws.String(tt.config.Bucket) |
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.
may we use newClient
directly?
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.
newClient
is a function. I'll reduce the type assertions and check that succeeded.
} | ||
|
||
func testMultiplePuts(t *testing.T, p *Plugin) { | ||
// Test multiple put operations, and check that onlt a call to PutObject is |
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.
// Test multiple put operations, and check that onlt a call to PutObject is | |
// Test multiple put operations, and check that onlt a call to PutObject is |
// Test multiple put operations, and check that onlt a call to PutObject is | |
// Test multiple put operations, and check that only a call to PutObject is |
require.NotNil(t, resp) | ||
|
||
if tt.testMultiplePuts { | ||
testMultiplePuts(t, p) |
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 looks to me, like a good option to have another unit test, not a test case inside this functions
|
||
func getTestBundle(t *testing.T) *types.Bundle { | ||
const ( | ||
certPEM = `-----BEGIN CERTIFICATE----- |
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: may we use test fixture here?
Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
{ | ||
name: "multiple times", | ||
bundle: testBundle, | ||
config: &Config{ | ||
AccessKeyID: "access-key-id", | ||
SecretAccessKey: "secret-access-key", | ||
Region: "region", | ||
Bucket: "bucket", | ||
ObjectKey: "object-key", | ||
Format: "spiffe", | ||
}, | ||
testMultiplePuts: true, | ||
}, |
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.
looks like this test case must be removed? since testMutiplePuts is never used
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.
Forgot to remove it, thanks!
return &s3.PutObjectOutput{}, nil | ||
} | ||
|
||
func TestPublishMultiple(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 you move this test before fakeClient declaration?
if err != nil { | ||
return nil, status.Errorf(codes.Internal, "failed to create client configuration: %v", err) | ||
} | ||
s3Client, err := p.hooks.newS3ClientFunc(awsCfg) |
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.
looks like env variables are never readed? can you add a test case to validate that we are able to use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESSKEY ?
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 have pretty much the same situation in all the plugins where we rely on the AWS SDK to use the creds from the env vars if they are available, so it looks like this would be a test of the AWS SDK itself rather than a test of this plugin.
Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
|
||
// Configure configures the plugin. | ||
func (p *Plugin) Configure(ctx context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { | ||
if req == nil { |
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: this check isn't practical since a nil request here would imply the gRPC library is broken
return nil, err | ||
} | ||
|
||
if req == nil { |
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: same thing here. gRPC will always pass a request.
return &bundlepublisherv1.PublishBundleResponse{}, nil | ||
} | ||
|
||
bundle := bundleformat.NewFormatter(req.Bundle) |
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:
bundle := bundleformat.NewFormatter(req.Bundle) | |
formatter := bundleformat.NewFormatter(req.Bundle) |
if err != nil { | ||
return nil, status.Errorf(codes.InvalidArgument, "could not parse bundle format from configuration: %v", err) | ||
} | ||
// The bundleformat package may support formats that this plugin do not |
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 bundleformat package may support formats that this plugin do not | |
// The bundleformat package may support formats that this plugin does not |
Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
Thank you for doing this, we were looking at implemented this plugin as well. |
Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
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.
LGTM!
This PR introduces the
aws_s3
BundlePublisher plugin, that puts the current trust bundle of the server in a designatedAmazon S3 bucket, keeping it updated.