-
Notifications
You must be signed in to change notification settings - Fork 49
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
fix: add customization for models missing SIGV4A trait #1171
Conversation
A new generated diff is ready to view. |
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.
Correctness: Let's add an E2E test for this as well.
.apply { | ||
symbol = KotlinTypes.Collections.list(RuntimeTypes.Auth.HttpAuth.AuthScheme, default = "listOf(${RuntimeTypes.Auth.HttpAuthAws.SigV4AsymmetricAuthScheme}(${RuntimeTypes.Auth.Signing.AwsSigningStandard.DefaultAwsSigner}))") | ||
} |
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.
Style: This type of default specification doesn't use imports and instead pastes large, fully-qualified names into the codegen output. Instead, we can use additionalImports
to make the resulting generated code cleaner:
val AuthSchemes = RuntimeConfigProperty
.AuthSchemes
.toBuilder()
.apply {
propertyType = ConfigPropertyType.RequiredWithDefault("SigV4AsymmetricAuthScheme(DefaultAwsSigner)")
additionalImports = listOf(
RuntimeTypes.Auth.HttpAuthAws.SigV4AsymmetricAuthScheme,
RuntimeTypes.Auth.Signing.AwsSigningStandard.DefaultAwsSigner,
)
}
val AuthSchemes = RuntimeConfigProperty | ||
.AuthSchemes | ||
.toBuilder() | ||
.apply { | ||
symbol = KotlinTypes.Collections.list(RuntimeTypes.Auth.HttpAuth.AuthScheme, default = "listOf(${RuntimeTypes.Auth.HttpAuthAws.SigV4AsymmetricAuthScheme}(${RuntimeTypes.Auth.Signing.AwsSigningStandard.DefaultAwsSigner}))") | ||
} | ||
.build() | ||
} |
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.
Question: I'm a little confused about this addition. Won't users still have to replace the auth scheme with one that uses the CRT signer in order for MRAP to work?
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.
Hmm, yes. I'm guessing we could avoid users having any additional configuration to use MRAP's by setting the CRT signer as the default for S3. Are there any implications/side effects we would need to worry about when doing that?
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 reason for setting the default auth scheme to SIGV4A is because the requests were silently falling back to SIGV4 and would succeed sometimes.
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.
So users would get the impression that everything is configured properly when that's not the case
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.
CRT signer as the default for S3. Are there any implications/side effects we would need to worry about when doing that?
Yes, we can't use CRT by default.
Won't users still have to replace the auth scheme with one that uses the CRT signer in order for MRAP to work?
Yes, when testing this though what happens is sigv4 is registered in the model and sigv4a comes from the endpoint rule properties. So we get a prioritized list of auth options [sigv4a, sigv]
after merging those. During selection we see that sigv4a isn't supported/configured and so don't consider it as an option and end up selecting sigv4. This actually works when the access point points to a bucket in the same region that you are configured to sign for. This means users would think sigv4a is working but it's not and in a failover scenario their requests would fail as they wouldn't be valid for a different region. I figured it was better to register support for sigv4a with the default signer and just fail loudly instead with an exception that the signer doesn't support that auth scheme.
documentation = """ | ||
Flag to disable [S3 multi-region access points](https://docs.aws.amazon.com/AmazonS3/latest/userguide/MultiRegionAccessPoints.html). | ||
""".trimIndent() | ||
} | ||
|
||
val AuthSchemes = RuntimeConfigProperty |
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.
fix:
This isn't the right approach. We want to register sigv4a support as a configured auth scheme but it doesn't belong in this list, these are user provided. We just want to register support for sigv4a as an entirely new auth scheme handler in smithy-kotlin
(e.g. here is the sigv4 auth scheme handler).
There are some thorny questions to answer about where we should register this since the current SigV4AuthSchemeIntegration is handling a bit of both right now and there is some overlap (e.g. sigv4a re-uses the same config property credentialsProvider
). Thats probably ok though since they resolve to the same types. My vote would be to create a new Sigv4AsymmetricAuthSchemeIntegration
and migrate sigv4a support/logic there.
We will also need to update the AuthIndex to also consider endpoint rules since s3 and eventbridge don't model sigv4a usage, they are considered only from endpoint rule properties. Effectively if the sigv4a scheme name shows up in any endpoint property authSchemes
array node (see here for what I'm talking about) we would consider sigv4a as being registered at the service level for possibly any operation.
NOTE: aws.auth#sigv4a
was added as a known auth scheme/shape id in smithy 1.42.0
val AuthSchemes = RuntimeConfigProperty | ||
.AuthSchemes | ||
.toBuilder() | ||
.apply { | ||
symbol = KotlinTypes.Collections.list(RuntimeTypes.Auth.HttpAuth.AuthScheme, default = "listOf(${RuntimeTypes.Auth.HttpAuthAws.SigV4AsymmetricAuthScheme}(${RuntimeTypes.Auth.Signing.AwsSigningStandard.DefaultAwsSigner}))") | ||
} | ||
.build() | ||
} |
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.
CRT signer as the default for S3. Are there any implications/side effects we would need to worry about when doing that?
Yes, we can't use CRT by default.
Won't users still have to replace the auth scheme with one that uses the CRT signer in order for MRAP to work?
Yes, when testing this though what happens is sigv4 is registered in the model and sigv4a comes from the endpoint rule properties. So we get a prioritized list of auth options [sigv4a, sigv]
after merging those. During selection we see that sigv4a isn't supported/configured and so don't consider it as an option and end up selecting sigv4. This actually works when the access point points to a bucket in the same region that you are configured to sign for. This means users would think sigv4a is working but it's not and in a failover scenario their requests would fail as they wouldn't be valid for a different region. I figured it was better to register support for sigv4a with the default signer and just fail loudly instead with an exception that the signer doesn't support that auth scheme.
A new generated diff is ready to view. |
A new generated diff is ready to view. |
A new generated diff is ready to view. |
A new generated diff is ready to view. |
@@ -54,10 +54,10 @@ class ClientConfigIntegration : KotlinIntegration { | |||
""".trimIndent() | |||
} | |||
|
|||
// FIXME: default signer doesn't yet implement sigv4a, default to mrap OFF until it does | |||
// FIXME: default signer doesn't yet implement sigv4a |
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.
This FIXME can just be removed, it's not descriptive / in the right place anymore
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 good to have some tests for this interceptor
A new generated diff is ready to view. |
override suspend fun modifyBeforeCompletion(context: ResponseInterceptorContext<Any, Any, HttpRequest?, HttpResponse?>): Result<Any> { | ||
context.response.exceptionOrNull()?.let { | ||
if (it is UnsupportedSigningAlgorithm && it.isSigV4a) { | ||
throw UnsupportedSigningAlgorithm( | ||
it.message!!, // TODO: Add a message and link pointing to AWS SDK for Kotlin developer guide | ||
true, | ||
) | ||
} | ||
} | ||
return super.modifyBeforeCompletion(context) | ||
} |
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.
Question: It seems strange to me to throw an exception from this interceptor rather than return one. Would other following interceptors get the chance to modify the UnsupportedSigningAlgorithm
? Does returning the exception achieve the same result?
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.
Does returning the exception achieve the same result?
Yeah, it does👍
I changed it so it returns the exception like you said
if (it is UnsupportedSigningAlgorithm && it.isSigV4a) { | ||
throw UnsupportedSigningAlgorithm( | ||
it.message!!, // TODO: Add a message and link pointing to AWS SDK for Kotlin developer guide | ||
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.
Nit: Use the original UnsupportedSigningAlgorithm
exception as the cause
for the newly-thrown one so the stack trace isn't lost.
) | ||
} | ||
|
||
assertEquals(UnsupportedSigningAlgorithm::class, exception::class) |
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 can use assertIs here
A new generated diff is ready to view. |
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: We still haven't added an E2E test here which I think we should do as a follow-up . Please create a backlog item.
A new generated diff is ready to view. |
Quality Gate passedThe SonarCloud Quality Gate passed, but some issues were introduced. 4 New issues |
A new generated diff is ready to view. |
*/ | ||
class UnsupportedSigningAlgorithmIntegration : KotlinIntegration { | ||
override fun enabledForService(model: Model, settings: KotlinSettings): Boolean = | ||
model.expectShape<ServiceShape>(settings.service).isS3 |
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.
fix: This doesn't match the set of sdkIds where we apply the sigv4a trait customization
mutableSetOf( | ||
SigV4ATrait | ||
.builder() | ||
.name(shape.expectTrait<ServiceTrait>().arnNamespace) |
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.
fix: This should fallback to the sigv4 trait if the arnNamespace isn't present/doesn't match the sigv4 trait.
This value SHOULD match the arnNamespace property of the aws.api#service trait if present and the name property of the aws.auth#sigv4 trait.
.builder() | ||
.name(shape.expectTrait<ServiceTrait>().arnNamespace) | ||
.build(), | ||
AuthTrait(mutableSetOf(SigV4ATrait.ID, SigV4Trait.ID)), |
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.
fix: This isn't right. (1) if the service has an auth
trait applied we need to respect it and modify it rather than replace it. (2) the auth
trait is a prioritized list, this places sigv4a in front of sigv4 which if we configure sigv4a by default then every operation would fail if endpoint rules doesn't return anything for an auth option. The reason it doesn't seem to for S3 right now is they are returning sigv4 and/or sigv4a from their endpoint provider for pretty much every branch. Nothing in endpoint rules dictates this and indeed Eventbridge doesn't appear to return sigv4 anywhere just sigv4a for specific branches (which we appear to have already triggered a customer issue).
See auth trait spec:
Issue #
closes #625
Description of changes
Changed the default auth scheme for S3 and added a test to verify
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.