Skip to content

feat(Go): support DB-ESDK in Go #1861

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

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open

feat(Go): support DB-ESDK in Go #1861

wants to merge 32 commits into from

Conversation

rishav-karanjit
Copy link
Member

@rishav-karanjit rishav-karanjit commented May 5, 2025

Issue #, if available:

Description of changes:

  • Add support for Go runtime
  • This is all reviewed code.
  • middleware.go is the middleware to intercept a DDB call which has been reviewed twice (by Shubham and Andy)

Callout:

  • Creating a PR to check in polymorph code right after this PR gets merged.
  • Will write example and make PR directly to main.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@rishav-karanjit rishav-karanjit changed the title feat(Go): DBESDK Go with some examples and some CI (#1719) feat(Go): Golang reviewed (#1719) May 5, 2025
@rishav-karanjit rishav-karanjit changed the title feat(Go): Golang reviewed (#1719) feat(Go): WIP Golang reviewed May 5, 2025
@rishav-karanjit rishav-karanjit changed the title feat(Go): WIP Golang reviewed feat(Go): WIP support DB-ESDK in Go May 29, 2025
Copy link
Contributor

@ShubhamChaturvedi7 ShubhamChaturvedi7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly questions, otherwise looks good.

options.APIOptions = append(options.APIOptions, func(stack *middleware.Stack) error {
// Add request interceptor at the beginning of Initialize step
requestIntercetor := m.createRequestInterceptor()
if err := stack.Initialize.Add(requestIntercetor, middleware.Before); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: I thought Initialize is where the request object is created. But it we add Interceptor before it, then request must exist. What does Initialize step do then?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A request is created only after Serialize step which comes after Initialize step. Initialize step does the following:

  • takes input parameters and processes them to ensure they're ready for the next steps in the pipeline.
  • Sets default parameters. It fills in any default values that might be needed but weren't explicitly provided in the input.

So, putting a middleware stack before initialize step means that once the input come from application layer, the input will be encrypted then initialize step will get the ciphertext instead of the plaintext

}

func (m DBEsdkMiddleware) createRequestInterceptor() middleware.InitializeMiddleware {
return middleware.InitializeMiddlewareFunc("RequestInterceptor", func(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ID RequestInterceptor is too generic, maybe add something like aws-ddbec-request-interceptor ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will make a PR for this.

}

// handleRequestInterception handles the interception logic before the DynamoDB operation
func (m DBEsdkMiddleware) handleRequestInterception(ctx context.Context, request interface{}) (context.Context, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume operation that is not handled here is passed as it-is (given that this is global interceptor)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is passed as it-is. We only handle 13 APIs for DB-ESDK because it makes sense to only have those and not have something like createTable.

Say, DynamoDB adds a new API which makes sense to include here, we will have to manually update all the interceptors in all the runtimes in DB-ESDK.

This is also what all other runtime does. Example (Java): https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/DynamoDbEncryption/runtimes/java/src/main/java/software/amazon/cryptography/dbencryptionsdk/dynamodb/DynamoDbEncryptionInterceptor.java#L326

switch v := request.(type) {
case *dynamodb.PutItemInput:
ctx = middleware.WithStackValue(ctx, ContextKeyOriginalInput, *v)
// Note: this context is not propagated downstream into dafny layer so it's left as context.TODO() https://issues.amazon.com/CrypTool-5403
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not put the actual context here? So that if Dafny or some other tooling starts accepting it, we don't have to do anything here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I was writing this middleware I thought context.TODO() made more sense as we don't support context yet. But, as I think now, if we send the context now then we don't have do to anything if dafny starts accepting one.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will make a PR for this.

if err != nil {
return nil, err
}
*v = transformedRequest.TransformedInput
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: if v is pointer type, I assume we are assigning value of TransformedInput to v and not address because we don't want to mutate the TransformedInput ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Its because we want to change content of v globally not just locally. *v = transformedRequest.TransformedInput means that it take a memory location that v points to and override the contents with the transformed input.

If we had done v = &transformedRequest.TransformedInput, this does not change the original v. We are just making a local variable v point to some different address and when the function returns the change to local variable is lost.

out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
) {
// First let the request complete
result, metadata, err := next.HandleFinalize(ctx, in)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't middleware.After mean the interceptor will be executed after the request is done?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we get a response from transportation layer, it goes back to application layer in the reverse order of request (Deserialize -> Finalize -> Build -> Serialize -> Initialize). Adding after finalize means that after the final message (which will be a ciphertext) is prepared, we decrypt the message and send it to Build step.

@rishav-karanjit rishav-karanjit changed the title feat(Go): WIP support DB-ESDK in Go feat(Go): support DB-ESDK in Go Jun 3, 2025
@rishav-karanjit rishav-karanjit marked this pull request as ready for review June 4, 2025 18:03
@rishav-karanjit rishav-karanjit requested a review from a team as a code owner June 4, 2025 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants